Example #1
0
 /**
  * Get the backlinks for a given table. Cached in process memory only.
  * @param $table String
  * @param $startId Integer or false
  * @param $endId Integer or false
  * @return TitleArray
  */
 public function getLinks($table, $startId = false, $endId = false)
 {
     wfProfileIn(__METHOD__);
     $fromField = $this->getPrefix($table) . '_from';
     if ($startId || $endId) {
         // Partial range, not cached
         wfDebug(__METHOD__ . ": from DB (uncacheable range)\n");
         $conds = $this->getConditions($table);
         // Use the from field in the condition rather than the joined page_id,
         // because databases are stupid and don't necessarily propagate indexes.
         if ($startId) {
             $conds[] = "{$fromField} >= " . intval($startId);
         }
         if ($endId) {
             $conds[] = "{$fromField} <= " . intval($endId);
         }
         $res = $this->getDB()->select(array($table, 'page'), array('page_namespace', 'page_title', 'page_id'), $conds, __METHOD__, array('STRAIGHT_JOIN', 'ORDER BY' => $fromField));
         $ta = TitleArray::newFromResult($res);
         wfProfileOut(__METHOD__);
         return $ta;
     }
     if (!isset($this->fullResultCache[$table])) {
         wfDebug(__METHOD__ . ": from DB\n");
         $res = $this->getDB()->select(array($table, 'page'), array('page_namespace', 'page_title', 'page_id'), $this->getConditions($table), __METHOD__, array('STRAIGHT_JOIN', 'ORDER BY' => $fromField));
         $this->fullResultCache[$table] = $res;
     }
     $ta = TitleArray::newFromResult($this->fullResultCache[$table]);
     wfProfileOut(__METHOD__);
     return $ta;
 }
Example #2
0
 /**
  * Fetch a TitleArray of up to $limit category members, beginning after the
  * category sort key $offset.
  * @param $limit integer
  * @param $offset string
  * @return TitleArray object for category members.
  */
 public function getMembers($limit = false, $offset = '')
 {
     $dbr = wfGetDB(DB_SLAVE);
     $conds = array('cl_to' => $this->getName(), 'cl_from = page_id');
     $options = array('ORDER BY' => 'cl_sortkey');
     if ($limit) {
         $options['LIMIT'] = $limit;
     }
     if ($offset !== '') {
         $conds[] = 'cl_sortkey > ' . $dbr->addQuotes($offset);
     }
     return TitleArray::newFromResult($dbr->select(array('page', 'categorylinks'), array('page_id', 'page_namespace', 'page_title', 'page_len', 'page_is_redirect', 'page_latest'), $conds, __METHOD__, $options));
 }
Example #3
0
 /**
  * Returns a list of categories this page is a member of.
  * Results will include hidden categories
  *
  * @return TitleArray
  */
 public function getCategories()
 {
     $id = $this->getId();
     if ($id == 0) {
         return TitleArray::newFromResult(new FakeResultWrapper([]));
     }
     $dbr = wfGetDB(DB_REPLICA);
     $res = $dbr->select('categorylinks', ['cl_to AS page_title, ' . NS_CATEGORY . ' AS page_namespace'], ['cl_from' => $id], __METHOD__);
     return TitleArray::newFromResult($res);
 }
