/**
  * Get the modification times of all titles that would be loaded for
  * a given context.
  * @param $context ResourceLoaderContext: Context object
  * @return array( prefixed DB key => UNIX timestamp ), nonexistent titles are dropped
  */
 protected function getTitleMtimes(ResourceLoaderContext $context)
 {
     $dbr = $this->getDB();
     if (!$dbr) {
         // We're dealing with a subclass that doesn't have a DB
         return array();
     }
     $hash = $context->getHash();
     if (isset($this->titleMtimes[$hash])) {
         return $this->titleMtimes[$hash];
     }
     $this->titleMtimes[$hash] = array();
     $batch = new LinkBatch();
     foreach ($this->getPages($context) as $titleText => $options) {
         $batch->addObj(Title::newFromText($titleText));
     }
     if (!$batch->isEmpty()) {
         $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_touched'), $batch->constructSet('page', $dbr), __METHOD__);
         foreach ($res as $row) {
             $title = Title::makeTitle($row->page_namespace, $row->page_title);
             $this->titleMtimes[$hash][$title->getPrefixedDBkey()] = wfTimestamp(TS_UNIX, $row->page_touched);
         }
     }
     return $this->titleMtimes[$hash];
 }
Ejemplo n.º 2
0
 /**
  * Modify $this->internals and $colours according to language variant linking rules
  */
 protected function doVariants(&$colours)
 {
     global $wgContLang;
     $linkBatch = new LinkBatch();
     $variantMap = array();
     // maps $pdbkey_Variant => $keys (of link holders)
     $output = $this->parent->getOutput();
     $linkCache = LinkCache::singleton();
     $threshold = $this->parent->getOptions()->getStubThreshold();
     $titlesToBeConverted = '';
     $titlesAttrs = array();
     // Concatenate titles to a single string, thus we only need auto convert the
     // single string to all variants. This would improve parser's performance
     // significantly.
     foreach ($this->internals as $ns => $entries) {
         foreach ($entries as $index => $entry) {
             $pdbk = $entry['pdbk'];
             // we only deal with new links (in its first query)
             if (!isset($colours[$pdbk])) {
                 $title = $entry['title'];
                 $titleText = $title->getText();
                 $titlesAttrs[] = array('ns' => $ns, 'key' => "{$ns}:{$index}", 'titleText' => $titleText);
                 // separate titles with \0 because it would never appears
                 // in a valid title
                 $titlesToBeConverted .= $titleText . "";
             }
         }
     }
     // Now do the conversion and explode string to text of titles
     $titlesAllVariants = $wgContLang->autoConvertToAllVariants($titlesToBeConverted);
     $allVariantsName = array_keys($titlesAllVariants);
     foreach ($titlesAllVariants as &$titlesVariant) {
         $titlesVariant = explode("", $titlesVariant);
     }
     $l = count($titlesAttrs);
     // Then add variants of links to link batch
     for ($i = 0; $i < $l; $i++) {
         foreach ($allVariantsName as $variantName) {
             $textVariant = $titlesAllVariants[$variantName][$i];
             if ($textVariant != $titlesAttrs[$i]['titleText']) {
                 $variantTitle = Title::makeTitle($titlesAttrs[$i]['ns'], $textVariant);
                 if (is_null($variantTitle)) {
                     continue;
                 }
                 $linkBatch->addObj($variantTitle);
                 $variantMap[$variantTitle->getPrefixedDBkey()][] = $titlesAttrs[$i]['key'];
             }
         }
     }
     // process categories, check if a category exists in some variant
     $categoryMap = array();
     // maps $category_variant => $category (dbkeys)
     $varCategories = array();
     // category replacements oldDBkey => newDBkey
     foreach ($output->getCategoryLinks() as $category) {
         $variants = $wgContLang->autoConvertToAllVariants($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
         $dbr = wfGetDB(DB_SLAVE);
         $varRes = $dbr->select('page', array('page_id', 'page_namespace', 'page_title', 'page_is_redirect', 'page_len', 'page_latest'), $linkBatch->constructSet('page', $dbr), __METHOD__);
         $linkcolour_ids = array();
         // for each found variants, figure out link holders and replace
         foreach ($varRes as $s) {
             $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->addGoodLinkObjFromRow($variantTitle, $s);
                 $output->addLink($variantTitle, $s->page_id);
             }
             // loop over link holders
             foreach ($holderKeys as $key) {
                 list($ns, $index) = explode(':', $key, 2);
                 $entry =& $this->internals[$ns][$index];
                 $pdbk = $entry['pdbk'];
                 if (!isset($colours[$pdbk])) {
                     // found link in some of the variants, replace the link holder data
                     $entry['title'] = $variantTitle;
                     $entry['pdbk'] = $varPdbk;
                     // set pdbk and colour
                     # @todo FIXME: Convoluted data flow
                     # The redirect status and length is passed to getLinkColour via the LinkCache
                     # Use formal parameters instead
                     $colours[$varPdbk] = Linker::getLinkColour($variantTitle, $threshold);
                     $linkcolour_ids[$s->page_id] = $pdbk;
                 }
             }
             // check if the object is a variant of a category
             if (isset($categoryMap[$vardbk])) {
                 $oldkey = $categoryMap[$vardbk];
                 if ($oldkey != $vardbk) {
                     $varCategories[$oldkey] = $vardbk;
                 }
             }
         }
         wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours));
         // rebuild the categories in original order (if there are replacements)
         if (count($varCategories) > 0) {
             $newCats = array();
             $originalCats = $output->getCategories();
             foreach ($originalCats as $cat => $sortkey) {
                 // make the replacement
                 if (array_key_exists($cat, $varCategories)) {
                     $newCats[$varCategories[$cat]] = $sortkey;
                 } else {
                     $newCats[$cat] = $sortkey;
                 }
             }
             $output->setCategoryLinks($newCats);
         }
     }
 }
