public function testHandleNormalization() { $context = new RequestContext(); $context->setRequest(new FauxRequest(['titles' => "a|B|å"])); $main = new ApiMain($context); $pageSet = new ApiPageSet($main); $pageSet->execute(); $this->assertSame([0 => ['A' => -1, 'B' => -2, 'Å' => -3]], $pageSet->getAllTitlesByNamespace()); $this->assertSame([['fromencoded' => true, 'from' => 'a%CC%8A', 'to' => 'å'], ['fromencoded' => false, 'from' => 'a', 'to' => 'A'], ['fromencoded' => false, 'from' => 'å', 'to' => 'Å']], $pageSet->getNormalizedTitlesAsResult()); }
/** * Query execution happens in the following steps: * #1 Create a PageSet object with any pages requested by the user * #2 If using a generator, execute it to get a new ApiPageSet object * #3 Instantiate all requested modules. * This way the PageSet object will know what shared data is required, * and minimize DB calls. * #4 Output all normalization and redirect resolution information * #5 Execute all requested modules */ public function execute() { $this->mParams = $this->extractRequestParams(); // Instantiate requested modules $allModules = array(); $this->instantiateModules($allModules, 'prop'); $propModules = array_keys($allModules); $this->instantiateModules($allModules, 'list'); $this->instantiateModules($allModules, 'meta'); // Filter modules based on continue parameter $continuationManager = new ApiContinuationManager($this, $allModules, $propModules); $this->setContinuationManager($continuationManager); $modules = $continuationManager->getRunModules(); if (!$continuationManager->isGeneratorDone()) { // Query modules may optimize data requests through the $this->getPageSet() // object by adding extra fields from the page table. foreach ($modules as $module) { $module->requestExtraData($this->mPageSet); } // Populate page/revision information $this->mPageSet->execute(); // Record page information (title, namespace, if exists, etc) $this->outputGeneralPageInfo(); } else { $this->mPageSet->executeDryRun(); } $cacheMode = $this->mPageSet->getCacheMode(); // Execute all unfinished modules /** @var $module ApiQueryBase */ foreach ($modules as $module) { $params = $module->extractRequestParams(); $cacheMode = $this->mergeCacheMode($cacheMode, $module->getCacheMode($params)); $module->execute(); Hooks::run('APIQueryAfterExecute', array(&$module)); } // Set the cache mode $this->getMain()->setCacheMode($cacheMode); // Write the continuation data into the result $this->setContinuationManager(null); if ($this->mParams['rawcontinue']) { $data = $continuationManager->getRawContinuation(); if ($data) { $this->getResult()->addValue(null, 'query-continue', $data, ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK); } } else { $continuationManager->setContinuationIntoResult($this->getResult()); } /// @todo: Remove this after a suitable period of time. When REL1_26 is cut, if not before. if ($this->mParams['continue'] === null && !$this->mParams['rawcontinue'] && $this->getResult()->getResultData('continue') !== null) { $this->setWarning('Formatting of continuation data has changed. ' . 'To receive raw query-continue data, use the \'rawcontinue\' parameter. ' . 'To silence this warning, pass an empty string for \'continue\' in the initial query.'); } }
/** * Query execution happens in the following steps: * #1 Create a PageSet object with any pages requested by the user * #2 If using a generator, execute it to get a new ApiPageSet object * #3 Instantiate all requested modules. * This way the PageSet object will know what shared data is required, * and minimize DB calls. * #4 Output all normalization and redirect resolution information * #5 Execute all requested modules */ public function execute() { $this->mParams = $this->extractRequestParams(); // Instantiate requested modules $allModules = []; $this->instantiateModules($allModules, 'prop'); $propModules = array_keys($allModules); $this->instantiateModules($allModules, 'list'); $this->instantiateModules($allModules, 'meta'); // Filter modules based on continue parameter $continuationManager = new ApiContinuationManager($this, $allModules, $propModules); $this->setContinuationManager($continuationManager); $modules = $continuationManager->getRunModules(); if (!$continuationManager->isGeneratorDone()) { // Query modules may optimize data requests through the $this->getPageSet() // object by adding extra fields from the page table. foreach ($modules as $module) { $module->requestExtraData($this->mPageSet); } // Populate page/revision information $this->mPageSet->execute(); // Record page information (title, namespace, if exists, etc) $this->outputGeneralPageInfo(); } else { $this->mPageSet->executeDryRun(); } $cacheMode = $this->mPageSet->getCacheMode(); // Execute all unfinished modules /** @var $module ApiQueryBase */ foreach ($modules as $module) { $params = $module->extractRequestParams(); $cacheMode = $this->mergeCacheMode($cacheMode, $module->getCacheMode($params)); $module->execute(); Hooks::run('APIQueryAfterExecute', [&$module]); } // Set the cache mode $this->getMain()->setCacheMode($cacheMode); // Write the continuation data into the result $this->setContinuationManager(null); if ($this->mParams['rawcontinue']) { $data = $continuationManager->getRawNonContinuation(); if ($data) { $this->getResult()->addValue(null, 'query-noncontinue', $data, ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK); } $data = $continuationManager->getRawContinuation(); if ($data) { $this->getResult()->addValue(null, 'query-continue', $data, ApiResult::ADD_ON_TOP | ApiResult::NO_SIZE_CHECK); } } else { $continuationManager->setContinuationIntoResult($this->getResult()); } }
/** * For generator mode, execute generator, and use its output as new * ApiPageSet * @param $generator ApiQueryGeneratorBase Generator Module * @param $modules array of module objects */ protected function executeGeneratorModule($generator, $modules) { // Generator results $resultPageSet = new ApiPageSet($this, $this->redirects, $this->convertTitles); // Add any additional fields modules may need $generator->requestExtraData($this->mPageSet); $this->addCustomFldsToPageSet($modules, $resultPageSet); // Populate page information with the original user input $this->mPageSet->execute(); // populate resultPageSet with the generator output $generator->profileIn(); $generator->executeGenerator($resultPageSet); wfRunHooks('APIQueryGeneratorAfterExecute', array(&$generator, &$resultPageSet)); $resultPageSet->finishPageSetGeneration(); $generator->profileOut(); // Swap the resulting pageset back in $this->mPageSet = $resultPageSet; }
/** * Query execution happens in the following steps: * #1 Create a PageSet object with any pages requested by the user * #2 If using a generator, execute it to get a new ApiPageSet object * #3 Instantiate all requested modules. * This way the PageSet object will know what shared data is required, * and minimize DB calls. * #4 Output all normalization and redirect resolution information * #5 Execute all requested modules */ public function execute() { $this->mParams = $this->extractRequestParams(); // Instantiate requested modules $allModules = array(); $this->instantiateModules($allModules, 'prop'); $propModules = array_keys($allModules); $this->instantiateModules($allModules, 'list'); $this->instantiateModules($allModules, 'meta'); // Filter modules based on continue parameter list($generatorDone, $modules) = $this->getResult()->beginContinuation($this->mParams['continue'], $allModules, $propModules); if (!$generatorDone) { // Query modules may optimize data requests through the $this->getPageSet() // object by adding extra fields from the page table. foreach ($modules as $module) { $module->requestExtraData($this->mPageSet); } // Populate page/revision information $this->mPageSet->execute(); // Record page information (title, namespace, if exists, etc) $this->outputGeneralPageInfo(); } else { $this->mPageSet->executeDryRun(); } $cacheMode = $this->mPageSet->getCacheMode(); // Execute all unfinished modules /** @var $module ApiQueryBase */ foreach ($modules as $module) { $params = $module->extractRequestParams(); $cacheMode = $this->mergeCacheMode($cacheMode, $module->getCacheMode($params)); $module->profileIn(); $module->execute(); wfRunHooks('APIQueryAfterExecute', array(&$module)); $module->profileOut(); } // Set the cache mode $this->getMain()->setCacheMode($cacheMode); // Write the continuation data into the result $this->getResult()->endContinuation($this->mParams['continue'] === null ? 'raw' : 'standard'); }
/** * Query execution happens in the following steps: * #1 Create a PageSet object with any pages requested by the user * #2 If using a generator, execute it to get a new ApiPageSet object * #3 Instantiate all requested modules. * This way the PageSet object will know what shared data is required, * and minimize DB calls. * #4 Output all normalization and redirect resolution information * #5 Execute all requested modules */ public function execute() { $this->mParams = $this->extractRequestParams(); // $pagesetParams is a array of parameter names used by the pageset generator // or null if pageset has already finished and is no longer needed // $completeModules is a set of complete modules with the name as key $this->initContinue($pagesetParams, $completeModules); // Instantiate requested modules $allModules = array(); $this->instantiateModules($allModules, 'prop'); $propModules = $allModules; // Keep a copy $this->instantiateModules($allModules, 'list'); $this->instantiateModules($allModules, 'meta'); // Filter modules based on continue parameter $modules = $this->initModules($allModules, $completeModules, $pagesetParams !== null); // Execute pageset if in legacy mode or if pageset is not done if ($completeModules === null || $pagesetParams !== null) { // Populate page/revision information $this->mPageSet->execute(); // Record page information (title, namespace, if exists, etc) $this->outputGeneralPageInfo(); } else { $this->mPageSet->executeDryRun(); } $cacheMode = $this->mPageSet->getCacheMode(); // Execute all unfinished modules /** @var $module ApiQueryBase */ foreach ($modules as $module) { $params = $module->extractRequestParams(); $cacheMode = $this->mergeCacheMode($cacheMode, $module->getCacheMode($params)); $module->profileIn(); $module->execute(); wfRunHooks('APIQueryAfterExecute', array(&$module)); $module->profileOut(); } // Set the cache mode $this->getMain()->setCacheMode($cacheMode); if ($completeModules === null) { return; // Legacy continue, we are done } // Reformat query-continue result section $result = $this->getResult(); $qc = $result->getData(); if (isset($qc['query-continue'])) { $qc = $qc['query-continue']; $result->unsetValue(null, 'query-continue'); } elseif ($this->mGeneratorContinue !== null) { $qc = array(); } else { // no more "continue"s, we are done! return; } // we are done with all the modules that do not have result in query-continue $completeModules = array_merge($completeModules, array_diff_key($modules, $qc)); if ($pagesetParams !== null) { // The pageset is still in use, check if all props have finished $incompleteProps = array_intersect_key($propModules, $qc); if (count($incompleteProps) > 0) { // Properties are not done, continue with the same pageset state - copy current parameters $main = $this->getMain(); $contValues = array(); foreach ($pagesetParams as $param) { // The param name is already prefix-encoded $contValues[$param] = $main->getVal($param); } } elseif ($this->mGeneratorContinue !== null) { // Move to the next set of pages produced by pageset, properties need to be restarted $contValues = $this->mGeneratorContinue; $pagesetParams = array_keys($contValues); $completeModules = array_diff_key($completeModules, $propModules); } else { // Done with the pageset, finish up with the the lists and meta modules $pagesetParams = null; } } $continue = '||' . implode('|', array_keys($completeModules)); if ($pagesetParams !== null) { // list of all pageset parameters to use in the next request $continue = implode('|', $pagesetParams) . $continue; } else { // we are done with the pageset $contValues = array(); $continue = '-' . $continue; } $contValues['continue'] = $continue; foreach ($qc as $qcModule) { foreach ($qcModule as $qcKey => $qcValue) { $contValues[$qcKey] = $qcValue; } } $this->getResult()->addValue(null, 'continue', $contValues); }
public function execute() { $user = $this->getUser(); if ($user->isAnon()) { $this->dieUsage('Anonymous users cannot use watchlist change notifications', 'notloggedin'); } $params = $this->extractRequestParams(); $this->requireMaxOneParameter($params, 'timestamp', 'torevid', 'newerthanrevid'); $pageSet = new ApiPageSet($this); $args = array_merge(array($params, 'entirewatchlist'), array_keys($pageSet->getAllowedParams())); call_user_func_array(array($this, 'requireOnlyOneParameter'), $args); $dbw = $this->getDB(DB_MASTER); $timestamp = null; if (isset($params['timestamp'])) { $timestamp = $dbw->timestamp($params['timestamp']); } if (!$params['entirewatchlist']) { $pageSet->execute(); } if (isset($params['torevid'])) { if ($params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1) { $this->dieUsage('torevid may only be used with a single page', 'multpages'); } $title = reset($pageSet->getGoodTitles()); $timestamp = Revision::getTimestampFromId($title, $params['torevid']); if ($timestamp) { $timestamp = $dbw->timestamp($timestamp); } else { $timestamp = null; } } elseif (isset($params['newerthanrevid'])) { if ($params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1) { $this->dieUsage('newerthanrevid may only be used with a single page', 'multpages'); } $title = reset($pageSet->getGoodTitles()); $revid = $title->getNextRevisionID($params['newerthanrevid']); if ($revid) { $timestamp = $dbw->timestamp(Revision::getTimestampFromId($title, $revid)); } else { $timestamp = null; } } $apiResult = $this->getResult(); $result = array(); if ($params['entirewatchlist']) { // Entire watchlist mode: Just update the thing and return a success indicator $dbw->update('watchlist', array('wl_notificationtimestamp' => $timestamp), array('wl_user' => $user->getID()), __METHOD__); $result['notificationtimestamp'] = is_null($timestamp) ? '' : wfTimestamp(TS_ISO_8601, $timestamp); } else { // First, log the invalid titles foreach ($pageSet->getInvalidTitles() as $title) { $r = array(); $r['title'] = $title; $r['invalid'] = ''; $result[] = $r; } foreach ($pageSet->getMissingPageIDs() as $p) { $page = array(); $page['pageid'] = $p; $page['missing'] = ''; $page['notwatched'] = ''; $result[] = $page; } foreach ($pageSet->getMissingRevisionIDs() as $r) { $rev = array(); $rev['revid'] = $r; $rev['missing'] = ''; $rev['notwatched'] = ''; $result[] = $rev; } // Now process the valid titles $lb = new LinkBatch($pageSet->getTitles()); $dbw->update('watchlist', array('wl_notificationtimestamp' => $timestamp), array('wl_user' => $user->getID(), $lb->constructSet('wl', $dbw)), __METHOD__); // Query the results of our update $timestamps = array(); $res = $dbw->select('watchlist', array('wl_namespace', 'wl_title', 'wl_notificationtimestamp'), array('wl_user' => $user->getID(), $lb->constructSet('wl', $dbw)), __METHOD__); foreach ($res as $row) { $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp; } // Now, put the valid titles into the result foreach ($pageSet->getTitles() as $title) { $ns = $title->getNamespace(); $dbkey = $title->getDBkey(); $r = array('ns' => intval($ns), 'title' => $title->getPrefixedText()); if (!$title->exists()) { $r['missing'] = ''; } if (isset($timestamps[$ns]) && array_key_exists($dbkey, $timestamps[$ns])) { $r['notificationtimestamp'] = ''; if ($timestamps[$ns][$dbkey] !== null) { $r['notificationtimestamp'] = wfTimestamp(TS_ISO_8601, $timestamps[$ns][$dbkey]); } } else { $r['notwatched'] = ''; } $result[] = $r; } $apiResult->setIndexedTagName($result, 'page'); } $apiResult->addValue(null, $this->getModuleName(), $result); }
public function execute() { // The data is hot but user-dependent, like page views, so we set vary cookies $this->getMain()->setCacheMode('anon-public-user-private'); // Get parameters $params = $this->extractRequestParams(); $text = $params['text']; $title = $params['title']; if ($title === null) { $titleProvided = false; // A title is needed for parsing, so arbitrarily choose one $title = 'API'; } else { $titleProvided = true; } $page = $params['page']; $pageid = $params['pageid']; $oldid = $params['oldid']; $model = $params['contentmodel']; $format = $params['contentformat']; if (!is_null($page) && (!is_null($text) || $titleProvided)) { $this->dieUsage('The page parameter cannot be used together with the text and title parameters', 'params'); } $prop = array_flip($params['prop']); if (isset($params['section'])) { $this->section = $params['section']; if (!preg_match('/^((T-)?\\d+|new)$/', $this->section)) { $this->dieUsage("The section parameter must be a valid section id or 'new'", "invalidsection"); } } else { $this->section = false; } // The parser needs $wgTitle to be set, apparently the // $title parameter in Parser::parse isn't enough *sigh* // TODO: Does this still need $wgTitle? global $wgParser, $wgTitle; $redirValues = null; // Return result $result = $this->getResult(); if (!is_null($oldid) || !is_null($pageid) || !is_null($page)) { if ($this->section === 'new') { $this->dieUsage('section=new cannot be combined with oldid, pageid or page parameters. ' . 'Please use text', 'params'); } if (!is_null($oldid)) { // Don't use the parser cache $rev = Revision::newFromId($oldid); if (!$rev) { $this->dieUsage("There is no revision ID {$oldid}", 'missingrev'); } if (!$rev->userCan(Revision::DELETED_TEXT, $this->getUser())) { $this->dieUsage("You don't have permission to view deleted revisions", 'permissiondenied'); } $titleObj = $rev->getTitle(); $wgTitle = $titleObj; $pageObj = WikiPage::factory($titleObj); $popts = $this->makeParserOptions($pageObj, $params); // If for some reason the "oldid" is actually the current revision, it may be cached // Deliberately comparing $pageObj->getLatest() with $rev->getId(), rather than // checking $rev->isCurrent(), because $pageObj is what actually ends up being used, // and if its ->getLatest() is outdated, $rev->isCurrent() won't tell us that. if ($rev->getId() == $pageObj->getLatest()) { // May get from/save to parser cache $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } else { // This is an old revision, so get the text differently $this->content = $rev->getContent(Revision::FOR_THIS_USER, $this->getUser()); if ($this->section !== false) { $this->content = $this->getSectionContent($this->content, 'r' . $rev->getId()); } // Should we save old revision parses to the parser cache? $p_result = $this->content->getParserOutput($titleObj, $rev->getId(), $popts); } } else { // Not $oldid, but $pageid or $page if ($params['redirects']) { $reqParams = array('redirects' => ''); if (!is_null($pageid)) { $reqParams['pageids'] = $pageid; } else { // $page $reqParams['titles'] = $page; } $req = new FauxRequest($reqParams); $main = new ApiMain($req); $pageSet = new ApiPageSet($main); $pageSet->execute(); $redirValues = $pageSet->getRedirectTitlesAsResult($this->getResult()); $to = $page; foreach ($pageSet->getRedirectTitles() as $title) { $to = $title->getFullText(); } $pageParams = array('title' => $to); } elseif (!is_null($pageid)) { $pageParams = array('pageid' => $pageid); } else { // $page $pageParams = array('title' => $page); } $pageObj = $this->getTitleOrPageId($pageParams, 'fromdb'); $titleObj = $pageObj->getTitle(); if (!$titleObj || !$titleObj->exists()) { $this->dieUsage("The page you specified doesn't exist", 'missingtitle'); } $wgTitle = $titleObj; if (isset($prop['revid'])) { $oldid = $pageObj->getLatest(); } $popts = $this->makeParserOptions($pageObj, $params); // Don't pollute the parser cache when setting options that aren't // in ParserOptions::optionsHash() /// @todo: This should be handled closer to the actual cache instead of here, see T110269 $suppressCache = $params['disablepp'] || $params['disablelimitreport'] || $params['preview'] || $params['sectionpreview'] || $params['disabletidy']; if ($suppressCache) { $this->content = $this->getContent($pageObj, $pageid); $p_result = $this->content->getParserOutput($titleObj, null, $popts); } else { // Potentially cached $p_result = $this->getParsedContent($pageObj, $popts, $pageid, isset($prop['wikitext'])); } } } else { // Not $oldid, $pageid, $page. Hence based on $text $titleObj = Title::newFromText($title); if (!$titleObj || $titleObj->isExternal()) { $this->dieUsageMsg(array('invalidtitle', $title)); } $wgTitle = $titleObj; if ($titleObj->canExist()) { $pageObj = WikiPage::factory($titleObj); } else { // Do like MediaWiki::initializeArticle() $article = Article::newFromTitle($titleObj, $this->getContext()); $pageObj = $article->getPage(); } $popts = $this->makeParserOptions($pageObj, $params); $textProvided = !is_null($text); if (!$textProvided) { if ($titleProvided && ($prop || $params['generatexml'])) { $this->setWarning("'title' used without 'text', and parsed page properties were requested " . "(did you mean to use 'page' instead of 'title'?)"); } // Prevent warning from ContentHandler::makeContent() $text = ''; } // If we are parsing text, do not use the content model of the default // API title, but default to wikitext to keep BC. if ($textProvided && !$titleProvided && is_null($model)) { $model = CONTENT_MODEL_WIKITEXT; $this->setWarning("No 'title' or 'contentmodel' was given, assuming {$model}."); } try { $this->content = ContentHandler::makeContent($text, $titleObj, $model, $format); } catch (MWContentSerializationException $ex) { $this->dieUsage($ex->getMessage(), 'parseerror'); } if ($this->section !== false) { if ($this->section === 'new') { // Insert the section title above the content. if (!is_null($params['sectiontitle']) && $params['sectiontitle'] !== '') { $this->content = $this->content->addSectionHeader($params['sectiontitle']); } } else { $this->content = $this->getSectionContent($this->content, $titleObj->getPrefixedText()); } } if ($params['pst'] || $params['onlypst']) { $this->pstContent = $this->content->preSaveTransform($titleObj, $this->getUser(), $popts); } if ($params['onlypst']) { // Build a result and bail out $result_array = array(); $result_array['text'] = $this->pstContent->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text'; if (isset($prop['wikitext'])) { $result_array['wikitext'] = $this->content->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext'; } if (!is_null($params['summary']) || !is_null($params['sectiontitle']) && $this->section === 'new') { $result_array['parsedsummary'] = $this->formatSummary($titleObj, $params); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary'; } $result->addValue(null, $this->getModuleName(), $result_array); return; } // Not cached (save or load) if ($params['pst']) { $p_result = $this->pstContent->getParserOutput($titleObj, null, $popts); } else { $p_result = $this->content->getParserOutput($titleObj, null, $popts); } } $result_array = array(); $result_array['title'] = $titleObj->getPrefixedText(); $result_array['pageid'] = $pageid ? $pageid : $pageObj->getId(); if (!is_null($oldid)) { $result_array['revid'] = intval($oldid); } if ($params['redirects'] && !is_null($redirValues)) { $result_array['redirects'] = $redirValues; } if ($params['disabletoc']) { $p_result->setTOCEnabled(false); } if (isset($prop['text'])) { $result_array['text'] = $p_result->getText(); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'text'; } if (!is_null($params['summary']) || !is_null($params['sectiontitle']) && $this->section === 'new') { $result_array['parsedsummary'] = $this->formatSummary($titleObj, $params); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsedsummary'; } if (isset($prop['langlinks'])) { $langlinks = $p_result->getLanguageLinks(); if ($params['effectivelanglinks']) { // Link flags are ignored for now, but may in the future be // included in the result. $linkFlags = array(); Hooks::run('LanguageLinks', array($titleObj, &$langlinks, &$linkFlags)); } } else { $langlinks = false; } if (isset($prop['langlinks'])) { $result_array['langlinks'] = $this->formatLangLinks($langlinks); } if (isset($prop['categories'])) { $result_array['categories'] = $this->formatCategoryLinks($p_result->getCategories()); } if (isset($prop['categorieshtml'])) { $result_array['categorieshtml'] = $this->categoriesHtml($p_result->getCategories()); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'categorieshtml'; } if (isset($prop['links'])) { $result_array['links'] = $this->formatLinks($p_result->getLinks()); } if (isset($prop['templates'])) { $result_array['templates'] = $this->formatLinks($p_result->getTemplates()); } if (isset($prop['images'])) { $result_array['images'] = array_keys($p_result->getImages()); } if (isset($prop['externallinks'])) { $result_array['externallinks'] = array_keys($p_result->getExternalLinks()); } if (isset($prop['sections'])) { $result_array['sections'] = $p_result->getSections(); } if (isset($prop['displaytitle'])) { $result_array['displaytitle'] = $p_result->getDisplayTitle() ? $p_result->getDisplayTitle() : $titleObj->getPrefixedText(); } if (isset($prop['headitems']) || isset($prop['headhtml'])) { $context = $this->getContext(); $context->setTitle($titleObj); $context->getOutput()->addParserOutputMetadata($p_result); if (isset($prop['headitems'])) { $headItems = $this->formatHeadItems($p_result->getHeadItems()); $css = $this->formatCss($context->getOutput()->buildCssLinksArray()); $scripts = array($context->getOutput()->getHeadScripts()); $result_array['headitems'] = array_merge($headItems, $css, $scripts); } if (isset($prop['headhtml'])) { $result_array['headhtml'] = $context->getOutput()->headElement($context->getSkin()); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml'; } } if (isset($prop['modules'])) { $result_array['modules'] = array_values(array_unique($p_result->getModules())); $result_array['modulescripts'] = array_values(array_unique($p_result->getModuleScripts())); $result_array['modulestyles'] = array_values(array_unique($p_result->getModuleStyles())); // To be removed in 1.27 $result_array['modulemessages'] = array(); $this->setWarning('modulemessages is deprecated since MediaWiki 1.26'); } if (isset($prop['jsconfigvars'])) { $result_array['jsconfigvars'] = ApiResult::addMetadataToResultVars($p_result->getJsConfigVars()); } if (isset($prop['encodedjsconfigvars'])) { $result_array['encodedjsconfigvars'] = FormatJson::encode($p_result->getJsConfigVars(), false, FormatJson::ALL_OK); $result_array[ApiResult::META_SUBELEMENTS][] = 'encodedjsconfigvars'; } if (isset($prop['modules']) && !isset($prop['jsconfigvars']) && !isset($prop['encodedjsconfigvars'])) { $this->setWarning("Property 'modules' was set but not 'jsconfigvars' " . "or 'encodedjsconfigvars'. Configuration variables are necessary " . "for proper module usage."); } if (isset($prop['indicators'])) { $result_array['indicators'] = (array) $p_result->getIndicators(); ApiResult::setArrayType($result_array['indicators'], 'BCkvp', 'name'); } if (isset($prop['iwlinks'])) { $result_array['iwlinks'] = $this->formatIWLinks($p_result->getInterwikiLinks()); } if (isset($prop['wikitext'])) { $result_array['wikitext'] = $this->content->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'wikitext'; if (!is_null($this->pstContent)) { $result_array['psttext'] = $this->pstContent->serialize($format); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'psttext'; } } if (isset($prop['properties'])) { $result_array['properties'] = (array) $p_result->getProperties(); ApiResult::setArrayType($result_array['properties'], 'BCkvp', 'name'); } if (isset($prop['limitreportdata'])) { $result_array['limitreportdata'] = $this->formatLimitReportData($p_result->getLimitReportData()); } if (isset($prop['limitreporthtml'])) { $result_array['limitreporthtml'] = EditPage::getPreviewLimitReport($p_result); $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'limitreporthtml'; } if (isset($prop['parsetree']) || $params['generatexml']) { if ($this->content->getModel() != CONTENT_MODEL_WIKITEXT) { $this->dieUsage("parsetree is only supported for wikitext content", "notwikitext"); } $wgParser->startExternalParse($titleObj, $popts, Parser::OT_PREPROCESS); $dom = $wgParser->preprocessToDom($this->content->getNativeData()); if (is_callable(array($dom, 'saveXML'))) { $xml = $dom->saveXML(); } else { $xml = $dom->__toString(); } $result_array['parsetree'] = $xml; $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'parsetree'; } $result_mapping = array('redirects' => 'r', 'langlinks' => 'll', 'categories' => 'cl', 'links' => 'pl', 'templates' => 'tl', 'images' => 'img', 'externallinks' => 'el', 'iwlinks' => 'iw', 'sections' => 's', 'headitems' => 'hi', 'modules' => 'm', 'indicators' => 'ind', 'modulescripts' => 'm', 'modulestyles' => 'm', 'modulemessages' => 'm', 'properties' => 'pp', 'limitreportdata' => 'lr'); $this->setIndexedTagNames($result_array, $result_mapping); $result->addValue(null, $this->getModuleName(), $result_array); }
/** * Purges the cache of a page */ public function execute() { $user = $this->getUser(); $params = $this->extractRequestParams(); if (!$user->isAllowed('purge') && !$this->getMain()->isInternalMode() && !$this->getRequest()->wasPosted()) { $this->dieUsageMsg(array('mustbeposted', $this->getModuleName())); } $forceLinkUpdate = $params['forcelinkupdate']; $pageSet = new ApiPageSet($this); $pageSet->execute(); $result = array(); foreach ($pageSet->getInvalidTitles() as $title) { $r = array(); $r['title'] = $title; $r['invalid'] = ''; $result[] = $r; } foreach ($pageSet->getMissingPageIDs() as $p) { $page = array(); $page['pageid'] = $p; $page['missing'] = ''; $result[] = $page; } foreach ($pageSet->getMissingRevisionIDs() as $r) { $rev = array(); $rev['revid'] = $r; $rev['missing'] = ''; $result[] = $rev; } foreach ($pageSet->getTitles() as $title) { $r = array(); ApiQueryBase::addTitleInfo($r, $title); if (!$title->exists()) { $r['missing'] = ''; $result[] = $r; continue; } $page = WikiPage::factory($title); $page->doPurge(); // Directly purge and skip the UI part of purge(). $r['purged'] = ''; if ($forceLinkUpdate) { if (!$user->pingLimiter()) { global $wgParser, $wgEnableParserCache; $popts = $page->makeParserOptions('canonical'); $p_result = $wgParser->parse($page->getRawText(), $title, $popts, true, true, $page->getLatest()); # Update the links tables $updates = $p_result->getSecondaryDataUpdates($title); DataUpdate::runUpdates($updates); $r['linkupdate'] = ''; if ($wgEnableParserCache) { $pcache = ParserCache::singleton(); $pcache->save($p_result, $page, $popts); } } else { $error = $this->parseMsg(array('actionthrottledtext')); $this->setWarning($error['info']); $forceLinkUpdate = false; } } $result[] = $r; } $apiResult = $this->getResult(); $apiResult->setIndexedTagName($result, 'page'); $apiResult->addValue(null, $this->getModuleName(), $result); }