Beispiel #1
0
 /**
  * Get the fields that have to be queried from the page table:
  * the ones requested through requestField() and a few basic ones
  * we always need
  * @return array Array of field names
  */
 public function getPageTableFields()
 {
     // Ensure we get minimum required fields
     // DON'T change this order
     $pageFlds = ['page_namespace' => null, 'page_title' => null, 'page_id' => null];
     if ($this->mResolveRedirects) {
         $pageFlds['page_is_redirect'] = null;
     }
     if ($this->getConfig()->get('ContentHandlerUseDB')) {
         $pageFlds['page_content_model'] = null;
     }
     if ($this->getConfig()->get('PageLanguageUseDB')) {
         $pageFlds['page_lang'] = null;
     }
     foreach (LinkCache::getSelectFields() as $field) {
         $pageFlds[$field] = null;
     }
     $pageFlds = array_merge($pageFlds, $this->mRequestedPageFields);
     return array_keys($pageFlds);
 }
Beispiel #2
0
 /**
  * Add an array of categories, with names in the keys
  *
  * @param array $categories Mapping category name => sort key
  */
 public function addCategoryLinks(array $categories)
 {
     global $wgContLang;
     if (!is_array($categories) || count($categories) == 0) {
         return;
     }
     # Add the links to a LinkBatch
     $arr = [NS_CATEGORY => $categories];
     $lb = new LinkBatch();
     $lb->setArray($arr);
     # Fetch existence plus the hiddencat property
     $dbr = wfGetDB(DB_REPLICA);
     $fields = array_merge(LinkCache::getSelectFields(), ['page_namespace', 'page_title', 'pp_value']);
     $res = $dbr->select(['page', 'page_props'], $fields, $lb->constructSet('page', $dbr), __METHOD__, [], ['page_props' => ['LEFT JOIN', ['pp_propname' => 'hiddencat', 'pp_page = page_id']]]);
     # Add the results to the link cache
     $lb->addResultToCache(LinkCache::singleton(), $res);
     # Set all the values to 'normal'.
     $categories = array_fill_keys(array_keys($categories), 'normal');
     # Mark hidden categories
     foreach ($res as $row) {
         if (isset($row->pp_value)) {
             $categories[$row->page_title] = 'hidden';
         }
     }
     # Add the remaining categories to the skin
     if (Hooks::run('OutputPageMakeCategoryLinks', [&$this, $categories, &$this->mCategoryLinks])) {
         foreach ($categories as $category => $type) {
             // array keys will cast numeric category names to ints, so cast back to string
             $category = (string) $category;
             $origcategory = $category;
             $title = Title::makeTitleSafe(NS_CATEGORY, $category);
             if (!$title) {
                 continue;
             }
             $wgContLang->findVariantLink($category, $title, true);
             if ($category != $origcategory && array_key_exists($category, $categories)) {
                 continue;
             }
             $text = $wgContLang->convertHtml($title->getText());
             $this->mCategories[] = $title->getText();
             $this->mCategoryLinks[$type][] = Linker::link($title, $text);
         }
     }
 }
 /**
  * Modify $this->internals and $colours according to language variant linking rules
  * @param array $colours
  */
 protected function doVariants(&$colours)
 {
     global $wgContLang;
     $linkBatch = new LinkBatch();
     $variantMap = [];
     // maps $pdbkey_Variant => $keys (of link holders)
     $output = $this->parent->getOutput();
     $linkCache = LinkCache::singleton();
     $threshold = $this->parent->getOptions()->getStubThreshold();
     $titlesToBeConverted = '';
     $titlesAttrs = [];
     // 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[] = [$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);
             // 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 = [];
     // maps $category_variant => $category (dbkeys)
     $varCategories = [];
     // 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] = [$category, $categoryTitle];
             }
         }
     }
     if (!$linkBatch->isEmpty()) {
         // construct query
         $dbr = wfGetDB(DB_SLAVE);
         $fields = array_merge(LinkCache::getSelectFields(), ['page_namespace', 'page_title']);
         $varRes = $dbr->select('page', $fields, $linkBatch->constructSet('page', $dbr), __METHOD__);
         $linkcolour_ids = [];
         // 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 = [];
             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
                     $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', [$linkcolour_ids, &$colours]);
         // rebuild the categories in original order (if there are replacements)
         if (count($varCategories) > 0) {
             $newCats = [];
             $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);
         }
     }
 }
 /**
  * @param int $namespace Default NS_MAIN
  * @param string $prefix
  * @param string $from List all pages from this name (default false)
  */
 protected function showPrefixChunk($namespace = NS_MAIN, $prefix, $from = null)
 {
     global $wgContLang;
     if ($from === null) {
         $from = $prefix;
     }
     $fromList = $this->getNamespaceKeyAndText($namespace, $from);
     $prefixList = $this->getNamespaceKeyAndText($namespace, $prefix);
     $namespaces = $wgContLang->getNamespaces();
     $res = null;
     $n = 0;
     $nextRow = null;
     if (!$prefixList || !$fromList) {
         $out = $this->msg('allpagesbadtitle')->parseAsBlock();
     } elseif (!array_key_exists($namespace, $namespaces)) {
         // Show errormessage and reset to NS_MAIN
         $out = $this->msg('allpages-bad-ns', $namespace)->parse();
         $namespace = NS_MAIN;
     } else {
         list($namespace, $prefixKey, $prefix) = $prefixList;
         list(, $fromKey, ) = $fromList;
         # ## @todo FIXME: Should complain if $fromNs != $namespace
         $dbr = wfGetDB(DB_REPLICA);
         $conds = ['page_namespace' => $namespace, 'page_title' . $dbr->buildLike($prefixKey, $dbr->anyString()), 'page_title >= ' . $dbr->addQuotes($fromKey)];
         if ($this->hideRedirects) {
             $conds['page_is_redirect'] = 0;
         }
         $res = $dbr->select('page', array_merge(['page_namespace', 'page_title'], LinkCache::getSelectFields()), $conds, __METHOD__, ['ORDER BY' => 'page_title', 'LIMIT' => $this->maxPerPage + 1, 'USE INDEX' => 'name_title']);
         // @todo FIXME: Side link to previous
         if ($res->numRows() > 0) {
             $out = Html::openElement('ul', ['class' => 'mw-prefixindex-list']);
             $linkCache = MediaWikiServices::getInstance()->getLinkCache();
             $prefixLength = strlen($prefix);
             foreach ($res as $row) {
                 if ($n >= $this->maxPerPage) {
                     $nextRow = $row;
                     break;
                 }
                 $title = Title::newFromRow($row);
                 // Make sure it gets into LinkCache
                 $linkCache->addGoodLinkObjFromRow($title, $row);
                 $displayed = $title->getText();
                 // Try not to generate unclickable links
                 if ($this->stripPrefix && $prefixLength !== strlen($displayed)) {
                     $displayed = substr($displayed, $prefixLength);
                 }
                 $link = ($title->isRedirect() ? '<div class="allpagesredirect">' : '') . Linker::linkKnown($title, htmlspecialchars($displayed)) . ($title->isRedirect() ? '</div>' : '');
                 $out .= "<li>{$link}</li>\n";
                 $n++;
             }
             $out .= Html::closeElement('ul');
             if ($res->numRows() > 2) {
                 // Only apply CSS column styles if there's more than 2 entries.
                 // Otherwise rendering is broken as "mw-prefixindex-body"'s CSS column count is 3.
                 $out = Html::rawElement('div', ['class' => 'mw-prefixindex-body'], $out);
             }
         } else {
             $out = '';
         }
     }
     $output = $this->getOutput();
     if ($this->including()) {
         // We don't show the nav-links and the form when included into other
         // pages so let's just finish here.
         $output->addHTML($out);
         return;
     }
     $topOut = $this->namespacePrefixForm($namespace, $prefix);
     if ($res && $n == $this->maxPerPage && $nextRow) {
         $query = ['from' => $nextRow->page_title, 'prefix' => $prefix, 'hideredirects' => $this->hideRedirects, 'stripprefix' => $this->stripPrefix];
         if ($namespace || $prefix == '') {
             // Keep the namespace even if it's 0 for empty prefixes.
             // This tells us we're not just a holdover from old links.
             $query['namespace'] = $namespace;
         }
         $nextLink = Linker::linkKnown($this->getPageTitle(), $this->msg('nextpage', str_replace('_', ' ', $nextRow->page_title))->escaped(), [], $query);
         // Link shown at the top of the page below the form
         $topOut .= Html::rawElement('div', ['class' => 'mw-prefixindex-nav'], $nextLink);
         // Link shown at the footer
         $out .= "\n" . Html::element('hr') . Html::rawElement('div', ['class' => 'mw-prefixindex-nav'], $nextLink);
     }
     $output->addHTML($topOut . $out);
 }
