/** * Replace <!--LINK--> link placeholders with actual links, in the buffer * Placeholders created in Skin::makeLinkObj() * Returns an array of link CSS classes, indexed by PDBK. * $options is a bit field, RLH_FOR_UPDATE to select for update */ function replaceLinkHolders(&$text, $options = 0) { global $wgUser; global $wgContLang; $fname = 'Parser::replaceLinkHolders'; wfProfileIn($fname); $pdbks = array(); $colours = array(); $linkcolour_ids = array(); $sk = $this->mOptions->getSkin(); $linkCache =& LinkCache::singleton(); if (!empty($this->mLinkHolders['namespaces'])) { wfProfileIn($fname . '-check'); $dbr = wfGetDB(DB_SLAVE); $page = $dbr->tableName('page'); $threshold = $wgUser->getOption('stubthreshold'); # Sort by namespace asort($this->mLinkHolders['namespaces']); # Generate query $query = false; $current = null; foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { # Make title object $title = $this->mLinkHolders['titles'][$key]; # Skip invalid entries. # Result will be ugly, but prevents crash. if (is_null($title)) { continue; } $pdbk = $pdbks[$key] = $title->getPrefixedDBkey(); # Check if it's a static known link, e.g. interwiki if ($title->isAlwaysKnown()) { $colours[$pdbk] = ''; } elseif (($id = $linkCache->getGoodLinkID($pdbk)) != 0) { $colours[$pdbk] = ''; $this->mOutput->addLink($title, $id); } elseif ($linkCache->isBadLink($pdbk)) { $colours[$pdbk] = 'new'; } elseif ($title->getNamespace() == NS_SPECIAL && !SpecialPage::exists($pdbk)) { $colours[$pdbk] = 'new'; } else { # Not in the link cache, add it to the query if (!isset($current)) { $current = $ns; $query = "SELECT page_id, page_namespace, page_title, page_is_redirect"; if ($threshold > 0) { $query .= ', page_len'; } $query .= " FROM {$page} WHERE (page_namespace={$ns} AND page_title IN("; } elseif ($current != $ns) { $current = $ns; $query .= ")) OR (page_namespace={$ns} AND page_title IN("; } else { $query .= ', '; } $query .= $dbr->addQuotes($this->mLinkHolders['dbkeys'][$key]); } } if ($query) { $query .= '))'; if ($options & RLH_FOR_UPDATE) { $query .= ' FOR UPDATE'; } $res = $dbr->query($query, $fname); # Fetch data and form into an associative array # non-existent = broken while ($s = $dbr->fetchObject($res)) { $title = Title::makeTitle($s->page_namespace, $s->page_title); $pdbk = $title->getPrefixedDBkey(); $linkCache->addGoodLinkObj($s->page_id, $title); $this->mOutput->addLink($title, $s->page_id); $colours[$pdbk] = $sk->getLinkColour($s, $threshold); //add id to the extension todolist $linkcolour_ids[$s->page_id] = $pdbk; } //pass an array of page_ids to an extension wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours)); } wfProfileOut($fname . '-check'); # Do a second query for different language variants of links and categories if ($wgContLang->hasVariants()) { $linkBatch = new LinkBatch(); $variantMap = array(); // maps $pdbkey_Variant => $keys (of link holders) $categoryMap = array(); // maps $category_variant => $category (dbkeys) $varCategories = array(); // category replacements oldDBkey => newDBkey $categories = $this->mOutput->getCategoryLinks(); // Add variants of links to link batch foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { $title = $this->mLinkHolders['titles'][$key]; if (is_null($title)) { continue; } $pdbk = $title->getPrefixedDBkey(); $titleText = $title->getText(); // generate all variants of the link title text $allTextVariants = $wgContLang->convertLinkToAllVariants($titleText); // if link was not found (in first query), add all variants to query if (!isset($colours[$pdbk])) { foreach ($allTextVariants as $textVariant) { if ($textVariant != $titleText) { $variantTitle = Title::makeTitle($ns, $textVariant); if (is_null($variantTitle)) { continue; } $linkBatch->addObj($variantTitle); $variantMap[$variantTitle->getPrefixedDBkey()][] = $key; } } } } // process categories, check if a category exists in some variant foreach ($categories as $category) { $variants = $wgContLang->convertLinkToAllVariants($category); foreach ($variants as $variant) { if ($variant != $category) { $variantTitle = Title::newFromDBkey(Title::makeName(NS_CATEGORY, $variant)); if (is_null($variantTitle)) { continue; } $linkBatch->addObj($variantTitle); $categoryMap[$variant] = $category; } } } if (!$linkBatch->isEmpty()) { // construct query $titleClause = $linkBatch->constructSet('page', $dbr); $variantQuery = "SELECT page_id, page_namespace, page_title, page_is_redirect"; if ($threshold > 0) { $variantQuery .= ', page_len'; } $variantQuery .= " FROM {$page} WHERE {$titleClause}"; if ($options & RLH_FOR_UPDATE) { $variantQuery .= ' FOR UPDATE'; } $varRes = $dbr->query($variantQuery, $fname); // for each found variants, figure out link holders and replace while ($s = $dbr->fetchObject($varRes)) { $variantTitle = Title::makeTitle($s->page_namespace, $s->page_title); $varPdbk = $variantTitle->getPrefixedDBkey(); $vardbk = $variantTitle->getDBkey(); $holderKeys = array(); if (isset($variantMap[$varPdbk])) { $holderKeys = $variantMap[$varPdbk]; $linkCache->addGoodLinkObj($s->page_id, $variantTitle); $this->mOutput->addLink($variantTitle, $s->page_id); } // loop over link holders foreach ($holderKeys as $key) { $title = $this->mLinkHolders['titles'][$key]; if (is_null($title)) { continue; } $pdbk = $title->getPrefixedDBkey(); if (!isset($colours[$pdbk])) { // found link in some of the variants, replace the link holder data $this->mLinkHolders['titles'][$key] = $variantTitle; $this->mLinkHolders['dbkeys'][$key] = $variantTitle->getDBkey(); // set pdbk and colour $pdbks[$key] = $varPdbk; $colours[$varPdbk] = $sk->getLinkColour($s, $threshold); $linkcolour_ids[$s->page_id] = $pdbk; } wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours)); } // check if the object is a variant of a category if (isset($categoryMap[$vardbk])) { $oldkey = $categoryMap[$vardbk]; if ($oldkey != $vardbk) { $varCategories[$oldkey] = $vardbk; } } } // rebuild the categories in original order (if there are replacements) if (count($varCategories) > 0) { $newCats = array(); $originalCats = $this->mOutput->getCategories(); foreach ($originalCats as $cat => $sortkey) { // make the replacement if (array_key_exists($cat, $varCategories)) { $newCats[$varCategories[$cat]] = $sortkey; } else { $newCats[$cat] = $sortkey; } } $this->mOutput->setCategoryLinks($newCats); } } } # Construct search and replace arrays wfProfileIn($fname . '-construct'); $replacePairs = array(); foreach ($this->mLinkHolders['namespaces'] as $key => $ns) { $pdbk = $pdbks[$key]; $searchkey = "<!--LINK {$key}-->"; $title = $this->mLinkHolders['titles'][$key]; if (!isset($colours[$pdbk]) || $colours[$pdbk] == 'new') { $linkCache->addBadLinkObj($title); $colours[$pdbk] = 'new'; $this->mOutput->addLink($title, 0); $replacePairs[$searchkey] = $sk->makeBrokenLinkObj($title, $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]); } else { $replacePairs[$searchkey] = $sk->makeColouredLinkObj($title, $colours[$pdbk], $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]); } } $replacer = new HashtableReplacer($replacePairs, 1); wfProfileOut($fname . '-construct'); # Do the thing wfProfileIn($fname . '-replace'); $text = preg_replace_callback('/(<!--LINK .*?-->)/', $replacer->cb(), $text); wfProfileOut($fname . '-replace'); } # Now process interwiki link holders # This is quite a bit simpler than internal links if (!empty($this->mInterwikiLinkHolders['texts'])) { wfProfileIn($fname . '-interwiki'); # Make interwiki link HTML $replacePairs = array(); foreach ($this->mInterwikiLinkHolders['texts'] as $key => $link) { $title = $this->mInterwikiLinkHolders['titles'][$key]; $replacePairs[$key] = $sk->makeLinkObj($title, $link); } $replacer = new HashtableReplacer($replacePairs, 1); $text = preg_replace_callback('/<!--IWLINK (.*?)-->/', $replacer->cb(), $text); wfProfileOut($fname . '-interwiki'); } wfProfileOut($fname); return $colours; }
/** * Replace interwiki links * @param string $text */ protected function replaceInterwiki(&$text) { if (empty($this->interwikis)) { return; } # Make interwiki link HTML $output = $this->parent->getOutput(); $replacePairs = array(); foreach ($this->interwikis as $key => $link) { $replacePairs[$key] = Linker::link($link['title'], $link['text']); $output->addInterwikiLink($link['title']); } $replacer = new HashtableReplacer($replacePairs, 1); $text = preg_replace_callback('/<!--IWLINK (.*?)-->/', $replacer->cb(), $text); }
/** * Replace interwiki links */ protected function replaceInterwiki(&$text) { if (empty($this->interwikis)) { return; } wfProfileIn(__METHOD__); # Make interwiki link HTML $sk = $this->parent->getOptions()->getSkin(); $replacePairs = array(); foreach ($this->interwikis as $key => $link) { $replacePairs[$key] = $sk->link($link['title'], $link['text']); } $replacer = new HashtableReplacer($replacePairs, 1); $text = preg_replace_callback('/<!--IWLINK (.*?)-->/', $replacer->cb(), $text); wfProfileOut(__METHOD__); }