Ejemplo n.º 3
0
 /**
  * Modify $this->internals and $colours according to language variant linking rules
  * @param array $colours
  */
 protected function doVariants(&$colours)
 {
     global $wgContLang, $wgContentHandlerUseDB;
     $linkBatch = new LinkBatch();
     $variantMap = array();
     // maps $pdbkey_Variant => $keys (of link holders)
     $output = $this->parent->getOutput();
     $linkCache = LinkCache::singleton();
     $threshold = $this->parent->getOptions()->getStubThreshold();
     $titlesToBeConverted = '';
     $titlesAttrs = array();
     // Concatenate titles to a single string, thus we only need auto convert the
     // single string to all variants. This would improve parser's performance
     // significantly.
     foreach ($this->internals as $ns => $entries) {
         if ($ns == NS_SPECIAL) {
             continue;
         }
         foreach ($entries as $index => $entry) {
             $pdbk = $entry['pdbk'];
             // we only deal with new links (in its first query)
             if (!isset($colours[$pdbk]) || $colours[$pdbk] === 'new') {
                 $titlesAttrs[] = array($index, $entry['title']);
                 // separate titles with \0 because it would never appears
                 // in a valid title
                 $titlesToBeConverted .= $entry['title']->getText() . "";
             }
         }
     }
     // Now do the conversion and explode string to text of titles
     $titlesAllVariants = $wgContLang->autoConvertToAllVariants(rtrim($titlesToBeConverted, ""));
     $allVariantsName = array_keys($titlesAllVariants);
     foreach ($titlesAllVariants as &$titlesVariant) {
         $titlesVariant = explode("", $titlesVariant);
     }
     // Then add variants of links to link batch
     $parentTitle = $this->parent->getTitle();
     foreach ($titlesAttrs as $i => $attrs) {
         /** @var Title $title */
         list($index, $title) = $attrs;
         $ns = $title->getNamespace();
         $text = $title->getText();
         foreach ($allVariantsName as $variantName) {
             $textVariant = $titlesAllVariants[$variantName][$i];
             if ($textVariant === $text) {
                 continue;
             }
             $variantTitle = Title::makeTitle($ns, $textVariant);
             if (is_null($variantTitle)) {
                 continue;
             }
             // Self-link checking for mixed/different variant titles. At this point, we
             // already know the exact title does not exist, so the link cannot be to a
             // variant of the current title that exists as a separate page.
             if ($variantTitle->equals($parentTitle) && !$title->hasFragment()) {
                 $this->internals[$ns][$index]['selflink'] = true;
                 continue 2;
             }
             $linkBatch->addObj($variantTitle);
             $variantMap[$variantTitle->getPrefixedDBkey()][] = "{$ns}:{$index}";
         }
     }
     // process categories, check if a category exists in some variant
     $categoryMap = array();
     // maps $category_variant => $category (dbkeys)
     $varCategories = array();
     // category replacements oldDBkey => newDBkey
     foreach ($output->getCategoryLinks() as $category) {
         $categoryTitle = Title::makeTitleSafe(NS_CATEGORY, $category);
         $linkBatch->addObj($categoryTitle);
         $variants = $wgContLang->autoConvertToAllVariants($category);
         foreach ($variants as $variant) {
             if ($variant !== $category) {
                 $variantTitle = Title::makeTitleSafe(NS_CATEGORY, $variant);
                 if (is_null($variantTitle)) {
                     continue;
                 }
                 $linkBatch->addObj($variantTitle);
                 $categoryMap[$variant] = array($category, $categoryTitle);
             }
         }
     }
     if (!$linkBatch->isEmpty()) {
         // construct query
         $dbr = wfGetDB(DB_SLAVE);
         $fields = array('page_id', 'page_namespace', 'page_title', 'page_is_redirect', 'page_len', 'page_latest');
         if ($wgContentHandlerUseDB) {
             $fields[] = 'page_content_model';
         }
         $varRes = $dbr->select('page', $fields, $linkBatch->constructSet('page', $dbr), __METHOD__);
         $linkcolour_ids = array();
         // for each found variants, figure out link holders and replace
         foreach ($varRes as $s) {
             $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->addGoodLinkObjFromRow($variantTitle, $s);
                 $output->addLink($variantTitle, $s->page_id);
             }
             // loop over link holders
             foreach ($holderKeys as $key) {
                 list($ns, $index) = explode(':', $key, 2);
                 $entry =& $this->internals[$ns][$index];
                 $pdbk = $entry['pdbk'];
                 if (!isset($colours[$pdbk]) || $colours[$pdbk] === 'new') {
                     // found link in some of the variants, replace the link holder data
                     $entry['title'] = $variantTitle;
                     $entry['pdbk'] = $varPdbk;
                     // set pdbk and colour
                     # @todo FIXME: Convoluted data flow
                     # The redirect status and length is passed to getLinkColour via the LinkCache
                     # Use formal parameters instead
                     $colours[$varPdbk] = Linker::getLinkColour($variantTitle, $threshold);
                     $linkcolour_ids[$s->page_id] = $pdbk;
                 }
             }
             // check if the object is a variant of a category
             if (isset($categoryMap[$vardbk])) {
                 list($oldkey, $oldtitle) = $categoryMap[$vardbk];
                 if (!isset($varCategories[$oldkey]) && !$oldtitle->exists()) {
                     $varCategories[$oldkey] = $vardbk;
                 }
             }
         }
         Hooks::run('GetLinkColours', array($linkcolour_ids, &$colours));
         // rebuild the categories in original order (if there are replacements)
         if (count($varCategories) > 0) {
             $newCats = array();
             $originalCats = $output->getCategories();
             foreach ($originalCats as $cat => $sortkey) {
                 // make the replacement
                 if (array_key_exists($cat, $varCategories)) {
                     $newCats[$varCategories[$cat]] = $sortkey;
                 } else {
                     $newCats[$cat] = $sortkey;
                 }
             }
             $output->setCategoryLinks($newCats);
         }
     }
 }
 /**
  * Get the information about the wiki pages for a given context.
  * @param ResourceLoaderContext $context
  * @return array Keyed by page name. Contains arrays with 'rev_len' and 'rev_sha1' keys
  */
 protected function getTitleInfo(ResourceLoaderContext $context)
 {
     $dbr = $this->getDB();
     if (!$dbr) {
         // We're dealing with a subclass that doesn't have a DB
         return array();
     }
     $pages = $this->getPages($context);
     $key = implode('|', array_keys($pages));
     if (!isset($this->titleInfo[$key])) {
         $this->titleInfo[$key] = array();
         $batch = new LinkBatch();
         foreach ($pages as $titleText => $options) {
             $batch->addObj(Title::newFromText($titleText));
         }
         if (!$batch->isEmpty()) {
             $res = $dbr->select(array('page', 'revision'), array('page_namespace', 'page_title', 'rev_len', 'rev_sha1'), $batch->constructSet('page', $dbr), __METHOD__, array(), array('revision' => array('INNER JOIN', array('page_latest=rev_id'))));
             foreach ($res as $row) {
                 // Avoid including ids or timestamps of revision/page tables so
                 // that versions are not wasted
                 $title = Title::makeTitle($row->page_namespace, $row->page_title);
                 $this->titleInfo[$key][$title->getPrefixedText()] = array('rev_len' => $row->rev_len, 'rev_sha1' => $row->rev_sha1);
             }
         }
     }
     return $this->titleInfo[$key];
 }