Example #4
0
 /**
  * Get the categories this file is a member of on the wiki where it was uploaded.
  * For local files, this is the same as getCategories().
  * For foreign API files (InstantCommons), this is not supported currently.
  * Results will include hidden categories.
  *
  * @return TitleArray|Title[]
  * @since 1.23
  */
 public function getForeignCategories()
 {
     $this->loadFile();
     $title = $this->mTitle;
     $file = $this->mFile;
     if (!$file instanceof LocalFile) {
         wfDebug(__CLASS__ . '::' . __METHOD__ . " is not supported for this file\n");
         return TitleArray::newFromResult(new FakeResultWrapper([]));
     }
     /** @var LocalRepo $repo */
     $repo = $file->getRepo();
     $dbr = $repo->getSlaveDB();
     $res = $dbr->select(['page', 'categorylinks'], ['page_title' => 'cl_to', 'page_namespace' => NS_CATEGORY], ['page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey()], __METHOD__, [], ['categorylinks' => ['INNER JOIN', 'page_id = cl_from']]);
     return TitleArray::newFromResult($res);
 }
Example #5
0
 /**
  * Get the backlinks for a given table. Cached in process memory only.
  * @param string $table
  * @param int|bool $startId
  * @param int|bool $endId
  * @param int|INF $max
  * @return TitleArrayFromResult
  */
 public function getLinks($table, $startId = false, $endId = false, $max = INF)
 {
     return TitleArray::newFromResult($this->queryLinks($table, $startId, $endId, $max));
 }
Example #6
0
 function doSubmit()
 {
     global $wgOut, $wgUser, $wgMaximumMovedPages, $wgLang;
     global $wgFixDoubleRedirects;
     if ($wgUser->pingLimiter('move')) {
         $wgOut->rateLimited();
         return;
     }
     $ot = $this->oldTitle;
     $nt = $this->newTitle;
     # Delete to make way if requested
     if ($wgUser->isAllowed('delete') && $this->deleteAndMove) {
         $article = new Article($nt);
         # Disallow deletions of big articles
         $bigHistory = $article->isBigDeletion();
         if ($bigHistory && !$nt->userCan('bigdelete')) {
             global $wgDeleteRevisionsLimit;
             $this->showForm(array('delete-toobig', $wgLang->formatNum($wgDeleteRevisionsLimit)));
             return;
         }
         // Delete an associated image if there is
         $file = wfLocalFile($nt);
         if ($file->exists()) {
             $file->delete(wfMsgForContent('delete_and_move_reason'), false);
         }
         // This may output an error message and exit
         $article->doDelete(wfMsgForContent('delete_and_move_reason'));
     }
     # don't allow moving to pages with # in
     if (!$nt || $nt->getFragment() != '') {
         $this->showForm('badtitletext');
         return;
     }
     # Show a warning if the target file exists on a shared repo
     if ($nt->getNamespace() == NS_FILE && !($this->moveOverShared && $wgUser->isAllowed('reupload-shared')) && !RepoGroup::singleton()->getLocalRepo()->findFile($nt) && wfFindFile($nt)) {
         $this->showForm(array('file-exists-sharedrepo'));
         return;
     }
     if ($wgUser->isAllowed('suppressredirect')) {
         $createRedirect = $this->leaveRedirect;
     } else {
         $createRedirect = true;
     }
     # Do the actual move.
     $error = $ot->moveTo($nt, true, $this->reason, $createRedirect);
     if ($error !== true) {
         # @todo FIXME: Show all the errors in a list, not just the first one
         $this->showForm(reset($error));
         return;
     }
     if ($wgFixDoubleRedirects && $this->fixRedirects) {
         DoubleRedirectJob::fixRedirects('move', $ot, $nt);
     }
     wfRunHooks('SpecialMovepageAfterMove', array(&$this, &$ot, &$nt));
     $wgOut->setPagetitle(wfMsg('pagemovedsub'));
     $oldUrl = $ot->getFullUrl('redirect=no');
     $newUrl = $nt->getFullUrl();
     $oldText = $ot->getPrefixedText();
     $newText = $nt->getPrefixedText();
     $oldLink = "<span class='plainlinks'>[{$oldUrl} {$oldText}]</span>";
     $newLink = "<span class='plainlinks'>[{$newUrl} {$newText}]</span>";
     $msgName = $createRedirect ? 'movepage-moved-redirect' : 'movepage-moved-noredirect';
     $wgOut->addWikiMsg('movepage-moved', $oldLink, $newLink, $oldText, $newText);
     $wgOut->addWikiMsg($msgName);
     # Now we move extra pages we've been asked to move: subpages and talk
     # pages.  First, if the old page or the new page is a talk page, we
     # can't move any talk pages: cancel that.
     if ($ot->isTalkPage() || $nt->isTalkPage()) {
         $this->moveTalk = false;
     }
     if (!$ot->userCan('move-subpages')) {
         $this->moveSubpages = false;
     }
     # Next make a list of id's.  This might be marginally less efficient
     # than a more direct method, but this is not a highly performance-cri-
     # tical code path and readable code is more important here.
     #
     # Note: this query works nicely on MySQL 5, but the optimizer in MySQL
     # 4 might get confused.  If so, consider rewriting as a UNION.
     #
     # If the target namespace doesn't allow subpages, moving with subpages
     # would mean that you couldn't move them back in one operation, which
     # is bad.
     # @todo FIXME: A specific error message should be given in this case.
     // @todo FIXME: Use Title::moveSubpages() here
     $dbr = wfGetDB(DB_MASTER);
     if ($this->moveSubpages && (MWNamespace::hasSubpages($nt->getNamespace()) || $this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace()))) {
         $conds = array('page_title' . $dbr->buildLike($ot->getDBkey() . '/', $dbr->anyString()) . ' OR page_title = ' . $dbr->addQuotes($ot->getDBkey()));
         $conds['page_namespace'] = array();
         if (MWNamespace::hasSubpages($nt->getNamespace())) {
             $conds['page_namespace'][] = $ot->getNamespace();
         }
         if ($this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace())) {
             $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace();
         }
     } elseif ($this->moveTalk) {
         $conds = array('page_namespace' => $ot->getTalkPage()->getNamespace(), 'page_title' => $ot->getDBkey());
     } else {
         # Skip the query
         $conds = null;
     }
     $extraPages = array();
     if (!is_null($conds)) {
         $extraPages = TitleArray::newFromResult($dbr->select('page', array('page_id', 'page_namespace', 'page_title'), $conds, __METHOD__));
     }
     $extraOutput = array();
     $skin = $this->getSkin();
     $count = 1;
     foreach ($extraPages as $oldSubpage) {
         if ($ot->equals($oldSubpage)) {
             # Already did this one.
             continue;
         }
         $newPageName = preg_replace('#^' . preg_quote($ot->getDBkey(), '#') . '#', StringUtils::escapeRegexReplacement($nt->getDBkey()), $oldSubpage->getDBkey());
         if ($oldSubpage->isTalkPage()) {
             $newNs = $nt->getTalkPage()->getNamespace();
         } else {
             $newNs = $nt->getSubjectPage()->getNamespace();
         }
         # Bug 14385: we need makeTitleSafe because the new page names may
         # be longer than 255 characters.
         $newSubpage = Title::makeTitleSafe($newNs, $newPageName);
         if (!$newSubpage) {
             $oldLink = $skin->linkKnown($oldSubpage);
             $extraOutput[] = wfMsgHtml('movepage-page-unmoved', $oldLink, htmlspecialchars(Title::makeName($newNs, $newPageName)));
             continue;
         }
         # This was copy-pasted from Renameuser, bleh.
         if ($newSubpage->exists() && !$oldSubpage->isValidMoveTarget($newSubpage)) {
             $link = $skin->linkKnown($newSubpage);
             $extraOutput[] = wfMsgHtml('movepage-page-exists', $link);
         } else {
             $success = $oldSubpage->moveTo($newSubpage, true, $this->reason, $createRedirect);
             if ($success === true) {
                 if ($this->fixRedirects) {
                     DoubleRedirectJob::fixRedirects('move', $oldSubpage, $newSubpage);
                 }
                 $oldLink = $skin->linkKnown($oldSubpage, null, array(), array('redirect' => 'no'));
                 $newLink = $skin->linkKnown($newSubpage);
                 $extraOutput[] = wfMsgHtml('movepage-page-moved', $oldLink, $newLink);
                 ++$count;
                 if ($count >= $wgMaximumMovedPages) {
                     $extraOutput[] = wfMsgExt('movepage-max-pages', array('parsemag', 'escape'), $wgLang->formatNum($wgMaximumMovedPages));
                     break;
                 }
             } else {
                 $oldLink = $skin->linkKnown($oldSubpage);
                 $newLink = $skin->link($newSubpage);
                 $extraOutput[] = wfMsgHtml('movepage-page-unmoved', $oldLink, $newLink);
             }
         }
     }
     if ($extraOutput !== array()) {
         $wgOut->addHTML("<ul>\n<li>" . implode("</li>\n<li>", $extraOutput) . "</li>\n</ul>");
     }
     # Deal with watches (we don't watch subpages)
     if ($this->watch && $wgUser->isLoggedIn()) {
         $wgUser->addWatch($ot);
         $wgUser->addWatch($nt);
     } else {
         $wgUser->removeWatch($ot);
         $wgUser->removeWatch($nt);
     }
     # Re-clear the file redirect cache, which may have been polluted by
     # parsing in messages above. See CR r56745.
     # @todo FIXME: Needs a more robust solution inside FileRepo.
     if ($ot->getNamespace() == NS_FILE) {
         RepoGroup::singleton()->getLocalRepo()->invalidateImageRedirect($ot);
     }
 }
