Index: DynamicPageList.php
===================================================================
RCS file: /cvsroot/wikipedia/extensions/intersection/DynamicPageList.php,v
retrieving revision 1.9
diff -u -r1.9 DynamicPageList.php
--- DynamicPageList.php 26 Aug 2005 17:59:22 -0000      1.9
+++ DynamicPageList.php 2 Dec 2005 22:00:25 -0000
@@ -6,9 +6,11 @@
                 of several categories.
 
 
- Contributors: n:en:User:IlyaHaykinson n:en:User:Amgine
+ Contributors: 
+ n:en:User:IlyaHaykinson n:en:User:Amgine w:de:Benutzer:Unendlich
  http://en.wikinews.org/wiki/User:Amgine
  http://en.wikinews.org/wiki/User:IlyaHaykinson
+ http://de.wikipedia.org/wiki/Benutzer:Unendlich
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
@@ -26,13 +28,13 @@
  http://www.gnu.org/copyleft/gpl.html
 
  Current feature request list
-     1. Unset cached of calling page
-     2. Alternative formatting (not just unordered list)
-     3. Configurable sort order, ascending/descending
-     4. RSS feed output?
+     1. RSS feed output?
 
  To install, add following to LocalSettings.php
    include("extensions/intersection/DynamicPageList.php");
+*
+@module DynamicPageList
+@version $ID 2.0$
 
 */
 
@@ -56,330 +58,436 @@
     global $wgParser, $wgMessageCache;
    
     $wgMessageCache->addMessages( array(
-                                       'dynamicpagelist_toomanycats' => 'DynamicPageList: Too many categories!',
-                                       'dynamicpagelist_toofewcats' => 'DynamicPageList: Too few categories!',
-                                       'dynamicpagelist_noresults' => 'DynamicPageList: No results!',
-                                       'dynamicpagelist_noincludecats' => 'DynamicPageList: You need to include at least one category, or specify a namespace!',
+                                       'dynamicpagelist_toomanycats'                                   => 'DynamicPageList: Too many categories!',
+                                       'dynamicpagelist_toofewcats'                                    => 'DynamicPageList: Too few categories!',
+                                       'dynamicpagelist_noresults'                                             => 'DynamicPageList: No results!',
+                                       'dynamicpagelist_noincludecats'                                 => 'DynamicPageList: You need to include at least one category, or specify a namespace!',
+                                       'dynamicpagelist_noincludedcatsbutcatdate'              => 'DynamicPageList: You need to include at least one category to use \'addfirstcategorydate=true\' or \'ordermethod=categoryadd\'!',
+                                       'dynamicpagelist_morethanonecatbutcatdate'              => 'DynamicPageList: If you include more than one category you cannot use \'addfirstcategorydate=true\' or \'ordermethod=categoryadd\'!',
+                                       'dynamicpagelist_catoutputwithwrongordermethod' => 'DynamicPageList: You need to use \'ordermethod=title\' when using category-style output!',
+
                                        )
                                  );
 
     $wgParser->setHook( "DynamicPageList", "DynamicPageList" );
 }