Ejemplo n.º 5
0
 /**
  * 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;
 }
Ejemplo n.º 6
0
 /**
  * Modify $this->internals and $colours according to language variant linking rules
  */
 protected function doVariants(&$colours)
 {
     global $wgContLang;
     $linkBatch = new LinkBatch();
     $variantMap = array();
     // maps $pdbkey_Variant => $keys (of link holders)
     $output = $this->parent->getOutput();
     $linkCache = LinkCache::singleton();
     $sk = $this->parent->getOptions()->getSkin();
     $threshold = $this->getStubThreshold();
     // Add variants of links to link batch
     foreach ($this->internals as $ns => $entries) {
         foreach ($entries as $index => $entry) {
             $key = "{$ns}:{$index}";
             $pdbk = $entry['pdbk'];
             $title = $entry['title'];
             $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
     $categoryMap = array();
     // maps $category_variant => $category (dbkeys)
     $varCategories = array();
     // category replacements oldDBkey => newDBkey
     foreach ($output->getCategoryLinks() 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
         $dbr = wfGetDB(DB_SLAVE);
         $page = $dbr->tableName('page');
         $titleClause = $linkBatch->constructSet('page', $dbr);
         $variantQuery = "SELECT page_id, page_namespace, page_title, page_is_redirect, page_len";
         $variantQuery .= " FROM {$page} WHERE {$titleClause}";
         $varRes = $dbr->query($variantQuery, __METHOD__);
         $linkcolour_ids = array();
         // 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, $s->page_len, $s->page_is_redirect);
                 $output->addLink($variantTitle, $s->page_id);
             }
             // loop over link holders
             foreach ($holderKeys as $key) {
                 list($ns, $index) = explode(':', $key, 2);
                 $entry =& $this->internals[$ns][$index];
                 $pdbk = $entry['pdbk'];
                 if (!isset($colours[$pdbk])) {
                     // found link in some of the variants, replace the link holder data
                     $entry['title'] = $variantTitle;
                     $entry['pdbk'] = $varPdbk;
                     // set pdbk and colour
                     # FIXME: convoluted data flow
                     # The redirect status and length is passed to getLinkColour via the LinkCache
                     # Use formal parameters instead
                     $colours[$varPdbk] = $sk->getLinkColour($variantTitle, $threshold);
                     $linkcolour_ids[$s->page_id] = $pdbk;
                 }
             }
             // check if the object is a variant of a category
             if (isset($categoryMap[$vardbk])) {
                 $oldkey = $categoryMap[$vardbk];
                 if ($oldkey != $vardbk) {
                     $varCategories[$oldkey] = $vardbk;
                 }
             }
         }
         wfRunHooks('GetLinkColours', array($linkcolour_ids, &$colours));
         // rebuild the categories in original order (if there are replacements)
         if (count($varCategories) > 0) {
             $newCats = array();
             $originalCats = $output->getCategories();
             foreach ($originalCats as $cat => $sortkey) {
                 // make the replacement
                 if (array_key_exists($cat, $varCategories)) {
                     $newCats[$varCategories[$cat]] = $sortkey;
                 } else {
                     $newCats[$cat] = $sortkey;
                 }
             }
             $output->setCategoryLinks($newCats);
         }
     }
 }
 protected function reallyGetTitleMtimes(ResourceLoaderContext $context)
 {
     wfProfileIn(__METHOD__);
     $dbr = $this->getDB();
     if (!$dbr) {
         // We're dealing with a subclass that doesn't have a DB
         wfProfileOut(__METHOD__);
         return array();
     }
     $mtimes = array();
     $local = array();
     $byWiki = array();
     $pages = $this->getPages($context);
     foreach ($pages as $titleText => $options) {
         $title = $this->createTitle($titleText, $options);
         if ($title instanceof GlobalTitle) {
             $byWiki[$title->getCityId()][] = array($title, $titleText, $options);
         } else {
             $local[] = array($title, $titleText, $options);
         }
     }
     if (!empty($local)) {
         $batch = new LinkBatch();
         foreach ($local as $page) {
             list($title, $titleText, $options) = $page;
             $batch->addObj($title);
         }
         if (!$batch->isEmpty()) {
             $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_touched'), $batch->constructSet('page', $dbr), __METHOD__);
             foreach ($res as $row) {
                 $title = Title::makeTitle($row->page_namespace, $row->page_title);
                 $mtimes[$title->getPrefixedDBkey()] = wfTimestamp(TS_UNIX, $row->page_touched);
             }
         }
     }
     foreach ($byWiki as $cityId => $pages) {
         // $pages[0][0] has to be GlobalTitle
         $dbName = $pages[0][0]->getDatabaseName();
         $dbr = wfGetDB(DB_SLAVE, array(), $dbName);
         $pagesData = array();
         foreach ($pages as $page) {
             list($title, $titleText, $options) = $page;
             /** @var $title GlobalTitle */
             $pagesData[$title->getNamespace()][$title->getDBkey()] = true;
         }
         $res = $dbr->select('page', array('page_namespace', 'page_title', 'page_touched'), $dbr->makeWhereFrom2d($pagesData, 'page_namespace', 'page_title'), __METHOD__);
         foreach ($res as $row) {
             $title = GlobalTitle::newFromTextCached($row->page_title, $row->page_namespace, $cityId);
             $mtimes[$dbName . '::' . $title->getPrefixedDBkey()] = wfTimestamp(TS_UNIX, $row->page_touched);
         }
     }
     wfProfileOut(__METHOD__);
     return $mtimes;
 }
