MediaWiki  REL1_21
ApiQuery.php
Go to the documentation of this file.
00001 <?php
00038 class ApiQuery extends ApiBase {
00039 
00044         private static $QueryPropModules = array(
00045                 'categories' => 'ApiQueryCategories',
00046                 'categoryinfo' => 'ApiQueryCategoryInfo',
00047                 'duplicatefiles' => 'ApiQueryDuplicateFiles',
00048                 'extlinks' => 'ApiQueryExternalLinks',
00049                 'images' => 'ApiQueryImages',
00050                 'imageinfo' => 'ApiQueryImageInfo',
00051                 'info' => 'ApiQueryInfo',
00052                 'links' => 'ApiQueryLinks',
00053                 'iwlinks' => 'ApiQueryIWLinks',
00054                 'langlinks' => 'ApiQueryLangLinks',
00055                 'pageprops' => 'ApiQueryPageProps',
00056                 'revisions' => 'ApiQueryRevisions',
00057                 'stashimageinfo' => 'ApiQueryStashImageInfo',
00058                 'templates' => 'ApiQueryLinks',
00059         );
00060 
00065         private static $QueryListModules = array(
00066                 'allcategories' => 'ApiQueryAllCategories',
00067                 'allimages' => 'ApiQueryAllImages',
00068                 'alllinks' => 'ApiQueryAllLinks',
00069                 'allpages' => 'ApiQueryAllPages',
00070                 'alltransclusions' => 'ApiQueryAllLinks',
00071                 'allusers' => 'ApiQueryAllUsers',
00072                 'backlinks' => 'ApiQueryBacklinks',
00073                 'blocks' => 'ApiQueryBlocks',
00074                 'categorymembers' => 'ApiQueryCategoryMembers',
00075                 'deletedrevs' => 'ApiQueryDeletedrevs',
00076                 'embeddedin' => 'ApiQueryBacklinks',
00077                 'exturlusage' => 'ApiQueryExtLinksUsage',
00078                 'filearchive' => 'ApiQueryFilearchive',
00079                 'imageusage' => 'ApiQueryBacklinks',
00080                 'iwbacklinks' => 'ApiQueryIWBacklinks',
00081                 'langbacklinks' => 'ApiQueryLangBacklinks',
00082                 'logevents' => 'ApiQueryLogEvents',
00083                 'pageswithprop' => 'ApiQueryPagesWithProp',
00084                 'pagepropnames' => 'ApiQueryPagePropNames',
00085                 'protectedtitles' => 'ApiQueryProtectedTitles',
00086                 'querypage' => 'ApiQueryQueryPage',
00087                 'random' => 'ApiQueryRandom',
00088                 'recentchanges' => 'ApiQueryRecentChanges',
00089                 'search' => 'ApiQuerySearch',
00090                 'tags' => 'ApiQueryTags',
00091                 'usercontribs' => 'ApiQueryContributions',
00092                 'users' => 'ApiQueryUsers',
00093                 'watchlist' => 'ApiQueryWatchlist',
00094                 'watchlistraw' => 'ApiQueryWatchlistRaw',
00095         );
00096 
00101         private static $QueryMetaModules = array(
00102                 'allmessages' => 'ApiQueryAllMessages',
00103                 'siteinfo' => 'ApiQuerySiteinfo',
00104                 'userinfo' => 'ApiQueryUserInfo',
00105         );
00106 
00110         private $mPageSet;
00111 
00112         private $mParams;
00113         private $mNamedDB = array();
00114         private $mModuleMgr;
00115         private $mGeneratorContinue;
00116         private $mUseLegacyContinue;
00117 
00122         public function __construct( $main, $action ) {
00123                 parent::__construct( $main, $action );
00124 
00125                 $this->mModuleMgr = new ApiModuleManager( $this );
00126 
00127                 // Allow custom modules to be added in LocalSettings.php
00128                 global $wgAPIPropModules, $wgAPIListModules, $wgAPIMetaModules;
00129                 $this->mModuleMgr->addModules( self::$QueryPropModules, 'prop' );
00130                 $this->mModuleMgr->addModules( $wgAPIPropModules, 'prop' );
00131                 $this->mModuleMgr->addModules( self::$QueryListModules, 'list' );
00132                 $this->mModuleMgr->addModules( $wgAPIListModules, 'list' );
00133                 $this->mModuleMgr->addModules( self::$QueryMetaModules, 'meta' );
00134                 $this->mModuleMgr->addModules( $wgAPIMetaModules, 'meta' );
00135 
00136                 // Create PageSet that will process titles/pageids/revids/generator
00137                 $this->mPageSet = new ApiPageSet( $this );
00138         }
00139 
00144         public function getModuleManager() {
00145                 return $this->mModuleMgr;
00146         }
00147 
00158         public function getNamedDB( $name, $db, $groups ) {
00159                 if ( !array_key_exists( $name, $this->mNamedDB ) ) {
00160                         $this->profileDBIn();
00161                         $this->mNamedDB[$name] = wfGetDB( $db, $groups );
00162                         $this->profileDBOut();
00163                 }
00164                 return $this->mNamedDB[$name];
00165         }
00166 
00171         public function getPageSet() {
00172                 return $this->mPageSet;
00173         }
00174 
00180         public function getModules() {
00181                 wfDeprecated( __METHOD__, '1.21' );
00182                 return $this->getModuleManager()->getNamesWithClasses();
00183         }
00184 
00190         public function getGenerators() {
00191                 wfDeprecated( __METHOD__, '1.21' );
00192                 $gens = array();
00193                 foreach ( $this->mModuleMgr->getNamesWithClasses() as $name => $class ) {
00194                         if ( is_subclass_of( $class, 'ApiQueryGeneratorBase' ) ) {
00195                                 $gens[$name] = $class;
00196                         }
00197                 }
00198                 return $gens;
00199         }
00200 
00207         function getModuleType( $moduleName ) {
00208                 return $this->getModuleManager()->getModuleGroup( $moduleName );
00209         }
00210 
00214         public function getCustomPrinter() {
00215                 // If &exportnowrap is set, use the raw formatter
00216                 if ( $this->getParameter( 'export' ) &&
00217                                 $this->getParameter( 'exportnowrap' ) )
00218                 {
00219                         return new ApiFormatRaw( $this->getMain(),
00220                                 $this->getMain()->createPrinterByName( 'xml' ) );
00221                 } else {
00222                         return null;
00223                 }
00224         }
00225 
00236         public function execute() {
00237                 $this->mParams = $this->extractRequestParams();
00238 
00239                 // $pagesetParams is a array of parameter names used by the pageset generator
00240                 //   or null if pageset has already finished and is no longer needed
00241                 // $completeModules is a set of complete modules with the name as key
00242                 $this->initContinue( $pagesetParams, $completeModules );
00243 
00244                 // Instantiate requested modules
00245                 $allModules = array();
00246                 $this->instantiateModules( $allModules, 'prop' );
00247                 $propModules = $allModules; // Keep a copy
00248                 $this->instantiateModules( $allModules, 'list' );
00249                 $this->instantiateModules( $allModules, 'meta' );
00250 
00251                 // Filter modules based on continue parameter
00252                 $modules = $this->initModules( $allModules, $completeModules, $pagesetParams !== null );
00253 
00254                 // Execute pageset if in legacy mode or if pageset is not done
00255                 if ( $completeModules === null || $pagesetParams !== null ) {
00256                         // Populate page/revision information
00257                         $this->mPageSet->execute();
00258                         // Record page information (title, namespace, if exists, etc)
00259                         $this->outputGeneralPageInfo();
00260                 } else {
00261                         $this->mPageSet->executeDryRun();
00262                 }
00263 
00264                 $cacheMode = $this->mPageSet->getCacheMode();
00265 
00266                 // Execute all unfinished modules
00268                 foreach ( $modules as $module ) {
00269                         $params = $module->extractRequestParams();
00270                         $cacheMode = $this->mergeCacheMode(
00271                                 $cacheMode, $module->getCacheMode( $params ) );
00272                         $module->profileIn();
00273                         $module->execute();
00274                         wfRunHooks( 'APIQueryAfterExecute', array( &$module ) );
00275                         $module->profileOut();
00276                 }
00277 
00278                 // Set the cache mode
00279                 $this->getMain()->setCacheMode( $cacheMode );
00280 
00281                 if ( $completeModules === null ) {
00282                         return; // Legacy continue, we are done
00283                 }
00284 
00285                 // Reformat query-continue result section
00286                 $result = $this->getResult();
00287                 $qc = $result->getData();
00288                 if ( isset( $qc['query-continue'] ) ) {
00289                         $qc = $qc['query-continue'];
00290                         $result->unsetValue( null, 'query-continue' );
00291                 } elseif ( $this->mGeneratorContinue !== null ) {
00292                         $qc = array();
00293                 } else {
00294                         // no more "continue"s, we are done!
00295                         return;
00296                 }
00297 
00298                 // we are done with all the modules that do not have result in query-continue
00299                 $completeModules = array_merge( $completeModules, array_diff_key( $modules, $qc ) );
00300                 if ( $pagesetParams !== null ) {
00301                         // The pageset is still in use, check if all props have finished
00302                         $incompleteProps = array_intersect_key( $propModules, $qc );
00303                         if ( count( $incompleteProps ) > 0 ) {
00304                                 // Properties are not done, continue with the same pageset state - copy current parameters
00305                                 $main = $this->getMain();
00306                                 $contValues = array();
00307                                 foreach ( $pagesetParams as $param ) {
00308                                         // The param name is already prefix-encoded
00309                                         $contValues[$param] = $main->getVal( $param );
00310                                 }
00311                         } elseif ( $this->mGeneratorContinue !== null ) {
00312                                 // Move to the next set of pages produced by pageset, properties need to be restarted
00313                                 $contValues = $this->mGeneratorContinue;
00314                                 $pagesetParams = array_keys( $contValues );
00315                                 $completeModules = array_diff_key( $completeModules, $propModules );
00316                         } else {
00317                                 // Done with the pageset, finish up with the the lists and meta modules
00318                                 $pagesetParams = null;
00319                         }
00320                 }
00321 
00322                 $continue = '||' . implode( '|', array_keys( $completeModules ) );
00323                 if ( $pagesetParams !== null ) {
00324                         // list of all pageset parameters to use in the next request
00325                         $continue = implode( '|', $pagesetParams ) . $continue;
00326                 } else {
00327                         // we are done with the pageset
00328                         $contValues = array();
00329                         $continue = '-' . $continue;
00330                 }
00331                 $contValues['continue'] = $continue;
00332                 foreach ( $qc as $qcModule ) {
00333                         foreach ( $qcModule as $qcKey => $qcValue ) {
00334                                 $contValues[$qcKey] = $qcValue;
00335                         }
00336                 }
00337                 $this->getResult()->addValue( null, 'continue', $contValues );
00338         }
00339 
00345         private function initContinue( &$pagesetParams, &$completeModules ) {
00346                 $pagesetParams = array();
00347                 $continue = $this->mParams['continue'];
00348                 if ( $continue !== null ) {
00349                         $this->mUseLegacyContinue = false;
00350                         if ( $continue !== '' ) {
00351                                 // Format: ' pagesetParam1 | pagesetParam2 || module1 | module2 | module3 | ...
00352                                 // If pageset is done, use '-'
00353                                 $continue = explode( '||', $continue );
00354                                 $this->dieContinueUsageIf( count( $continue ) !== 2 );
00355                                 if ( $continue[0] === '-' ) {
00356                                         $pagesetParams = null; // No need to execute pageset
00357                                 } elseif ( $continue[0] !== '' ) {
00358                                         // list of pageset params that might need to be repeated
00359                                         $pagesetParams = explode( '|', $continue[0] );
00360                                 }
00361                                 $continue = $continue[1];
00362                         }
00363                         if ( $continue !== '' ) {
00364                                 $completeModules = array_flip( explode( '|', $continue ) );
00365                         } else {
00366                                 $completeModules = array();
00367                         }
00368                 } else {
00369                         $this->mUseLegacyContinue = true;
00370                         $completeModules = null;
00371                 }
00372         }
00373 
00381         private function initModules( $allModules, $completeModules, $usePageset ) {
00382                 $modules = $allModules;
00383                 $tmp = $completeModules;
00384                 $wasPosted = $this->getRequest()->wasPosted();
00385                 $main = $this->getMain();
00386 
00388                 foreach ( $allModules as $moduleName => $module ) {
00389                         if ( !$wasPosted && $module->mustBePosted() ) {
00390                                 $this->dieUsageMsgOrDebug( array( 'mustbeposted', $moduleName ) );
00391                         }
00392                         if ( $completeModules !== null && array_key_exists( $moduleName, $completeModules ) ) {
00393                                 // If this module is done, mark all its params as used
00394                                 $module->extractRequestParams();
00395                                 // Make sure this module is not used during execution
00396                                 unset( $modules[$moduleName] );
00397                                 unset( $tmp[$moduleName] );
00398                         } elseif ( $completeModules === null || $usePageset ) {
00399                                 // Query modules may optimize data requests through the $this->getPageSet()
00400                                 // object by adding extra fields from the page table.
00401                                 // This function will gather all the extra request fields from the modules.
00402                                 $module->requestExtraData( $this->mPageSet );
00403                         } else {
00404                                 // Error - this prop module must have finished before generator is done
00405                                 $this->dieContinueUsageIf( $this->mModuleMgr->getModuleGroup( $moduleName ) === 'prop' );
00406                         }
00407                 }
00408                 $this->dieContinueUsageIf( $completeModules !== null && count( $tmp ) !== 0 );
00409                 return $modules;
00410         }
00411 
00421         protected function mergeCacheMode( $cacheMode, $modCacheMode ) {
00422                 if ( $modCacheMode === 'anon-public-user-private' ) {
00423                         if ( $cacheMode !== 'private' ) {
00424                                 $cacheMode = 'anon-public-user-private';
00425                         }
00426                 } elseif ( $modCacheMode === 'public' ) {
00427                         // do nothing, if it's public already it will stay public
00428                 } else { // private
00429                         $cacheMode = 'private';
00430                 }
00431                 return $cacheMode;
00432         }
00433 
00439         private function instantiateModules( &$modules, $param ) {
00440                 if ( isset( $this->mParams[$param] ) ) {
00441                         foreach ( $this->mParams[$param] as $moduleName ) {
00442                                 $instance = $this->mModuleMgr->getModule( $moduleName, $param );
00443                                 if ( $instance === null ) {
00444                                         ApiBase::dieDebug( __METHOD__, 'Error instantiating module' );
00445                                 }
00446                                 // Ignore duplicates. TODO 2.0: die()?
00447                                 if ( !array_key_exists( $moduleName, $modules ) ) {
00448                                         $modules[$moduleName] = $instance;
00449                                 }
00450                         }
00451                 }
00452         }
00453 
00459         private function outputGeneralPageInfo() {
00460                 $pageSet = $this->getPageSet();
00461                 $result = $this->getResult();
00462 
00463                 // We don't check for a full result set here because we can't be adding
00464                 // more than 380K. The maximum revision size is in the megabyte range,
00465                 // and the maximum result size must be even higher than that.
00466 
00467                 $values = $pageSet->getNormalizedTitlesAsResult( $result );
00468                 if ( $values ) {
00469                         $result->addValue( 'query', 'normalized', $values );
00470                 }
00471                 $values = $pageSet->getConvertedTitlesAsResult( $result );
00472                 if ( $values ) {
00473                         $result->addValue( 'query', 'converted', $values );
00474                 }
00475                 $values = $pageSet->getInterwikiTitlesAsResult( $result, $this->mParams['iwurl'] );
00476                 if ( $values ) {
00477                         $result->addValue( 'query', 'interwiki', $values );
00478                 }
00479                 $values = $pageSet->getRedirectTitlesAsResult( $result );
00480                 if ( $values ) {
00481                         $result->addValue( 'query', 'redirects', $values );
00482                 }
00483                 $values = $pageSet->getMissingRevisionIDsAsResult( $result );
00484                 if ( $values ) {
00485                         $result->addValue( 'query', 'badrevids', $values );
00486                 }
00487 
00488                 // Page elements
00489                 $pages = array();
00490 
00491                 // Report any missing titles
00492                 foreach ( $pageSet->getMissingTitles() as $fakeId => $title ) {
00493                         $vals = array();
00494                         ApiQueryBase::addTitleInfo( $vals, $title );
00495                         $vals['missing'] = '';
00496                         $pages[$fakeId] = $vals;
00497                 }
00498                 // Report any invalid titles
00499                 foreach ( $pageSet->getInvalidTitles() as $fakeId => $title ) {
00500                         $pages[$fakeId] = array( 'title' => $title, 'invalid' => '' );
00501                 }
00502                 // Report any missing page ids
00503                 foreach ( $pageSet->getMissingPageIDs() as $pageid ) {
00504                         $pages[$pageid] = array(
00505                                 'pageid' => $pageid,
00506                                 'missing' => ''
00507                         );
00508                 }
00509                 // Report special pages
00511                 foreach ( $pageSet->getSpecialTitles() as $fakeId => $title ) {
00512                         $vals = array();
00513                         ApiQueryBase::addTitleInfo( $vals, $title );
00514                         $vals['special'] = '';
00515                         if ( $title->isSpecialPage() &&
00516                                         !SpecialPageFactory::exists( $title->getDbKey() ) ) {
00517                                 $vals['missing'] = '';
00518                         } elseif ( $title->getNamespace() == NS_MEDIA &&
00519                                         !wfFindFile( $title ) ) {
00520                                 $vals['missing'] = '';
00521                         }
00522                         $pages[$fakeId] = $vals;
00523                 }
00524 
00525                 // Output general page information for found titles
00526                 foreach ( $pageSet->getGoodTitles() as $pageid => $title ) {
00527                         $vals = array();
00528                         $vals['pageid'] = $pageid;
00529                         ApiQueryBase::addTitleInfo( $vals, $title );
00530                         $pages[$pageid] = $vals;
00531                 }
00532 
00533                 if ( count( $pages ) ) {
00534                         if ( $this->mParams['indexpageids'] ) {
00535                                 $pageIDs = array_keys( $pages );
00536                                 // json treats all map keys as strings - converting to match
00537                                 $pageIDs = array_map( 'strval', $pageIDs );
00538                                 $result->setIndexedTagName( $pageIDs, 'id' );
00539                                 $result->addValue( 'query', 'pageids', $pageIDs );
00540                         }
00541 
00542                         $result->setIndexedTagName( $pages, 'page' );
00543                         $result->addValue( 'query', 'pages', $pages );
00544                 }
00545                 if ( $this->mParams['export'] ) {
00546                         $this->doExport( $pageSet, $result );
00547                 }
00548         }
00549 
00559         public function setGeneratorContinue( $module, $paramName, $paramValue ) {
00560                 if ( $this->mUseLegacyContinue ) {
00561                         return false;
00562                 }
00563                 $paramName = $module->encodeParamName( $paramName );
00564                 if ( $this->mGeneratorContinue === null ) {
00565                         $this->mGeneratorContinue = array();
00566                 }
00567                 $this->mGeneratorContinue[$paramName] = $paramValue;
00568                 return true;
00569         }
00570 
00575         private function doExport( $pageSet, $result ) {
00576                 $exportTitles = array();
00577                 $titles = $pageSet->getGoodTitles();
00578                 if ( count( $titles ) ) {
00579                         $user = $this->getUser();
00581                         foreach ( $titles as $title ) {
00582                                 if ( $title->userCan( 'read', $user ) ) {
00583                                         $exportTitles[] = $title;
00584                                 }
00585                         }
00586                 }
00587 
00588                 $exporter = new WikiExporter( $this->getDB() );
00589                 // WikiExporter writes to stdout, so catch its
00590                 // output with an ob
00591                 ob_start();
00592                 $exporter->openStream();
00593                 foreach ( $exportTitles as $title ) {
00594                         $exporter->pageByTitle( $title );
00595                 }
00596                 $exporter->closeStream();
00597                 $exportxml = ob_get_contents();
00598                 ob_end_clean();
00599 
00600                 // Don't check the size of exported stuff
00601                 // It's not continuable, so it would cause more
00602                 // problems than it'd solve
00603                 $result->disableSizeCheck();
00604                 if ( $this->mParams['exportnowrap'] ) {
00605                         $result->reset();
00606                         // Raw formatter will handle this
00607                         $result->addValue( null, 'text', $exportxml );
00608                         $result->addValue( null, 'mime', 'text/xml' );
00609                 } else {
00610                         $r = array();
00611                         ApiResult::setContent( $r, $exportxml );
00612                         $result->addValue( 'query', 'export', $r );
00613                 }
00614                 $result->enableSizeCheck();
00615         }
00616 
00617         public function getAllowedParams( $flags = 0 ) {
00618                 $result = array(
00619                         'prop' => array(
00620                                 ApiBase::PARAM_ISMULTI => true,
00621                                 ApiBase::PARAM_TYPE => $this->mModuleMgr->getNames( 'prop' )
00622                         ),
00623                         'list' => array(
00624                                 ApiBase::PARAM_ISMULTI => true,
00625                                 ApiBase::PARAM_TYPE => $this->mModuleMgr->getNames( 'list' )
00626                         ),
00627                         'meta' => array(
00628                                 ApiBase::PARAM_ISMULTI => true,
00629                                 ApiBase::PARAM_TYPE => $this->mModuleMgr->getNames( 'meta' )
00630                         ),
00631                         'indexpageids' => false,
00632                         'export' => false,
00633                         'exportnowrap' => false,
00634                         'iwurl' => false,
00635                         'continue' => null,
00636                 );
00637                 if ( $flags ) {
00638                         $result += $this->getPageSet()->getFinalParams( $flags );
00639                 }
00640                 return $result;
00641         }
00642 
00647         public function makeHelpMsg() {
00648 
00649                 // Use parent to make default message for the query module
00650                 $msg = parent::makeHelpMsg();
00651 
00652                 $querySeparator = str_repeat( '--- ', 12 );
00653                 $moduleSeparator = str_repeat( '*** ', 14 );
00654                 $msg .= "\n$querySeparator Query: Prop  $querySeparator\n\n";
00655                 $msg .= $this->makeHelpMsgHelper( 'prop' );
00656                 $msg .= "\n$querySeparator Query: List  $querySeparator\n\n";
00657                 $msg .= $this->makeHelpMsgHelper( 'list' );
00658                 $msg .= "\n$querySeparator Query: Meta  $querySeparator\n\n";
00659                 $msg .= $this->makeHelpMsgHelper( 'meta' );
00660                 $msg .= "\n\n$moduleSeparator Modules: continuation  $moduleSeparator\n\n";
00661 
00662                 return $msg;
00663         }
00664 
00670         private function makeHelpMsgHelper( $group ) {
00671                 $moduleDescriptions = array();
00672 
00673                 $moduleNames = $this->mModuleMgr->getNames( $group );
00674                 sort( $moduleNames );
00675                 foreach ( $moduleNames as $name ) {
00679                         $module = $this->mModuleMgr->getModule( $name );
00680 
00681                         $msg = ApiMain::makeHelpMsgHeader( $module, $group );
00682                         $msg2 = $module->makeHelpMsg();
00683                         if ( $msg2 !== false ) {
00684                                 $msg .= $msg2;
00685                         }
00686                         if ( $module instanceof ApiQueryGeneratorBase ) {
00687                                 $msg .= "Generator:\n  This module may be used as a generator\n";
00688                         }
00689                         $moduleDescriptions[] = $msg;
00690                 }
00691 
00692                 return implode( "\n", $moduleDescriptions );
00693         }
00694 
00695         public function shouldCheckMaxlag() {
00696                 return true;
00697         }
00698 
00699         public function getParamDescription() {
00700                 return $this->getPageSet()->getParamDescription() + array(
00701                         'prop' => 'Which properties to get for the titles/revisions/pageids. Module help is available below',
00702                         'list' => 'Which lists to get. Module help is available below',
00703                         'meta' => 'Which metadata to get about the site. Module help is available below',
00704                         'indexpageids' => 'Include an additional pageids section listing all returned page IDs',
00705                         'export' => 'Export the current revisions of all given or generated pages',
00706                         'exportnowrap' => 'Return the export XML without wrapping it in an XML result (same format as Special:Export). Can only be used with export',
00707                         'iwurl' => 'Whether to get the full URL if the title is an interwiki link',
00708                         'continue' => array(
00709                                 'When present, formats query-continue as key-value pairs that should simply be merged into the original request.',
00710                                 'This parameter must be set to an empty string in the initial query.',
00711                                 'This parameter is recommended for all new development, and will be made default in the next API version.' ),
00712                 );
00713         }
00714 
00715         public function getDescription() {
00716                 return array(
00717                         'Query API module allows applications to get needed pieces of data from the MediaWiki databases,',
00718                         'and is loosely based on the old query.php interface.',
00719                         'All data modifications will first have to use query to acquire a token to prevent abuse from malicious sites'
00720                 );
00721         }
00722 
00723         public function getPossibleErrors() {
00724                 return array_merge(
00725                         parent::getPossibleErrors(),
00726                         $this->getPageSet()->getPossibleErrors()
00727                 );
00728         }
00729 
00730         public function getExamples() {
00731                 return array(
00732                         'api.php?action=query&prop=revisions&meta=siteinfo&titles=Main%20Page&rvprop=user|comment&continue=',
00733                         'api.php?action=query&generator=allpages&gapprefix=API/&prop=revisions&continue=',
00734                 );
00735         }
00736 
00737         public function getHelpUrls() {
00738                 return array(
00739                         'https://www.mediawiki.org/wiki/API:Meta',
00740                         'https://www.mediawiki.org/wiki/API:Properties',
00741                         'https://www.mediawiki.org/wiki/API:Lists',
00742                 );
00743         }
00744 }