/** * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { $titles = array(); $user = $this->getUser(); $title = $this->getRelevantTitle(); // User/talk link if ($user->isLoggedIn() || $this->showIPinHeader()) { $titles[] = $user->getUserPage(); $titles[] = $user->getTalkPage(); } // Other tab link if ($title->isSpecialPage()) { // nothing } elseif ($title->isTalkPage()) { $titles[] = $title->getSubjectPage(); } else { $titles[] = $title->getTalkPage(); } Hooks::run('SkinPreloadExistence', array(&$titles, $this)); if (count($titles)) { $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); } }
function showSubpagesList($subpages, $pagecount, $wikiMsg, $noSubpageMsg = false) { $out = $this->getOutput(); # No subpages. if ($pagecount == 0 && $noSubpageMsg) { $out->addWikiMsg('movenosubpage'); return; } $out->addWikiMsg($wikiMsg, $this->getLanguage()->formatNum($pagecount)); $out->addHTML("<ul>\n"); $linkBatch = new LinkBatch($subpages); $linkBatch->setCaller(__METHOD__); $linkBatch->execute(); $linkRenderer = $this->getLinkRenderer(); foreach ($subpages as $subpage) { $link = $linkRenderer->makeLink($subpage); $out->addHTML("<li>{$link}</li>\n"); } $out->addHTML("</ul>\n"); }
/** * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { $titles = array(); $user = $this->getUser(); $title = $this->getRelevantTitle(); // User/talk link if ($user->isLoggedIn() || $this->showIPinHeader()) { $titles[] = $user->getUserPage(); $titles[] = $user->getTalkPage(); } // Check, if the page can hold some kind of content, otherwise do nothing if (!$title->canExist()) { // nothing } elseif ($title->isTalkPage()) { $titles[] = $title->getSubjectPage(); } else { $titles[] = $title->getTalkPage(); } Hooks::run('SkinPreloadExistence', array(&$titles, $this)); if (count($titles)) { $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); } }
/** * BeforePageDisplay hook handler. * @param $out OutputPage * @return bool */ public static function beforePageDisplay($out) { global $wgUser; wfProfileIn(__METHOD__); $gadgets = Gadget::loadList(); if (!$gadgets) { wfProfileOut(__METHOD__); return true; } $lb = new LinkBatch(); $lb->setCaller(__METHOD__); $pages = array(); /** * @var $gadget Gadget */ foreach ($gadgets as $gadget) { if ($gadget->isEnabled($wgUser) && $gadget->isAllowed($wgUser)) { if ($gadget->hasModule()) { $out->addModuleStyles($gadget->getModuleName()); $out->addModules($gadget->getModuleName()); } foreach ($gadget->getLegacyScripts() as $page) { $lb->add(NS_MEDIAWIKI, $page); $pages[] = $page; } } } $lb->execute(__METHOD__); $done = array(); foreach ($pages as $page) { if (isset($done[$page])) { continue; } $done[$page] = true; self::applyScript($page, $out); } wfProfileOut(__METHOD__); return true; }
/** * Do a LinkBatch query to minimise database load when generating all these links * @param $result */ function preprocessResults($result) { wfProfileIn(__METHOD__); # Do a link batch query $lb = new LinkBatch(); $lb->setCaller(__METHOD__); $userids = array(); foreach ($result as $row) { $userids[] = $row->ipb_by; # Usernames and titles are in fact related by a simple substitution of space -> underscore # The last few lines of Title::secureAndSplit() tell the story. $name = str_replace(' ', '_', $row->ipb_address); $lb->add(NS_USER, $name); $lb->add(NS_USER_TALK, $name); } $ua = UserArray::newFromIDs($userids); foreach ($ua as $user) { $name = str_replace(' ', '_', $user->getName()); $lb->add(NS_USER, $name); $lb->add(NS_USER_TALK, $name); } $lb->execute(); wfProfileOut(__METHOD__); }
/** * BeforePageDisplay hook handler. * @param $out OutputPage * @return bool */ public static function beforePageDisplay($out) { wfProfileIn(__METHOD__); $gadgets = Gadget::loadList(); if (!$gadgets) { wfProfileOut(__METHOD__); return true; } $lb = new LinkBatch(); $lb->setCaller(__METHOD__); $pages = array(); /** * @var $gadget Gadget */ $user = $out->getUser(); foreach ($gadgets as $gadget) { if ($gadget->isEnabled($user) && $gadget->isAllowed($user)) { if ($gadget->hasModule()) { $out->addModuleStyles($gadget->getModuleName()); $out->addModules($gadget->getModuleName()); } foreach ($gadget->getLegacyScripts() as $page) { $lb->add(NS_MEDIAWIKI, $page); $pages[] = $page; } } } // Allow other extensions, e.g. MobileFrontend, to disallow legacy gadgets if (wfRunHooks('Gadgets::allowLegacy', array($out->getContext()))) { $lb->execute(__METHOD__); $done = array(); foreach ($pages as $page) { if (isset($done[$page])) { continue; } $done[$page] = true; self::applyScript($page, $out); } } wfProfileOut(__METHOD__); return true; }
/** * Process completion search results. * Resolves the titles and rescores. * @param SearchSuggestionSet $suggestions * @return SearchSuggestionSet */ protected function processCompletionResults($search, SearchSuggestionSet $suggestions) { if ($suggestions->getSize() == 0) { // If we don't have anything, don't bother return $suggestions; } $search = trim($search); // preload the titles with LinkBatch $titles = $suggestions->map(function (SearchSuggestion $sugg) { return $sugg->getSuggestedTitle(); }); $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); $results = $suggestions->map(function (SearchSuggestion $sugg) { return $sugg->getSuggestedTitle()->getPrefixedText(); }); // Rescore results with an exact title match $rescorer = new SearchExactMatchRescorer(); $rescoredResults = $rescorer->rescore($search, $this->namespaces, $results, $this->limit); if (count($rescoredResults) > 0) { $found = array_search($rescoredResults[0], $results); if ($found === false) { // If the first result is not in the previous array it // means that we found a new exact match $exactMatch = SearchSuggestion::fromTitle(0, Title::newFromText($rescoredResults[0])); $suggestions->prepend($exactMatch); $suggestions->shrink($this->limit); } else { // if the first result is not the same we need to rescore if ($found > 0) { $suggestions->rescore($found); } } } return $suggestions; }
/** * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { global $wgUser; // User/talk link $titles = array($wgUser->getUserPage(), $wgUser->getTalkPage()); // Other tab link if ($this->mTitle->getNamespace() == NS_SPECIAL) { // nothing } elseif ($this->mTitle->isTalkPage()) { $titles[] = $this->mTitle->getSubjectPage(); } else { $titles[] = $this->mTitle->getTalkPage(); } $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); }
/** * Performs a link batch on a series of templates. * * @param $parameters Array: Templates to perform the link batch on. */ protected static function mTemplateLinkBatch($parameters) { wfProfileIn(__METHOD__); $titles = array(); foreach ($parameters as $name) { $title = Title::newFromText(wfMessage('babel-template', $name)->inContentLanguage()->text()); if (is_object($title)) { $titles[] = $title; } } $batch = new LinkBatch($titles); $batch->setCaller(__METHOD__); $batch->execute(); wfProfileOut(__METHOD__); }
/** * BeforePageDisplay hook handler. * @param $out OutputPage * @return bool */ public static function beforePageDisplay($out) { $repo = GadgetRepo::singleton(); $ids = $repo->getGadgetIds(); if (!$ids) { return true; } $lb = new LinkBatch(); $lb->setCaller(__METHOD__); $enabledLegacyGadgets = array(); /** * @var $gadget Gadget */ $user = $out->getUser(); foreach ($ids as $id) { $gadget = $repo->getGadget($id); if ($gadget->isEnabled($user) && $gadget->isAllowed($user)) { if ($gadget->hasModule()) { $out->addModuleStyles($gadget->getModuleName()); $out->addModules($gadget->getModuleName()); } if ($gadget->getLegacyScripts()) { $enabledLegacyGadgets[] = $id; } } } $strings = array(); foreach ($enabledLegacyGadgets as $id) { $strings[] = self::makeLegacyWarning($id); } $out->addHTML(WrappedString::join("\n", $strings)); return true; }
/** * Preload the existence of three commonly-requested pages in a single query */ protected function preloadExistence() { $titles = []; // User/talk link $user = $this->getUser(); if ($user->isLoggedIn()) { $titles[] = $user->getUserPage(); $titles[] = $user->getTalkPage(); } // Check, if the page can hold some kind of content, otherwise do nothing $title = $this->getRelevantTitle(); if ($title->canExist()) { if ($title->isTalkPage()) { $titles[] = $title->getSubjectPage(); } else { $titles[] = $title->getTalkPage(); } } Hooks::run('SkinPreloadExistence', [&$titles, $this]); if ($titles) { $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); } }
/** * Update in-process title existence cache with NS_USER and * NS_USER_TALK pages related to the provided usernames. * * @param string $wiki Wiki the users belong to * @param array $usernames List of user names */ protected function resolveUserPages($wiki, array $usernames) { // LinkBatch currently only supports the current wiki if ($wiki !== wfWikiId() || !$usernames) { return; } $lb = new \LinkBatch(); foreach ($usernames as $name) { $user = User::newFromName($name); if ($user) { $lb->addObj($user->getUserPage()); $lb->addObj($user->getTalkPage()); } } $lb->setCaller(__METHOD__); $lb->execute(); }
/** * Replace internal links * @param string $text */ protected function replaceInternal(&$text) { if (!$this->internals) { return; } global $wgContLang; $colours = []; $linkCache = LinkCache::singleton(); $output = $this->parent->getOutput(); $linkRenderer = $this->parent->getLinkRenderer(); $threshold = $linkRenderer->getStubThreshold(); $dbr = wfGetDB(DB_SLAVE); # Sort by namespace ksort($this->internals); $linkcolour_ids = []; # Generate query $lb = new LinkBatch(); $lb->setCaller(__METHOD__); foreach ($this->internals as $ns => $entries) { foreach ($entries as $entry) { /** @var Title $title */ $title = $entry['title']; $pdbk = $entry['pdbk']; # Skip invalid entries. # Result will be ugly, but prevents crash. if (is_null($title)) { continue; } # Check if it's a static known link, e.g. interwiki if ($title->isAlwaysKnown()) { $colours[$pdbk] = ''; } elseif ($ns == NS_SPECIAL) { $colours[$pdbk] = 'new'; } else { $id = $linkCache->getGoodLinkID($pdbk); if ($id != 0) { $colours[$pdbk] = Linker::getLinkColour($title, $threshold); $output->addLink($title, $id); $linkcolour_ids[$id] = $pdbk; } elseif ($linkCache->isBadLink($pdbk)) { $colours[$pdbk] = 'new'; } else { # Not in the link cache, add it to the query $lb->addObj($title); } } } } if (!$lb->isEmpty()) { $fields = array_merge(LinkCache::getSelectFields(), ['page_namespace', 'page_title']); $res = $dbr->select('page', $fields, $lb->constructSet('page', $dbr), __METHOD__); # Fetch data and form into an associative array # non-existent = broken foreach ($res as $s) { $title = Title::makeTitle($s->page_namespace, $s->page_title); $pdbk = $title->getPrefixedDBkey(); $linkCache->addGoodLinkObjFromRow($title, $s); $output->addLink($title, $s->page_id); $colours[$pdbk] = Linker::getLinkColour($title, $threshold); // add id to the extension todolist $linkcolour_ids[$s->page_id] = $pdbk; } unset($res); } if (count($linkcolour_ids)) { // pass an array of page_ids to an extension Hooks::run('GetLinkColours', [$linkcolour_ids, &$colours]); } # Do a second query for different language variants of links and categories if ($wgContLang->hasVariants()) { $this->doVariants($colours); } # Construct search and replace arrays $replacePairs = []; foreach ($this->internals as $ns => $entries) { foreach ($entries as $index => $entry) { $pdbk = $entry['pdbk']; $title = $entry['title']; $query = isset($entry['query']) ? $entry['query'] : []; $key = "{$ns}:{$index}"; $searchkey = "<!--LINK {$key}-->"; $displayText = $entry['text']; if (isset($entry['selflink'])) { $replacePairs[$searchkey] = Linker::makeSelfLinkObj($title, $displayText, $query); continue; } if ($displayText === '') { $displayText = null; } else { $displayText = new HtmlArmor($displayText); } if (!isset($colours[$pdbk])) { $colours[$pdbk] = 'new'; } $attribs = []; if ($colours[$pdbk] == 'new') { $linkCache->addBadLinkObj($title); $output->addLink($title, 0); $link = $linkRenderer->makeBrokenLink($title, $displayText, $attribs, $query); } else { $link = $linkRenderer->makePreloadedLink($title, $displayText, $colours[$pdbk], $attribs, $query); } $replacePairs[$searchkey] = $link; } } $replacer = new HashtableReplacer($replacePairs, 1); # Do the thing $text = preg_replace_callback('/(<!--LINK .*?-->)/', $replacer->cb(), $text); }
/** * BeforePageDisplay hook handler. * @param $out OutputPage */ public static function beforePageDisplay($out) { global $wgUser; wfProfileIn(__METHOD__); $gadgets = Gadget::loadList(); if (!$gadgets) { wfProfileOut(__METHOD__); return true; } $lb = new LinkBatch(); $lb->setCaller(__METHOD__); $pages = array(); $stylesModules = array(); foreach ($gadgets as $gadget) { if ($gadget->isEnabled($wgUser) && $gadget->isAllowed($wgUser)) { if ($gadget->hasModule()) { $out->addModules($gadget->getModuleName()); } if ($gadget->hasStylesModule()) { $stylesModules[] = $gadget->getStylesModuleName(); } foreach ($gadget->getLegacyScripts() as $page) { $lb->add(NS_MEDIAWIKI, $page); $pages[] = $page; } } } if (count($stylesModules)) { $out->addHeadItem('ext.gadget', $out->makeResourceLoaderLink($stylesModules, ResourceLoaderModule::TYPE_STYLES) . Html::inlineScript(ResourceLoader::makeLoaderConditionalScript(ResourceLoader::makeLoaderStateScript(array_fill_keys($stylesModules, 'ready'))))); } $lb->execute(__METHOD__); $done = array(); foreach ($pages as $page) { if (isset($done[$page])) { continue; } $done[$page] = true; self::applyScript($page, $out); } wfProfileOut(__METHOD__); return true; }
/** * Do a LinkBatch query to minimise database load when generating all these links * @param ResultWrapper $result */ function preprocessResults($result) { # Do a link batch query $lb = new LinkBatch(); $lb->setCaller(__METHOD__); foreach ($result as $row) { $lb->add(NS_USER, $row->ipb_address); $lb->add(NS_USER_TALK, $row->ipb_address); if (isset($row->by_user_name)) { $lb->add(NS_USER, $row->by_user_name); $lb->add(NS_USER_TALK, $row->by_user_name); } } $lb->execute(); }
/** * Process completion search results. * Resolves the titles and rescores. * @param SearchSuggestionSet $suggestions * @return SearchSuggestionSet */ protected function processCompletionResults($search, SearchSuggestionSet $suggestions) { $search = trim($search); // preload the titles with LinkBatch $titles = $suggestions->map(function (SearchSuggestion $sugg) { return $sugg->getSuggestedTitle(); }); $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); $results = $suggestions->map(function (SearchSuggestion $sugg) { return $sugg->getSuggestedTitle()->getPrefixedText(); }); if ($this->offset === 0) { // Rescore results with an exact title match // NOTE: in some cases like cross-namespace redirects // (frequently used as shortcuts e.g. WP:WP on huwiki) some // backends like Cirrus will return no results. We should still // try an exact title match to workaround this limitation $rescorer = new SearchExactMatchRescorer(); $rescoredResults = $rescorer->rescore($search, $this->namespaces, $results, $this->limit); } else { // No need to rescore if offset is not 0 // The exact match must have been returned at position 0 // if it existed. $rescoredResults = $results; } if (count($rescoredResults) > 0) { $found = array_search($rescoredResults[0], $results); if ($found === false) { // If the first result is not in the previous array it // means that we found a new exact match $exactMatch = SearchSuggestion::fromTitle(0, Title::newFromText($rescoredResults[0])); $suggestions->prepend($exactMatch); $suggestions->shrink($this->limit); } else { // if the first result is not the same we need to rescore if ($found > 0) { $suggestions->rescore($found); } } } return $suggestions; }
protected function strings(array $strings) { $titles = array_map('Title::newFromText', $strings); $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); return $titles; }
protected function doLinkBatch() { $batch = new LinkBatch(); $batch->setCaller(__METHOD__); foreach ($this->collection->getTitles() as $title) { $batch->addObj($title); } $batch->execute(); }
/** * Preload the existence of three commonly-requested pages in a single query */ function preloadExistence() { $user = $this->getUser(); // User/talk link $titles = array($user->getUserPage(), $user->getTalkPage()); // Other tab link if ($this->getTitle()->isSpecialPage()) { // nothing } elseif ($this->getTitle()->isTalkPage()) { $titles[] = $this->getTitle()->getSubjectPage(); } else { $titles[] = $this->getTitle()->getTalkPage(); } $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); }
/** * This implementation will run the completion suggester if it's enabled and if the * query is for NS_MAIN. Fallback to SearchEngine default implemention otherwise. * * @param string $search the user query * @return SearchSuggestionSet the suggestions */ public function searchSuggestions($search) { $config = ConfigFactory::getDefaultInstance()->makeConfig('CirrusSearch'); $useCompletionSuggester = $config->getElement('CirrusSearchUseCompletionSuggester'); $context = RequestContext::getMain(); $request = $context->getRequest(); // Allow experimentation with query parameters if ($request && $request->getVal('cirrusUseCompletionSuggester') === 'yes') { $useCompletionSuggester = true; } if (!$useCompletionSuggester) { // Completion suggester is not enabled, fallback to // default implementation return $this->searchSuggestionsPrefixSearchFallback($search); } // We use Title to extract namespace from a Title string // We append a random letter behind just in case the search // string ends with ':'. $title = Title::newFromText($search . "A"); if ($title->getNamespace() != NS_MAIN || count($this->namespaces) != 1 || reset($this->namespaces) != NS_MAIN) { // Fallback to prefix search if we are not on content namespace return $this->searchSuggestionsPrefixSearchFallback($search); } $user = $context->getUser(); // offset is omitted, searchSuggestion does not support // scrolling results $suggester = new CompletionSuggester($this->connection, $this->limit, $config, $this->namespaces, $user, $this->indexBaseName); // Not really useful, mostly for testing purpose $variants = $request->getArray('cirrusCompletionSuggesterVariant'); if (empty($variants)) { global $wgContLang; $variants = $wgContLang->autoConvertToAllVariants($search); } else { if (count($variants) > 3) { // We should not allow too many variants $variants = array_slice($variants, 0, 3); } } $response = $suggester->suggest($search, $variants); if ($response->isOK()) { // Errors will be logged, let's try the exact db match $suggestions = $response->getValue(); } else { $suggestions = SearchSuggestionSet::emptySuggestionSet(); } // preload the titles with LinkBatch $titles = $suggestions->map(function ($sugg) { return $sugg->getSuggestedTitle(); }); $lb = new LinkBatch($titles); $lb->setCaller(__METHOD__); $lb->execute(); $results = $suggestions->map(function ($sugg) { return $sugg->getSuggestedTitle()->getPrefixedText(); }); // now we can trim $search = trim($search); // Rescore results with an exact title match $rescorer = new SearchExactMatchRescorer(); $rescoredResults = $rescorer->rescore($search, $this->namespaces, $results, $this->limit); if (count($rescoredResults) > 0) { $found = array_search($rescoredResults[0], $results); if ($found === false) { // If the first result is not in the previous array it // means that we found a new exact match $exactMatch = SearchSuggestion::fromTitle(0, Title::newFromText($rescoredResults[0])); $suggestions->prepend($exactMatch); $suggestions->shrink($this->limit); } else { // if the first result is not the same we need to rescore if ($found > 0) { $suggestions->rescore($found); } } } return $suggestions; }