Ejemplo n.º 8
0
 /**
  * Perform the search
  *
  * @param string $search Text to search
  * @param int $limit Maximum items to return
  * @param array $namespaces Namespaces to search
  * @param bool $resolveRedir Whether to resolve redirects
  * @param array &$results Put results here. Keys have to be integers.
  */
 protected function search($search, $limit, $namespaces, $resolveRedir, &$results)
 {
     $searchEngine = MediaWikiServices::getInstance()->newSearchEngine();
     $searchEngine->setLimitOffset($limit);
     $searchEngine->setNamespaces($namespaces);
     $titles = $searchEngine->extractTitles($searchEngine->completionSearchWithVariants($search));
     if (!$titles) {
         return;
     }
     // Special pages need unique integer ids in the return list, so we just
     // assign them negative numbers because those won't clash with the
     // always positive articleIds that non-special pages get.
     $nextSpecialPageId = -1;
     if ($resolveRedir) {
         // Query for redirects
         $redirects = [];
         $lb = new LinkBatch($titles);
         if (!$lb->isEmpty()) {
             $db = $this->getDB();
             $res = $db->select(['page', 'redirect'], ['page_namespace', 'page_title', 'rd_namespace', 'rd_title'], ['rd_from = page_id', 'rd_interwiki IS NULL OR rd_interwiki = ' . $db->addQuotes(''), $lb->constructSet('page', $db)], __METHOD__);
             foreach ($res as $row) {
                 $redirects[$row->page_namespace][$row->page_title] = [$row->rd_namespace, $row->rd_title];
             }
         }
         // Bypass any redirects
         $seen = [];
         foreach ($titles as $title) {
             $ns = $title->getNamespace();
             $dbkey = $title->getDBkey();
             $from = null;
             if (isset($redirects[$ns][$dbkey])) {
                 list($ns, $dbkey) = $redirects[$ns][$dbkey];
                 $from = $title;
                 $title = Title::makeTitle($ns, $dbkey);
             }
             if (!isset($seen[$ns][$dbkey])) {
                 $seen[$ns][$dbkey] = true;
                 $resultId = $title->getArticleID();
                 if ($resultId === 0) {
                     $resultId = $nextSpecialPageId;
                     $nextSpecialPageId -= 1;
                 }
                 $results[$resultId] = ['title' => $title, 'redirect from' => $from, 'extract' => false, 'extract trimmed' => false, 'image' => false, 'url' => wfExpandUrl($title->getFullURL(), PROTO_CURRENT)];
             }
         }
     } else {
         foreach ($titles as $title) {
             $resultId = $title->getArticleID();
             if ($resultId === 0) {
                 $resultId = $nextSpecialPageId;
                 $nextSpecialPageId -= 1;
             }
             $results[$resultId] = ['title' => $title, 'redirect from' => null, 'extract' => false, 'extract trimmed' => false, 'image' => false, 'url' => wfExpandUrl($title->getFullURL(), PROTO_CURRENT)];
         }
     }
 }