Example #7
0
 function doSubmit()
 {
     $user = $this->getUser();
     if ($user->pingLimiter('move')) {
         throw new ThrottledError();
     }
     $ot = $this->oldTitle;
     $nt = $this->newTitle;
     # don't allow moving to pages with # in
     if (!$nt || $nt->hasFragment()) {
         $this->showForm(array(array('badtitletext')));
         return;
     }
     # Show a warning if the target file exists on a shared repo
     if ($nt->getNamespace() == NS_FILE && !($this->moveOverShared && $user->isAllowed('reupload-shared')) && !RepoGroup::singleton()->getLocalRepo()->findFile($nt) && wfFindFile($nt)) {
         $this->showForm(array(array('file-exists-sharedrepo')));
         return;
     }
     # Delete to make way if requested
     if ($this->deleteAndMove) {
         $permErrors = $nt->getUserPermissionsErrors('delete', $user);
         if (count($permErrors)) {
             # Only show the first error
             $this->showForm($permErrors);
             return;
         }
         $reason = $this->msg('delete_and_move_reason', $ot)->inContentLanguage()->text();
         // Delete an associated image if there is
         if ($nt->getNamespace() == NS_FILE) {
             $file = wfLocalFile($nt);
             $file->load(File::READ_LATEST);
             if ($file->exists()) {
                 $file->delete($reason, false, $user);
             }
         }
         $error = '';
         // passed by ref
         $page = WikiPage::factory($nt);
         $deleteStatus = $page->doDeleteArticleReal($reason, false, 0, true, $error, $user);
         if (!$deleteStatus->isGood()) {
             $this->showForm($deleteStatus->getErrorsArray());
             return;
         }
     }
     $handler = ContentHandler::getForTitle($ot);
     if (!$handler->supportsRedirects()) {
         $createRedirect = false;
     } elseif ($user->isAllowed('suppressredirect')) {
         $createRedirect = $this->leaveRedirect;
     } else {
         $createRedirect = true;
     }
     # Do the actual move.
     $mp = new MovePage($ot, $nt);
     $valid = $mp->isValidMove();
     if (!$valid->isOK()) {
         $this->showForm($valid->getErrorsArray());
         return;
     }
     $permStatus = $mp->checkPermissions($user, $this->reason);
     if (!$permStatus->isOK()) {
         $this->showForm($permStatus->getErrorsArray());
         return;
     }
     $status = $mp->move($user, $this->reason, $createRedirect);
     if (!$status->isOK()) {
         $this->showForm($status->getErrorsArray());
         return;
     }
     if ($this->getConfig()->get('FixDoubleRedirects') && $this->fixRedirects) {
         DoubleRedirectJob::fixRedirects('move', $ot, $nt);
     }
     $out = $this->getOutput();
     $out->setPageTitle($this->msg('pagemovedsub'));
     $oldLink = Linker::link($ot, null, array('id' => 'movepage-oldlink'), array('redirect' => 'no'));
     $newLink = Linker::linkKnown($nt, null, array('id' => 'movepage-newlink'));
     $oldText = $ot->getPrefixedText();
     $newText = $nt->getPrefixedText();
     if ($ot->exists()) {
         // NOTE: we assume that if the old title exists, it's because it was re-created as
         // a redirect to the new title. This is not safe, but what we did before was
         // even worse: we just determined whether a redirect should have been created,
         // and reported that it was created if it should have, without any checks.
         // Also note that isRedirect() is unreliable because of bug 37209.
         $msgName = 'movepage-moved-redirect';
     } else {
         $msgName = 'movepage-moved-noredirect';
     }
     $out->addHTML($this->msg('movepage-moved')->rawParams($oldLink, $newLink)->params($oldText, $newText)->parseAsBlock());
     $out->addWikiMsg($msgName);
     Hooks::run('SpecialMovepageAfterMove', array(&$this, &$ot, &$nt));
     # Now we move extra pages we've been asked to move: subpages and talk
     # pages.  First, if the old page or the new page is a talk page, we
     # can't move any talk pages: cancel that.
     if ($ot->isTalkPage() || $nt->isTalkPage()) {
         $this->moveTalk = false;
     }
     if (count($ot->getUserPermissionsErrors('move-subpages', $user))) {
         $this->moveSubpages = false;
     }
     # Next make a list of id's.  This might be marginally less efficient
     # than a more direct method, but this is not a highly performance-cri-
     # tical code path and readable code is more important here.
     #
     # Note: this query works nicely on MySQL 5, but the optimizer in MySQL
     # 4 might get confused.  If so, consider rewriting as a UNION.
     #
     # If the target namespace doesn't allow subpages, moving with subpages
     # would mean that you couldn't move them back in one operation, which
     # is bad.
     # @todo FIXME: A specific error message should be given in this case.
     // @todo FIXME: Use Title::moveSubpages() here
     $dbr = wfGetDB(DB_MASTER);
     if ($this->moveSubpages && (MWNamespace::hasSubpages($nt->getNamespace()) || $this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace()))) {
         $conds = array('page_title' . $dbr->buildLike($ot->getDBkey() . '/', $dbr->anyString()) . ' OR page_title = ' . $dbr->addQuotes($ot->getDBkey()));
         $conds['page_namespace'] = array();
         if (MWNamespace::hasSubpages($nt->getNamespace())) {
             $conds['page_namespace'][] = $ot->getNamespace();
         }
         if ($this->moveTalk && MWNamespace::hasSubpages($nt->getTalkPage()->getNamespace())) {
             $conds['page_namespace'][] = $ot->getTalkPage()->getNamespace();
         }
     } elseif ($this->moveTalk) {
         $conds = array('page_namespace' => $ot->getTalkPage()->getNamespace(), 'page_title' => $ot->getDBkey());
     } else {
         # Skip the query
         $conds = null;
     }
     $extraPages = array();
     if (!is_null($conds)) {
         $extraPages = TitleArray::newFromResult($dbr->select('page', array('page_id', 'page_namespace', 'page_title'), $conds, __METHOD__));
     }
     $extraOutput = array();
     $count = 1;
     foreach ($extraPages as $oldSubpage) {
         if ($ot->equals($oldSubpage) || $nt->equals($oldSubpage)) {
             # Already did this one.
             continue;
         }
         $newPageName = preg_replace('#^' . preg_quote($ot->getDBkey(), '#') . '#', StringUtils::escapeRegexReplacement($nt->getDBkey()), $oldSubpage->getDBkey());
         if ($oldSubpage->isSubpage() && ($ot->isTalkPage() xor $nt->isTalkPage())) {
             // Moving a subpage from a subject namespace to a talk namespace or vice-versa
             $newNs = $nt->getNamespace();
         } elseif ($oldSubpage->isTalkPage()) {
             $newNs = $nt->getTalkPage()->getNamespace();
         } else {
             $newNs = $nt->getSubjectPage()->getNamespace();
         }
         # Bug 14385: we need makeTitleSafe because the new page names may
         # be longer than 255 characters.
         $newSubpage = Title::makeTitleSafe($newNs, $newPageName);
         if (!$newSubpage) {
             $oldLink = Linker::linkKnown($oldSubpage);
             $extraOutput[] = $this->msg('movepage-page-unmoved')->rawParams($oldLink)->params(Title::makeName($newNs, $newPageName))->escaped();
             continue;
         }
         # This was copy-pasted from Renameuser, bleh.
         if ($newSubpage->exists() && !$oldSubpage->isValidMoveTarget($newSubpage)) {
             $link = Linker::linkKnown($newSubpage);
             $extraOutput[] = $this->msg('movepage-page-exists')->rawParams($link)->escaped();
         } else {
             $success = $oldSubpage->moveTo($newSubpage, true, $this->reason, $createRedirect);
             if ($success === true) {
                 if ($this->fixRedirects) {
                     DoubleRedirectJob::fixRedirects('move', $oldSubpage, $newSubpage);
                 }
                 $oldLink = Linker::link($oldSubpage, null, array(), array('redirect' => 'no'));
                 $newLink = Linker::linkKnown($newSubpage);
                 $extraOutput[] = $this->msg('movepage-page-moved')->rawParams($oldLink, $newLink)->escaped();
                 ++$count;
                 $maximumMovedPages = $this->getConfig()->get('MaximumMovedPages');
                 if ($count >= $maximumMovedPages) {
                     $extraOutput[] = $this->msg('movepage-max-pages')->numParams($maximumMovedPages)->escaped();
                     break;
                 }
             } else {
                 $oldLink = Linker::linkKnown($oldSubpage);
                 $newLink = Linker::link($newSubpage);
                 $extraOutput[] = $this->msg('movepage-page-unmoved')->rawParams($oldLink, $newLink)->escaped();
             }
         }
     }
     if ($extraOutput !== array()) {
         $out->addHTML("<ul>\n<li>" . implode("</li>\n<li>", $extraOutput) . "</li>\n</ul>");
     }
     # Deal with watches (we don't watch subpages)
     WatchAction::doWatchOrUnwatch($this->watch, $ot, $user);
     WatchAction::doWatchOrUnwatch($this->watch, $nt, $user);
 }
	public function getTranslationPages() {
		// Fetch the available translation pages from database
		$dbr = wfGetDB( DB_SLAVE );
		$prefix = $this->getTitle()->getDBkey() . '/';
		$likePattern = $dbr->buildLike( $prefix, $dbr->anyString() );
		$res = $dbr->select(
			'page',
			array( 'page_namespace', 'page_title' ),
			array(
				'page_namespace' => $this->getTitle()->getNamespace(),
				"page_title $likePattern"
			),
			__METHOD__
		);

		$titles = TitleArray::newFromResult( $res );
		$filtered = array();

		// Make sure we only get translation subpages while ignoring others
		$codes = Language::getLanguageNames( false );
		$prefix = $this->getTitle()->getText();
		foreach ( $titles as $title ) {
			list( $name, $code ) = TranslateUtils::figureMessage( $title->getText() );
			if ( !isset( $codes[$code] ) || $name !== $prefix ) {
				continue;
			}
			$filtered[] = $title;
		}

		return $filtered;
	}
