MediaWiki  REL1_19
ApiQuery.php
Go to the documentation of this file.
00001 <?php
00038 class ApiQuery extends ApiBase {
00039 
00040         private $mPropModuleNames, $mListModuleNames, $mMetaModuleNames;
00041 
00045         private $mPageSet;
00046 
00047         private $params, $redirects, $convertTitles, $iwUrl;
00048 
00049         private $mQueryPropModules = array(
00050                 'info' => 'ApiQueryInfo',
00051                 'revisions' => 'ApiQueryRevisions',
00052                 'links' => 'ApiQueryLinks',
00053                 'iwlinks' => 'ApiQueryIWLinks',
00054                 'langlinks' => 'ApiQueryLangLinks',
00055                 'images' => 'ApiQueryImages',
00056                 'imageinfo' => 'ApiQueryImageInfo',
00057                 'stashimageinfo' => 'ApiQueryStashImageInfo',
00058                 'templates' => 'ApiQueryLinks',
00059                 'categories' => 'ApiQueryCategories',
00060                 'extlinks' => 'ApiQueryExternalLinks',
00061                 'categoryinfo' => 'ApiQueryCategoryInfo',
00062                 'duplicatefiles' => 'ApiQueryDuplicateFiles',
00063                 'pageprops' => 'ApiQueryPageProps',
00064         );
00065 
00066         private $mQueryListModules = array(
00067                 'allimages' => 'ApiQueryAllimages',
00068                 'allpages' => 'ApiQueryAllpages',
00069                 'alllinks' => 'ApiQueryAllLinks',
00070                 'allcategories' => 'ApiQueryAllCategories',
00071                 'allusers' => 'ApiQueryAllUsers',
00072                 'backlinks' => 'ApiQueryBacklinks',
00073                 'blocks' => 'ApiQueryBlocks',
00074                 'categorymembers' => 'ApiQueryCategoryMembers',
00075                 'deletedrevs' => 'ApiQueryDeletedrevs',
00076                 'embeddedin' => 'ApiQueryBacklinks',
00077                 'filearchive' => 'ApiQueryFilearchive',
00078                 'imageusage' => 'ApiQueryBacklinks',
00079                 'iwbacklinks' => 'ApiQueryIWBacklinks',
00080                 'langbacklinks' => 'ApiQueryLangBacklinks',
00081                 'logevents' => 'ApiQueryLogEvents',
00082                 'recentchanges' => 'ApiQueryRecentChanges',
00083                 'search' => 'ApiQuerySearch',
00084                 'tags' => 'ApiQueryTags',
00085                 'usercontribs' => 'ApiQueryContributions',
00086                 'watchlist' => 'ApiQueryWatchlist',
00087                 'watchlistraw' => 'ApiQueryWatchlistRaw',
00088                 'exturlusage' => 'ApiQueryExtLinksUsage',
00089                 'users' => 'ApiQueryUsers',
00090                 'random' => 'ApiQueryRandom',
00091                 'protectedtitles' => 'ApiQueryProtectedTitles',
00092                 'querypage' => 'ApiQueryQueryPage',
00093         );
00094 
00095         private $mQueryMetaModules = array(
00096                 'siteinfo' => 'ApiQuerySiteinfo',
00097                 'userinfo' => 'ApiQueryUserInfo',
00098                 'allmessages' => 'ApiQueryAllmessages',
00099         );
00100 
00101         private $mSlaveDB = null;
00102         private $mNamedDB = array();
00103 
00104         protected $mAllowedGenerators = array();
00105 
00106         public function __construct( $main, $action ) {
00107                 parent::__construct( $main, $action );
00108 
00109                 // Allow custom modules to be added in LocalSettings.php
00110                 global $wgAPIPropModules, $wgAPIListModules, $wgAPIMetaModules;
00111                 self::appendUserModules( $this->mQueryPropModules, $wgAPIPropModules );
00112                 self::appendUserModules( $this->mQueryListModules, $wgAPIListModules );
00113                 self::appendUserModules( $this->mQueryMetaModules, $wgAPIMetaModules );
00114 
00115                 $this->mPropModuleNames = array_keys( $this->mQueryPropModules );
00116                 $this->mListModuleNames = array_keys( $this->mQueryListModules );
00117                 $this->mMetaModuleNames = array_keys( $this->mQueryMetaModules );
00118 
00119                 $this->makeHelpMsgHelper( $this->mQueryPropModules, 'prop' );
00120                 $this->makeHelpMsgHelper( $this->mQueryListModules, 'list' );
00121         }
00122 
00128         private static function appendUserModules( &$modules, $newModules ) {
00129                 if ( is_array( $newModules ) ) {
00130                         foreach ( $newModules as $moduleName => $moduleClass ) {
00131                                 $modules[$moduleName] = $moduleClass;
00132                         }
00133                 }
00134         }
00135 
00140         public function getDB() {
00141                 if ( !isset( $this->mSlaveDB ) ) {
00142                         $this->profileDBIn();
00143                         $this->mSlaveDB = wfGetDB( DB_SLAVE, 'api' );
00144                         $this->profileDBOut();
00145                 }
00146                 return $this->mSlaveDB;
00147         }
00148 
00159         public function getNamedDB( $name, $db, $groups ) {
00160                 if ( !array_key_exists( $name, $this->mNamedDB ) ) {
00161                         $this->profileDBIn();
00162                         $this->mNamedDB[$name] = wfGetDB( $db, $groups );
00163                         $this->profileDBOut();
00164                 }
00165                 return $this->mNamedDB[$name];
00166         }
00167 
00172         public function getPageSet() {
00173                 return $this->mPageSet;
00174         }
00175 
00180         function getModules() {
00181                 return array_merge( $this->mQueryPropModules, $this->mQueryListModules, $this->mQueryMetaModules );
00182         }
00183 
00189         function getModuleType( $moduleName ) {
00190                 if ( isset( $this->mQueryPropModules[$moduleName] ) ) {
00191                         return 'prop';
00192                 }
00193 
00194                 if ( isset( $this->mQueryListModules[$moduleName] ) ) {
00195                         return 'list';
00196                 }
00197 
00198                 if ( isset( $this->mQueryMetaModules[$moduleName] ) ) {
00199                         return 'meta';
00200                 }
00201 
00202                 return null;
00203         }
00204 
00205         public function getCustomPrinter() {
00206                 // If &exportnowrap is set, use the raw formatter
00207                 if ( $this->getParameter( 'export' ) &&
00208                                 $this->getParameter( 'exportnowrap' ) )
00209                 {
00210                         return new ApiFormatRaw( $this->getMain(),
00211                                 $this->getMain()->createPrinterByName( 'xml' ) );
00212                 } else {
00213                         return null;
00214                 }
00215         }
00216 
00227         public function execute() {
00228                 $this->params = $this->extractRequestParams();
00229                 $this->redirects = $this->params['redirects'];
00230                 $this->convertTitles = $this->params['converttitles'];
00231                 $this->iwUrl = $this->params['iwurl'];
00232 
00233                 // Create PageSet
00234                 $this->mPageSet = new ApiPageSet( $this, $this->redirects, $this->convertTitles );
00235 
00236                 // Instantiate requested modules
00237                 $modules = array();
00238                 $this->instantiateModules( $modules, 'prop', $this->mQueryPropModules );
00239                 $this->instantiateModules( $modules, 'list', $this->mQueryListModules );
00240                 $this->instantiateModules( $modules, 'meta', $this->mQueryMetaModules );
00241 
00242                 $cacheMode = 'public';
00243 
00244                 // If given, execute generator to substitute user supplied data with generated data.
00245                 if ( isset( $this->params['generator'] ) ) {
00246                         $generator = $this->newGenerator( $this->params['generator'] );
00247                         $params = $generator->extractRequestParams();
00248                         $cacheMode = $this->mergeCacheMode( $cacheMode,
00249                                 $generator->getCacheMode( $params ) );
00250                         $this->executeGeneratorModule( $generator, $modules );
00251                 } else {
00252                         // Append custom fields and populate page/revision information
00253                         $this->addCustomFldsToPageSet( $modules, $this->mPageSet );
00254                         $this->mPageSet->execute();
00255                 }
00256 
00257                 // Record page information (title, namespace, if exists, etc)
00258                 $this->outputGeneralPageInfo();
00259 
00260                 // Execute all requested modules.
00261                 foreach ( $modules as $module ) {
00262                         $params = $module->extractRequestParams();
00263                         $cacheMode = $this->mergeCacheMode(
00264                                 $cacheMode, $module->getCacheMode( $params ) );
00265                         $module->profileIn();
00266                         $module->execute();
00267                         wfRunHooks( 'APIQueryAfterExecute', array( &$module ) );
00268                         $module->profileOut();
00269                 }
00270 
00271                 // Set the cache mode
00272                 $this->getMain()->setCacheMode( $cacheMode );
00273         }
00274 
00284         protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
00285                 if ( $modCacheMode === 'anon-public-user-private' ) {
00286                         if ( $cacheMode !== 'private' ) {
00287                                 $cacheMode = 'anon-public-user-private';
00288                         }
00289                 } elseif ( $modCacheMode === 'public' ) {
00290                         // do nothing, if it's public already it will stay public
00291                 } else { // private
00292                         $cacheMode = 'private';
00293                 }
00294                 return $cacheMode;
00295         }
00296 
00304         private function addCustomFldsToPageSet( $modules, $pageSet ) {
00305                 // Query all requested modules.
00306                 foreach ( $modules as $module ) {
00307                         $module->requestExtraData( $pageSet );
00308                 }
00309         }
00310 
00317         private function instantiateModules( &$modules, $param, $moduleList ) {
00318                 if ( isset( $this->params[$param] ) ) {
00319                         foreach ( $this->params[$param] as $moduleName ) {
00320                                 $modules[] = new $moduleList[$moduleName] ( $this, $moduleName );
00321                         }
00322                 }
00323         }
00324 
00330         private function outputGeneralPageInfo() {
00331                 $pageSet = $this->getPageSet();
00332                 $result = $this->getResult();
00333 
00334                 // We don't check for a full result set here because we can't be adding
00335                 // more than 380K. The maximum revision size is in the megabyte range,
00336                 // and the maximum result size must be even higher than that.
00337 
00338                 // Title normalizations
00339                 $normValues = array();
00340                 foreach ( $pageSet->getNormalizedTitles() as $rawTitleStr => $titleStr ) {
00341                         $normValues[] = array(
00342                                 'from' => $rawTitleStr,
00343                                 'to' => $titleStr
00344                         );
00345                 }
00346 
00347                 if ( count( $normValues ) ) {
00348                         $result->setIndexedTagName( $normValues, 'n' );
00349                         $result->addValue( 'query', 'normalized', $normValues );
00350                 }
00351 
00352                 // Title conversions
00353                 $convValues = array();
00354                 foreach ( $pageSet->getConvertedTitles() as $rawTitleStr => $titleStr ) {
00355                         $convValues[] = array(
00356                                 'from' => $rawTitleStr,
00357                                 'to' => $titleStr
00358                         );
00359                 }
00360 
00361                 if ( count( $convValues ) ) {
00362                         $result->setIndexedTagName( $convValues, 'c' );
00363                         $result->addValue( 'query', 'converted', $convValues );
00364                 }
00365 
00366                 // Interwiki titles
00367                 $intrwValues = array();
00368                 foreach ( $pageSet->getInterwikiTitles() as $rawTitleStr => $interwikiStr ) {
00369                         $item = array(
00370                                 'title' => $rawTitleStr,
00371                                 'iw' => $interwikiStr,
00372                         );
00373                         if ( $this->iwUrl ) {
00374                                 $title = Title::newFromText( $rawTitleStr );
00375                                 $item['url'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT );
00376                         }
00377                         $intrwValues[] = $item;
00378                 }
00379 
00380                 if ( count( $intrwValues ) ) {
00381                         $result->setIndexedTagName( $intrwValues, 'i' );
00382                         $result->addValue( 'query', 'interwiki', $intrwValues );
00383                 }
00384 
00385                 // Show redirect information
00386                 $redirValues = array();
00387                 foreach ( $pageSet->getRedirectTitles() as $titleStrFrom => $titleTo ) {
00388                         $r = array(
00389                                 'from' => strval( $titleStrFrom ),
00390                                 'to' => $titleTo->getPrefixedText(),
00391                         );
00392                         if ( $titleTo->getFragment() !== '' ) {
00393                                 $r['tofragment'] = $titleTo->getFragment();
00394                         }
00395                         $redirValues[] = $r;
00396                 }
00397 
00398                 if ( count( $redirValues ) ) {
00399                         $result->setIndexedTagName( $redirValues, 'r' );
00400                         $result->addValue( 'query', 'redirects', $redirValues );
00401                 }
00402 
00403                 // Missing revision elements
00404                 $missingRevIDs = $pageSet->getMissingRevisionIDs();
00405                 if ( count( $missingRevIDs ) ) {
00406                         $revids = array();
00407                         foreach ( $missingRevIDs as $revid ) {
00408                                 $revids[$revid] = array(
00409                                         'revid' => $revid
00410                                 );
00411                         }
00412                         $result->setIndexedTagName( $revids, 'rev' );
00413                         $result->addValue( 'query', 'badrevids', $revids );
00414                 }
00415 
00416                 // Page elements
00417                 $pages = array();
00418 
00419                 // Report any missing titles
00420                 foreach ( $pageSet->getMissingTitles() as $fakeId => $title ) {
00421                         $vals = array();
00422                         ApiQueryBase::addTitleInfo( $vals, $title );
00423                         $vals['missing'] = '';
00424                         $pages[$fakeId] = $vals;
00425                 }
00426                 // Report any invalid titles
00427                 foreach ( $pageSet->getInvalidTitles() as $fakeId => $title ) {
00428                         $pages[$fakeId] = array( 'title' => $title, 'invalid' => '' );
00429                 }
00430                 // Report any missing page ids
00431                 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
00432                         $pages[$pageid] = array(
00433                                 'pageid' => $pageid,
00434                                 'missing' => ''
00435                         );
00436                 }
00437                 // Report special pages
00438                 foreach ( $pageSet->getSpecialTitles() as $fakeId => $title ) {
00439                         $vals = array();
00440                         ApiQueryBase::addTitleInfo( $vals, $title );
00441                         $vals['special'] = '';
00442                         if ( $title->isSpecialPage() &&
00443                                         !SpecialPageFactory::exists( $title->getDbKey() ) ) {
00444                                 $vals['missing'] = '';
00445                         } elseif ( $title->getNamespace() == NS_MEDIA &&
00446                                         !wfFindFile( $title ) ) {
00447                                 $vals['missing'] = '';
00448                         }
00449                         $pages[$fakeId] = $vals;
00450                 }
00451 
00452                 // Output general page information for found titles
00453                 foreach ( $pageSet->getGoodTitles() as $pageid => $title ) {
00454                         $vals = array();
00455                         $vals['pageid'] = $pageid;
00456                         ApiQueryBase::addTitleInfo( $vals, $title );
00457                         $pages[$pageid] = $vals;
00458                 }
00459 
00460                 if ( count( $pages ) ) {
00461                         if ( $this->params['indexpageids'] ) {
00462                                 $pageIDs = array_keys( $pages );
00463                                 // json treats all map keys as strings - converting to match
00464                                 $pageIDs = array_map( 'strval', $pageIDs );
00465                                 $result->setIndexedTagName( $pageIDs, 'id' );
00466                                 $result->addValue( 'query', 'pageids', $pageIDs );
00467                         }
00468 
00469                         $result->setIndexedTagName( $pages, 'page' );
00470                         $result->addValue( 'query', 'pages', $pages );
00471                 }
00472                 if ( $this->params['export'] ) {
00473                         $this->doExport( $pageSet, $result );
00474                 }
00475         }
00476 
00481         private function doExport( $pageSet, $result )  {
00482                 $exportTitles = array();
00483                 $titles = $pageSet->getGoodTitles();
00484                 if ( count( $titles ) ) {
00485                         foreach ( $titles as $title ) {
00486                                 if ( $title->userCan( 'read' ) ) {
00487                                         $exportTitles[] = $title;
00488                                 }
00489                         }
00490                 }
00491 
00492                 $exporter = new WikiExporter( $this->getDB() );
00493                 // WikiExporter writes to stdout, so catch its
00494                 // output with an ob
00495                 ob_start();
00496                 $exporter->openStream();
00497                 foreach ( $exportTitles as $title ) {
00498                         $exporter->pageByTitle( $title );
00499                 }
00500                 $exporter->closeStream();
00501                 $exportxml = ob_get_contents();
00502                 ob_end_clean();
00503 
00504                 // Don't check the size of exported stuff
00505                 // It's not continuable, so it would cause more
00506                 // problems than it'd solve
00507                 $result->disableSizeCheck();
00508                 if ( $this->params['exportnowrap'] ) {
00509                         $result->reset();
00510                         // Raw formatter will handle this
00511                         $result->addValue( null, 'text', $exportxml );
00512                         $result->addValue( null, 'mime', 'text/xml' );
00513                 } else {
00514                         $r = array();
00515                         ApiResult::setContent( $r, $exportxml );
00516                         $result->addValue( 'query', 'export', $r );
00517                 }
00518                 $result->enableSizeCheck();
00519         }
00520 
00526         public function newGenerator( $generatorName ) {
00527                 // Find class that implements requested generator
00528                 if ( isset( $this->mQueryListModules[$generatorName] ) ) {
00529                         $className = $this->mQueryListModules[$generatorName];
00530                 } elseif ( isset( $this->mQueryPropModules[$generatorName] ) ) {
00531                         $className = $this->mQueryPropModules[$generatorName];
00532                 } else {
00533                         ApiBase::dieDebug( __METHOD__, "Unknown generator=$generatorName" );
00534                 }
00535                 $generator = new $className ( $this, $generatorName );
00536                 if ( !$generator instanceof ApiQueryGeneratorBase ) {
00537                         $this->dieUsage( "Module $generatorName cannot be used as a generator", 'badgenerator' );
00538                 }
00539                 $generator->setGeneratorMode();
00540                 return $generator;
00541         }
00542 
00549         protected function executeGeneratorModule( $generator, $modules ) {
00550                 // Generator results
00551                 $resultPageSet = new ApiPageSet( $this, $this->redirects, $this->convertTitles );
00552 
00553                 // Add any additional fields modules may need
00554                 $generator->requestExtraData( $this->mPageSet );
00555                 $this->addCustomFldsToPageSet( $modules, $resultPageSet );
00556 
00557                 // Populate page information with the original user input
00558                 $this->mPageSet->execute();
00559 
00560                 // populate resultPageSet with the generator output
00561                 $generator->profileIn();
00562                 $generator->executeGenerator( $resultPageSet );
00563                 wfRunHooks( 'APIQueryGeneratorAfterExecute', array( &$generator, &$resultPageSet ) );
00564                 $resultPageSet->finishPageSetGeneration();
00565                 $generator->profileOut();
00566 
00567                 // Swap the resulting pageset back in
00568                 $this->mPageSet = $resultPageSet;
00569         }
00570 
00571         public function getAllowedParams() {
00572                 return array(
00573                         'prop' => array(
00574                                 ApiBase::PARAM_ISMULTI => true,
00575                                 ApiBase::PARAM_TYPE => $this->mPropModuleNames
00576                         ),
00577                         'list' => array(
00578                                 ApiBase::PARAM_ISMULTI => true,
00579                                 ApiBase::PARAM_TYPE => $this->mListModuleNames
00580                         ),
00581                         'meta' => array(
00582                                 ApiBase::PARAM_ISMULTI => true,
00583                                 ApiBase::PARAM_TYPE => $this->mMetaModuleNames
00584                         ),
00585                         'generator' => array(
00586                                 ApiBase::PARAM_TYPE => $this->mAllowedGenerators
00587                         ),
00588                         'redirects' => false,
00589                         'converttitles' => false,
00590                         'indexpageids' => false,
00591                         'export' => false,
00592                         'exportnowrap' => false,
00593                         'iwurl' => false,
00594                 );
00595         }
00596 
00601         public function makeHelpMsg() {
00602                 // Make sure the internal object is empty
00603                 // (just in case a sub-module decides to optimize during instantiation)
00604                 $this->mPageSet = null;
00605                 $this->mAllowedGenerators = array(); // Will be repopulated
00606 
00607                 $querySeparator = str_repeat( '--- ', 12 );
00608                 $moduleSeparator = str_repeat( '*** ', 14 );
00609                 $msg = "\n$querySeparator Query: Prop  $querySeparator\n\n";
00610                 $msg .= $this->makeHelpMsgHelper( $this->mQueryPropModules, 'prop' );
00611                 $msg .= "\n$querySeparator Query: List  $querySeparator\n\n";
00612                 $msg .= $this->makeHelpMsgHelper( $this->mQueryListModules, 'list' );
00613                 $msg .= "\n$querySeparator Query: Meta  $querySeparator\n\n";
00614                 $msg .= $this->makeHelpMsgHelper( $this->mQueryMetaModules, 'meta' );
00615                 $msg .= "\n\n$moduleSeparator Modules: continuation  $moduleSeparator\n\n";
00616 
00617                 // Perform the base call last because the $this->mAllowedGenerators
00618                 // will be updated inside makeHelpMsgHelper()
00619                 // Use parent to make default message for the query module
00620                 $msg = parent::makeHelpMsg() . $msg;
00621 
00622                 return $msg;
00623         }
00624 
00631         private function makeHelpMsgHelper( $moduleList, $paramName ) {
00632                 $moduleDescriptions = array();
00633 
00634                 foreach ( $moduleList as $moduleName => $moduleClass ) {
00638                         $module = new $moduleClass( $this, $moduleName, null );
00639 
00640                         $msg = ApiMain::makeHelpMsgHeader( $module, $paramName );
00641                         $msg2 = $module->makeHelpMsg();
00642                         if ( $msg2 !== false ) {
00643                                 $msg .= $msg2;
00644                         }
00645                         if ( $module instanceof ApiQueryGeneratorBase ) {
00646                                 $this->mAllowedGenerators[] = $moduleName;
00647                                 $msg .= "Generator:\n  This module may be used as a generator\n";
00648                         }
00649                         $moduleDescriptions[] = $msg;
00650                 }
00651 
00652                 return implode( "\n", $moduleDescriptions );
00653         }
00654 
00659         public function makeHelpMsgParameters() {
00660                 $psModule = new ApiPageSet( $this );
00661                 return $psModule->makeHelpMsgParameters() . parent::makeHelpMsgParameters();
00662         }
00663 
00664         public function shouldCheckMaxlag() {
00665                 return true;
00666         }
00667 
00668         public function getParamDescription() {
00669                 return array(
00670                         'prop' => 'Which properties to get for the titles/revisions/pageids. Module help is available below',
00671                         'list' => 'Which lists to get. Module help is available below',
00672                         'meta' => 'Which metadata to get about the site. Module help is available below',
00673                         'generator' => array( 'Use the output of a list as the input for other prop/list/meta items',
00674                                         'NOTE: generator parameter names must be prefixed with a \'g\', see examples' ),
00675                         'redirects' => 'Automatically resolve redirects',
00676                         'converttitles' => array( "Convert titles to other variants if necessary. Only works if the wiki's content language supports variant conversion.",
00677                                         'Languages that support variant conversion include gan, iu, kk, ku, shi, sr, tg, zh' ),
00678                         'indexpageids' => 'Include an additional pageids section listing all returned page IDs',
00679                         'export' => 'Export the current revisions of all given or generated pages',
00680                         'exportnowrap' => 'Return the export XML without wrapping it in an XML result (same format as Special:Export). Can only be used with export',
00681                         'iwurl' => 'Whether to get the full URL if the title is an interwiki link',
00682                 );
00683         }
00684 
00685         public function getDescription() {
00686                 return array(
00687                         'Query API module allows applications to get needed pieces of data from the MediaWiki databases,',
00688                         'and is loosely based on the old query.php interface.',
00689                         'All data modifications will first have to use query to acquire a token to prevent abuse from malicious sites'
00690                 );
00691         }
00692 
00693         public function getPossibleErrors() {
00694                 return array_merge( parent::getPossibleErrors(), array(
00695                         array( 'code' => 'badgenerator', 'info' => 'Module $generatorName cannot be used as a generator' ),
00696                 ) );
00697         }
00698 
00699         public function getExamples() {
00700                 return array(
00701                         'api.php?action=query&prop=revisions&meta=siteinfo&titles=Main%20Page&rvprop=user|comment',
00702                         'api.php?action=query&generator=allpages&gapprefix=API/&prop=revisions',
00703                 );
00704         }
00705 
00706         public function getHelpUrls() {
00707                 return array(
00708                         'https://www.mediawiki.org/wiki/API:Meta',
00709                         'https://www.mediawiki.org/wiki/API:Properties',
00710                         'https://www.mediawiki.org/wiki/API:Lists',
00711                 );
00712         }
00713 
00714         public function getVersion() {
00715                 $psModule = new ApiPageSet( $this );
00716                 $vers = array();
00717                 $vers[] = __CLASS__ . ': $Id$';
00718                 $vers[] = $psModule->getVersion();
00719                 return $vers;
00720         }
00721 }