- 
-// The callback function for converting the input text to HTML output
-function DynamicPageList( $input ) {
-    global $wgUser;
-    global $wgLang;
-    global $wgContLang;
-    global $wgDLPminCategories, $wgDLPmaxCategories,$wgDLPMinResultCount, $wgDLPMaxResultCount;
-    global $wgDLPAllowUnlimitedResults, $wgDLPAllowUnlimitedCategories;
-     
-    $aParams = array();
-    $bCountSet = false;
-
-    $sStartList = '<ul>';
-    $sEndList = '</ul>';
-    $sStartItem = '<li>';
-    $sEndItem = '</li>';
-
-    $sOrderMethod = 'categoryadd';
-    $sOrder = 'descending';
-    $sRedirects = 'exclude';
-
-    $bNamespace = false;
-    $iNamespace = 0;
-
-    $bSuppressErrors = false;
-    $bShowNamespace = true;
-    $bAddFirstCategoryDate = false;
-
-    $aParams = explode("\n", $input);
-
-    foreach($aParams as $sParam)
-    {
-      $aParam = explode("=", $sParam);
-      if( count( $aParam ) < 2 )
-         continue;
-      $sType = trim($aParam[0]);
-      $sArg = trim($aParam[1]);
-      if ($sType == 'category')
-      {
-        $title = Title::newFromText( $sArg );
-        if( is_null( $title ) )
-          continue;
-        $aCategories[] = $title; 
-      }
-      else if ($sType == 'notcategory')
-      {
-        $title = Title::newFromText( $sArg );
-        if( is_null( $title ) )
-          continue;
-        $aExcludeCategories[] = $title; 
-      }
-      else if ('namespace' == $sType)
-      {
-        $ns = $wgContLang->getNsIndex($sArg);
-       if (NULL != $ns)
-       {
-         $iNamespace = $ns;
-         $bNamespace = true;
-       }
-       else
-       {
-         $iNamespace = intval($sArg);
-         if ($iNamespace >= 0)
-         {
-           $bNamespace = true;
-         }
-         else
-         {
-           $bNamespace = false;
-         }
-       }
-      }
-      else if ('count' == $sType)
-      {
-        //ensure that $iCount is a number;
-        $iCount = IntVal( $sArg );
-        $bCountSet = true;
-      }
-      else if ('mode' == $sType)
-      {
-       switch ($sArg)
-       {
-       case 'none':
-         $sStartList = '';
-         $sEndList = '';
-         $sStartItem = '';
-         $sEndItem = '<br/>';
-         break;
-       case 'ordered':
-         $sStartList = '<ol>';
-         $sEndList = '</ol>';
-         $sStartItem = '<li>';
-         $sEndItem = '</li>';
-         break;
-       case 'unordered':
-       default:
-         $sStartList = '<ul>';
-         $sEndList = '</ul>';
-         $sStartItem = '<li>';
-         $sEndItem = '</li>';
-         break;
-       }
-      }
-      else if ('order' == $sType)
-      {
-        switch ($sArg)
-       {
-       case 'ascending':
-         $sOrder = 'ascending';
-         break;
-       case 'descending':
-       default:
-         $sOrder = 'descending';
-         break;
-       }
-      }
-      else if ('ordermethod' == $sType)
-      {
-       switch ($sArg)
-       {
-       case 'lastedit':
-         $sOrderMethod = 'lastedit';
-         break;
-       case 'categoryadd':
-       default:
-         $sOrderMethod = 'categoryadd';
-         break;
-       }
-      }
-      else if ('redirects' == $sType)
-      {
-       switch ($sArg)
-       {
-       case 'include':
-         $sRedirects = 'include';
-         break;
-       case 'only':
-         $sRedirects = 'only';
-         break;
-       case 'exclude':
-       default:
-         $sRedirects = 'exclude';
-         break;
-       }
-      }
-      else if ('suppresserrors' == $sType)
-      {
-       if ('true' == $sArg)
-         $bSuppressErrors = true;
-       else
-         $bSuppressErrors = false;
-      }
-      else if ('addfirstcategorydate' == $sType)
-      {
-        if ('true' == $sArg)
-          $bAddFirstCategoryDate = true;
-        else
-          $bAddFirstCategoryDate = false;
-      }
-      else if ('shownamespace' == $sType)
-      {
-       if ('false' == $sArg)
-         $bShowNamespace = false;
-       else
-         $bShowNamespace = true;
-      }
-    }
 
-    $iCatCount = count($aCategories);
-    $iExcludeCatCount = count($aExcludeCategories);
-    $iTotalCatCount = $iCatCount + $iExcludeCatCount;
-
-    if ($iCatCount < 1 && false == $bNamespace)
-    {
-      if (false == $bSuppressErrors)
-       return htmlspecialchars( wfMsg( 'dynamicpagelist_noincludecats' ) ); // "!!no included categories!!";
-      else
-       return '';
-    }
-
-    if ($iTotalCatCount < $wgDLPminCategories)
-    {
-      if (false == $bSuppressErrors)
-       return htmlspecialchars( wfMsg( 'dynamicpagelist_toofewcats' ) ); // "!!too few categories!!";
-      else
-       return '';
-    }
-
-    if ( $iTotalCatCount > $wgDLPmaxCategories && !$wgDLPAllowUnlimitedCategories )
-    {
-      if (false == $bSuppressErrors)
-       return htmlspecialchars( wfMsg( 'dynamicpagelist_toomanycats' ) ); // "!!too many categories!!";
-      else
-       return '';
-    }
-
-    if ($bCountSet)
-    {
-      if ($iCount < $wgDLPMinResultCount)
-        $iCount = $wgDLPMinResultCount;
-      if ($iCount > $wgDLPMaxResultCount)
-        $iCount = $wgDLPMaxResultCount;
-    }
-    else
-    {
-      if (!$wgDLPAllowUnlimitedResults)
-      {
-        $iCount = $wgDLPMaxResultCount;
-        $bCountSet = true;
-      }
-    }
-    
-    //disallow showing date if the query doesn't have an inclusion category parameter
-    if ($iCatCount < 1)
-      $bAddFirstCategoryDate = false;
-
-
-    //build the SQL query
-    $dbr =& wfGetDB( DB_SLAVE );
-    $sPageTable = $dbr->tableName( 'page' );
-    $categorylinks = $dbr->tableName( 'categorylinks' );
-    $sSqlSelectFrom = "SELECT page_namespace, page_title, c1.cl_timestamp FROM $sPageTable";
-
-    if (true == $bNamespace)
-      $sSqlWhere = ' WHERE page_namespace='.$iNamespace.' ';
-    else
-      $sSqlWhere = ' WHERE 1=1 ';
-      
-    switch ($sRedirects)
-    {
-      case 'only':
-        $sSqlWhere .= ' AND page_is_redirect = 1 ';
-        break;
-      case 'exclude':
-        $sSqlWhere .= ' AND page_is_redirect = 0 ';
-        break;
-    }
-
-    $iCurrentTableNumber = 0;
-
-    for ($i = 0; $i < $iCatCount; $i++) {
-      $sSqlSelectFrom .= " INNER JOIN $categorylinks AS c" . ($iCurrentTableNumber+1);
-      $sSqlSelectFrom .= ' ON page_id = c'.($iCurrentTableNumber+1).'.cl_from';
-      $sSqlSelectFrom .= ' AND c'.($iCurrentTableNumber+1).'.cl_to='.
-        $dbr->addQuotes( $aCategories[$i]->getDbKey() );
-
-      $iCurrentTableNumber++;
-    }
+       /* **
+        * function: setParams
+        * **
+        * Purpose: constructor, parse parameters
+        * parameters
+        *      aCategories                             ARRAY   category names
+        *      aExcludeCategories              ARRAY   notcategory names
+        *      bShowNamespace                  BOOL    true = show namespace in link
+        *      bNamespace                              BOOL    true = only from namespace
+        *      iNamspace                               INTEGER namespace id
+        *      sOrder                                  STRING  sorting direction
+        *      sOrderMethod                    STRING  method of sorting to use
+        *      bSuppressErrors                 BOOL    true = do not return errors
+        *      sRedirects                              STRING  show, show only, or exclude redirects
+        *      bAddFirstCategoryDate   BOOL    display date added to 1st category
+        *      sStartList                              STRING  HTML list type opening tag
+        *      sEndList                                STRING  HTML list type closing tag
+        *      sStartItem                              STRING  HTML list item opening tag
+        *      sEndItem                                STRING  HTML list item closing tag
+        *      iCatCount                               INTEGER count of include categories
+        *      iExcludeCatCount                INTEGER count of exclued categories
+        *      iTotalCatCount                  INTEGER count of both included and excluded
+        *      bCountSet                               BOOL    true = final category count determined
+        *      iCount                                  INTEGER total categories
+        * **
+        * @param STRING $input
+        * @return ARRAY $aParameters
+        * ** */
+function setParams ( $input ) {
+       // Globals
+       global $wgContLang, $wgDLPminCategories;
+       global $wgDLPmaxCategories, $wgDLPMinResultCount, $wgDLPMaxResultCount;
+       global $wgDLPAllowUnlimitedResults, $wgDLPAllowUnlimitedCategories;
+
+       $aParameters = array(
+               'aCategories' => array(),
+               'aExcludeCategories' => array(),
+               'bShowNamespace' => true,
+               'aNamespace' => array(),
+               'abNamespace' => array(),
+               'sOrder' => 'descending',
+               'sOrderMethod' => 'lastedit',
+               'bSuppressErrors' => false,
+               'sRedirects' => 'exclude',
+               'bAddFirstCategoryDate' => false,
+               'sStartList' => '<ul>',
+               'sEndList' => '</ul>',
+               'sStartItem' => '<li>',
+               'sEndItem' => '</li>'
+               );
+
+       $aParams = explode("\n", $input);
+
+       // Loop through passed parameters
+       foreach ($aParams as $sParam) {
+               $aParam = explode('=', $sParam);
+
+               // if improper, skip
+               if (  count( $aParam ) < 2 ) continue;
 
-    for ($i = 0; $i < $iExcludeCatCount; $i++) {
-      $sSqlSelectFrom .= " LEFT OUTER JOIN $categorylinks AS c" . ($iCurrentTableNumber+1);
-      $sSqlSelectFrom .= ' ON page_id = c'.($iCurrentTableNumber+1).'.cl_from';
-      $sSqlSelectFrom .= ' AND c'.($iCurrentTableNumber+1).'.cl_to='.
-        $dbr->addQuotes( $aExcludeCategories[$i]->getDbKey() );
+               $sType = trim($aParam[0]);
+               $sArg = trim($aParam[1]);
+
+               switch ( $sType ) {
+                       case 'category':
+                               $aCats = explode(',', $sArg);
+                               $aaCats = array();
+                               foreach($aCats as $sParam) {
+                                       $sParam=trim($sParam);
+                                       $title = Title::newFromText( $sParam );
+                                       if( $title != NULL ) $aaCats[] = $title;
+                               }
+                               if (!empty($aaCats)) $aParameters['aCategories'][] = $aaCats;
+                               break;
+                       case 'notcategory':
+                               $title = Title::newFromText( $sArg );
+                               // if not a real category, skip
+                               if( is_null( $title ) ) continue;
+                               $aParameters['aExcludeCategories'][] = $title;
+                               break;
+                       case 'namespace':
+                               $aNS = explode(',', $sArg);
+                               if (count($aNS)) {
+                                       // If second namespace assignment, reset the array
+                                       $aParameters['aNamespace'] = array();
+                                       $aParameters['abNamespace'] = array();
+                                       foreach ($aNS as $key => $sNS) {
+                                               $sNS = trim($sNS);
+                                               // check valid namespace value
+                                               $ns = $wgContLang->getNsIndex($sNS);
+                                               if (NULL != $ns) {
+                                                       $aParameters['aNamespace'][$key] = $ns;
+                                                       $aParameters['abNamespace'][$key] = true;
+                                               } else {
+                                                       $aParameters['aNamespace'][$key] = intval($sNS);
+                                                       if ($aParameters['aNamespace'][$key] >= 0) {
+                                                               $aParameters['abNamespace'][$key] = true;
+                                                       } else {
+                                                               $aParameters['abNamespace'][$key] = false;
+                                                       }
+                                               }
+                                       }
+                               }
+                               break;
+                       case 'shownamespace':
+                               if ('false' == $sArg) $aParameters['bShowNamespace'] = false;
+                               else $aParameters['bShowNamespace'] = true;
+                               break;
+                       case 'mode':
+                               switch ($sArg) {
+                                       case 'none':
+                                               $aParameters['sStartList'] = '';
+                                               $aParameters['sEndList'] = '';
+                                               $aParameters['sStartItem'] = '';
+                                               $aParameters['sEndItem'] = '<br/>';
+                                               $aParameters['bLastEndItem'] = false;
+                                               break;
+                                       case 'inline':
+                                               $aParameters['sStartList'] = '';
+                                               $aParameters['sEndList'] = '';
+                                               $aParameters['sStartItem'] = '';
+                                               $aParameters['sEndItem'] = ' - ';
+                                               $aParameters['bLastEndItem'] = false;
+                                               break;
+                                       case 'ordered':
+                                               $aParameters['sStartList'] = '<ol>';
+                                               $aParameters['sEndList'] = '</ol>';
+                                               $aParameters['sStartItem'] = '<li>';
+                                               $aParameters['sEndItem'] = '</li>';
+                                               $aParameters['bLastEndItem'] = true;
+                                               break;
+                                       case 'unordered':
+                                       default:
+                                               $aParameters['sStartList'] = '<ul>';
+                                               $aParameters['sEndList'] = '</ul>';
+                                               $aParameters['sStartItem'] = '<li>';
+                                               $aParameters['sEndItem'] = '</li>';
+                                               $aParameters['bLastEndItem'] = true;
+                               }
+                               break;
+                       case 'order':
+                               switch ($sArg) {
+                                       case 'ascending':
+                                               $aParameters['sOrder'] = 'ascending';
+                                               break;
+                                       case 'descending':
+                                       default:
+                                               $aParameters['sOrder'] = 'descending';
+                               }
+                               break;
+                       case 'ordermethod':
+                               switch ($sArg) {
+                                       case 'lastedit':
+                                               $aParameters['sOrderMethod'] = 'lastedit';
+                                               break;
+                                       case 'categoryadd':
+                                       default:
+                                               $aParameters['sOrderMethod'] = 'categoryadd';
+                               }
+                               break;
+                       case 'count':
+                               $aParameters['iCount'] = IntVal( $sArg );
+                               $aParameters['bCountSet'] = true;
+                               break;
+                       case 'suppresserrors':
+                               if ('true' == $sArg) $aParameters['bSuppressErrors'] = true;
+                               else $aParameters['bSuppressErrors'] = false;
+                               break;
+                       case 'redirects':
+                               switch ($sArg) {
+                                       case 'include':
+                                               $aParameters['sRedirects'] = 'include';
+                                               break;
+                                       case 'only':
+                                               $aParameters['sRedirects'] = 'only';
+                                               break;
+                                       case 'exclude':
+                                       default:
+                                               $aParameters['sRedirects'] = 'exclude';
+                               }
+                               break;
+                       case 'addfirstcategorydate':
+                               if ('true' == $sArg) $aParameters['bAddFirstCategoryDate'] = true;
+                               else $aParameters['bAddFirstCategoryDate'] = false;
+                               break;
+                       default:
+               }
+       }
 
-      $sSqlWhere .= ' AND c'.($iCurrentTableNumber+1).'.cl_to IS NULL';
+       // Calculate and check category counts against configuration limits
+
+       $aParameters['iCatCount'] = count($aParameters['aCategories']);
+       $aParameters['iTotalIncludeCatCount'] = count($aParameters['aCategories'], COUNT_RECURSIVE) - $aParameters['iCatCount'];
+       $aParameters['iExcludeCatCount'] = count($aParameters['aExcludeCategories']);
+       $aParameters['iTotalCatCount'] = $aParameters['iCatCount'] + $aParameters['iExcludeCatCount'];
+
+       // 'DynamicPageList: You need to include at least one category, or specify a namespace!'
+       if ($aParameters['iCatCount'] < 1 && !count($aParameters['abNamespace'])) {
+               if (false == $aParameters['bSuppressErrors']) {
+                       return htmlspecialchars( wfMsg( 'dynamicpagelist_noincludecats' ) ); 
+               } else return '';
+       }
+
+       // 'DynamicPageList: Too few categories!'
+       if ($aParameters['iTotalIncludeCatCount'] < $wgDLPminCategories && !count($aParameters['abNamespace'])) {
+               if (false == $aParameters['bSuppressErrors']) {
+                       echo $aParameters['iTotalIncludeCatCount'], $wgDLPminCategories;
+                       return htmlspecialchars( wfMsg( 'dynamicpagelist_toofewcats' ) );
+               } else return '';
+       }
+       // 'DynamicPageList: Too many categories!'
+       if ( $aParameters['iTotalCatCount'] > $wgDLPmaxCategories && !$wgDLPAllowUnlimitedCategories ) {
+               if (false == $aParameters['bSuppressErrors'])
+                       return htmlspecialchars( wfMsg( 'dynamicpagelist_toomanycats' ) ); 
+               else return '';
+       }
+       // DynamicPageList: You need to include at least one category to use \'addfirstcategorydate=true\' or \'ordermethod=categoryadd\'!
+       if ( $aParameters['iCatCount'] == 0 && ($aParameters['sOrderMethod'] == 'categoryadd' || $aParameters['bAddFirstCategoryDate'] == true) ) {
+               if (false == $aParameters['bSuppressErrors'])
+                       return htmlspecialchars( wfMsg( 'dynamicpagelist_noincludedcatsbutcatdate' ) );
+               else return '';
+       }
+       // DynamicPageList: If you include more than one category you cannot use \'addfirstcategorydate=true\' or \'ordermethod=categoryadd\'!
+       if ($aParameters['iTotalCatCount'] > 1 && ($aParameters['sOrderMethod'] == 'categoryadd' || $aParameters['bAddFirstCategoryDate'] == true) ) {
+               if (false == $aParameters['bSuppressErrors'])
+                       return htmlspecialchars( wfMsg( 'dynamicpagelist_morethanonecatbutcatdate' ) );
+               else return '';
+       }
+       // DynamicPageList: You need to use \'ordermethod=title\' when using category-style output!
+       if ($aParameters['sOutputMode'] == 'category' && $aParameters['sOrderMethod'] != 'title') {
+               if (false == $aParameters['bSuppressErrors'])
+                       return htmlspecialchars( wfMsg( 'dpl2_catoutputwithwrongordermethod' ) );
+               else return '';
+       }
+
+       if ($aParameters['bCountSet']) {
+               if ($aParameters['iCount'] < $wgDLPMinResultCount) $aParameters['iCount'] = $wgDLPMinResultCount;
+               if ($aParameters['iCount'] > $wgDLPMaxResultCount) $aParameters['iCount'] = $wgDLPMaxResultCount;
+       } else {
+               if (!$wgDLPAllowUnlimitedResults) {
+                       $aParameters['iCount'] = $wgDLPMaxResultCount;
+                       $aParameters['bCountSet'] = true;
+               }
+       }
+
+       // prevent display of date when no include category defined
+       if ($aParameters['iCatCount'] < 1) $aParameters['bAddFirstCategoryDate'] = false;
+
+       return $aParameters;
+}
+
+/* **
+ * function: BuildSQL
+ * **
+ * Purpose: build the necessary SQL statement for the given parameters
+ * **
+ * @return STRING SQL query
+ * ** */
+function BuildSQL ( $aParameters ) {
+       // Globals
+
+       $dbr =& wfGetDB( DB_SLAVE );
 
-      $iCurrentTableNumber++;
+       //build the SQL query
+       $sPageTable = $dbr->tableName( 'page' );
+       $categorylinks = $dbr->tableName( 'categorylinks' );
+       if ($aParameters['iTotalIncludeCatCount'] == 1) 
+               $sSqlSelectFrom = "SELECT DISTINCT page_namespace, page_touched, page_title, c1.cl_timestamp FROM $sPageTable";
+       else
+               $sSqlSelectFrom = "SELECT DISTINCT page_namespace, page_touched, page_title FROM $sPageTable";
+
+       // Set the selectfrom
+       $iCurrentTableNumber = 0;
+
+    for ($i = 0; $i < $aParameters['iCatCount']; $i++) {
+               $sSqlSelectFrom .= " INNER JOIN $categorylinks AS c" . ($iCurrentTableNumber+1);
+               $sSqlSelectFrom .= ' ON page_id = c'.($iCurrentTableNumber+1).'.cl_from';
+               $sSqlSelectFrom .= ' AND (c'.($iCurrentTableNumber+1).'.cl_to='. $dbr->addQuotes( $aParameters['aCategories'][$i][0]->getDbKey() );
+               for ($j = 1; $j < count($aParameters['aCategories'][$i]); $j++) {
+                       $sSqlSelectFrom .= ' OR c' . ($iCurrentTableNumber+1) . '.cl_to=' . $dbr->addQuotes( $aParameters['aCategories'][$i][$j]->getDbKey() );
+               }
+               $sSqlSelectFrom .= ') ';
+               $iCurrentTableNumber++;
     }
+
+       // if namespace
+       $i = count($aParameters['abNamespace']);
+       if ($i > 0) {
+               $sSqlWhere = ' WHERE (page_namespace=' . $aParameters['aNamespace'][0] . ' ';
+               if ($i > 1) {
+                       for ($i = 1; $i < count($aParameters['aNamespace']); $i++ ) {
+                               if (true == $aParameters['abNamespace'][$i])
+                                       $sSqlWhere .= ' OR page_namespace=' . $aParameters['aNamespace'][$i];
+                       }
+               }
+               $sSqlWhere .= ') ';
+       }
+       // if only or exclude redirects...
+    switch ($aParameters['sRedirects']) {
+               case 'only':
+                       if (isset($sSqlWhere)) $sSqlWhere .= ' AND page_is_redirect = 1 ';
+                       else $sSqlWhere = ' WHERE page_is_redirect = 1 ';
+                       break;
+               case 'exclude':
+                       if (isset($sSqlWhere)) $sSqlWhere .= ' AND page_is_redirect = 0 ';
+                       else $sSqlWhere = ' WHERE page_is_redirect = 0 ';
+                       break;
+       }
+       if (!isset($sSqlWhere)) $sSqlWhere = ' WHERE 1=1 ';
+
+       for ($i = 0; $i < $aParameters['iExcludeCatCount']; $i++) {
+               $sSqlSelectFrom .= " LEFT OUTER JOIN $categorylinks AS c" . ($iCurrentTableNumber+1);
+               $sSqlSelectFrom .= ' ON page_id = c'.($iCurrentTableNumber+1).'.cl_from';
+               $sSqlSelectFrom .= ' AND c'.($iCurrentTableNumber+1).'.cl_to='.
+        $dbr->addQuotes( $aParameters['aExcludeCategories'][$i]->getDbKey() );
+
+               $sSqlWhere .= ' AND c'.($iCurrentTableNumber+1).'.cl_to IS NULL';
+
+               $iCurrentTableNumber++;
+       }
+
+       // Set the sort method, direction
+       switch ($aParameters['sOrderMethod']) {
+               case 'lastedit':
+                       $sSqlWhere .= ' ORDER BY page_touched ';
+                       break;
+               case 'categoryadd':
+                       $sSqlWhere .= ' ORDER BY c1.cl_timestamp ';
+                       break;
+               case 'title':
+               default:
+                       $sSqlWhere .= ' ORDER BY page_title ';
+                       break;
+       }
+
+       if ('descending' == $aParameters['sOrder']) $sSqlWhere .= 'DESC';
+       else $sSqlWhere .= 'ASC';
+
+       // if count parameter set
+       if ($aParameters['bCountSet']) $sSqlWhere .= ' LIMIT ' . $aParameters['iCount'];
 
-    if ('descending' == $sOrder)
-      $sSqlOrder = 'DESC';
-    else
-      $sSqlOrder = 'ASC';
-
-    if ('lastedit' == $sOrderMethod)
-      $sSqlWhere .= ' ORDER BY page_touched ';
-    else
-      $sSqlWhere .= ' ORDER BY c1.cl_timestamp ';
-
-    $sSqlWhere .= $sSqlOrder;
-    
 
-    if ($bCountSet)
-    {
-      $sSqlWhere .= ' LIMIT ' . $iCount;
-    }
+       return $sSqlSelectFrom . $sSqlWhere;
+}
 
-    //DEBUG: output SQL query 
-    //$output .= 'QUERY: [' . $sSqlSelectFrom . $sSqlWhere . "]<br />";    
+function processQuery ( $sSql, $aParameters ) {
+       // Globals
+       global $wgUser, $wgLang;
+
+       $dbr =& wfGetDB( DB_SLAVE );
+
+       //DEBUG: output SQL query 
+       $output .= "QUERY: [{$sSql}]<br /><br />";    
 
     // process the query
-    $res = $dbr->query($sSqlSelectFrom . $sSqlWhere);
+    $res = $dbr->query($sSql);
 
     $sk =& $wgUser->getSkin();
 
-    if ($dbr->numRows( $res ) == 0) 
-    {
-      if (false == $bSuppressErrors)
-       return htmlspecialchars( wfMsg( 'dynamicpagelist_noresults' ) );
-      else
-       return '';
+       // if no results returned
+    if ($dbr->numRows( $res ) == 0) {
+               if (false == $aParameters['bSuppressErrors'])
+                       return $output . htmlspecialchars( wfMsg( 'dynamicpagelist_noresults' ) );
+               else return '';
     }
+
     
-    //start unordered list
-    $output .= $sStartList . "\n";
+       // Display the output
+    //start list
+    $output .= $aParameters['sStartList'] . "\n";
 
     //process results of query, outputing equivalent of <li>[[Article]]</li> for each result,
     //or something similar if the list uses other startlist/endlist
     while ($row = $dbr->fetchObject( $res ) ) {
-      $title = Title::makeTitle( $row->page_namespace, $row->page_title);
-      $output .= $sStartItem;
-      if (true == $bAddFirstCategoryDate)
-        $output .= $wgLang->date($row->cl_timestamp) . ': ';
-
-      if (true == $bShowNamespace)
-       $output .= $sk->makeKnownLinkObj($title);
-      else
-       $output .= $sk->makeKnownLinkObj($title, htmlspecialchars($title->getText()));
-      $output .= $sEndItem . "\n";
+               $title = Title::makeTitle( $row->page_namespace, $row->page_title);
+               $output .= $aParameters['sStartItem'];
+               if (true == $aParameters['bAddFirstCategoryDate'])
+                       $output .= $wgLang->date($row->cl_timestamp) . ': ';
+
+               if (true == $aParameters['bShowNamespace'])
+                       $output .= $sk->makeKnownLinkObj($title);
+               else 
+                       $output .= $sk->makeKnownLinkObj($title, htmlspecialchars($title->getText()));
+               $output .= $aParameters['sEndItem'] . "\n";
     }
 
     //end unordered list
-    $output .= $sEndList . "\n";
+    $output .= $aParameters['sEndList'] . "\n";                                                              
+
+       return $output;
 
-    return $output;
+}
+ 
+// The callback function for converting the input text to HTML output
+function DynamicPageList( $input ) {
+
+    // Disable page cache
+    global $wgTitle;
+    $dbw =& wfGetDB( DB_MASTER );
+    $dbw->update( 'page', array( 'page_touched' => $dbw->timestamp( time() + 120 )), 
+       array( 
+               'page_namespace' => $wgTitle->getNamespace(), 
+               'page_title' => $wgTitle->getDBkey() 
+               ), 'DynamicPageList'
+       );
+
+       // parse the parameters
+       $aParameters = setParams( $input );
+       if (!is_array($aParameters)) return $aParameters;
+
+       // build the query
+       $sSql = BuildSql( $aParameters );
+
+       // Get output
+       $output = processQuery( $sSql, $aParameters );
+
+       return $output;
 }
 ?>