Example #9
0
 /**
  * @param array $pages Map of (page ID => (namespace, DB key)) entries
  */
 protected function invalidateTitles(array $pages)
 {
     global $wgUpdateRowsPerQuery, $wgUseFileCache;
     // Get all page IDs in this query into an array
     $pageIds = array_keys($pages);
     if (!$pageIds) {
         return;
     }
     // The page_touched field will need to be bumped for these pages.
     // Only bump it to the present time if no "rootJobTimestamp" was known.
     // If it is known, it can be used instead, which avoids invalidating output
     // that was in fact generated *after* the relevant dependency change time
     // (e.g. template edit). This is particularily useful since refreshLinks jobs
     // save back parser output and usually run along side htmlCacheUpdate jobs;
     // their saved output would be invalidated by using the current timestamp.
     if (isset($this->params['rootJobTimestamp'])) {
         $touchTimestamp = $this->params['rootJobTimestamp'];
     } else {
         $touchTimestamp = wfTimestampNow();
     }
     $dbw = wfGetDB(DB_MASTER);
     // Update page_touched (skipping pages already touched since the root job).
     // Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
     foreach (array_chunk($pageIds, $wgUpdateRowsPerQuery) as $batch) {
         $dbw->commit(__METHOD__, 'flush');
         wfWaitForSlaves();
         $dbw->update('page', array('page_touched' => $dbw->timestamp($touchTimestamp)), array('page_id' => $batch, "page_touched < " . $dbw->addQuotes($dbw->timestamp($touchTimestamp))), __METHOD__);
     }
     // Get the list of affected pages (races only mean something else did the purge)
     $titleArray = TitleArray::newFromResult($dbw->select('page', array('page_namespace', 'page_title'), array('page_id' => $pageIds, 'page_touched' => $dbw->timestamp($touchTimestamp)), __METHOD__));
     // Update squid
     $u = SquidUpdate::newFromTitles($titleArray);
     $u->doUpdate();
     // Update file cache
     if ($wgUseFileCache) {
         foreach ($titleArray as $title) {
             HTMLFileCache::clearFileCache($title);
         }
     }
 }