Ejemplo n.º 9
0
 /**
  * Replace <!--LINK--> link placeholders with actual links, in the buffer
  * Placeholders created in Skin::makeLinkObj()
  * Returns an array of links found, indexed by PDBK:
  *  0 - broken
  *  1 - normal link
  *  2 - stub
  * $options is a bit field, RLH_FOR_UPDATE to select for update
  */
 function replaceLinkHolders(&$text, $options = 0)
 {
     global $wgUser;
     global $wgOutputReplace;
     global $wgContLang, $wgLanguageCode;
     $fname = 'Parser::replaceLinkHolders';
     wfProfileIn($fname);
     $pdbks = array();
     $colours = 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;
         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] = 1;
             } elseif (($id = $linkCache->getGoodLinkID($pdbk)) != 0) {
                 $colours[$pdbk] = 1;
                 $this->mOutput->addLink($title, $id);
             } elseif ($linkCache->isBadLink($pdbk)) {
                 $colours[$pdbk] = 0;
             } else {
                 # Not in the link cache, add it to the query
                 if (!isset($current)) {
                     $current = $ns;
                     $query = "SELECT page_id, page_namespace, page_title";
                     if ($threshold > 0) {
                         $query .= ', page_len, page_is_redirect';
                     }
                     $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
             # 1 = known
             # 2 = stub
             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);
                 if ($threshold > 0) {
                     $size = $s->page_len;
                     if ($s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold) {
                         $colours[$pdbk] = 1;
                     } else {
                         $colours[$pdbk] = 2;
                     }
                 } else {
                     $colours[$pdbk] = 1;
                 }
             }
         }
         wfProfileOut($fname . '-check');
         # Do a second query for different language variants of links (if needed)
         if ($wgContLang->hasVariants()) {
             $linkBatch = new LinkBatch();
             $variantMap = array();
             // maps $pdbkey_Variant => $pdbkey_original
             // 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();
                 // generate all variants of the link title text
                 $allTextVariants = $wgContLang->convertLinkToAllVariants($title->getText());
                 // if link was not found (in first query), add all variants to query
                 if (!isset($colours[$pdbk])) {
                     foreach ($allTextVariants as $textVariant) {
                         $variantTitle = Title::makeTitle($ns, $textVariant);
                         if (is_null($variantTitle)) {
                             continue;
                         }
                         $linkBatch->addObj($variantTitle);
                         $variantMap[$variantTitle->getPrefixedDBkey()][] = $key;
                     }
                 }
             }
             if (!$linkBatch->isEmpty()) {
                 // construct query
                 $titleClause = $linkBatch->constructSet('page', $dbr);
                 $variantQuery = "SELECT page_id, page_namespace, page_title";
                 if ($threshold > 0) {
                     $variantQuery .= ', page_len, page_is_redirect';
                 }
                 $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();
                     $linkCache->addGoodLinkObj($s->page_id, $variantTitle);
                     $this->mOutput->addLink($variantTitle, $s->page_id);
                     $holderKeys = $variantMap[$varPdbk];
                     // 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;
                             if ($threshold > 0) {
                                 $size = $s->page_len;
                                 if ($s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold) {
                                     $colours[$varPdbk] = 1;
                                 } else {
                                     $colours[$varPdbk] = 2;
                                 }
                             } else {
                                 $colours[$varPdbk] = 1;
                             }
                         }
                     }
                 }
             }
         }
         # Construct search and replace arrays
         wfProfileIn($fname . '-construct');
         $wgOutputReplace = array();
         foreach ($this->mLinkHolders['namespaces'] as $key => $ns) {
             $pdbk = $pdbks[$key];
             $searchkey = "<!--LINK {$key}-->";
             $title = $this->mLinkHolders['titles'][$key];
             if (empty($colours[$pdbk])) {
                 $linkCache->addBadLinkObj($title);
                 $colours[$pdbk] = 0;
                 $this->mOutput->addLink($title, 0);
                 $wgOutputReplace[$searchkey] = $sk->makeBrokenLinkObj($title, $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]);
             } elseif ($colours[$pdbk] == 1) {
                 $wgOutputReplace[$searchkey] = $sk->makeKnownLinkObj($title, $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]);
             } elseif ($colours[$pdbk] == 2) {
                 $wgOutputReplace[$searchkey] = $sk->makeStubLinkObj($title, $this->mLinkHolders['texts'][$key], $this->mLinkHolders['queries'][$key]);
             }
         }
         wfProfileOut($fname . '-construct');
         # Do the thing
         wfProfileIn($fname . '-replace');
         $text = preg_replace_callback('/(<!--LINK .*?-->)/', "wfOutputReplaceMatches", $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
         $wgOutputReplace = array();
         foreach ($this->mInterwikiLinkHolders['texts'] as $key => $link) {
             $title = $this->mInterwikiLinkHolders['titles'][$key];
             $wgOutputReplace[$key] = $sk->makeLinkObj($title, $link);
         }
         $text = preg_replace_callback('/<!--IWLINK (.*?)-->/', "wfOutputReplaceMatches", $text);
         wfProfileOut($fname . '-interwiki');
     }
     wfProfileOut($fname);
     return $colours;
 }
Ejemplo n.º 10
0
 protected static function fetchTitleInfo(IDatabase $db, array $pages, $fname = __METHOD__)
 {
     $titleInfo = [];
     $batch = new LinkBatch();
     foreach ($pages as $titleText) {
         $title = Title::newFromText($titleText);
         if ($title) {
             // Page name may be invalid if user-provided (e.g. gadgets)
             $batch->addObj($title);
         }
     }
     if (!$batch->isEmpty()) {
         $res = $db->select('page', ['page_namespace', 'page_title', 'page_touched', 'page_len', 'page_latest'], $batch->constructSet('page', $db), $fname);
         foreach ($res as $row) {
             // Avoid including ids or timestamps of revision/page tables so
             // that versions are not wasted
             $title = Title::makeTitle($row->page_namespace, $row->page_title);
             $titleInfo[$title->getPrefixedText()] = ['page_len' => $row->page_len, 'page_latest' => $row->page_latest, 'page_touched' => $row->page_touched];
         }
     }
     return $titleInfo;
 }