Beispiel #5
0
 /**
  * Perform the existence test query, return a ResultWrapper with page_id fields
  * @return bool|ResultWrapper
  */
 public function doQuery()
 {
     if ($this->isEmpty()) {
         return false;
     }
     // This is similar to LinkHolderArray::replaceInternal
     $dbr = wfGetDB(DB_SLAVE);
     $table = 'page';
     $fields = array_merge(LinkCache::getSelectFields(), ['page_namespace', 'page_title']);
     $conds = $this->constructSet('page', $dbr);
     // Do query
     $caller = __METHOD__;
     if (strval($this->caller) !== '') {
         $caller .= " (for {$this->caller})";
     }
     $res = $dbr->select($table, $fields, $conds, $caller);
     return $res;
 }
Beispiel #6
0
 function doCategoryQuery()
 {
     $dbr = wfGetDB(DB_REPLICA, 'category');
     $this->nextPage = ['page' => null, 'subcat' => null, 'file' => null];
     $this->prevPage = ['page' => null, 'subcat' => null, 'file' => null];
     $this->flip = ['page' => false, 'subcat' => false, 'file' => false];
     foreach (['page', 'subcat', 'file'] as $type) {
         # Get the sortkeys for start/end, if applicable.  Note that if
         # the collation in the database differs from the one
         # set in $wgCategoryCollation, pagination might go totally haywire.
         $extraConds = ['cl_type' => $type];
         if (isset($this->from[$type]) && $this->from[$type] !== null) {
             $extraConds[] = 'cl_sortkey >= ' . $dbr->addQuotes($this->collation->getSortKey($this->from[$type]));
         } elseif (isset($this->until[$type]) && $this->until[$type] !== null) {
             $extraConds[] = 'cl_sortkey < ' . $dbr->addQuotes($this->collation->getSortKey($this->until[$type]));
             $this->flip[$type] = true;
         }
         $res = $dbr->select(['page', 'categorylinks', 'category'], array_merge(LinkCache::getSelectFields(), ['page_namespace', 'page_title', 'cl_sortkey', 'cat_id', 'cat_title', 'cat_subcats', 'cat_pages', 'cat_files', 'cl_sortkey_prefix', 'cl_collation']), array_merge(['cl_to' => $this->title->getDBkey()], $extraConds), __METHOD__, ['USE INDEX' => ['categorylinks' => 'cl_sortkey'], 'LIMIT' => $this->limit + 1, 'ORDER BY' => $this->flip[$type] ? 'cl_sortkey DESC' : 'cl_sortkey'], ['categorylinks' => ['INNER JOIN', 'cl_from = page_id'], 'category' => ['LEFT JOIN', ['cat_title = page_title', 'page_namespace' => NS_CATEGORY]]]);
         Hooks::run('CategoryViewer::doCategoryQuery', [$type, $res]);
         $linkCache = MediaWikiServices::getInstance()->getLinkCache();
         $count = 0;
         foreach ($res as $row) {
             $title = Title::newFromRow($row);
             $linkCache->addGoodLinkObjFromRow($title, $row);
             if ($row->cl_collation === '') {
                 // Hack to make sure that while updating from 1.16 schema
                 // and db is inconsistent, that the sky doesn't fall.
                 // See r83544. Could perhaps be removed in a couple decades...
                 $humanSortkey = $row->cl_sortkey;
             } else {
                 $humanSortkey = $title->getCategorySortkey($row->cl_sortkey_prefix);
             }
             if (++$count > $this->limit) {
                 # We've reached the one extra which shows that there
                 # are additional pages to be had. Stop here...
                 $this->nextPage[$type] = $humanSortkey;
                 break;
             }
             if ($count == $this->limit) {
                 $this->prevPage[$type] = $humanSortkey;
             }
             if ($title->getNamespace() == NS_CATEGORY) {
                 $cat = Category::newFromRow($row, $title);
                 $this->addSubcategoryObject($cat, $humanSortkey, $row->page_len);
             } elseif ($title->getNamespace() == NS_FILE) {
                 $this->addImage($title, $humanSortkey, $row->page_len, $row->page_is_redirect);
             } else {
                 $this->addPage($title, $humanSortkey, $row->page_len, $row->page_is_redirect);
             }
         }
     }
 }