Example #10
0
 /**
  * Get a Title iterator for cascade-protected template/file use backlinks
  *
  * @return TitleArray
  * @since 1.25
  */
 public function getCascadeProtectedLinks()
 {
     $dbr = $this->getDB();
     // @todo: use UNION without breaking tests that use temp tables
     $resSets = array();
     $resSets[] = $dbr->select(array('templatelinks', 'page_restrictions', 'page'), array('page_namespace', 'page_title', 'page_id'), array('tl_namespace' => $this->title->getNamespace(), 'tl_title' => $this->title->getDBkey(), 'tl_from = pr_page', 'pr_cascade' => 1, 'page_id = tl_from'), __METHOD__, array('DISTINCT'));
     if ($this->title->getNamespace() == NS_FILE) {
         $resSets[] = $dbr->select(array('imagelinks', 'page_restrictions', 'page'), array('page_namespace', 'page_title', 'page_id'), array('il_to' => $this->title->getDBkey(), 'il_from = pr_page', 'pr_cascade' => 1, 'page_id = il_from'), __METHOD__, array('DISTINCT'));
     }
     // Combine and de-duplicate the results
     $mergedRes = array();
     foreach ($resSets as $res) {
         foreach ($res as $row) {
             $mergedRes[$row->page_id] = $row;
         }
     }
     return TitleArray::newFromResult(new FakeResultWrapper(array_values($mergedRes)));
 }
 /**
  * Fetch the available translation pages from database
  * @return Title[]
  */
 public function getTranslationPages()
 {
     // Avoid replication lag issues
     $dbr = wfGetDB(DB_MASTER);
     $prefix = $this->getTitle()->getDBkey() . '/';
     $likePattern = $dbr->buildLike($prefix, $dbr->anyString());
     $res = $dbr->select('page', array('page_namespace', 'page_title'), array('page_namespace' => $this->getTitle()->getNamespace(), "page_title {$likePattern}"), __METHOD__);
     $titles = TitleArray::newFromResult($res);
     $filtered = array();
     // Make sure we only get translation subpages while ignoring others
     $codes = Language::fetchLanguageNames();
     $prefix = $this->getTitle()->getText();
     /** @var Title $title */
     foreach ($titles as $title) {
         list($name, $code) = TranslateUtils::figureMessage($title->getText());
         if (!isset($codes[$code]) || $name !== $prefix) {
             continue;
         }
         $filtered[] = $title;
     }
     return $filtered;
 }
