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 getCacheMode( $params ) {
00047 return 'public';
00048 }
00049
00050 public function executeGenerator( $resultPageSet ) {
00051 $this->run( $resultPageSet );
00052 }
00053
00054 private function run( $resultPageSet = null ) {
00055
00056 $params = $this->extractRequestParams();
00057
00058 if ( !isset( $params['title'] ) || is_null( $params['title'] ) )
00059 $this->dieUsage( "The cmtitle parameter is required", 'notitle' );
00060 $categoryTitle = Title::newFromText( $params['title'] );
00061
00062 if ( is_null( $categoryTitle ) || $categoryTitle->getNamespace() != NS_CATEGORY )
00063 $this->dieUsage( "The category name you entered is not valid", 'invalidcategory' );
00064
00065 $prop = array_flip( $params['prop'] );
00066 $fld_ids = isset( $prop['ids'] );
00067 $fld_title = isset( $prop['title'] );
00068 $fld_sortkey = isset( $prop['sortkey'] );
00069 $fld_timestamp = isset( $prop['timestamp'] );
00070
00071 if ( is_null( $resultPageSet ) ) {
00072 $this->addFields( array( 'cl_from', 'cl_sortkey', 'page_namespace', 'page_title' ) );
00073 $this->addFieldsIf( 'page_id', $fld_ids );
00074 } else {
00075 $this->addFields( $resultPageSet->getPageTableFields() );
00076 $this->addFields( array( 'cl_from', 'cl_sortkey' ) );
00077 }
00078
00079 $this->addFieldsIf( 'cl_timestamp', $fld_timestamp || $params['sort'] == 'timestamp' );
00080 $this->addTables( array( 'page', 'categorylinks' ) );
00081
00082 if ( $params['sort'] == 'timestamp' )
00083 $this->addOption( 'USE INDEX', 'cl_timestamp' );
00084 else
00085 $this->addOption( 'USE INDEX', 'cl_sortkey' );
00086
00087 $this->addWhere( 'cl_from=page_id' );
00088 $this->setContinuation( $params['continue'], $params['dir'] );
00089 $this->addWhereFld( 'cl_to', $categoryTitle->getDBkey() );
00090
00091
00092 global $wgMiserMode;
00093 $miser_ns = array();
00094 if ( $wgMiserMode ) {
00095 $miser_ns = $params['namespace'];
00096 } else {
00097 $this->addWhereFld( 'page_namespace', $params['namespace'] );
00098 }
00099 if ( $params['sort'] == 'timestamp' )
00100 $this->addWhereRange( 'cl_timestamp', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), $params['start'], $params['end'] );
00101 else
00102 {
00103 $this->addWhereRange( 'cl_sortkey', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), $params['startsortkey'], $params['endsortkey'] );
00104 $this->addWhereRange( 'cl_from', ( $params['dir'] == 'asc' ? 'newer' : 'older' ), null, null );
00105 }
00106
00107 $limit = $params['limit'];
00108 $this->addOption( 'LIMIT', $limit + 1 );
00109
00110 $db = $this->getDB();
00111
00112 $data = array ();
00113 $count = 0;
00114 $lastSortKey = null;
00115 $res = $this->select( __METHOD__ );
00116 while ( $row = $db->fetchObject( $res ) ) {
00117 if ( ++ $count > $limit ) {
00118
00119
00120 if ( $params['sort'] == 'timestamp' )
00121 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) );
00122 else
00123 $this->setContinueEnumParameter( 'continue', $this->getContinueStr( $row, $lastSortKey ) );
00124 break;
00125 }
00126
00127
00128
00129
00130
00131 if ( count( $miser_ns ) && !in_array( $row->page_namespace, $miser_ns ) )
00132 continue;
00133
00134 if ( is_null( $resultPageSet ) ) {
00135 $vals = array();
00136 if ( $fld_ids )
00137 $vals['pageid'] = intval( $row->page_id );
00138 if ( $fld_title ) {
00139 $title = Title :: makeTitle( $row->page_namespace, $row->page_title );
00140 ApiQueryBase::addTitleInfo( $vals, $title );
00141 }
00142 if ( $fld_sortkey )
00143 $vals['sortkey'] = $row->cl_sortkey;
00144 if ( $fld_timestamp )
00145 $vals['timestamp'] = wfTimestamp( TS_ISO_8601, $row->cl_timestamp );
00146 $fit = $this->getResult()->addValue( array( 'query', $this->getModuleName() ),
00147 null, $vals );
00148 if ( !$fit )
00149 {
00150 if ( $params['sort'] == 'timestamp' )
00151 $this->setContinueEnumParameter( 'start', wfTimestamp( TS_ISO_8601, $row->cl_timestamp ) );
00152 else
00153 $this->setContinueEnumParameter( 'continue', $this->getContinueStr( $row, $lastSortKey ) );
00154 break;
00155 }
00156 } else {
00157 $resultPageSet->processDbRow( $row );
00158 }
00159 $lastSortKey = $row->cl_sortkey;
00160 }
00161 $db->freeResult( $res );
00162
00163 if ( is_null( $resultPageSet ) ) {
00164 $this->getResult()->setIndexedTagName_internal(
00165 array( 'query', $this->getModuleName() ), 'cm' );
00166 }
00167 }
00168
00169 private function getContinueStr( $row, $lastSortKey ) {
00170 $ret = $row->cl_sortkey . '|';
00171 if ( $row->cl_sortkey == $lastSortKey )
00172 $ret .= $row->cl_from;
00173 return $ret;
00174 }
00175
00179 private function setContinuation( $continue, $dir ) {
00180 if ( is_null( $continue ) )
00181 return;
00182
00183 $pos = strrpos( $continue, '|' );
00184 $sortkey = substr( $continue, 0, $pos );
00185 $fromstr = substr( $continue, $pos + 1 );
00186 $from = intval( $fromstr );
00187
00188 if ( $from == 0 && strlen( $fromstr ) > 0 )
00189 $this->dieUsage( "Invalid continue param. You should pass the original value returned by the previous query", "badcontinue" );
00190
00191 $encSortKey = $this->getDB()->addQuotes( $sortkey );
00192 $encFrom = $this->getDB()->addQuotes( $from );
00193
00194 $op = ( $dir == 'desc' ? '<' : '>' );
00195
00196 if ( $from != 0 ) {
00197
00198 $this->addWhere( "cl_sortkey$op$encSortKey OR (cl_sortkey=$encSortKey AND cl_from$op=$encFrom)" );
00199 } else {
00200 $this->addWhere( "cl_sortkey$op=$encSortKey" );
00201 }
00202 }
00203
00204 public function getAllowedParams() {
00205 return array (
00206 'title' => null,
00207 'prop' => array (
00208 ApiBase :: PARAM_DFLT => 'ids|title',
00209 ApiBase :: PARAM_ISMULTI => true,
00210 ApiBase :: PARAM_TYPE => array (
00211 'ids',
00212 'title',
00213 'sortkey',
00214 'timestamp',
00215 )
00216 ),
00217 'namespace' => array (
00218 ApiBase :: PARAM_ISMULTI => true,
00219 ApiBase :: PARAM_TYPE => 'namespace',
00220 ),
00221 'continue' => null,
00222 'limit' => array (
00223 ApiBase :: PARAM_TYPE => 'limit',
00224 ApiBase :: PARAM_DFLT => 10,
00225 ApiBase :: PARAM_MIN => 1,
00226 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
00227 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
00228 ),
00229 'sort' => array(
00230 ApiBase :: PARAM_DFLT => 'sortkey',
00231 ApiBase :: PARAM_TYPE => array(
00232 'sortkey',
00233 'timestamp'
00234 )
00235 ),
00236 'dir' => array(
00237 ApiBase :: PARAM_DFLT => 'asc',
00238 ApiBase :: PARAM_TYPE => array(
00239 'asc',
00240 'desc'
00241 )
00242 ),
00243 'start' => array(
00244 ApiBase :: PARAM_TYPE => 'timestamp'
00245 ),
00246 'end' => array(
00247 ApiBase :: PARAM_TYPE => 'timestamp'
00248 ),
00249 'startsortkey' => null,
00250 'endsortkey' => null,
00251 );
00252 }
00253
00254 public function getParamDescription() {
00255 global $wgMiserMode;
00256 $desc = array (
00257 'title' => 'Which category to enumerate (required). Must include Category: prefix',
00258 'prop' => 'What pieces of information to include',
00259 'namespace' => 'Only include pages in these namespaces',
00260 'sort' => 'Property to sort by',
00261 'dir' => 'In which direction to sort',
00262 'start' => 'Timestamp to start listing from. Can only be used with cmsort=timestamp',
00263 'end' => 'Timestamp to end listing at. Can only be used with cmsort=timestamp',
00264 'startsortkey' => 'Sortkey to start listing from. Can only be used with cmsort=sortkey',
00265 'endsortkey' => 'Sortkey to end listing at. Can only be used with cmsort=sortkey',
00266 'continue' => 'For large categories, give the value retured from previous query',
00267 'limit' => 'The maximum number of pages to return.',
00268 );
00269 if ( $wgMiserMode ) {
00270 $desc['namespace'] = array(
00271 $desc['namespace'],
00272 'NOTE: Due to $wgMiserMode, using this may result in fewer than "limit" results',
00273 'returned before continuing; in extreme cases, zero results may be returned.',
00274 );
00275 }
00276 return $desc;
00277 }
00278
00279 public function getDescription() {
00280 return 'List all pages in a given category';
00281 }
00282
00283 public function getPossibleErrors() {
00284 return array_merge( parent::getPossibleErrors(), array(
00285 array( 'code' => 'notitle', 'info' => 'The cmtitle parameter is required' ),
00286 array( 'code' => 'invalidcategory', 'info' => 'The category name you entered is not valid' ),
00287 array( 'code' => 'badcontinue', 'info' => 'Invalid continue param. You should pass the original value returned by the previous query' ),
00288 ) );
00289 }
00290
00291 protected function getExamples() {
00292 return array (
00293 "Get first 10 pages in [[Category:Physics]]:",
00294 " api.php?action=query&list=categorymembers&cmtitle=Category:Physics",
00295 "Get page info about first 10 pages in [[Category:Physics]]:",
00296 " api.php?action=query&generator=categorymembers&gcmtitle=Category:Physics&prop=info",
00297 );
00298 }
00299
00300 public function getVersion() {
00301 return __CLASS__ . ': $Id: ApiQueryCategoryMembers.php 69932 2010-07-26 08:03:21Z tstarling $';
00302 }
00303 }