* API: pageSet now supports pageids, revised revisions listings, lots of examples.
authorYuri Astrakhan <yurik@users.mediawiki.org>
Sun, 1 Oct 2006 20:17:16 +0000 (20:17 +0000)
committerYuri Astrakhan <yurik@users.mediawiki.org>
Sun, 1 Oct 2006 20:17:16 +0000 (20:17 +0000)
15 files changed:
includes/api/ApiBase.php
includes/api/ApiFormatJson.php
includes/api/ApiFormatXml.php
includes/api/ApiFormatYaml.php
includes/api/ApiHelp.php
includes/api/ApiLogin.php
includes/api/ApiMain.php
includes/api/ApiPageSet.php
includes/api/ApiQuery.php
includes/api/ApiQueryAllpages.php
includes/api/ApiQueryBase.php
includes/api/ApiQueryInfo.php
includes/api/ApiQueryRevisions.php
includes/api/ApiQuerySiteinfo.php
includes/api/ApiResult.php

index d0aab37..c145b1d 100644 (file)
@@ -70,8 +70,7 @@ abstract class ApiBase {
                // Main module has getResult() method overriden
                // Safety - avoid infinite loop:
                if ($this->isMain())
-                       ApiBase :: dieDebug(__METHOD__ .
-                       ' base method was called on main module. ');
+                       ApiBase :: dieDebug(__METHOD__, 'base method was called on main module. ');
                return $this->getMain()->getResult();
        }
 