Example #12
0
 /**
  * @param array $pages Map of (page ID => (namespace, DB key)) entries
  */
 protected function invalidateTitles(array $pages)
 {
     global $wgUpdateRowsPerQuery, $wgUseFileCache;
     // Get all page IDs in this query into an array
     $pageIds = array_keys($pages);
     if (!$pageIds) {
         return;
     }
     // Bump page_touched to the current timestamp. This used to use the root job timestamp
     // (e.g. template/file edit time), which was a bit more efficient when template edits are
     // rare and don't effect the same pages much. However, this way allows for better
     // de-duplication, which is much more useful for wikis with high edit rates. Note that
     // RefreshLinksJob, which is enqueued alongside HTMLCacheUpdateJob, saves the parser output
     // since it has to parse anyway. We assume that vast majority of the cache jobs finish
     // before the link jobs, so using the current timestamp instead of the root timestamp is
     // not expected to invalidate these cache entries too often.
     $touchTimestamp = wfTimestampNow();
     $dbw = wfGetDB(DB_MASTER);
     $factory = wfGetLBFactory();
     $ticket = $factory->getEmptyTransactionTicket(__METHOD__);
     // Update page_touched (skipping pages already touched since the root job).
     // Check $wgUpdateRowsPerQuery for sanity; batch jobs are sized by that already.
     foreach (array_chunk($pageIds, $wgUpdateRowsPerQuery) as $batch) {
         $factory->commitAndWaitForReplication(__METHOD__, $ticket);
         $dbw->update('page', ['page_touched' => $dbw->timestamp($touchTimestamp)], ['page_id' => $batch, "page_touched < " . $dbw->addQuotes($dbw->timestamp($touchTimestamp))], __METHOD__);
     }
     // Get the list of affected pages (races only mean something else did the purge)
     $titleArray = TitleArray::newFromResult($dbw->select('page', ['page_namespace', 'page_title'], ['page_id' => $pageIds, 'page_touched' => $dbw->timestamp($touchTimestamp)], __METHOD__));
     // Update CDN
     $u = CdnCacheUpdate::newFromTitles($titleArray);
     $u->doUpdate();
     // Update file cache
     if ($wgUseFileCache) {
         foreach ($titleArray as $title) {
             HTMLFileCache::clearFileCache($title);
         }
     }
 }
