/** * @return PageProps */ public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; }
public function execute() { # Only operate on existing pages $pages = $this->getPageSet()->getGoodTitles(); $this->params = $this->extractRequestParams(); if ($this->params['continue']) { $continueValue = intval($this->params['continue']); $this->dieContinueUsageIf(strval($continueValue) !== $this->params['continue']); $filteredPages = []; foreach ($pages as $id => $page) { if ($id >= $continueValue) { $filteredPages[$id] = $page; } } $pages = $filteredPages; } if (!count($pages)) { # Nothing to do return; } $pageProps = PageProps::getInstance(); $result = $this->getResult(); if ($this->params['prop']) { $propnames = $this->params['prop']; $properties = $pageProps->getProperties($pages, $propnames); } else { $properties = $pageProps->getAllProperties($pages); } ksort($properties); foreach ($properties as $page => $props) { if (!$this->addPageProps($result, $page, $props)) { break; } } }
/** * @dataProvider provideCategoryContent * @covers WikiCategoryPage::isHidden */ public function testHiddenCategory_PropertyIsSet($isHidden) { $categoryTitle = Title::makeTitle(NS_CATEGORY, 'CategoryPage'); $categoryPage = WikiCategoryPage::factory($categoryTitle); $pageProps = $this->getMockPageProps(); $pageProps->expects($this->once())->method('getProperties')->with($categoryTitle, 'hiddencat')->will($this->returnValue($isHidden ? [$categoryTitle->getArticleID() => ''] : [])); $scopedOverride = PageProps::overrideInstance($pageProps); $this->assertEquals($isHidden, $categoryPage->isHidden()); ScopedCallback::consume($scopedOverride); }
/** * @dataProvider provideCategoryContent * @covers RecentChange::newForCategorization */ public function testHiddenCategoryChange($isHidden) { $categoryTitle = Title::newFromText('CategoryPage', NS_CATEGORY); $pageProps = $this->getMockPageProps(); $pageProps->expects($this->once())->method('getProperties')->with($categoryTitle, 'hiddencat')->will($this->returnValue($isHidden ? [$categoryTitle->getArticleID() => ''] : [])); $scopedOverride = PageProps::overrideInstance($pageProps); $rc = RecentChange::newForCategorization('0', $categoryTitle, $this->user, $this->user_comment, $this->title, $categoryTitle->getLatestRevID(), $categoryTitle->getLatestRevID(), '0', false); $this->assertEquals($isHidden, $rc->getParam('hidden-cat')); ScopedCallback::consume($scopedOverride); }
/** * Returns page information in an easily-manipulated format. Array keys are used so extensions * may add additional information in arbitrary positions. Array values are arrays with one * element to be rendered as a header, arrays with two elements to be rendered as a table row. * * @return array */ protected function pageInfo() { global $wgContLang; $user = $this->getUser(); $lang = $this->getLanguage(); $title = $this->getTitle(); $id = $title->getArticleID(); $config = $this->context->getConfig(); $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer(); $pageCounts = $this->pageCounts($this->page); $pageProperties = []; $props = PageProps::getInstance()->getAllProperties($title); if (isset($props[$id])) { $pageProperties = $props[$id]; } // Basic information $pageInfo = []; $pageInfo['header-basic'] = []; // Display title $displayTitle = $title->getPrefixedText(); if (isset($pageProperties['displaytitle'])) { $displayTitle = $pageProperties['displaytitle']; } $pageInfo['header-basic'][] = [$this->msg('pageinfo-display-title'), $displayTitle]; // Is it a redirect? If so, where to? if ($title->isRedirect()) { $pageInfo['header-basic'][] = [$this->msg('pageinfo-redirectsto'), Linker::link($this->page->getRedirectTarget()) . $this->msg('word-separator')->escaped() . $this->msg('parentheses')->rawParams(Linker::link($this->page->getRedirectTarget(), $this->msg('pageinfo-redirectsto-info')->escaped(), [], ['action' => 'info']))->escaped()]; } // Default sort key $sortKey = $title->getCategorySortkey(); if (isset($pageProperties['defaultsort'])) { $sortKey = $pageProperties['defaultsort']; } $sortKey = htmlspecialchars($sortKey); $pageInfo['header-basic'][] = [$this->msg('pageinfo-default-sort'), $sortKey]; // Page length (in bytes) $pageInfo['header-basic'][] = [$this->msg('pageinfo-length'), $lang->formatNum($title->getLength())]; // Page ID (number not localised, as it's a database ID) $pageInfo['header-basic'][] = [$this->msg('pageinfo-article-id'), $id]; // Language in which the page content is (supposed to be) written $pageLang = $title->getPageLanguage()->getCode(); if ($config->get('PageLanguageUseDB') && $this->getTitle()->userCan('pagelang', $this->getUser())) { // Link to Special:PageLanguage with pre-filled page title if user has permissions $titleObj = SpecialPage::getTitleFor('PageLanguage', $title->getPrefixedText()); $langDisp = Linker::link($titleObj, $this->msg('pageinfo-language')->escaped()); } else { // Display just the message $langDisp = $this->msg('pageinfo-language')->escaped(); } $pageInfo['header-basic'][] = [$langDisp, Language::fetchLanguageName($pageLang, $lang->getCode()) . ' ' . $this->msg('parentheses', $pageLang)->escaped()]; // Content model of the page $modelHtml = htmlspecialchars(ContentHandler::getLocalizedName($title->getContentModel())); // If the user can change it, add a link to Special:ChangeContentModel if ($title->quickUserCan('editcontentmodel')) { $modelHtml .= ' ' . $this->msg('parentheses')->rawParams($linkRenderer->makeLink(SpecialPage::getTitleValueFor('ChangeContentModel', $title->getPrefixedText()), $this->msg('pageinfo-content-model-change')->text()))->escaped(); } $pageInfo['header-basic'][] = [$this->msg('pageinfo-content-model'), $modelHtml]; if ($title->inNamespace(NS_USER)) { $pageUser = User::newFromName($title->getRootText()); if ($pageUser && $pageUser->getId() && !$pageUser->isHidden()) { $pageInfo['header-basic'][] = [$this->msg('pageinfo-user-id'), $pageUser->getId()]; } } // Search engine status $pOutput = new ParserOutput(); if (isset($pageProperties['noindex'])) { $pOutput->setIndexPolicy('noindex'); } if (isset($pageProperties['index'])) { $pOutput->setIndexPolicy('index'); } // Use robot policy logic $policy = $this->page->getRobotPolicy('view', $pOutput); $pageInfo['header-basic'][] = [$this->msg('pageinfo-robot-policy'), $this->msg("pageinfo-robot-{$policy['index']}")]; $unwatchedPageThreshold = $config->get('UnwatchedPageThreshold'); if ($user->isAllowed('unwatchedpages') || $unwatchedPageThreshold !== false && $pageCounts['watchers'] >= $unwatchedPageThreshold) { // Number of page watchers $pageInfo['header-basic'][] = [$this->msg('pageinfo-watchers'), $lang->formatNum($pageCounts['watchers'])]; if ($config->get('ShowUpdatedMarker') && isset($pageCounts['visitingWatchers'])) { $minToDisclose = $config->get('UnwatchedPageSecret'); if ($pageCounts['visitingWatchers'] > $minToDisclose || $user->isAllowed('unwatchedpages')) { $pageInfo['header-basic'][] = [$this->msg('pageinfo-visiting-watchers'), $lang->formatNum($pageCounts['visitingWatchers'])]; } else { $pageInfo['header-basic'][] = [$this->msg('pageinfo-visiting-watchers'), $this->msg('pageinfo-few-visiting-watchers')]; } } } elseif ($unwatchedPageThreshold !== false) { $pageInfo['header-basic'][] = [$this->msg('pageinfo-watchers'), $this->msg('pageinfo-few-watchers')->numParams($unwatchedPageThreshold)]; } // Redirects to this page $whatLinksHere = SpecialPage::getTitleFor('Whatlinkshere', $title->getPrefixedText()); $pageInfo['header-basic'][] = [Linker::link($whatLinksHere, $this->msg('pageinfo-redirects-name')->escaped(), [], ['hidelinks' => 1, 'hidetrans' => 1, 'hideimages' => $title->getNamespace() == NS_FILE]), $this->msg('pageinfo-redirects-value')->numParams(count($title->getRedirectsHere()))]; // Is it counted as a content page? if ($this->page->isCountable()) { $pageInfo['header-basic'][] = [$this->msg('pageinfo-contentpage'), $this->msg('pageinfo-contentpage-yes')]; } // Subpages of this page, if subpages are enabled for the current NS if (MWNamespace::hasSubpages($title->getNamespace())) { $prefixIndex = SpecialPage::getTitleFor('Prefixindex', $title->getPrefixedText() . '/'); $pageInfo['header-basic'][] = [Linker::link($prefixIndex, $this->msg('pageinfo-subpages-name')->escaped()), $this->msg('pageinfo-subpages-value')->numParams($pageCounts['subpages']['total'], $pageCounts['subpages']['redirects'], $pageCounts['subpages']['nonredirects'])]; } if ($title->inNamespace(NS_CATEGORY)) { $category = Category::newFromTitle($title); // $allCount is the total number of cat members, // not the count of how many members are normal pages. $allCount = (int) $category->getPageCount(); $subcatCount = (int) $category->getSubcatCount(); $fileCount = (int) $category->getFileCount(); $pagesCount = $allCount - $subcatCount - $fileCount; $pageInfo['category-info'] = [[$this->msg('pageinfo-category-total'), $lang->formatNum($allCount)], [$this->msg('pageinfo-category-pages'), $lang->formatNum($pagesCount)], [$this->msg('pageinfo-category-subcats'), $lang->formatNum($subcatCount)], [$this->msg('pageinfo-category-files'), $lang->formatNum($fileCount)]]; } // Page protection $pageInfo['header-restrictions'] = []; // Is this page affected by the cascading protection of something which includes it? if ($title->isCascadeProtected()) { $cascadingFrom = ''; $sources = $title->getCascadeProtectionSources()[0]; foreach ($sources as $sourceTitle) { $cascadingFrom .= Html::rawElement('li', [], Linker::linkKnown($sourceTitle)); } $cascadingFrom = Html::rawElement('ul', [], $cascadingFrom); $pageInfo['header-restrictions'][] = [$this->msg('pageinfo-protect-cascading-from'), $cascadingFrom]; } // Is out protection set to cascade to other pages? if ($title->areRestrictionsCascading()) { $pageInfo['header-restrictions'][] = [$this->msg('pageinfo-protect-cascading'), $this->msg('pageinfo-protect-cascading-yes')]; } // Page protection foreach ($title->getRestrictionTypes() as $restrictionType) { $protectionLevel = implode(', ', $title->getRestrictions($restrictionType)); if ($protectionLevel == '') { // Allow all users $message = $this->msg('protect-default')->escaped(); } else { // Administrators only // Messages: protect-level-autoconfirmed, protect-level-sysop $message = $this->msg("protect-level-{$protectionLevel}"); if ($message->isDisabled()) { // Require "$1" permission $message = $this->msg("protect-fallback", $protectionLevel)->parse(); } else { $message = $message->escaped(); } } $expiry = $title->getRestrictionExpiry($restrictionType); $formattedexpiry = $this->msg('parentheses', $this->getLanguage()->formatExpiry($expiry))->escaped(); $message .= $this->msg('word-separator')->escaped() . $formattedexpiry; // Messages: restriction-edit, restriction-move, restriction-create, // restriction-upload $pageInfo['header-restrictions'][] = [$this->msg("restriction-{$restrictionType}"), $message]; } if (!$this->page->exists()) { return $pageInfo; } // Edit history $pageInfo['header-edits'] = []; $firstRev = $this->page->getOldestRevision(); $lastRev = $this->page->getRevision(); $batch = new LinkBatch(); if ($firstRev) { $firstRevUser = $firstRev->getUserText(Revision::FOR_THIS_USER); if ($firstRevUser !== '') { $firstRevUserTitle = Title::makeTitle(NS_USER, $firstRevUser); $batch->addObj($firstRevUserTitle); $batch->addObj($firstRevUserTitle->getTalkPage()); } } if ($lastRev) { $lastRevUser = $lastRev->getUserText(Revision::FOR_THIS_USER); if ($lastRevUser !== '') { $lastRevUserTitle = Title::makeTitle(NS_USER, $lastRevUser); $batch->addObj($lastRevUserTitle); $batch->addObj($lastRevUserTitle->getTalkPage()); } } $batch->execute(); if ($firstRev) { // Page creator $pageInfo['header-edits'][] = [$this->msg('pageinfo-firstuser'), Linker::revUserTools($firstRev)]; // Date of page creation $pageInfo['header-edits'][] = [$this->msg('pageinfo-firsttime'), Linker::linkKnown($title, htmlspecialchars($lang->userTimeAndDate($firstRev->getTimestamp(), $user)), [], ['oldid' => $firstRev->getId()])]; } if ($lastRev) { // Latest editor $pageInfo['header-edits'][] = [$this->msg('pageinfo-lastuser'), Linker::revUserTools($lastRev)]; // Date of latest edit $pageInfo['header-edits'][] = [$this->msg('pageinfo-lasttime'), Linker::linkKnown($title, htmlspecialchars($lang->userTimeAndDate($this->page->getTimestamp(), $user)), [], ['oldid' => $this->page->getLatest()])]; } // Total number of edits $pageInfo['header-edits'][] = [$this->msg('pageinfo-edits'), $lang->formatNum($pageCounts['edits'])]; // Total number of distinct authors if ($pageCounts['authors'] > 0) { $pageInfo['header-edits'][] = [$this->msg('pageinfo-authors'), $lang->formatNum($pageCounts['authors'])]; } // Recent number of edits (within past 30 days) $pageInfo['header-edits'][] = [$this->msg('pageinfo-recent-edits', $lang->formatDuration($config->get('RCMaxAge'))), $lang->formatNum($pageCounts['recent_edits'])]; // Recent number of distinct authors $pageInfo['header-edits'][] = [$this->msg('pageinfo-recent-authors'), $lang->formatNum($pageCounts['recent_authors'])]; // Array of MagicWord objects $magicWords = MagicWord::getDoubleUnderscoreArray(); // Array of magic word IDs $wordIDs = $magicWords->names; // Array of IDs => localized magic words $localizedWords = $wgContLang->getMagicWords(); $listItems = []; foreach ($pageProperties as $property => $value) { if (in_array($property, $wordIDs)) { $listItems[] = Html::element('li', [], $localizedWords[$property][1]); } } $localizedList = Html::rawElement('ul', [], implode('', $listItems)); $hiddenCategories = $this->page->getHiddenCategories(); if (count($listItems) > 0 || count($hiddenCategories) > 0 || $pageCounts['transclusion']['from'] > 0 || $pageCounts['transclusion']['to'] > 0) { $options = ['LIMIT' => $config->get('PageInfoTransclusionLimit')]; $transcludedTemplates = $title->getTemplateLinksFrom($options); if ($config->get('MiserMode')) { $transcludedTargets = []; } else { $transcludedTargets = $title->getTemplateLinksTo($options); } // Page properties $pageInfo['header-properties'] = []; // Magic words if (count($listItems) > 0) { $pageInfo['header-properties'][] = [$this->msg('pageinfo-magic-words')->numParams(count($listItems)), $localizedList]; } // Hidden categories if (count($hiddenCategories) > 0) { $pageInfo['header-properties'][] = [$this->msg('pageinfo-hidden-categories')->numParams(count($hiddenCategories)), Linker::formatHiddenCategories($hiddenCategories)]; } // Transcluded templates if ($pageCounts['transclusion']['from'] > 0) { if ($pageCounts['transclusion']['from'] > count($transcludedTemplates)) { $more = $this->msg('morenotlisted')->escaped(); } else { $more = null; } $templateListFormatter = new TemplatesOnThisPageFormatter($this->getContext(), $linkRenderer); $pageInfo['header-properties'][] = [$this->msg('pageinfo-templates')->numParams($pageCounts['transclusion']['from']), $templateListFormatter->format($transcludedTemplates, false, $more)]; } if (!$config->get('MiserMode') && $pageCounts['transclusion']['to'] > 0) { if ($pageCounts['transclusion']['to'] > count($transcludedTargets)) { $more = Linker::link($whatLinksHere, $this->msg('moredotdotdot')->escaped(), [], ['hidelinks' => 1, 'hideredirs' => 1]); } else { $more = null; } $templateListFormatter = new TemplatesOnThisPageFormatter($this->getContext(), $linkRenderer); $pageInfo['header-properties'][] = [$this->msg('pageinfo-transclusions')->numParams($pageCounts['transclusion']['to']), $templateListFormatter->format($transcludedTargets, false, $more)]; } } return $pageInfo; }
public function augmentAll(SearchResultSet $resultSet) { $titles = $resultSet->extractTitles(); return PageProps::getInstance()->getProperties($titles, $this->propnames); }
/** * Test that getting all properties clears the single properties * that have been cached by getting a property, saving a new value for * the property, getting all properties (which clears the cached single * properties), then getting the property again. The new value for the * property rather than the cached value of the property should be * returned. */ public function testClearCache() { $pageProps = PageProps::getInstance(); $page1ID = $this->title1->getArticleID(); $pageProps->getProperty($this->title1, "property1"); $new_value = "another value"; $this->setProperty($page1ID, "property1", $new_value); $pageProps->getProperties($this->title1); $result = $pageProps->getProperty($this->title1, "property1"); $this->assertArrayHasKey($page1ID, $result, "Found property"); $this->assertEquals($result[$page1ID], "another value", "Clear cache"); }
/** * Checks if a category is hidden. * * @since 1.27 * * @return bool */ public function isHidden() { $pageId = $this->getTitle()->getArticleID(); $pageProps = PageProps::getInstance()->getProperties($this->getTitle(), 'hiddencat'); return isset($pageProps[$pageId]) ? true : false; }