@@ -189,9 +188,9 @@ abstract class ApiBase {
                        $multi = false;
                        $type = gettype($paramSettings);
                } else {
-                       $default = isset ($paramSettings[self::PARAM_DFLT]) ? $paramSettings[self::PARAM_DFLT] : null;
-                       $multi = isset ($paramSettings[self::PARAM_ISMULTI]) ? $paramSettings[self::PARAM_ISMULTI] : false;
-                       $type = isset ($paramSettings[self::PARAM_TYPE]) ? $paramSettings[self::PARAM_TYPE] : null;
+                       $default = isset ($paramSettings[self :: PARAM_DFLT]) ? $paramSettings[self :: PARAM_DFLT] : null;
+                       $multi = isset ($paramSettings[self :: PARAM_ISMULTI]) ? $paramSettings[self :: PARAM_ISMULTI] : false;
+                       $type = isset ($paramSettings[self :: PARAM_TYPE]) ? $paramSettings[self :: PARAM_TYPE] : null;
 
                        // When type is not given, and no choices, the type is the same as $default
                        if (!isset ($type)) {
@@ -205,7 +204,7 @@ abstract class ApiBase {
                if ($type == 'boolean') {
                        if (isset ($default) && $default !== false) {
                                // Having a default value of anything other than 'false' is pointless
-                               ApiBase :: dieDebug("Boolean param $paramName's default is set to '$default'");
+                               ApiBase :: dieDebug(__METHOD__, "Boolean param $paramName's default is set to '$default'");
                        }
 
                        $value = $wgRequest->getCheck($paramName);
@@ -228,25 +227,26 @@ abstract class ApiBase {
                                        $value = is_array($value) ? array_map('intval', $value) : intval($value);
                                        break;
                                case 'limit' :
-                                       if (!isset ($paramSettings[self::PARAM_MAX1]) || !isset ($paramSettings[self::PARAM_MAX2]))
-                                               ApiBase :: dieDebug("MAX1 or MAX2 are not defined for the limit $paramName");
+                                       if (!isset ($paramSettings[self :: PARAM_MAX1]) || !isset ($paramSettings[self :: PARAM_MAX2]))
+                                               ApiBase :: dieDebug(__METHOD__, "MAX1 or MAX2 are not defined for the limit $paramName");
                                        if ($multi)
-                                               ApiBase :: dieDebug("Multi-values not supported for $paramName");
-                                       $min = isset ($paramSettings[self::PARAM_MIN]) ? $paramSettings[self::PARAM_MIN] : 0;
+                                               ApiBase :: dieDebug(__METHOD__, "Multi-values not supported for $paramName");
+                                       $min = isset ($paramSettings[self :: PARAM_MIN]) ? $paramSettings[self :: PARAM_MIN] : 0;
                                        $value = intval($value);
-                                       $this->validateLimit($paramName, $value, $min, $paramSettings[self::PARAM_MAX1], $paramSettings[self::PARAM_MAX2]);
+                                       $this->validateLimit($paramName, $value, $min, $paramSettings[self :: PARAM_MAX1], $paramSettings[self :: PARAM_MAX2]);
                                        break;
                                case 'boolean' :
                                        if ($multi)
-                                               ApiBase :: dieDebug("Multi-values not supported for $paramName");
+                                               ApiBase :: dieDebug(__METHOD__, "Multi-values not supported for $paramName");
                                        break;
                                case 'timestamp' :
                                        if ($multi)
-                                               ApiBase :: dieDebug("Multi-values not supported for $paramName");
-                                       $value = $this->prepareTimestamp($value); // Adds quotes around timestamp                                                       
+                                               ApiBase :: dieDebug(__METHOD__, "Multi-values not supported for $paramName");
+                                       if (!preg_match('/^[0-9]{14}$/', $value))
+                                               $this->dieUsage("Invalid value '$value' for timestamp parameter $paramName", "badtimestamp_{$valueName}");
                                        break;
                                default :
-                                       ApiBase :: dieDebug("Param $paramName's type is unknown - $type");
+                                       ApiBase :: dieDebug(__METHOD__, "Param $paramName's type is unknown - $type");
 
                        }
                }
@@ -280,17 +280,6 @@ abstract class ApiBase {
                return $allowMultiple ? $valuesList : $valuesList[0];
        }
 
-       /**
-       * Validate the proper format of the timestamp string (14 digits), and add quotes to it.
-       */
-       function prepareTimestamp($value) {
-               if (preg_match('/^[0-9]{14}$/', $value)) {
-                       return $this->db->addQuotes($value);
-               } else {
-                       $this->dieUsage('Incorrect timestamp format', 'badtimestamp');
-               }
-       }
-
        /**
        * Validate the value against the minimum and user/bot maximum limits. Prints usage info on failure.
        */
@@ -305,10 +294,9 @@ abstract class ApiBase {
                        if ($value > $botMax) {
                                $this->dieUsage("$varname may not be over $botMax (set to $value) for bots", $varname);
                        }
-               } else {
-                       if ($value > $max) {
-                               $this->dieUsage("$varname may not be over $max (set to $value) for users", $varname);
-                       }
+               }
+               elseif ($value > $max) {
+                       $this->dieUsage("$varname may not be over $max (set to $value) for users", $varname);
                }
        }
 
@@ -322,8 +310,8 @@ abstract class ApiBase {
        /**
         * Internal code errors should be reported with this method
         */
-       protected static function dieDebug($message) {
-               wfDebugDieBacktrace("Internal error: $message");
+       protected static function dieDebug($method, $message) {
+               wfDebugDieBacktrace("Internal error in $method: $message");
        }
 
        /**
@@ -336,7 +324,7 @@ abstract class ApiBase {
         */
        public function profileIn() {
                if ($this->mTimeIn !== 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called twice without calling profileOut()');
+                       ApiBase :: dieDebug(__METHOD__, 'called twice without calling profileOut()');
                $this->mTimeIn = microtime(true);
        }
 
@@ -345,9 +333,9 @@ abstract class ApiBase {
         */
        public function profileOut() {
                if ($this->mTimeIn === 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called without calling profileIn() first');
+                       ApiBase :: dieDebug(__METHOD__, 'called without calling profileIn() first');
                if ($this->mDBTimeIn !== 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' must be called after database profiling is done with profileDBOut()');
+                       ApiBase :: dieDebug(__METHOD__, 'must be called after database profiling is done with profileDBOut()');
 
                $this->mModuleTime += microtime(true) - $this->mTimeIn;
                $this->mTimeIn = 0;
@@ -358,7 +346,7 @@ abstract class ApiBase {
         */
        public function getProfileTime() {
                if ($this->mTimeIn !== 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called without calling profileOut() first');
+                       ApiBase :: dieDebug(__METHOD__, 'called without calling profileOut() first');
                return $this->mModuleTime;
        }
 
@@ -372,9 +360,9 @@ abstract class ApiBase {
         */
        public function profileDBIn() {
                if ($this->mTimeIn === 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' must be called while profiling the entire module with profileIn()');
+                       ApiBase :: dieDebug(__METHOD__, 'must be called while profiling the entire module with profileIn()');
                if ($this->mDBTimeIn !== 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called twice without calling profileDBOut()');
+                       ApiBase :: dieDebug(__METHOD__, 'called twice without calling profileDBOut()');
                $this->mDBTimeIn = microtime(true);
        }
 
@@ -383,9 +371,9 @@ abstract class ApiBase {
         */
        public function profileDBOut() {
                if ($this->mTimeIn === 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' must be called while profiling the entire module with profileIn()');
+                       ApiBase :: dieDebug(__METHOD__, 'must be called while profiling the entire module with profileIn()');
                if ($this->mDBTimeIn === 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called without calling profileDBIn() first');
+                       ApiBase :: dieDebug(__METHOD__, 'called without calling profileDBIn() first');
 
                $time = microtime(true) - $this->mDBTimeIn;
                $this->mDBTimeIn = 0;
@@ -399,7 +387,7 @@ abstract class ApiBase {
         */
        public function getProfileDBTime() {
                if ($this->mDBTimeIn !== 0)
-                       ApiBase :: dieDebug(__METHOD__ . ' called without calling profileDBOut() first');
+                       ApiBase :: dieDebug(__METHOD__, 'called without calling profileDBOut() first');
                return $this->mDBTime;
        }
 }
index bce60d9..12048d0 100644 (file)
@@ -42,7 +42,7 @@ class ApiFormatJson extends ApiFormatBase {
        public function execute() {
                require ('ApiFormatJson_json.php');
                $json = new Services_JSON();
-               $this->printText($json->encode($this->getResult()->getData(), true));
+               $this->printText($json->encode($this->getResultData(), true));
        }
 
        protected function getDescription() {
index ad0655a..31edc84 100644 (file)
@@ -99,38 +99,36 @@ class ApiFormatXml extends ApiFormatBase {
                                foreach ($elemValue as $subElemId => & $subElemValue) {
                                        if (gettype($subElemId) === 'integer') {
                                                if (!is_array($subElemValue))
-                                                       ApiBase :: dieDebug(__FUNCTION__ . "($elemName, ...) has a scalar indexed value.");
+                                                       ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has a scalar indexed value.");
                                                $indElements[] = $subElemValue;
                                                unset ($elemValue[$subElemId]);
-                                       } else
-                                               if (is_array($subElemValue)) {
-                                                       $subElements[$subElemId] = $subElemValue;
-                                                       unset ($elemValue[$subElemId]);
-                                               }
+                                       } elseif (is_array($subElemValue)) {
+                                               $subElements[$subElemId] = $subElemValue;
+                                               unset ($elemValue[$subElemId]);
+                                       }
                                }
 
                                if (is_null($subElemIndName) && !empty ($indElements))
-                                       ApiBase :: dieDebug(__FUNCTION__ . "($elemName, ...) has integer keys without _element value");
+                                       ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has integer keys without _element value");
 
                                if (!empty ($subElements) && !empty ($indElements) && !is_null($subElemContent))
-                                       ApiBase :: dieDebug(__FUNCTION__ . "($elemName, ...) has content and subelements");
+                                       ApiBase :: dieDebug(__METHOD__, "($elemName, ...) has content and subelements");
 
                                if (!is_null($subElemContent)) {
                                        $this->printText($indstr . wfElement($elemName, $elemValue, $subElemContent));
-                               } else
-                                       if (empty ($indElements) && empty ($subElements)) {
+                               } elseif (empty ($indElements) && empty ($subElements)) {
                                                $this->printText($indstr . wfElement($elemName, $elemValue));
-                                       } else {
-                                               $this->printText($indstr . wfElement($elemName, $elemValue, null));
+                               } else {
+                                       $this->printText($indstr . wfElement($elemName, $elemValue, null));
 
-                                               foreach ($subElements as $subElemId => & $subElemValue)
-                                                       $this->recXmlPrint($subElemId, $subElemValue, $indent);
+                                       foreach ($subElements as $subElemId => & $subElemValue)
+                                               $this->recXmlPrint($subElemId, $subElemValue, $indent);
 
-                                               foreach ($indElements as $subElemId => & $subElemValue)
-                                                       $this->recXmlPrint($subElemIndName, $subElemValue, $indent);
+                                       foreach ($indElements as $subElemId => & $subElemValue)
+                                               $this->recXmlPrint($subElemIndName, $subElemValue, $indent);
 
-                                               $this->printText($indstr . wfCloseElement($elemName));
-                                       }
+                                       $this->printText($indstr . wfCloseElement($elemName));
+                               }
                                break;
                        case 'object' :
                                // ignore
index 8b74b06..ed52fb5 100644 (file)
@@ -41,7 +41,7 @@ class ApiFormatYaml extends ApiFormatBase {
 
        public function execute() {
                require ('ApiFormatYaml_spyc.php');
-               $this->printText(Spyc :: YAMLDump($this->getResult()->getData()));
+               $this->printText(Spyc :: YAMLDump($this->getResultData()));
        }
 
        protected function getDescription() {
index 80ca546..b90ab0c 100644 (file)
@@ -1,51 +1,51 @@
-<?php\r
-\r
-\r
-/*\r
- * Created on Sep 6, 2006\r
- *\r
- * API for MediaWiki 1.8+\r
- *\r
- * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
- * http://www.gnu.org/copyleft/gpl.html\r
- */\r
-\r
-if (!defined('MEDIAWIKI')) {\r
-       // Eclipse helper - will be ignored in production\r
-       require_once ('ApiBase.php');\r
-}\r
-\r
-class ApiHelp extends ApiBase {\r
-\r
-       public function __construct($main, $action) {\r
-               parent :: __construct($main);\r
-       }\r
-\r
-       /**\r
-        * Stub module for displaying help when no parameters are given\r
-        */\r
-       public function execute() {\r
-               $this->dieUsage('', 'help');\r
-       }\r
-\r
-       protected function getDescription() {\r
-               return array (\r
-                       'Display this help screen.'\r
-               );\r
-       }\r
-}\r
+<?php
+
+
+/*
+ * Created on Sep 6, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ('ApiBase.php');
+}
+
+class ApiHelp extends ApiBase {
+
+       public function __construct($main, $action) {
+               parent :: __construct($main);
+       }
+
+       /**
+        * Stub module for displaying help when no parameters are given
+        */
+       public function execute() {
+               $this->dieUsage('', 'help');
+       }
+
+       protected function getDescription() {
+               return array (
+                       'Display this help screen.'
+               );
+       }
+}
 ?>
\ No newline at end of file
index b01691f..d253804 100644 (file)
@@ -81,7 +81,7 @@ class ApiLogin extends ApiBase {
                                $result['result'] = 'EmptyPass';
                                break;
                        default :
-                               $this->dieDebug('Unhandled case value');
+                               ApiBase :: dieDebug(__METHOD__, 'Unhandled case value');
                }
 
                $this->getResult()->addValue(null, 'login', $result);
index 60e0ff0..767c7d9 100644 (file)
@@ -57,12 +57,12 @@ class ApiMain extends ApiBase {
        protected function getAllowedParams() {
                return array (
                        'format' => array (
-                               ApiBase::PARAM_DFLT => API_DEFAULT_FORMAT,
-                               ApiBase::PARAM_TYPE => $this->mFormatNames
+                               ApiBase :: PARAM_DFLT => API_DEFAULT_FORMAT,
+                               ApiBase :: PARAM_TYPE => $this->mFormatNames
                        ),
                        'action' => array (
-                               ApiBase::PARAM_DFLT => 'help',
-                               ApiBase::PARAM_TYPE => $this->mModuleNames
+                               ApiBase :: PARAM_DFLT => 'help',
+                               ApiBase :: PARAM_TYPE => $this->mModuleNames
                        )
                );
        }
@@ -131,7 +131,7 @@ class ApiMain extends ApiBase {
                $data = array (
                        'code' => $errorCode
                );
-               ApiResult :: addContent($data, $this->makeHelpMsg());
+               ApiResult :: setContent($data, $this->makeHelpMsg());
                $this->mResult->addValue(null, 'error', $data);
 
                throw new UsageException($description, $errorCode);
index 1343c1e..13c3751 100644 (file)
@@ -32,7 +32,7 @@ if (!defined('MEDIAWIKI')) {
 class ApiPageSet extends ApiQueryBase {
 
        private $mAllPages; // [ns][dbkey] => page_id or 0 when missing
-       private $mGoodTitles, $mMissingTitles, $mRedirectTitles, $mNormalizedTitles;
+       private $mGoodTitles, $mMissingTitles, $mMissingPageIDs, $mRedirectTitles, $mNormalizedTitles;
 
        private $mRequestedFields;
 
@@ -42,6 +42,7 @@ class ApiPageSet extends ApiQueryBase {
                $this->mAllPages = array ();
                $this->mGoodTitles = array ();
                $this->mMissingTitles = array ();
+               $this->mMissingPageIDs = array ();
                $this->mRedirectTitles = array ();
                $this->mNormalizedTitles = array ();
 
@@ -52,6 +53,10 @@ class ApiPageSet extends ApiQueryBase {
                $this->mRequestedFields[$fieldName] = null;
        }
 
+       public function getCustomField($fieldName) {
+               return $this->mRequestedFields[$fieldName];
+       }
+
        /**
         * Title objects that were found in the database.
         * @return array page_id (int) => Title (obj)
@@ -68,6 +73,14 @@ class ApiPageSet extends ApiQueryBase {
                return $this->mMissingTitles;
        }
 
+       /**
+        * Page IDs that were not found in the database
+        * @return array of page IDs
+        */
+       public function getMissingPageIDs() {
+               return $this->mMissingPageIDs;
+       }
+
        /**
         * Get a list of redirects when doing redirect resolution
         * @return array prefixed_title (string) => prefixed_title (string)
@@ -120,7 +133,10 @@ class ApiPageSet extends ApiQueryBase {
         * #5 Substitute the original LinkBatch object with the new list
         * #6 Repeat from step #1     
         */
-       private function populateTitles($titles, $redirects) {
+       private function populatePages($titles, $pageids, $redirects) {
+               if (!is_null($titles) && !is_null($pageids))
+                       ApiBase :: dieDebug(__METHOD__, 'bad parameters');
+               $processTitles = !is_null($titles);
 
                // Ensure we get minimum required fields
                $pageFlds = array (
@@ -135,20 +151,33 @@ class ApiPageSet extends ApiQueryBase {
                if ($redirects)
                        $pageFlds['page_is_redirect'] = null;
 
-               $pageFlds = array_keys(array_merge($this->mRequestedFields, $pageFlds));
-
-               // Get validated and normalized title objects
-               $linkBatch = $this->processTitlesStrArray($titles);
+               $pageFlds = array_keys(array_merge($pageFlds, $this->mRequestedFields));
 
                $db = $this->getDB();
 
+               if ($processTitles) {
+
+                       // Get validated and normalized title objects
+                       $linkBatch = $this->processTitlesStrArray($titles);
+
+                       $set = $linkBatch->constructSet('page', $db);
+               } else {
+                       $set = array (
+                               'page_id' => $pageids
+                       );
+               }
+
                //
                // Repeat until all redirects have been resolved
+               // The infinite loop is prevented by keeping all known pages in $this->mAllPages
                //
-               while (false !== ($set = $linkBatch->constructSet('page', $db))) {
-
-                       // Hack: get the ns:titles stored in array(ns => array(titles)) format
-                       $remaining = $linkBatch->data;
+               do {
+                       if ($processTitles) {
+                               // Hack: get the ns:titles stored in array(ns => array(titles)) format
+                               $remaining = $linkBatch->data;
+                       } else {
+                               $remaining = array_flip($pageids); // turn pageids into keys 
+                       }
 
                        $redirectIds = array ();
 
@@ -160,25 +189,40 @@ class ApiPageSet extends ApiQueryBase {
                        $this->profileDBOut();
                        while ($row = $db->fetchObject($res)) {
 
-                               unset ($remaining[$row->page_namespace][$row->page_title]);
+                               $pageId = intval($row->page_id);
+
+                               if ($processTitles)
+                                       unset ($remaining[$row->page_namespace][$row->page_title]);
+                               else
+                                       unset ($remaining[$pageId]);
+
                                $title = Title :: makeTitle($row->page_namespace, $row->page_title);
-                               $this->mAllPages[$row->page_namespace][$row->page_title] = $row->page_id;
+                               $this->mAllPages[$row->page_namespace][$row->page_title] = $pageId;
 
                                if ($redirects && $row->page_is_redirect == '1') {
-                                       $redirectIds[$row->page_id] = $title;
+                                       $redirectIds[$pageId] = $title;
                                } else {
-                                       $this->mGoodTitles[$row->page_id] = $title;
+                                       $this->mGoodTitles[$pageId] = $title;
+                               }
+
+                               foreach ($this->mRequestedFields as $fieldName => & $fieldValues) {
+                                       $fieldValues[$pageId] = $row-> $fieldName;
                                }
                        }
                        $db->freeResult($res);
 
-                       //
-                       // The remaining titles in $remaining are non-existant pages
-                       //
-                       foreach ($remaining as $ns => $dbkeys) {
-                               foreach ($dbkeys as $dbkey => $nothing) {
-                                       $this->mMissingTitles[] = Title :: makeTitle($ns, $dbkey);
-                                       $this->mAllPages[$ns][$dbkey] = 0;
+                       if ($processTitles) {
+                               // The remaining titles in $remaining are non-existant pages
+                               foreach ($remaining as $ns => $dbkeys) {
+                                       foreach ($dbkeys as $dbkey => $nothing) {
+                                               $this->mMissingTitles[] = Title :: makeTitle($ns, $dbkey);
+                                               $this->mAllPages[$ns][$dbkey] = 0;
+                                       }
+                               }
+                       } else {
+                               // The remaining pageids in $remaining do not exist
+                               foreach ($remaining as $pageid => $ignore) {
+                                       $this->mMissingPageIDs[] = $pageid;
                                }
                        }
 
@@ -187,44 +231,75 @@ class ApiPageSet extends ApiQueryBase {
 
                        //
                        // Resolve redirects by querying the pagelinks table, and repeat the process
-                       //
-
                        // Create a new linkBatch object for the next pass
-                       $linkBatch = new LinkBatch();
-
-                       // find redirect targets for all redirect pages
-                       $this->profileDBIn();
-                       $res = $db->select('pagelinks', array (
-                               'pl_from',
-                               'pl_namespace',
-                               'pl_title'
-                       ), array (
-                               'pl_from' => array_keys($redirectIds
-                       )), __METHOD__);
-                       $this->profileDBOut();
-
-                       while ($row = $db->fetchObject($res)) {
+                       //
+                       $linkBatch = $this->ResolveRedirectList($redirectIds);
 
-                               // Bug 7304 workaround 
-                               // ( http://bugzilla.wikipedia.org/show_bug.cgi?id=7304 )
-                               // A redirect page may have more than one link.
-                               // This code will only use the first link returned. 
-                               if (isset ($redirectIds[$row->pl_from])) { // remove line when 7304 is fixed 
+                       // Redirects are always titles
+                       $processTitles = true;
+               }
+               while (false !== ($set = $linkBatch->constructSet('page', $db)));
+       }
 
-                                       $titleStrFrom = $redirectIds[$row->pl_from]->getPrefixedText();
-                                       $titleStrTo = Title :: makeTitle($row->pl_namespace, $row->pl_title)->getPrefixedText();
-                                       $this->mRedirectTitles[$titleStrFrom] = $titleStrTo;
+       private function ResolveRedirectList($redirectIds) {
 
-                                       unset ($redirectIds[$row->pl_from]); // remove line when 7304 is fixed
+               $linkBatch = new LinkBatch();
+               $db = $this->getDB();
 
-                                       // Avoid an infinite loop by checking if we have already processed this target
-                                       if (!isset ($this->mAllPages[$row->pl_namespace][$row->pl_title])) {
-                                               $linkBatch->add($row->pl_namespace, $row->pl_title);
-                                       }
+               // find redirect targets for all redirect pages
+               $this->profileDBIn();
+               $res = $db->select('pagelinks', array (
+                       'pl_from',
+                       'pl_namespace',
+                       'pl_title'
+               ), array (
+                       'pl_from' => array_keys($redirectIds
+               )), __METHOD__);
+               $this->profileDBOut();
+
+               while ($row = $db->fetchObject($res)) {
+
+                       $plfrom = intval($row->pl_from);
+
+                       // Bug 7304 workaround 
+                       // ( http://bugzilla.wikipedia.org/show_bug.cgi?id=7304 )
+                       // A redirect page may have more than one link.
+                       // This code will only use the first link returned. 
+                       if (isset ($redirectIds[$plfrom])) { // remove line when bug 7304 is fixed 
+
+                               $titleStrFrom = $redirectIds[$plfrom]->getPrefixedText();
+                               $titleStrTo = Title :: makeTitle($row->pl_namespace, $row->pl_title)->getPrefixedText();
+                               unset ($redirectIds[$plfrom]); // remove line when bug 7304 is fixed
+
+                               // Avoid an infinite loop by checking if we have already processed this target
+                               if (!isset ($this->mAllPages[$row->pl_namespace][$row->pl_title])) {
+                                       $linkBatch->add($row->pl_namespace, $row->pl_title);
+                               }
+                       } else {
+                               // This redirect page has more than one link.
+                               // This is very slow, but safer until bug 7304 is resolved
+                               $title = Title :: newFromID($plfrom);
+                               $titleStrFrom = $title->getPrefixedText();
+
+                               $article = new Article($title);
+                               $text = $article->getContent();
+                               $titleTo = Title :: newFromRedirect($text);
+                               $titleStrTo = $titleTo->getPrefixedText();
+
+                               if (is_null($titleStrTo))
+                                       ApiBase :: dieDebug(__METHOD__, 'Bug7304 workaround: redir target from {$title->getPrefixedText()} not found');
+
+                               // Avoid an infinite loop by checking if we have already processed this target
+                               if (!isset ($this->mAllPages[$titleTo->getNamespace()][$titleTo->getDBkey()])) {
+                                       $linkBatch->addObj($titleTo);
                                }
                        }
-                       $db->freeResult($res);
+
+                       $this->mRedirectTitles[$titleStrFrom] = $titleStrTo;
                }
+               $db->freeResult($res);
+
+               return $linkBatch;
        }
 
        /**
@@ -262,7 +337,7 @@ class ApiPageSet extends ApiQueryBase {
                return $linkBatch;
        }
 
-       private function populatePageIDs($pageids) {
+       private function populateRevIDs($revids) {
                $this->dieUsage(__METHOD__ . ' is not implemented', 'notimplemented');
        }
 
@@ -287,10 +362,8 @@ class ApiPageSet extends ApiQueryBase {
 
                switch ($dataSource) {
                        case 'titles' :
-                               $this->populateTitles($titles, $redirects);
-                               break;
                        case 'pageids' :
-                               $this->populatePageIDs($pageids, $redirects);
+                               $this->populatePages($titles, $pageids, $redirects);
                                break;
                        case 'revids' :
                                $this->populateRevIDs($revids);
@@ -304,15 +377,15 @@ class ApiPageSet extends ApiQueryBase {
        protected function getAllowedParams() {
                return array (
                        'titles' => array (
-                               ApiBase::PARAM_ISMULTI => true
+                               ApiBase :: PARAM_ISMULTI => true
                        ),
                        'pageids' => array (
-                               ApiBase::PARAM_TYPE => 'integer',
-                               ApiBase::PARAM_ISMULTI => true
+                               ApiBase :: PARAM_TYPE => 'integer',
+                               ApiBase :: PARAM_ISMULTI => true
                        ),
                        'revids' => array (
-                               ApiBase::PARAM_TYPE => 'integer',
-                               ApiBase::PARAM_ISMULTI => true
+                               ApiBase :: PARAM_TYPE => 'integer',
+                               ApiBase :: PARAM_ISMULTI => true
                        ),
                        'redirects' => false
                );
index 458007b..533c95c 100644 (file)
@@ -31,13 +31,8 @@ if (!defined('MEDIAWIKI')) {
 
 class ApiQuery extends ApiBase {
 
-       private $mMetaModuleNames, $mPropModuleNames, $mListModuleNames;
-       private $mData;
-
-       private $mQueryMetaModules = array (
-               'siteinfo' => 'ApiQuerySiteinfo'
-       );
-       //      'userinfo' => 'ApiQueryUserinfo',
+       private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames;
+       private $mPageSet;
 
        private $mQueryPropModules = array (
                'info' => 'ApiQueryInfo',
@@ -62,13 +57,18 @@ class ApiQuery extends ApiBase {
        //      'users' => 'ApiQueryUsers',
        //      'watchlist' => 'ApiQueryWatchlist',
 
+       private $mQueryMetaModules = array (
+               'siteinfo' => 'ApiQuerySiteinfo'
+       );
+       //      'userinfo' => 'ApiQueryUserinfo',
+
        private $mSlaveDB = null;
 
        public function __construct($main, $action) {
                parent :: __construct($main);
-               $this->mMetaModuleNames = array_keys($this->mQueryMetaModules);
                $this->mPropModuleNames = array_keys($this->mQueryPropModules);
                $this->mListModuleNames = array_keys($this->mQueryListModules);
+               $this->mMetaModuleNames = array_keys($this->mQueryMetaModules);
 
                // Allow the entire list of modules at first,
                // but during module instantiation check if it can be used as a generator.
@@ -81,8 +81,8 @@ class ApiQuery extends ApiBase {
                return $this->mSlaveDB;
        }
 
-       public function getData() {
-               return $this->mData;
+       public function getPageSet() {
+               return $this->mPageSet;
        }
 
        /**
@@ -96,13 +96,13 @@ class ApiQuery extends ApiBase {
         * #5 Execute all requested modules
         */
        public function execute() {
-               $meta = $prop = $list = $generator = null;
+               $prop = $list = $meta = $generator = null;
                extract($this->extractRequestParams());
 
                //
                // Create PageSet
                //
-               $this->mData = new ApiPageSet($this);
+               $this->mPageSet = new ApiPageSet($this);
 
                //
                // If generator is provided, get a new dataset to work on
@@ -111,29 +111,50 @@ class ApiQuery extends ApiBase {
                        $this->executeGenerator($generator);
 
                // Instantiate required modules
-               // During instantiation, modules may optimize data requests through the $this->mData object 
-               // $this->mData will be lazy loaded when modules begin to request data during execution
                $modules = array ();
-               if (isset ($meta))
-                       foreach ($meta as $moduleName)
-                               $modules[] = new $this->mQueryMetaModules[$moduleName] ($this, $moduleName);
                if (isset ($prop))
                        foreach ($prop as $moduleName)
                                $modules[] = new $this->mQueryPropModules[$moduleName] ($this, $moduleName);
                if (isset ($list))
                        foreach ($list as $moduleName)
                                $modules[] = new $this->mQueryListModules[$moduleName] ($this, $moduleName);
+               if (isset ($meta))
+                       foreach ($meta as $moduleName)
+                               $modules[] = new $this->mQueryMetaModules[$moduleName] ($this, $moduleName);
+
+               // Modules may optimize data requests through the $this->getPageSet() object 
+               // Execute all requested modules.
+               foreach ($modules as $module) {
+                       $module->requestExtraData();
+               }
 
                //
                // Get page information for the given pageSet
                //
-               $this->mData->profileIn();
-               $this->mData->execute();
-               $this->mData->profileOut();
+               $this->mPageSet->profileIn();
+               $this->mPageSet->execute();
+               $this->mPageSet->profileOut();
+
+               //
+               // Record page information
+               //
+               $this->outputGeneralPageInfo();
+
+               // Execute all requested modules.
+               foreach ($modules as $module) {
+                       $module->profileIn();
+                       $module->execute();
+                       $module->profileOut();
+               }
+       }
+
+       private function outputGeneralPageInfo() {
+
+               $pageSet = $this->getPageSet();
 
                // Title normalizations
                $normValues = array ();
-               foreach ($this->mData->getNormalizedTitles() as $rawTitleStr => $titleStr) {
+               foreach ($pageSet->getNormalizedTitles() as $rawTitleStr => $titleStr) {
                        $normValues[] = array (
                                'from' => $rawTitleStr,
                                'to' => $titleStr
@@ -147,7 +168,7 @@ class ApiQuery extends ApiBase {
 
                // Show redirect information
                $redirValues = array ();
-               foreach ($this->mData->getRedirectTitles() as $titleStrFrom => $titleStrTo) {
+               foreach ($pageSet->getRedirectTitles() as $titleStrFrom => $titleStrTo) {
                        $redirValues[] = array (
                                'from' => $titleStrFrom,
                                'to' => $titleStrTo
@@ -159,17 +180,35 @@ class ApiQuery extends ApiBase {
                        $this->getResult()->addValue('query', 'redirects', $redirValues);
                }
 
-               // Execute all requested modules.
-               foreach ($modules as $module) {
-                       $module->profileIn();
-                       $module->execute();
-                       $module->profileOut();
+               //
+               // Page elements
+               //
+               $pages = array ();
+
+               // Report any missing titles
+               $fakepageid = -1;
+               foreach ($pageSet->getMissingTitles() as $title) {
+                       $pages[$fakepageid--] = array (
+                       'ns' => $title->getNamespace(), 'title' => $title->getPrefixedText(), 'missing' => '');
                }
 
-               // Ensure that pages are shown as '<page>' elements
-               $data = & $this->getResultData();
-               if (isset ($data['query']['pages'])) {
-                       ApiResult :: setIndexedTagName($data['query']['pages'], 'page');
+               // Report any missing page ids
+               foreach ($pageSet->getMissingPageIDs() as $pageid) {
+                       $pages[$pageid] = array (
+                               'id' => $pageid,
+                               'missing' => ''
+                       );
+               }
+
+               // Output general page information for found titles
+               foreach ($pageSet->getGoodTitles() as $pageid => $title) {
+                       $pages[$pageid] = array (
+                       'ns' => $title->getNamespace(), 'title' => $title->getPrefixedText(), 'id' => $pageid);
+               }
+
+               if (!empty ($pages)) {
+                       ApiResult :: setIndexedTagName($pages, 'page');
+                       $this->getResult()->addValue('query', 'pages', $pages);
                }
        }
 
@@ -178,20 +217,19 @@ class ApiQuery extends ApiBase {
                // Find class that implements requested generator
                if (isset ($this->mQueryListModules[$generator]))
                        $className = $this->mQueryListModules[$generator];
+               elseif (isset ($this->mQueryPropModules[$generator])) $className = $this->mQueryPropModules[$generator];
                else
-                       if (isset ($this->mQueryPropModules[$generator]))
-                               $className = $this->mQueryPropModules[$generator];
-                       else
-                               ApiBase :: dieDebug("Unknown generator=$generator");
+                       ApiBase :: dieDebug(__METHOD__, "Unknown generator=$generator");
 
                $module = new $className ($this, $generator, true);
+               $module->requestExtraData();
 
                // execute pageSet here to get the data required by the generator module
-               $this->mData->profileIn();
-               $this->mData->execute();
-               $this->mData->profileOut();
+               $this->mPageSet->profileIn();
+               $this->mPageSet->execute();
+               $this->mPageSet->profileOut();
 
-               // change $this->mData
+               // change $this->mPageSet
 
                // TODO: implement
                $this->dieUsage('Generator execution has not been implemented', 'notimplemented');
@@ -199,17 +237,17 @@ class ApiQuery extends ApiBase {
 
        protected function getAllowedParams() {
                return array (
-                       'meta' => array (
-                               ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => $this->mMetaModuleNames
-                       ),
                        'prop' => array (
-                               ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => $this->mPropModuleNames
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => $this->mPropModuleNames
                        ),
                        'list' => array (
-                               ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => $this->mListModuleNames
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => $this->mListModuleNames
+                       ),
+                       'meta' => array (
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => $this->mMetaModuleNames
                        )
                        //                      'generator' => array (
                        //                              ApiBase::PARAM_TYPE => $this->mAllowedGenerators
@@ -229,34 +267,35 @@ class ApiQuery extends ApiBase {
 
                // Make sure the internal object is empty
                // (just in case a sub-module decides to optimize during instantiation)
-               $this->mData = null;
+               $this->mPageSet = null;
 
                $astriks = str_repeat('--- ', 8);
-               $msg .= "\n$astriks Query: Meta  $astriks\n\n";
-               $msg .= $this->makeHelpMsgHelper($this->mQueryMetaModules, 'meta');
                $msg .= "\n$astriks Query: Prop  $astriks\n\n";
                $msg .= $this->makeHelpMsgHelper($this->mQueryPropModules, 'prop');
                $msg .= "\n$astriks Query: List  $astriks\n\n";
                $msg .= $this->makeHelpMsgHelper($this->mQueryListModules, 'list');
+               $msg .= "\n$astriks Query: Meta  $astriks\n\n";
+               $msg .= $this->makeHelpMsgHelper($this->mQueryMetaModules, 'meta');
 
                return $msg;
        }
 
        private function makeHelpMsgHelper($moduleList, $paramName) {
-               $msg = '';
+
+               $moduleDscriptions = array ();
 
                foreach ($moduleList as $moduleName => $moduleClass) {
-                       $msg .= "* $paramName=$moduleName *";
+                       $msg = "* $paramName=$moduleName *";
                        $module = new $moduleClass ($this, $moduleName, null);
                        $msg2 = $module->makeHelpMsg();
                        if ($msg2 !== false)
                                $msg .= $msg2;
-                       $msg .= "\n";
                        if ($module->getCanGenerate())
-                               $msg .= "  * Can be used as a generator\n";
+                               $msg .= "Generator:\n  This module may be used as a generator\n";
+                       $moduleDscriptions[] = $msg;
                }
 
-               return $msg;
+               return implode("\n", $moduleDscriptions);
        }
 
        /**
@@ -269,12 +308,10 @@ class ApiQuery extends ApiBase {
 
        protected function getParamDescription() {
                return array (
-                       'meta' => 'Which meta data to get about the site',
                        'prop' => 'Which properties to get for the titles/revisions/pageids',
                        'list' => 'Which lists to get',
-                       'generator' => 'Use the output of a list as the input for other prop/list/meta items',
-
-                       
+                       'meta' => 'Which meta data to get about the site',
+                       'generator' => 'Use the output of a list as the input for other prop/list/meta items'
                );
        }
 
index db7f9ef..6c519c5 100644 (file)
@@ -48,9 +48,7 @@ class ApiQueryAllpages extends ApiQueryBase {
 
                if ($apfilterredir === 'redirects')
                        $where['page_is_redirect'] = 1;
-               else
-                       if ($apfilterredir === 'nonredirects')
-                               $where['page_is_redirect'] = 0;
+               elseif ($apfilterredir === 'nonredirects') $where['page_is_redirect'] = 0;
 
                $this->profileDBIn();
                $res = $db->select('page', array (
@@ -107,23 +105,23 @@ class ApiQueryAllpages extends ApiQueryBase {
                return array (
                        'apfrom' => null,
                        'apnamespace' => array (
-                               ApiBase::PARAM_DFLT => 0,
-                               ApiBase::PARAM_TYPE => $validNamespaces
+                               ApiBase :: PARAM_DFLT => 0,
+                               ApiBase :: PARAM_TYPE => $validNamespaces
                        ),
                        'apfilterredir' => array (
-                               ApiBase::PARAM_DFLT => 'all',
-                               ApiBase::PARAM_TYPE => array (
+                               ApiBase :: PARAM_DFLT => 'all',
+                               ApiBase :: PARAM_TYPE => array (
                                        'all',
                                        'redirects',
                                        'nonredirects'
                                )
                        ),
                        'aplimit' => array (
-                               ApiBase::PARAM_DFLT => 10,
-                               ApiBase::PARAM_TYPE => 'limit',
-                               ApiBase::PARAM_MIN => 1,
-                               ApiBase::PARAM_MAX1 => 500,
-                               ApiBase::PARAM_MAX2 => 5000
+                               ApiBase :: PARAM_DFLT => 10,
+                               ApiBase :: PARAM_TYPE => 'limit',
+                               ApiBase :: PARAM_MIN => 1,
+                               ApiBase :: PARAM_MAX1 => 500,
+                               ApiBase :: PARAM_MAX2 => 5000
                        )
                );
        }
index 10ebc13..927af18 100644 (file)
-<?php\r
-\r
-\r
-/*\r
- * Created on Sep 7, 2006\r
- *\r
- * API for MediaWiki 1.8+\r
- *\r
- * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License along\r
- * with this program; if not, write to the Free Software Foundation, Inc.,\r
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
- * http://www.gnu.org/copyleft/gpl.html\r
- */\r
-\r
-if (!defined('MEDIAWIKI')) {\r
-       // Eclipse helper - will be ignored in production\r
-       require_once ('ApiBase.php');\r
-}\r
-\r
-abstract class ApiQueryBase extends ApiBase {\r
-\r
-       private $mQueryModule, $mModuleName, $mGenerator;\r
-\r
-       public function __construct($query, $moduleName, $generator = false) {\r
-               parent :: __construct($query->getMain());\r
-               $this->mQueryModule = $query;\r
-               $this->mModuleName = $moduleName;\r
-               $this->mGenerator = $generator;\r
-       }\r
-\r
-       /**\r
-        * Get the main Query module \r
-        */\r
-       public function getQuery() {\r
-               return $this->mQueryModule;\r
-       }\r
-\r
-       /**\r
-        * Get the name of the query being executed by this instance \r
-        */\r
-       public function getModuleName() {\r
-               return $this->mModuleName;\r
-       }\r
-\r
-       /**\r
-        * Get the Query database connection (readonly)\r
-        */\r
-       protected function getDB() {\r
-               return $this->getQuery()->getDB();\r
-       }\r
-\r
-       /**\r
-        * Get the PageSet object to work on\r
-        * @return ApiPageSet data\r
-        */\r
-       protected function getData() {\r
-               return $this->mQueryModule->getData();\r
-       }\r
-\r
-       /**\r
-        * Return true if this instance is being used as a generator.\r
-        */\r
-       protected function getIsGenerator() {\r
-               return $this->mGenerator;\r
-       }\r
-\r
-       /**\r
-        * Derived classes return true when they can be used as title generators for other query modules.\r
-        */\r
-       public function getCanGenerate() {\r
-               return false;\r
-       }\r
-\r
-       public static function titleToKey($title) {\r
-               return str_replace(' ', '_', $title);\r
-       }\r
-       public static function keyToTitle($key) {\r
-               return str_replace('_', ' ', $key);\r
-       }\r
-}\r
-?>\r
+<?php
+
+
+/*
+ * Created on Sep 7, 2006
+ *
+ * API for MediaWiki 1.8+
+ *
+ * Copyright (C) 2006 Yuri Astrakhan <FirstnameLastname@gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+if (!defined('MEDIAWIKI')) {
+       // Eclipse helper - will be ignored in production
+       require_once ('ApiBase.php');
+}
+
+abstract class ApiQueryBase extends ApiBase {
+
+       private $mQueryModule, $mModuleName, $mGenerator;
+
+       public function __construct($query, $moduleName, $generator = false) {
+               parent :: __construct($query->getMain());
+               $this->mQueryModule = $query;
+               $this->mModuleName = $moduleName;
+               $this->mGenerator = $generator;
+       }
+
+       /**
+        * Override this method to request extra fields from the pageSet
+        * using $this->getPageSet()->requestField('fieldName')
+        */
+       public function requestExtraData() {
+       }
+
+       /**
+        * Get the main Query module 
+        */
+       public function getQuery() {
+               return $this->mQueryModule;
+       }
+
+       /**
+        * Get the name of the query being executed by this instance 
+        */
+       public function getModuleName() {
+               return $this->mModuleName;
+       }
+
+       /**
+        * Get the Query database connection (readonly)
+        */
+       protected function getDB() {
+               return $this->getQuery()->getDB();
+       }
+
+       /**
+        * Get the PageSet object to work on
+        * @return ApiPageSet data
+        */
+       protected function getPageSet() {
+               return $this->mQueryModule->getPageSet();
+       }
+
+       /**
+        * Return true if this instance is being used as a generator.
+        */
+       protected function getIsGenerator() {
+               return $this->mGenerator;
+       }
+
+       /**
+        * Derived classes return true when they can be used as title generators for other query modules.
+        */
+       public function getCanGenerate() {
+               return false;
+       }
+
+       public static function titleToKey($title) {
+               return str_replace(' ', '_', $title);
+       }
+       public static function keyToTitle($key) {
+               return str_replace('_', ' ', $key);
+       }
+}
+?>
index dccad67..2a1e059 100644 (file)
@@ -31,39 +31,49 @@ if (!defined('MEDIAWIKI')) {
 
 class ApiQueryInfo extends ApiQueryBase {
 
+       //      private $mParameters;
+
        public function __construct($query, $moduleName, $generator = false) {
                parent :: __construct($query, $moduleName, $generator);
        }
 
+       public function requestExtraData() {
+               $pageSet = $this->getPageSet();
+               $pageSet->requestField('page_is_redirect');
+               $pageSet->requestField('page_touched');
+               $pageSet->requestField('page_latest');
+       }
+
        public function execute() {
 
-       }
+               $pageSet = $this->getPageSet();
+               $titles = $pageSet->getGoodTitles();
+               $result = & $this->getResult();
 
-       protected function getAllowedParams() {
-               return array (
-                       'param' => 'default',
-                       'enumparam' => array (
-                               ApiBase::PARAM_DFLT => 'default',
-                               ApiBase::PARAM_ISMULTI => false,
-                               ApiBase::PARAM_TYPE => array (
-                                       'a',
-                                       'b'
-                               )
-                       )
-               );
-       }
+               $pageIsRedir = $pageSet->getCustomField('page_is_redirect');
+               $pageTouched = $pageSet->getCustomField('page_touched');
+               $pageLatest = $pageSet->getCustomField('page_latest');
+
+               foreach ($titles as $pageid => $title) {
+                       $pageInfo = array ('touched' => $pageTouched[$pageid], 'lastrevid' => $pageLatest[$pageid]);
+
+                       if ($pageIsRedir[$pageid])
+                               $pageInfo['redirect'] = '';
 
-       protected function getParamDescription() {
-               return array ();
+                       $result->addValue(array (
+                               'query',
+                               'pages'
+                       ), $pageid, $pageInfo);
+               }
        }
 
        protected function getDescription() {
-               return 'module a';
+               return 'Get basic page information such as namespace, title, last touched date, ...';
        }
 
        protected function getExamples() {
                return array (
-                       'http://...'
+                       'api.php?action=query&prop=info&titles=Main%20Page'
                );
        }
 }
index e8e6efb..7a12ce7 100644 (file)
@@ -39,6 +39,8 @@ class ApiQueryRevisions extends ApiQueryBase {
                $rvlimit = $rvstartid = $rvendid = $rvstart = $rvend = $rvdir = $rvprop = null;
                extract($this->extractRequestParams());
 
+               $db = $this->getDB();
+
                // true when ordered by timestamp from older to newer, false otherwise
                $dirNewer = ($rvdir === 'newer');
 
@@ -48,9 +50,9 @@ class ApiQueryRevisions extends ApiQueryBase {
                // difficult to manage continuations and require additional sql indexes  
                $enumRevMode = ($rvlimit !== 0 || $rvstartid !== 0 || $rvendid !== 0 || $dirNewer || isset ($rvstart) || isset ($rvend));
 
-               $data = $this->getData();
-               $pageCount = $data->getGoodTitleCount();
-               $revCount = $data->getRevisionCount();
+               $pageSet = $this->getPageSet();
+               $pageCount = $pageSet->getGoodTitleCount();
+               $revCount = $pageSet->getRevisionCount();
 
                // Optimization -- nothing to do
                if ($revCount === 0 && $pageCount === 0)
@@ -108,7 +110,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                                                $showContent = true;
                                                break;
                                        default :
-                                               ApiBase :: dieDebug("unknown rvprop $prop");
+                                               ApiBase :: dieDebug(__METHOD__, "unknown rvprop $prop");
                                }
                        }
                }
@@ -134,9 +136,9 @@ class ApiQueryRevisions extends ApiQueryBase {
                        if ($rvendid !== 0)
                                $conds[] = 'rev_id' . $before . intval($rvendid);
                        if (isset ($rvstart))
-                               $conds[] = 'rev_timestamp' . $after . $this->prepareTimestamp($rvstart);
+                               $conds[] = 'rev_timestamp' . $after . $db->addQuotes($rvstart);
                        if (isset ($rvend))
-                               $conds[] = 'rev_timestamp' . $before . $this->prepareTimestamp($rvend);
+                               $conds[] = 'rev_timestamp' . $before . $db->addQuotes($rvend);
 
                        // must manually initialize unset rvlimit
                        if (!isset ($rvlimit))
@@ -145,35 +147,34 @@ class ApiQueryRevisions extends ApiQueryBase {
                        $this->validateLimit('rvlimit', $rvlimit, 1, $userMax, $botMax);
 
                        // There is only one ID, use it
-                       $conds['rev_page'] = array_pop(array_keys($data->getGoodTitles()));
-
-               } else
-                       if ($pageCount > 0) {
-                               // When working in multi-page non-enumeration mode,
-                               // limit to the latest revision only
-                               $tables[] = 'page';
-                               $conds[] = 'page_id=rev_page';
-                               $conds[] = 'page_latest=rev_id';
-                               $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax);
+                       $conds['rev_page'] = array_pop(array_keys($pageSet->getGoodTitles()));
 
-                               // Get all page IDs
-                               $conds['page_id'] = array_keys($data->getGoodTitles());
-
-                               $rvlimit = $pageCount; // assumption testing -- we should never get more then $pageCount rows.
-                       } else
-                               if ($revCount > 0) {
-                                       $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax);
+               }
+               elseif ($pageCount > 0) {
+                       // When working in multi-page non-enumeration mode,
+                       // limit to the latest revision only
+                       $tables[] = 'page';
+                       $conds[] = 'page_id=rev_page';
+                       $conds[] = 'page_latest=rev_id';
+                       $this->validateLimit('page_count', $pageCount, 1, $userMax, $botMax);
+
+                       // Get all page IDs
+                       $conds['page_id'] = array_keys($pageSet->getGoodTitles());
+
+                       $rvlimit = $pageCount; // assumption testing -- we should never get more then $pageCount rows.
+               }
+               elseif ($revCount > 0) {
+                       $this->validateLimit('rev_count', $revCount, 1, $userMax, $botMax);
 
-                                       // Get all revision IDs
-                                       $conds['rev_id'] = array_keys($data->getRevisionIDs());
+                       // Get all revision IDs
+                       $conds['rev_id'] = array_keys($pageSet->getRevisionIDs());
 
-                                       $rvlimit = $revCount; // assumption testing -- we should never get more then $revCount rows.
-                               } else
-                                       ApiBase :: dieDebug('param validation?');
+                       $rvlimit = $revCount; // assumption testing -- we should never get more then $revCount rows.
+               } else
+                       ApiBase :: dieDebug(__METHOD__, 'param validation?');
 
                $options['LIMIT'] = $rvlimit +1;
 
-               $db = $this->getDB();
                $this->profileDBIn();
                $res = $db->select($tables, $fields, $conds, __METHOD__, $options);
                $this->profileDBOut();
@@ -185,7 +186,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                        if (++ $count > $rvlimit) {
                                // We've reached the one extra which shows that there are additional pages to be had. Stop here...
                                if (!$enumRevMode)
-                                       ApiBase :: dieDebug('Got more rows then expected'); // bug report
+                                       ApiBase :: dieDebug(__METHOD__, 'Got more rows then expected'); // bug report
 
                                $startStr = 'rvstartid=' . $row->rev_id;
                                $msg = array (
@@ -216,7 +217,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                                $vals['comment'] = $row->rev_comment;
 
                        if ($showContent) {
-                               ApiResult :: addContent($vals, Revision :: getRevisionText($row));
+                               ApiResult :: setContent($vals, Revision :: getRevisionText($row));
                        }
 
                        $this->getResult()->addValue(array (
@@ -230,7 +231,7 @@ class ApiQueryRevisions extends ApiQueryBase {
                // Ensure that all revisions are shown as '<r>' elements
                $data = & $this->getResultData();
                foreach ($data['query']['pages'] as & $page) {
-                       if (isset ($page['revisions'])) {
+                       if (is_array($page) && array_key_exists('revisions', $page)) {
                                ApiResult :: setIndexedTagName($page['revisions'], 'rev');
                        }
                }
@@ -238,53 +239,73 @@ class ApiQueryRevisions extends ApiQueryBase {
 
        protected function getAllowedParams() {
                return array (
+                       'rvprop' => array (
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => array (
+                                       'timestamp',
+                                       'user',
+                                       'comment',
+                                       'content'
+                               )
+                       ),
                        'rvlimit' => array (
-                               ApiBase::PARAM_DFLT => 0,
-                               ApiBase::PARAM_TYPE => 'limit',
-                               ApiBase::PARAM_MIN => 0,
-                               ApiBase::PARAM_MAX1 => 50,
-                               ApiBase::PARAM_MAX2 => 500
+                               ApiBase :: PARAM_DFLT => 0,
+                               ApiBase :: PARAM_TYPE => 'limit',
+                               ApiBase :: PARAM_MIN => 0,
+                               ApiBase :: PARAM_MAX1 => 50,
+                               ApiBase :: PARAM_MAX2 => 500
                        ),
                        'rvstartid' => 0,
                        'rvendid' => 0,
                        'rvstart' => array (
-                               ApiBase::PARAM_TYPE => 'timestamp'
+                               ApiBase :: PARAM_TYPE => 'timestamp'
                        ),
                        'rvend' => array (
-                               ApiBase::PARAM_TYPE => 'timestamp'
+                               ApiBase :: PARAM_TYPE => 'timestamp'
                        ),
                        'rvdir' => array (
-                               ApiBase::PARAM_DFLT => 'older',
-                               ApiBase::PARAM_TYPE => array (
+                               ApiBase :: PARAM_DFLT => 'older',
+                               ApiBase :: PARAM_TYPE => array (
                                        'newer',
                                        'older'
                                )
-                       ),
-                       'rvprop' => array (
-                               ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => array (
-                                       'timestamp',
-                                       'user',
-                                       'comment',
-                                       'content'
-                               )
                        )
                );
        }
 
+       protected function getParamDescription() {
+               return array (
+                       'rvprop' => 'Which properties to get for each revision: user|timestamp|comment|content',
+                       'rvlimit' => 'limit how many revisions will be returned (enum)',
+                       'rvstartid' => 'from which revision id to start enumeration (enum)',
+                       'rvendid' => 'stop revision enumeration on this revid (enum)',
+                       'rvstart' => 'from which revision timestamp to start enumeration (enum)',
+                       'rvend' => 'enumerate up to this timestamp (enum)',
+                       'rvdir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)'
+               );
+       }
+
        protected function getDescription() {
                return array (
                        'Get revision information.',
                        'This module may be used in several ways:',
                        ' 1) Get data about a set of pages (last revision), by setting titles or pageids parameter.',
                        ' 2) Get revisions for one given page, by using titles/pageids with rvstart/rvend/rvlimit params.',
-                       ' 3) Get data about a set of revisions by setting their IDs with revids parameter.'
+                       ' 3) Get data about a set of revisions by setting their IDs with revids parameter.',
+                       'All parameters marked as (enum) may only be used with a single page (#2).'
                );
        }
 
        protected function getExamples() {
                return array (
-                       'api.php?action=query&prop=revisions&titles=Main%20Page&rvprop=timestamp|user|comment|content'
+                       'Get data with content for the last revision of titles "API" and "Main Page":',
+                       '  api.php?action=query&prop=revisions&titles=API|Main%20Page&rvprop=timestamp|user|comment|content',
+                       'Get last 5 revisions of the "Main Page":',
+                       '  api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment',
+                       'Get first 5 revisions of the "Main Page":',
+                       '  api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer',
+                       'Get first 5 revisions of the "Main Page" made after 2006-05-01:',
+                       '  api.php?action=query&prop=revisions&titles=Main%20Page&rvlimit=5&rvprop=timestamp|user|comment&rvdir=newer&rvstart=20060501000000'
                );
        }
 }
index 6bddee2..0ec37dd 100644 (file)
@@ -63,14 +63,14 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                                                $data[$ns] = array (
                                                        'id' => $ns
                                                );
-                                               ApiResult :: addContent($data[$ns], $title);
+                                               ApiResult :: setContent($data[$ns], $title);
                                        }
                                        ApiResult :: setIndexedTagName($data, 'ns');
                                        $this->getResult()->addValue('query', $prop, $data);
                                        break;
 
                                default :
-                                       ApiBase :: dieDebug("Unknown siprop=$prop");
+                                       ApiBase :: dieDebug(__METHOD__, "Unknown siprop=$prop");
                        }
                }
        }
@@ -78,9 +78,9 @@ class ApiQuerySiteinfo extends ApiQueryBase {
        protected function getAllowedParams() {
                return array (
                        'siprop' => array (
-                               ApiBase::PARAM_DFLT => 'general',
-                               ApiBase::PARAM_ISMULTI => true,
-                               ApiBase::PARAM_TYPE => array (
+                               ApiBase :: PARAM_DFLT => 'general',
+                               ApiBase :: PARAM_ISMULTI => true,
+                               ApiBase :: PARAM_TYPE => array (
                                        'general',
                                        'namespaces'
                                )
index 3e65b57..55cdafb 100644 (file)
@@ -53,27 +53,36 @@ class ApiResult extends ApiBase {
         * Add an output value to the array by name.
         * Verifies that value with the same name has not been added before.
         */
-       public static function addElement(& $arr, $name, $value) {
+       public static function setElement(& $arr, $name, $value) {
                if ($arr === null || $name === null || $value === null || !is_array($arr) || is_array($name))
-                       ApiBase :: dieDebug('Bad parameter for ' . __METHOD__);
-               if (isset ($arr[$name]))
-                       ApiBase :: dieDebug("Attempting to add element $name=$value, existing value is {$arr[$name]}");
-               $arr[$name] = $value;
+                       ApiBase :: dieDebug(__METHOD__, 'Bad parameter');
+
+               if (!isset ($arr[$name])) {
+                       $arr[$name] = $value;
+               }
+               elseif (is_array($arr[$name]) && is_array($value)) {
+                       $merged = array_intersect_key($arr[$name], $value);
+                       if (empty ($merged))
+                               $arr[$name] += $value;
+                       else
+                               ApiBase :: dieDebug(__METHOD__, "Attempting to merge element $name");
+               } else
+                       ApiBase :: dieDebug(__METHOD__, "Attempting to add element $name=$value, existing value is {$arr[$name]}");
        }
 
        /**
         * Adds the content element to the array.
         * Use this function instead of hardcoding the '*' element.
         */
-       public static function addContent(& $arr, $value) {
+       public static function setContent(& $arr, $value) {
                if (is_array($value))
-                       ApiBase :: dieDebug('Bad parameter for ' . __METHOD__);
-               ApiResult :: addElement($arr, '*', $value);
+                       ApiBase :: dieDebug(__METHOD__, 'Bad parameter');
+               ApiResult :: setElement($arr, '*', $value);
        }
 
        //      public static function makeContentElement($tag, $value) {
        //              $result = array();
-       //              ApiResult::addContent($result, )
+       //              ApiResult::setContent($result, )
        //      }
        //
        /**
@@ -81,9 +90,9 @@ class ApiResult extends ApiBase {
         * all indexed values will have the given tag name.
         */
        public static function setIndexedTagName(& $arr, $tag) {
-               // Do not use addElement() as it is ok to call this more than once
+               // Do not use setElement() as it is ok to call this more than once
                if ($arr === null || $tag === null || !is_array($arr) || is_array($tag))
-                       ApiBase :: dieDebug('Bad parameter for ' . __METHOD__);
+                       ApiBase :: dieDebug(__METHOD__, 'Bad parameter');
                $arr['_element'] = $tag;
        }
 
@@ -110,7 +119,7 @@ class ApiResult extends ApiBase {
                        }
                }
 
-               ApiResult :: addElement($data, $name, $value);
+               ApiResult :: setElement($data, $name, $value);
        }
 
        /**
@@ -127,9 +136,6 @@ class ApiResult extends ApiBase {
                        if ($key[0] === '_') {
                                unset ($data[$key]);
                        }
-                       elseif ($key === '*' && $value === '') {
-                               unset ($data[$key]);
-                       }
                        elseif (is_array($value)) {
                                ApiResult :: SanitizeDataInt($value);
                        }
@@ -137,7 +143,7 @@ class ApiResult extends ApiBase {
        }
 
        public function execute() {
-               $this->dieDebug('execute() is not supported on Result object');
+               ApiBase :: dieDebug(__METHOD__, 'execute() is not supported on Result object');
        }
 }
-?>
+?>
\ No newline at end of file