Example #13
0
 /**
  * Unless overridden by PrefixSearchBackend hook...
  * This is case-sensitive (First character may
  * be automatically capitalized by Title::secureAndSpit()
  * later on depending on $wgCapitalLinks)
  *
  * @param array|null $namespaces Namespaces to search in
  * @param string $search Term
  * @param int $limit Max number of items to return
  * @param int $offset Number of items to skip
  * @return Title[] Array of Title objects
  */
 public function defaultSearchBackend($namespaces, $search, $limit, $offset)
 {
     // Backwards compatability with old code. Default to NS_MAIN if no namespaces provided.
     if ($namespaces === null) {
         $namespaces = [];
     }
     if (!$namespaces) {
         $namespaces[] = NS_MAIN;
     }
     // Construct suitable prefix for each namespace. They differ in cases where
     // some namespaces always capitalize and some don't.
     $prefixes = [];
     foreach ($namespaces as $namespace) {
         // For now, if special is included, ignore the other namespaces
         if ($namespace == NS_SPECIAL) {
             return $this->specialSearch($search, $limit, $offset);
         }
         $title = Title::makeTitleSafe($namespace, $search);
         // Why does the prefix default to empty?
         $prefix = $title ? $title->getDBkey() : '';
         $prefixes[$prefix][] = $namespace;
     }
     $dbr = wfGetDB(DB_REPLICA);
     // Often there is only one prefix that applies to all requested namespaces,
     // but sometimes there are two if some namespaces do not always capitalize.
     $conds = [];
     foreach ($prefixes as $prefix => $namespaces) {
         $condition = ['page_namespace' => $namespaces, 'page_title' . $dbr->buildLike($prefix, $dbr->anyString())];
         $conds[] = $dbr->makeList($condition, LIST_AND);
     }
     $table = 'page';
     $fields = ['page_id', 'page_namespace', 'page_title'];
     $conds = $dbr->makeList($conds, LIST_OR);
     $options = ['LIMIT' => $limit, 'ORDER BY' => ['page_title', 'page_namespace'], 'OFFSET' => $offset];
     $res = $dbr->select($table, $fields, $conds, __METHOD__, $options);
     return iterator_to_array(TitleArray::newFromResult($res));
 }
