$msg = $lnPrfx . implode($lnPrfx, $msg) . "\n";\r
\r
// Parameters\r
- $params = $this->getAllowedParams();\r
- if ($params !== false) {\r
- $paramsDescription = $this->getParamDescription();\r
- $msg .= "Parameters:\n";\r
- foreach (array_keys($params) as $paramName) {\r
- $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';\r
- if (is_array($desc))\r
- $desc = implode("\n" . str_repeat(' ', 19), $desc);\r
- $msg .= sprintf(" %-14s - %s\n", $paramName, $desc);\r
- }\r
+ $paramsMsg = $this->makeHelpMsgParameters();\r
+ if ($paramsMsg !== false) {\r
+ $msg .= "Parameters:\n$paramsMsg";\r
}\r
\r
// Examples\r
return $msg;\r
}\r
\r
+ public function makeHelpMsgParameters() {\r
+ $params = $this->getAllowedParams();\r
+ if ($params !== false) {\r
+ \r
+ $paramsDescription = $this->getParamDescription();\r
+ $msg = '';\r
+ foreach (array_keys($params) as $paramName) {\r
+ $desc = isset ($paramsDescription[$paramName]) ? $paramsDescription[$paramName] : '';\r
+ if (is_array($desc))\r
+ $desc = implode("\n" . str_repeat(' ', 19), $desc);\r
+ $msg .= sprintf(" %-14s - %s\n", $paramName, $desc);\r
+ }\r
+ return $msg;\r
+ \r
+ }\r
+ else\r
+ return false; \r
+ }\r
+\r
/**\r
* Returns the description string for this module\r
*/\r
* This method can be used to generate local variables using extract().\r
*/\r
public function extractRequestParams() {\r
- global $wgRequest;\r
-\r
$params = $this->getAllowedParams();\r
$results = array ();\r
\r
- foreach ($params as $param => $enumParams) {\r
-\r
- if (!is_array($enumParams)) {\r
- $default = $enumParams;\r
- $multi = false;\r
- $type = gettype($enumParams);\r
- } else {\r
- $default = isset ($enumParams[GN_ENUM_DFLT]) ? $enumParams[GN_ENUM_DFLT] : null;\r
- $multi = isset ($enumParams[GN_ENUM_ISMULTI]) ? $enumParams[GN_ENUM_ISMULTI] : false;\r
- $type = isset ($enumParams[GN_ENUM_TYPE]) ? $enumParams[GN_ENUM_TYPE] : null;\r
-\r
- // When type is not given, and no choices, the type is the same as $default\r
- if (!isset ($type)) {\r
- if (isset ($default))\r
- $type = gettype($default);\r
- else\r
- $type = 'NULL'; // allow everything\r
- }\r
- }\r
+ foreach ($params as $paramName => $paramSettings)\r
+ $results[$paramName] = $this->getParameter($paramName, $paramSettings);\r
\r
- if ($type == 'boolean') {\r
- if (!isset ($default))\r
- $default = false;\r
+ return $results;\r
+ }\r
\r
- if ($default !== false) {\r
- // Having a default value of anything other than 'false' is pointless\r
- $this->dieDebug("Boolean param $param's default is set to '$default'");\r
- }\r
+ public function getParameter($paramName, $paramSettings){\r
+ global $wgRequest;\r
+\r
+ if (!is_array($paramSettings)) {\r
+ $default = $paramSettings;\r
+ $multi = false;\r
+ $type = gettype($paramSettings);\r
+ } else {\r
+ $default = isset ($paramSettings[GN_ENUM_DFLT]) ? $paramSettings[GN_ENUM_DFLT] : null;\r
+ $multi = isset ($paramSettings[GN_ENUM_ISMULTI]) ? $paramSettings[GN_ENUM_ISMULTI] : false;\r
+ $type = isset ($paramSettings[GN_ENUM_TYPE]) ? $paramSettings[GN_ENUM_TYPE] : null;\r
+\r
+ // When type is not given, and no choices, the type is the same as $default\r
+ if (!isset ($type)) {\r
+ if (isset ($default))\r
+ $type = gettype($default);\r
+ else\r
+ $type = 'NULL'; // allow everything\r
}\r
+ }\r
\r
- $value = $wgRequest->getVal($param, $default);\r
-\r
- if (isset ($value) && ($multi || is_array($type)))\r
- $value = $this->parseMultiValue($param, $value, $multi, is_array($type) ? $type : null);\r
-\r
- // More validation only when choices were not given\r
- // choices were validated in parseMultiValue()\r
- if (!is_array($type) && isset ($value)) {\r
-\r
- switch ($type) {\r
- case 'NULL' : // nothing to do\r
- break;\r
- case 'string' : // nothing to do\r
- break;\r
- case 'integer' : // Force everything using intval()\r
- $value = is_array($value) ? array_map('intval', $value) : intval($value);\r
- break;\r
- case 'limit' :\r
- if (!isset ($enumParams[GN_ENUM_MAX1]) || !isset ($enumParams[GN_ENUM_MAX2]))\r
- $this->dieDebug("MAX1 or MAX2 are not defined for the limit $param");\r
- if ($multi)\r
- $this->dieDebug("Multi-values not supported for $param");\r
- $min = isset ($enumParams[GN_ENUM_MIN]) ? $enumParams[GN_ENUM_MIN] : 0;\r
- $value = intval($value);\r
- $this->validateLimit($param, $value, $min, $enumParams[GN_ENUM_MAX1], $enumParams[GN_ENUM_MAX2]);\r
- break;\r
- case 'boolean' :\r
- if ($multi)\r
- $this->dieDebug("Multi-values not supported for $param");\r
- $value = isset ($value);\r
- break;\r
- case 'timestamp' :\r
- if ($multi)\r
- $this->dieDebug("Multi-values not supported for $param");\r
- $value = $this->prepareTimestamp($value); // Adds quotes around timestamp \r
- break;\r
- default :\r
- $this->dieDebug("Param $param's type is unknown - $type");\r
-\r
- }\r
+ if ($type == 'boolean') {\r
+ if (isset ($default) && $default !== false) {\r
+ // Having a default value of anything other than 'false' is pointless\r
+ $this->dieDebug("Boolean param $paramName's default is set to '$default'");\r
}\r
\r
- $results[$param] = $value;\r
+ $value = $wgRequest->getCheck($paramName);\r
+ } else\r
+ $value = $wgRequest->getVal($paramName, $default);\r
+\r
+ if (isset ($value) && ($multi || is_array($type)))\r
+ $value = $this->parseMultiValue($paramName, $value, $multi, is_array($type) ? $type : null);\r
+\r
+ // More validation only when choices were not given\r
+ // choices were validated in parseMultiValue()\r
+ if (!is_array($type) && isset ($value)) {\r
+\r
+ switch ($type) {\r
+ case 'NULL' : // nothing to do\r
+ break;\r
+ case 'string' : // nothing to do\r
+ break;\r
+ case 'integer' : // Force everything using intval()\r
+ $value = is_array($value) ? array_map('intval', $value) : intval($value);\r
+ break;\r
+ case 'limit' :\r
+ if (!isset ($paramSettings[GN_ENUM_MAX1]) || !isset ($paramSettings[GN_ENUM_MAX2]))\r
+ $this->dieDebug("MAX1 or MAX2 are not defined for the limit $paramName");\r
+ if ($multi)\r
+ $this->dieDebug("Multi-values not supported for $paramName");\r
+ $min = isset ($paramSettings[GN_ENUM_MIN]) ? $paramSettings[GN_ENUM_MIN] : 0;\r
+ $value = intval($value);\r
+ $this->validateLimit($paramName, $value, $min, $paramSettings[GN_ENUM_MAX1], $paramSettings[GN_ENUM_MAX2]);\r
+ break;\r
+ case 'boolean' :\r
+ if ($multi)\r
+ $this->dieDebug("Multi-values not supported for $paramName");\r
+ break;\r
+ case 'timestamp' :\r
+ if ($multi)\r
+ $this->dieDebug("Multi-values not supported for $paramName");\r
+ $value = $this->prepareTimestamp($value); // Adds quotes around timestamp \r
+ break;\r
+ default :\r
+ $this->dieDebug("Param $paramName's type is unknown - $type");\r
+\r
+ }\r
}\r
\r
- return $results;\r
+ return $value; \r
}\r
-\r
+ \r
/**\r
* Return an array of values that were given in a "a|b|c" notation,\r
* after it optionally validates them against the list allowed values.\r
class ApiPageSet extends ApiQueryBase {
private $mAllPages; // [ns][dbkey] => page_id or 0 when missing
- private $mResolveRedirs;
private $mGoodTitles, $mMissingTitles, $mRedirectTitles, $mNormalizedTitles;
- public function __construct($query, $resolveRedirs) {
+ public function __construct($query) {
parent :: __construct($query, __CLASS__);
- $this->mResolveRedirs = $resolveRedirs;
$this->mAllPages = array ();
$this->mGoodTitles = array ();
/**
* Returns the number of unique pages (not revisions) in the set.
*/
- public function getPageCount() {
+ public function getGoodTitleCount() {
return count($this->getGoodTitles());
}
+
+ /**
+ * Get the list of revision IDs (requested with revids= parameter)
+ */
+ public function getRevisionIDs() {
+ $this->dieUsage(__FUNCTION__ . " is not implemented", 'notimplemented');
+ }
+
+ /**
+ * Returns the number of revisions (requested with revids= parameter)
+ */
+ public function getRevisionCount() {
+ return 0; // TODO: implement
+ }
/**
* This method populates internal variables with page information
* #5 Substitute the original LinkBatch object with the new list
* #6 Repeat from step #1
*/
- public function populateTitles($titles) {
- $this->profileIn();
+ private function populateTitles($titles, $redirects) {
+
$pageFlds = array (
'page_id',
'page_namespace',
'page_title'
);
- if ($this->mResolveRedirs) {
+ if ($redirects) {
$pageFlds[] = 'page_is_redirect';
}
// Get validated and normalized title objects
- $linkBatch = $this->processTitlesStrings($titles);
+ $linkBatch = $this->processTitlesStrArray($titles);
$db = $this->getDB();
$title = Title :: makeTitle($row->page_namespace, $row->page_title);
$this->mAllPages[$row->page_namespace][$row->page_title] = $row->page_id;
- if ($this->mResolveRedirs && $row->page_is_redirect == '1') {
+ if ($redirects && $row->page_is_redirect == '1') {
$redirectIds[$row->page_id] = $title;
} else {
$this->mGoodTitles[$row->page_id] = $title;
}
}
- if (!$this->mResolveRedirs || empty ($redirectIds))
+ if (!$redirects || empty ($redirectIds))
break;
//
}
$db->freeResult($res);
}
- $this->profileOut();
}
/**
*
* @return LinkBatch of title objects.
*/
- private function processTitlesStrings($titles) {
+ private function processTitlesStrArray($titles) {
$linkBatch = new LinkBatch();
return $linkBatch;
}
- public function populatePageIDs($pageids) {
+ private function populatePageIDs($pageids) {
$this->dieUsage(__FUNCTION__ . " is not implemented", 'notimplemented');
}
public function execute() {
- $this->dieDebug("execute() is not supported on this object");
+ $titles = $pageids = $revids = $redirects = null;
+ extract($this->extractRequestParams());
+
+ // Only one of the titles/pageids/revids is allowed at the same time
+ $dataSource = null;
+ if (isset ($titles))
+ $dataSource = 'titles';
+ if (isset ($pageids)) {
+ if (isset ($dataSource))
+ $this->dieUsage("Cannot use 'pageids' at the same time as '$dataSource'", 'multisource');
+ $dataSource = 'pageids';
+ }
+ if (isset ($revids)) {
+ if (isset ($dataSource))
+ $this->dieUsage("Cannot use 'revids' at the same time as '$dataSource'", 'multisource');
+ $dataSource = 'revids';
+ }
+
+ switch ($dataSource) {
+ case 'titles' :
+ $this->populateTitles($titles, $redirects);
+ break;
+ case 'pageids' :
+ $this->populatePageIDs($pageids, $redirects);
+ break;
+ case 'revids' :
+ $this->populateRevIDs($revids);
+ break;
+ default :
+ // Do nothing - some queries do not need any of the data sources.
+ break;
+ }
+ }
+
+ protected function getAllowedParams() {
+ return array (
+ 'titles' => array (
+ GN_ENUM_ISMULTI => true
+ ),
+ 'pageids' => array (
+ GN_ENUM_TYPE => 'integer',
+ GN_ENUM_ISMULTI => true
+ ),
+ 'revids' => array (
+ GN_ENUM_TYPE => 'integer',
+ GN_ENUM_ISMULTI => true
+ ),
+ 'redirects' => false
+ );
+ }
+
+ protected function getParamDescription() {
+ return array (
+ 'titles' => 'A list of titles to work on',
+ 'pageids' => 'A list of page IDs to work on',
+ 'revids' => 'A list of revision IDs to work on',
+ 'redirects' => 'Automatically resolve redirects'
+ );
}
}
?>
\ No newline at end of file
* #5 Execute all requested modules\r
*/\r
public function execute() {\r
- $meta = $prop = $list = $generator = $titles = $pageids = null;\r
- $redirects = null;\r
+ $meta = $prop = $list = $generator = null;\r
extract($this->extractRequestParams());\r
\r
//\r
// Create and initialize PageSet\r
//\r
- $dataSource = null;\r
- if (isset ($titles) && isset($pageids))\r
- $this->dieUsage("At present you may not use titles= and pageids= at the same time", 'multisource');\r
-\r
- $this->mData = new ApiPageSet($this, $redirects);\r
-\r
- if (isset($titles))\r
- $this->mData->populateTitles($titles);\r
-\r
- if (isset($pageids))\r
- $this->mData->populatePageIDs($pageids);\r
+ $this->mData = new ApiPageSet($this);\r
+ $this->mData->profileIn();\r
+ $this->mData->execute();\r
+ $this->mData->profileOut();\r
\r
//\r
// If generator is provided, get a new dataset to work on\r
//\r
if (isset ($generator))\r
- $this->executeGenerator($generator, $redirects);\r
+ $this->executeGenerator($generator);\r
\r
// Instantiate required modules\r
// During instantiation, modules may optimize data requests through the $this->mData object \r
}\r
\r
// Show redirect information\r
- if ($redirects) {\r
- foreach ($this->mData->getRedirectTitles() as $titleStrFrom => $titleStrTo) {\r
- $this->getResult()->addMessage('query', 'redirects', array (\r
- 'from' => $titleStrFrom,\r
- 'to' => $titleStrTo,\r
- '*' => ''\r
- ), 'r');\r
- }\r
+ foreach ($this->mData->getRedirectTitles() as $titleStrFrom => $titleStrTo) {\r
+ $this->getResult()->addMessage('query', 'redirects', array (\r
+ 'from' => $titleStrFrom,\r
+ 'to' => $titleStrTo,\r
+ '*' => ''\r
+ ), 'r');\r
}\r
\r
// Execute all requested modules.\r
}\r
}\r
\r
- protected function executeGenerator($generator, $redirects) {\r
+ protected function executeGenerator($generator) {\r
\r
// Find class that implements requested generator\r
if (isset ($this->mQueryListModules[$generator]))\r
'list' => array (\r
GN_ENUM_ISMULTI => true,\r
GN_ENUM_TYPE => $this->mListModuleNames\r
- ),\r
+ )\r
// 'generator' => array (\r
// GN_ENUM_TYPE => $this->mAllowedGenerators\r
// ),\r
- 'titles' => array (\r
- GN_ENUM_ISMULTI => true\r
- ),\r
- // 'pageids' => array (\r
- // GN_ENUM_TYPE => 'integer',\r
- // GN_ENUM_ISMULTI => true\r
- // ),\r
- 'redirects' => false\r
);\r
}\r
\r
return $msg;\r
}\r
\r
+ /**\r
+ * Override to add extra parameters from PageSet\r
+ */ \r
+ public function makeHelpMsgParameters() {\r
+ $module = new ApiPageSet($this);\r
+ return $module->makeHelpMsgParameters() . parent :: makeHelpMsgParameters();\r
+ }\r
+ \r
+\r
protected function getParamDescription() {\r
return array (\r
'meta' => 'Which meta data to get about the site',\r
'prop' => 'Which properties to get for the titles/revisions/pageids',\r
'list' => 'Which lists to get',\r
'generator' => 'Use the output of a list as the input for other prop/list/meta items',\r
- 'titles' => 'A list of titles to work on',\r
- 'pageids' => 'A list of page IDs to work on',\r
- 'redirects' => 'Automatically resolve redirects'\r
);\r
}\r
\r
}
public function execute() {
- $rvrevids = $rvlimit = $rvstartid = $rvendid = $rvstart = $rvend = $rvdir = $rvprop = null;
+ $rvlimit = $rvstartid = $rvendid = $rvstart = $rvend = $rvdir = $rvprop = null;
extract($this->extractRequestParams());
- //
- // Parameter validation
- //
-
// true when ordered by timestamp from older to newer, false otherwise
$dirNewer = ($rvdir === 'newer');
- // If any of those parameters are used, we can only work with a single page
+ // If any of those parameters are used, work in "enumeration" mode.
+ // Enum mode can only be used when exactly one page is provided.
// Enumerating revisions on multiple pages make it extremelly
// difficult to manage continuations and require additional sql indexes
$enumRevMode = ($rvlimit !== 0 || $rvstartid !== 0 || $rvendid !== 0 || $dirNewer || isset ($rvstart) || isset ($rvend));
- if ($rvstartid !== 0 || $rvendid !== 0)
- $this->dieUsage('rvstartid/rvendid not implemented', 'notimplemented');
-
$data = $this->getData();
- $pageCount = $data->getPageCount();
+ $pageCount = $data->getGoodTitleCount();
+ $revCount = $data->getRevisionCount();
- if (!empty ($rvrevids)) {
- if ($pageCount > 0)
- $this->dieUsage('The rvrevids= parameter may not be used with titles, pageids, and generator options.', 'rv_rvrevids');
+ if ($revCount > 0 && $pageCount > 0)
+ $this->dieUsage('The rvrevids= parameter may not be used with titles, pageids, and generator options.', 'rv_rvrevids');
- if ($enumRevMode)
- $this->dieUsage('The rvrevids= parameter may not be used with the list options (rvlimit, rvstartid, rvendid, dirNewer, rvstart, rvend).', 'rv_rvrevids');
- } else {
- if ($pageCount < 1)
- $this->dieUsage('No pages were given. Please use titles, pageids or a generator to provide page(s) to work on.', 'rv_no_pages');
+ if ($revCount > 0 && $enumRevMode)
+ $this->dieUsage('The rvrevids= parameter may not be used with the list options (rvlimit, rvstartid, rvendid, dirNewer, rvstart, rvend).', 'rv_rvrevids');
- if ($enumRevMode && $pageCount > 1)
- $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the rvlimit, rvstartid, rvendid, dirNewer, rvstart, and rvend parameters may only be used on a single page.', 'rv_multpages');
- }
+ if ($revCount === 0 && $pageCount === 0)
+ $this->dieUsage('No pages were given. Please use titles, pageids or a generator to provide page(s) to work on.', 'rv_no_pages');
+
+ if ($revCount === 0 && $pageCount > 1 && $enumRevMode)
+ $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the rvlimit, rvstartid, rvendid, dirNewer, rvstart, and rvend parameters may only be used on a single page.', 'rv_multpages');
$tables = array (
'revision'
$fields[] = 'old_id';
$fields[] = 'old_text';
$fields[] = 'old_flags';
- $showContent = true;
+ $showContent = true;
break;
default :
$this->dieDebug("unknown rvprop $prop");
if ($enumRevMode) {
+ // This is mostly to prevent parameter errors (and optimize sql?)
+ if ($rvstartid !== 0 && isset ($rvstart))
+ $this->dieUsage('rvstart and rvstartid cannot be used together', 'rv_badparams');
+
+ if ($rvendid !== 0 && isset ($rvend))
+ $this->dieUsage('rvend and rvend cannot be used together', 'rv_badparams');
+
+ $options['ORDER BY'] = 'rev_timestamp' . ($dirNewer ? '' : ' DESC');
+ $before = ($dirNewer ? '<=' : '>=');
+ $after = ($dirNewer ? '>=' : '<=');
+
+ if ($rvstartid !== 0)
+ $conds[] = 'rev_id' . $after . intval($rvstartid);
+ if ($rvendid !== 0)
+ $conds[] = 'rev_id' . $before . intval($rvendid);
if (isset ($rvstart))
- $conds[] = 'rev_timestamp >= ' . $this->prepareTimestamp($rvstart);
+ $conds[] = 'rev_timestamp' . $after . $this->prepareTimestamp($rvstart);
if (isset ($rvend))
- $conds[] = 'rev_timestamp <= ' . $this->prepareTimestamp($rvend);
+ $conds[] = 'rev_timestamp' . $before . $this->prepareTimestamp($rvend);
// must manually initialize unset rvlimit
if (!isset ($rvlimit))
$rvlimit = 10;
- $options['ORDER BY'] = 'rev_timestamp' . ($dirNewer ? '' : ' DESC');
-
$this->validateLimit('rvlimit', $rvlimit, 1, $userMax, $botMax);
- // There is only one ID
- $conds['rev_page'] = array_keys($data->getGoodTitles());
-
- } else {
- // 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($data->getGoodTitles());
-
- $rvlimit = $pageCount; // assumption testing -- we should never get more then $pageCount rows.
- }
+ // 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);
+
+ // 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);
+
+ // Get all revision IDs
+ $conds['rev_id'] = array_keys($data->getRevisionIDs());
- $options['LIMIT'] = $rvlimit +1;
+ $rvlimit = $revCount; // assumption testing -- we should never get more then $revCount rows.
+ } else
+ $this->dieDebug('param validation?');
+
+ $options['LIMIT'] = $rvlimit +1;
$db = $this->getDB();
$this->profileDBIn();
if (++ $count > $rvlimit) {
// We've reached the one extra which shows that there are additional pages to be had. Stop here...
- if (!$enumRevMode)
- $this->dieDebug('Got more rows then expected'); // bug report
-
+ if (!$enumRevMode)
+ $this->dieDebug('Got more rows then expected'); // bug report
+
$startStr = 'rvstartid=' . $row->rev_id;
$msg = array (
'continue' => $startStr
}
$vals = array (
- 'revid' => intval($row->rev_id),
- 'oldid' => intval($row->rev_text_id
- ));
+ 'revid' => intval($row->rev_id
+ ), 'oldid' => intval($row->rev_text_id));
if ($row->rev_minor_edit) {
$vals['minor'] = '';
}
protected function getDescription() {
- return 'module a';
+ 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.'
+ );
}
protected function getExamples() {