00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 if (!defined('MEDIAWIKI')) {
00027
00028 require_once ("ApiQueryBase.php");
00029 }
00030
00036 class ApiQueryCategoryMembers extends ApiQueryGeneratorBase {
00037
00038 public function __construct($query, $moduleName) {
00039 parent :: __construct($query, $moduleName, 'cm');
00040 }
00041
00042 public function execute() {
00043 $this->run();
00044 }
00045
00046 public function executeGenerator($resultPageSet) {
00047 $this->run($resultPageSet);
00048 }
00049
00050 private function run($resultPageSet = null) {
00051
00052 $params = $this->extractRequestParams();
00053
00054 if ( !isset($params['title']) || is_null($params['title']) )
00055 $this->dieUsage("The cmtitle parameter is required", 'notitle');
00056 $categoryTitle = Title::newFromText($params['title']);
00057
00058 if ( is_null( $categoryTitle ) || $categoryTitle->getNamespace() != NS_CATEGORY )
00059 $this->dieUsage("The category name you entered is not valid", 'invalidcategory');
00060
00061 $prop = array_flip($params['prop']);
00062 $fld_ids = isset($prop['ids']);
00063 $fld_title = isset($prop['title']);
00064 $fld_sortkey = isset($prop['sortkey']);
00065 $fld_timestamp = isset($prop['timestamp']);
00066
00067 if (is_null($resultPageSet)) {
00068 $this->addFields(array('cl_from', 'cl_sortkey', 'page_namespace', 'page_title'));
00069 $this->addFieldsIf('page_id', $fld_ids);
00070 } else {
00071 $this->addFields($resultPageSet->getPageTableFields());
00072 $this->addFields(array('cl_from', 'cl_sortkey'));
00073 }
00074
00075 $this->addFieldsIf('cl_timestamp', $fld_timestamp || $params['sort'] == 'timestamp');
00076 $this->addTables(array('page','categorylinks'));
00077
00078 if($params['sort'] == 'timestamp')
00079 $this->addOption('USE INDEX', 'cl_timestamp');
00080 else
00081 $this->addOption('USE INDEX', 'cl_sortkey');
00082
00083 $this->addWhere('cl_from=page_id');
00084 $this->setContinuation($params['continue'], $params['dir']);
00085 $this->addWhereFld('cl_to', $categoryTitle->getDBkey());
00086 $this->addWhereFld('page_namespace', $params['namespace']);
00087 if($params['sort'] == 'timestamp')
00088 $this->addWhereRange('cl_timestamp', ($params['dir'] == 'asc' ? 'newer' : 'older'), $params['start'], $params['end']);
00089 else
00090 {
00091 $this->addWhereRange('cl_sortkey', ($params['dir'] == 'asc' ? 'newer' : 'older'), $params['startsortkey'], $params['endsortkey']);
00092 $this->addWhereRange('cl_from', ($params['dir'] == 'asc' ? 'newer' : 'older'), null, null);
00093 }
00094
00095 $limit = $params['limit'];
00096 $this->addOption('LIMIT', $limit +1);
00097
00098 $db = $this->getDB();
00099
00100 $data = array ();
00101 $count = 0;
00102 $lastSortKey = null;
00103 $res = $this->select(__METHOD__);
00104 while ($row = $db->fetchObject($res)) {
00105 if (++ $count > $limit) {
00106
00107
00108 if ($params['sort'] == 'timestamp')
00109 $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->cl_timestamp));
00110 else
00111 $this->setContinueEnumParameter('continue', $this->getContinueStr($row, $lastSortKey));
00112 break;
00113 }
00114
00115 if (is_null($resultPageSet)) {
00116 $vals = array();
00117 if ($fld_ids)
00118 $vals['pageid'] = intval($row->page_id);
00119 if ($fld_title) {
00120 $title = Title :: makeTitle($row->page_namespace, $row->page_title);
00121 ApiQueryBase::addTitleInfo($vals, $title);
00122 }
00123 if ($fld_sortkey)
00124 $vals['sortkey'] = $row->cl_sortkey;
00125 if ($fld_timestamp)
00126 $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $row->cl_timestamp);
00127 $fit = $this->getResult()->addValue(array('query', $this->getModuleName()),
00128 null, $vals);
00129 if(!$fit)
00130 {
00131 if ($params['sort'] == 'timestamp')
00132 $this->setContinueEnumParameter('start', wfTimestamp(TS_ISO_8601, $row->cl_timestamp));
00133 else
00134 $this->setContinueEnumParameter('continue', $this->getContinueStr($row, $lastSortKey));
00135 break;
00136 }
00137 } else {
00138 $resultPageSet->processDbRow($row);
00139 }
00140 $lastSortKey = $row->cl_sortkey;
00141 }
00142 $db->freeResult($res);
00143
00144 if (is_null($resultPageSet)) {
00145 $this->getResult()->setIndexedTagName_internal(
00146 array('query', $this->getModuleName()), 'cm');
00147 }
00148 }
00149
00150 private function getContinueStr($row, $lastSortKey) {
00151 $ret = $row->cl_sortkey . '|';
00152 if ($row->cl_sortkey == $lastSortKey)
00153 $ret .= $row->cl_from;
00154 return $ret;
00155 }
00156
00160 private function setContinuation($continue, $dir) {
00161 if (is_null($continue))
00162 return;
00163
00164 $pos = strrpos($continue, '|');
00165 $sortkey = substr($continue, 0, $pos);
00166 $fromstr = substr($continue, $pos + 1);
00167 $from = intval($fromstr);
00168
00169 if ($from == 0 && strlen($fromstr) > 0)
00170 $this->dieUsage("Invalid continue param. You should pass the original value returned by the previous query", "badcontinue");
00171
00172 $encSortKey = $this->getDB()->addQuotes($sortkey);
00173 $encFrom = $this->getDB()->addQuotes($from);
00174
00175 $op = ($dir == 'desc' ? '<' : '>');
00176
00177 if ($from != 0) {
00178
00179 $this->addWhere( "cl_sortkey$op$encSortKey OR (cl_sortkey=$encSortKey AND cl_from$op=$encFrom)" );
00180 } else {
00181 $this->addWhere( "cl_sortkey$op=$encSortKey" );
00182 }
00183 }
00184
00185 public function getAllowedParams() {
00186 return array (
00187 'title' => null,
00188 'prop' => array (
00189 ApiBase :: PARAM_DFLT => 'ids|title',
00190 ApiBase :: PARAM_ISMULTI => true,
00191 ApiBase :: PARAM_TYPE => array (
00192 'ids',
00193 'title',
00194 'sortkey',
00195 'timestamp',
00196 )
00197 ),
00198 'namespace' => array (
00199 ApiBase :: PARAM_ISMULTI => true,
00200 ApiBase :: PARAM_TYPE => 'namespace',
00201 ),
00202 'continue' => null,
00203 'limit' => array (
00204 ApiBase :: PARAM_TYPE => 'limit',
00205 ApiBase :: PARAM_DFLT => 10,
00206 ApiBase :: PARAM_MIN => 1,
00207 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
00208 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
00209 ),
00210 'sort' => array(
00211 ApiBase :: PARAM_DFLT => 'sortkey',
00212 ApiBase :: PARAM_TYPE => array(
00213 'sortkey',
00214 'timestamp'
00215 )
00216 ),
00217 'dir' => array(
00218 ApiBase :: PARAM_DFLT => 'asc',
00219 ApiBase :: PARAM_TYPE => array(
00220 'asc',
00221 'desc'
00222 )
00223 ),
00224 'start' => array(
00225 ApiBase :: PARAM_TYPE => 'timestamp'
00226 ),
00227 'end' => array(
00228 ApiBase :: PARAM_TYPE => 'timestamp'
00229 ),
00230 'startsortkey' => null,
00231 'endsortkey' => null,
00232 );
00233 }
00234
00235 public function getParamDescription() {
00236 return array (
00237 'title' => 'Which category to enumerate (required). Must include Category: prefix',
00238 'prop' => 'What pieces of information to include',
00239 'namespace' => 'Only include pages in these namespaces',
00240 'sort' => 'Property to sort by',
00241 'dir' => 'In which direction to sort',
00242 'start' => 'Timestamp to start listing from. Can only be used with cmsort=timestamp',
00243 'end' => 'Timestamp to end listing at. Can only be used with cmsort=timestamp',
00244 'startsortkey' => 'Sortkey to start listing from. Can only be used with cmsort=sortkey',
00245 'endsortkey' => 'Sortkey to end listing at. Can only be used with cmsort=sortkey',
00246 'continue' => 'For large categories, give the value retured from previous query',
00247 'limit' => 'The maximum number of pages to return.',
00248 );
00249 }
00250
00251 public function getDescription() {
00252 return 'List all pages in a given category';
00253 }
00254
00255 protected function getExamples() {
00256 return array (
00257 "Get first 10 pages in [[Category:Physics]]:",
00258 " api.php?action=query&list=categorymembers&cmtitle=Category:Physics",
00259 "Get page info about first 10 pages in [[Category:Physics]]:",
00260 " api.php?action=query&generator=categorymembers&gcmtitle=Category:Physics&prop=info",
00261 );
00262 }
00263
00264 public function getVersion() {
00265 return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 47865 2009-02-27 16:03:01Z catrope $';
00266 }
00267 }