Example #14
0
 /**
  * Get all subpages of this page.
  *
  * @param int $limit Maximum number of subpages to fetch; -1 for no limit
  * @return TitleArray|array TitleArray, or empty array if this page's namespace
  *  doesn't allow subpages
  */
 public function getSubpages($limit = -1)
 {
     if (!MWNamespace::hasSubpages($this->getNamespace())) {
         return array();
     }
     $dbr = wfGetDB(DB_SLAVE);
     $conds['page_namespace'] = $this->getNamespace();
     $conds[] = 'page_title ' . $dbr->buildLike($this->getDBkey() . '/', $dbr->anyString());
     $options = array();
     if ($limit > -1) {
         $options['LIMIT'] = $limit;
     }
     $this->mSubpages = TitleArray::newFromResult($dbr->select('page', array('page_id', 'page_namespace', 'page_title', 'page_is_redirect'), $conds, __METHOD__, $options));
     return $this->mSubpages;
 }
	/**
	 * Returns all section pages, including those which are currently not active.
	 * @return TitleArray.
	 */
	protected function getSectionPages() {
		if ( !isset( $this->sectionPages ) ) {
			$base = $this->page->getTitle()->getPrefixedDBKey();

			$dbw = wfGetDB( DB_MASTER );
			if ( $this->singleLanguage() ) {
				$like = $dbw->buildLike( "$base/", $dbw->anyString(), "/{$this->code}" );
			} else {
				$like = $dbw->buildLike( "$base/", $dbw->anyString() );
			}

			$fields = array( 'page_namespace', 'page_title' );
			$titleCond = 'page_title ' . $like;
			$conds = array( 'page_namespace' => NS_TRANSLATIONS, $titleCond );
			$result = $dbw->select( 'page', $fields, $conds, __METHOD__ );
			$this->sectionPages = TitleArray::newFromResult( $result );
		}
		return $this->sectionPages;
	}
Example #16
0
	/**
	 * Returns a list of categories this page is a member of.
	 * Results will include hidden categories
	 *
	 * @return TitleArray
	 */
	public function getCategories() {
		$id = $this->getId();
		if ( $id == 0 ) {
			return TitleArray::newFromResult( new FakeResultWrapper( array() ) );
		}

		$dbr = wfGetDB( DB_SLAVE );
		$res = $dbr->select( 'categorylinks',
			array( 'cl_to AS page_title, ' . NS_CATEGORY . ' AS page_namespace' ),
			// Have to do that since DatabaseBase::fieldNamesWithAlias treats numeric indexes
			// as not being aliases, and NS_CATEGORY is numeric
			array( 'cl_from' => $id ),
			__METHOD__ );

		return TitleArray::newFromResult( $res );
	}
	/**
	 * Returns a title iterator with all the subpages of the base page
	 * for the provided title. This will include the provided title itself,
	 * unless the provided title is a base page.
	 * 
	 * @since 0.3
	 * 
	 * @param string $baseTitle
	 * @param integer $ns
	 * 
	 * @return TitleArray
	 */
	protected static function getBaseSubPages( $baseTitle, $ns ) {
		$dbr = wfGetDB( DB_SLAVE );
		
		$titleArray = TitleArray::newFromResult(
			$dbr->select( 'page',
				array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ),
				array(
					'page_namespace' => $ns, 
					'page_title' => $dbr->buildLike( $baseTitle . '/', $dbr->anyString() )
				),
				__METHOD__,
				array( 'LIMIT' => 500 )
			)
		);
		
		return $titleArray;
	}