Example #1
0
 /**
  * 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();
     }
 }
Example #2
0
 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");
 }
Example #3
0
 /**
  * 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();
     }
 }
Example #4
0
 /**
  * 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;
 }
Example #7
0
 /**
  * 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;
 }
Example #8
0
 /**
  * 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();
 }
Example #9
0
 /**
  * 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;
 }
Example #11
0
 /**
  * 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();
 }
Example #13
0
 /**
  * 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;
 }
Example #15
0
 /**
  * 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();
 }
Example #16
0
 /**
  * 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;
 }
Example #17
0
 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();
 }
Example #19
0
 /**
  * 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;
 }