/** * Return a clause with the list of disambiguation templates. * This function was copied verbatim from specials/SpecialDisambiguations.php */ function disambiguation_templates( $dbr ) { $dMsgText = wfMsgForContent('disambiguationspage'); $linkBatch = new LinkBatch; # If the text can be treated as a title, use it verbatim. # Otherwise, pull the titles from the links table $dp = Title::newFromText($dMsgText); if( $dp ) { if($dp->getNamespace() != NS_TEMPLATE) { # FIXME we assume the disambiguation message is a template but # the page can potentially be from another namespace :/ wfDebug("Mediawiki:disambiguationspage message does not refer to a template!\n"); } $linkBatch->addObj( $dp ); } else { # Get all the templates linked from the Mediawiki:Disambiguationspage $disPageObj = Title::makeTitleSafe( NS_MEDIAWIKI, 'disambiguationspage' ); $res = $dbr->select( array('pagelinks', 'page'), 'pl_title', array('page_id = pl_from', 'pl_namespace' => NS_TEMPLATE, 'page_namespace' => $disPageObj->getNamespace(), 'page_title' => $disPageObj->getDBkey()), __METHOD__ ); foreach ( $res as $row ) { $linkBatch->addObj( Title::makeTitle( NS_TEMPLATE, $row->pl_title )); } } return $linkBatch->constructSet( 'tl', $dbr ); }
function getQueryInfo() { $dbr = wfGetDB(DB_SLAVE); $dMsgText = wfMsgForContent('disambiguationspage'); $linkBatch = new LinkBatch(); # If the text can be treated as a title, use it verbatim. # Otherwise, pull the titles from the links table $dp = Title::newFromText($dMsgText); if ($dp) { if ($dp->getNamespace() != NS_TEMPLATE) { # @todo FIXME: We assume the disambiguation message is a template but # the page can potentially be from another namespace :/ wfDebug("Mediawiki:disambiguationspage message does not refer to a template!\n"); } $linkBatch->addObj($dp); } else { # Get all the templates linked from the Mediawiki:Disambiguationspage $disPageObj = Title::makeTitleSafe(NS_MEDIAWIKI, 'disambiguationspage'); $res = $dbr->select(array('pagelinks', 'page'), 'pl_title', array('page_id = pl_from', 'pl_namespace' => NS_TEMPLATE, 'page_namespace' => $disPageObj->getNamespace(), 'page_title' => $disPageObj->getDBkey()), __METHOD__); foreach ($res as $row) { $linkBatch->addObj(Title::makeTitle(NS_TEMPLATE, $row->pl_title)); } } $set = $linkBatch->constructSet('tl', $dbr); if ($set === false) { # We must always return a valid SQL query, but this way # the DB will always quickly return an empty result $set = 'FALSE'; wfDebug("Mediawiki:disambiguationspage message does not link to any templates!\n"); } // @todo FIXME: What are pagelinks and p2 doing here? return array('tables' => array('templatelinks', 'p1' => 'page', 'pagelinks', 'p2' => 'page'), 'fields' => array('p1.page_namespace AS namespace', 'p1.page_title AS title', 'pl_from AS value'), 'conds' => array($set, 'p1.page_id = tl_from', 'pl_namespace = p1.page_namespace', 'pl_title = p1.page_title', 'p2.page_id = pl_from', 'p2.page_namespace' => MWNamespace::getContentNamespaces())); }
function getSQL() { $dbr =& wfGetDB(DB_SLAVE); list($page, $pagelinks, $templatelinks) = $dbr->tableNamesN('page', 'pagelinks', 'templatelinks'); $dMsgText = wfMsgForContent('disambiguationspage'); $linkBatch = new LinkBatch(); # If the text can be treated as a title, use it verbatim. # Otherwise, pull the titles from the links table $dp = Title::newFromText($dMsgText); if ($dp) { if ($dp->getNamespace() != NS_TEMPLATE) { # FIXME we assume the disambiguation message is a template but # the page can potentially be from another namespace :/ wfDebug("Mediawiki:disambiguationspage message does not refer to a template!\n"); } $linkBatch->addObj($dp); } else { # Get all the templates linked from the Mediawiki:Disambiguationspage $disPageObj = $this->getDisambiguationPageObj(); $res = $dbr->select(array('pagelinks', 'page'), 'pl_title', array('page_id = pl_from', 'pl_namespace' => NS_TEMPLATE, 'page_namespace' => $disPageObj->getNamespace(), 'page_title' => $disPageObj->getDBkey()), 'DisambiguationsPage::getSQL'); while ($row = $dbr->fetchObject($res)) { $linkBatch->addObj(Title::makeTitle(NS_TEMPLATE, $row->pl_title)); } $dbr->freeResult($res); } $set = $linkBatch->constructSet('lb.tl', $dbr); if ($set === false) { $set = 'FALSE'; # We must always return a valid sql query, but this way DB will always quicly return an empty result wfDebug("Mediawiki:disambiguationspage message does not link to any templates!\n"); } $sql = "SELECT 'Disambiguations' AS \"type\", pb.page_namespace AS namespace," . " pb.page_title AS title, la.pl_from AS value" . " FROM {$templatelinks} AS lb, {$page} AS pb, {$pagelinks} AS la, {$page} AS pa" . " WHERE {$set}" . ' AND pa.page_id = la.pl_from' . ' AND pa.page_namespace = ' . NS_MAIN . ' AND pb.page_id = lb.tl_from' . ' AND pb.page_namespace = la.pl_namespace' . ' AND pb.page_title = la.pl_title' . ' ORDER BY lb.tl_namespace, lb.tl_title'; return $sql; }
function preprocessResults(&$dbo, &$res) { # Do a batch existence check on the user and talk pages $linkBatch = new LinkBatch(); while ($row = $dbo->fetchObject($res)) { $linkBatch->addObj(Title::makeTitleSafe(NS_USER, $row->user_text)); $linkBatch->addObj(Title::makeTitleSafe(NS_USER_TALK, $row->user_text)); } $linkBatch->execute(); # Seek to start if ($dbo->numRows($res) > 0) { $dbo->dataSeek($res, 0); } }
/** * Main execution point * * @param string $subpage */ public function execute($subpage) { $this->rcSubpage = $subpage; $this->setHeaders(); $this->outputHeader(); $this->addModules(); $rows = $this->getRows(); $opts = $this->getOptions(); if ($rows === false) { if (!$this->including()) { $this->doHeader($opts, 0); $this->getOutput()->setStatusCode(404); } return; } $batch = new LinkBatch(); foreach ($rows as $row) { $batch->add(NS_USER, $row->rc_user_text); $batch->add(NS_USER_TALK, $row->rc_user_text); $batch->add($row->rc_namespace, $row->rc_title); if ($row->rc_source === RecentChange::SRC_LOG) { $formatter = LogFormatter::newFromRow($row); foreach ($formatter->getPreloadTitles() as $title) { $batch->addObj($title); } } } $batch->execute(); $this->webOutput($rows, $opts); $rows->free(); }
protected function preprocessResults($results) { $names = array(); foreach ($results as $result) { $names[] = $result->utr_name; } if (!$names) { return; } $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('user', 'ipblocks'), User::selectFields(), array('user_name' => array_unique($names), 'ipb_deleted IS NULL OR ipb_deleted = 0'), __METHOD__, array(), array('ipblocks' => array('LEFT JOIN', 'user_id = ipb_user'))); $userArray = UserArray::newFromResult($res); $lb = new LinkBatch(); foreach ($userArray as $user) { $this->users[$user->getName()] = $user; $lb->addObj($user->getUserPage()); $lb->addObj($user->getTalkPage()); } $lb->execute(); }
public function getBody() { $batch = new LinkBatch(); $this->mResult->rewind(); while ($row = $this->mResult->fetchObject()) { $batch->addObj(Title::makeTitleSafe(NS_CATEGORY, $row->cat_title)); } $batch->execute(); $this->mResult->rewind(); return parent::getBody(); }
/** * Pre-fill the link cache */ function preprocessResults(&$db, &$res) { if ($db->numRows($res) > 0) { $linkBatch = new LinkBatch(); while ($row = $db->fetchObject($res)) { $linkBatch->addObj(Title::makeTitleSafe($row->namespace, $row->title)); } $db->dataSeek($res, 0); $linkBatch->execute(); } }
public function getBody() { $batch = new LinkBatch(); $this->mResult->rewind(); foreach ($this->mResult as $row) { $batch->addObj(Title::makeTitleSafe(NS_CATEGORY, $row->cat_title)); } $batch->execute(); $this->mResult->rewind(); return parent::getBody(); }
/** * Pre-cache page existence to speed up link generation * * @param Database $dbr Database connection * @param int $res Result pointer */ public function preprocessResults($dbr, $res) { $batch = new LinkBatch(); while ($row = $dbr->fetchObject($res)) { $title = Title::makeTitleSafe($row->namespace, $row->title); $batch->addObj($title); } $batch->execute(); if ($dbr->numRows($res) > 0) { $dbr->dataSeek($res, 0); } }
/** * Fetch user page links and cache their existence */ function preprocessResults(&$db, &$res) { $batch = new LinkBatch(); while ($row = $db->fetchObject($res)) { $batch->addObj(Title::makeTitleSafe($row->namespace, $row->title)); } $batch->execute(); // Back to start for display if ($db->numRows($res) > 0) { // If there are no rows we get an error seeking. $db->dataSeek($res, 0); } }
function getStartBody() { # Do a link batch query $this->mResult->seek(0); $batch = new LinkBatch(); # Give some pointers to make (last) links $this->mForm->prevId = []; foreach ($this->mResult as $row) { $batch->addObj(Title::makeTitleSafe(NS_USER, $row->user_name)); $batch->addObj(Title::makeTitleSafe(NS_USER_TALK, $row->user_name)); $rev_id = isset($rev_id) ? $rev_id : $row->rev_id; if ($rev_id > $row->rev_id) { $this->mForm->prevId[$rev_id] = $row->rev_id; } elseif ($rev_id < $row->rev_id) { $this->mForm->prevId[$row->rev_id] = $rev_id; } $rev_id = $row->rev_id; } $batch->execute(); $this->mResult->seek(0); return ''; }
function execute($par) { $this->setHeaders(); $this->outputHeader(); $this->getOutput()->allowClickjacking(); $this->getOutput()->addHTML(Html::openElement('table', ['class' => 'mw-datatable', 'id' => 'mw-trackingcategories-table']) . "\n" . "<thead><tr>\n\t\t\t<th>" . $this->msg('trackingcategories-msg')->escaped() . "\n\t\t\t</th>\n\t\t\t<th>" . $this->msg('trackingcategories-name')->escaped() . "</th>\n\t\t\t<th>" . $this->msg('trackingcategories-desc')->escaped() . "\n\t\t\t</th>\n\t\t\t</tr></thead>"); $trackingCategories = $this->prepareTrackingCategoriesData(); $batch = new LinkBatch(); foreach ($trackingCategories as $catMsg => $data) { $batch->addObj($data['msg']); foreach ($data['cats'] as $catTitle) { $batch->addObj($catTitle); } } $batch->execute(); foreach ($trackingCategories as $catMsg => $data) { $allMsgs = []; $catDesc = $catMsg . '-desc'; $catMsgTitleText = Linker::link($data['msg'], htmlspecialchars($catMsg)); foreach ($data['cats'] as $catTitle) { $catTitleText = Linker::link($catTitle, htmlspecialchars($catTitle->getText())); $allMsgs[] = $catTitleText; } # Extra message, when no category was found if (!count($allMsgs)) { $allMsgs[] = $this->msg('trackingcategories-disabled')->parse(); } /* * Show category description if it exists as a system message * as category-name-desc */ $descMsg = $this->msg($catDesc); if ($descMsg->isBlank()) { $descMsg = $this->msg('trackingcategories-nodesc'); } $this->getOutput()->addHTML(Html::openElement('tr') . Html::openElement('td', ['class' => 'mw-trackingcategories-name']) . $this->getLanguage()->commaList(array_unique($allMsgs)) . Html::closeElement('td') . Html::openElement('td', ['class' => 'mw-trackingcategories-msg']) . $catMsgTitleText . Html::closeElement('td') . Html::openElement('td', ['class' => 'mw-trackingcategories-desc']) . $descMsg->parse() . Html::closeElement('td') . Html::closeElement('tr')); } $this->getOutput()->addHTML(Html::closeElement('table')); }
/** * Cache page existence for performance * * @param IDatabase $db * @param ResultWrapper $res */ function preprocessResults($db, $res) { if (!$res->numRows()) { return; } $batch = new LinkBatch(); foreach ($res as $row) { $batch->add($row->namespace, $row->title); $batch->addObj($this->getRedirectTarget($row)); } $batch->execute(); // Back to start for display $res->seek(0); }
function getBody() { if (!$this->mQueryDone) { $this->doQuery(); } $batch = new LinkBatch(); $this->mResult->rewind(); while ($row = $this->mResult->fetchObject()) { $batch->addObj(Title::makeTitleSafe(NS_CATEGORY, $row->cl_to)); } $batch->execute(); $this->mResult->rewind(); return parent::getBody(); }
/** * Cache page existence for performance * * @param $db DatabaseBase * @param $res ResultWrapper */ function preprocessResults($db, $res) { $batch = new LinkBatch(); foreach ($res as $row) { $batch->add($row->namespace, $row->title); $batch->addObj($this->getRedirectTarget($row)); } $batch->execute(); // Back to start for display if ($db->numRows($res) > 0) { // If there are no rows we get an error seeking. $db->dataSeek($res, 0); } }
function preprocessResults(&$db, &$res) { # There's no point doing a batch check if we aren't caching results; # the page must exist for it to have been pulled out of the table if ($this->isCached()) { $batch = new LinkBatch(); while ($row = $db->fetchObject($res)) { $batch->addObj(Title::makeTitleSafe($row->namespace, $row->title)); } $batch->execute(); if ($db->numRows($res) > 0) { $db->dataSeek($res, 0); } } }
/** * Cache page existence for performance */ function preprocessResults(&$db, &$res) { global $wgUser; $batch = new LinkBatch(); while ($row = $db->fetchObject($res)) { # <jld> $ns = $row->pl_namespace; if (!$wgUser->isAllowedEx($ns, "~", "browse")) { continue; } #if (! $wgUser->isAllowed( hnpClass::buildPermissionKey($ns,"~","browse") )) continue; # </jld> $batch->addObj(Title::makeTitleSafe($row->namespace, $row->title)); } $batch->execute(); // Back to start for display if ($db->numRows($res) > 0) { // If there are no rows we get an error seeking. $db->dataSeek($res, 0); } }
/** * Make an HTML list of templates, and then add a "More..." link at * the bottom. If $more is null, do not add a "More..." link. If $more * is a LinkTarget, make a link to that title and use it. If $more is a string, * directly paste it in as the link (escaping needs to be done manually). * * @param LinkTarget[] $templates * @param string|bool $type 'preview' if a preview, 'section' if a section edit, false if neither * @param LinkTarget|string|null $more An escaped link for "More..." of the templates * @return string HTML output */ public function format(array $templates, $type = false, $more = null) { if (!$templates) { // No templates return ''; } # Do a batch existence check $batch = new LinkBatch(); foreach ($templates as $title) { $batch->addObj($title); } $batch->execute(); # Construct the HTML $outText = '<div class="mw-templatesUsedExplanation">'; $count = count($templates); if ($type === 'preview') { $outText .= $this->context->msg('templatesusedpreview')->numParams($count)->parseAsBlock(); } elseif ($type === 'section') { $outText .= $this->context->msg('templatesusedsection')->numParams($count)->parseAsBlock(); } else { $outText .= $this->context->msg('templatesused')->numParams($count)->parseAsBlock(); } $outText .= "</div><ul>\n"; usort($templates, 'Title::compare'); foreach ($templates as $template) { $outText .= $this->formatTemplate($template); } if ($more instanceof LinkTarget) { $outText .= Html::rawElement('li', [], $this->linkRenderer->makeLink($more, $this->context->msg('moredotdotdot')->text())); } elseif ($more) { // Documented as should already be escaped $outText .= Html::rawElement('li', [], $more); } $outText .= '</ul>'; return $outText; }
public function getStartBody() { # Do a link batch query if ($this->getNumRows() > 0) { $lb = new LinkBatch(); foreach ($this->mResult as $row) { $lb->add($row->log_namespace, $row->log_title); $lb->addObj(Title::makeTitleSafe(NS_USER, $row->user_name)); $lb->addObj(Title::makeTitleSafe(NS_USER_TALK, $row->user_name)); $formatter = LogFormatter::newFromRow($row); foreach ($formatter->getPreloadTitles() as $title) { $lb->addObj($title); } } $lb->execute(); $this->mResult->seek(0); } return ''; }
/** * If a language supports multiple variants, it is possible that * non-existing link in one variant actually exists in another variant. * This function tries to find it. See e.g. LanguageZh.php * The input parameters may be modified upon return * * @param string &$link The name of the link * @param Title &$nt The title object of the link * @param bool $ignoreOtherCond To disable other conditions when * we need to transclude a template or update a category's link */ public function findVariantLink(&$link, &$nt, $ignoreOtherCond = false) { # If the article has already existed, there is no need to # check it again, otherwise it may cause a fault. if (is_object($nt) && $nt->exists()) { return; } global $wgDisableLangConversion, $wgDisableTitleConversion, $wgRequest; $isredir = $wgRequest->getText('redirect', 'yes'); $action = $wgRequest->getText('action'); if ($action == 'edit' && $wgRequest->getBool('redlink')) { $action = 'view'; } $linkconvert = $wgRequest->getText('linkconvert', 'yes'); $disableLinkConversion = $wgDisableLangConversion || $wgDisableTitleConversion; $linkBatch = new LinkBatch(); $ns = NS_MAIN; if ($disableLinkConversion || !$ignoreOtherCond && ($isredir == 'no' || $action == 'edit' || $action == 'submit' || $linkconvert == 'no')) { return; } if (is_object($nt)) { $ns = $nt->getNamespace(); } $variants = $this->autoConvertToAllVariants($link); if (!$variants) { // give up return; } $titles = []; foreach ($variants as $v) { if ($v != $link) { $varnt = Title::newFromText($v, $ns); if (!is_null($varnt)) { $linkBatch->addObj($varnt); $titles[] = $varnt; } } } // fetch all variants in single query $linkBatch->execute(); foreach ($titles as $varnt) { if ($varnt->getArticleID() > 0) { $nt = $varnt; $link = $varnt->getText(); break; } } }
/** * Returns HTML for the "templates used on this page" list. * * @param $templates Array of templates from Article::getUsedTemplate * or similar * @param $preview Boolean: whether this is for a preview * @param $section Boolean: whether this is for a section edit * @return String: HTML output */ public static function formatTemplates($templates, $preview = false, $section = false) { wfProfileIn(__METHOD__); $outText = ''; if (count($templates) > 0) { # Do a batch existence check $batch = new LinkBatch(); foreach ($templates as $title) { $batch->addObj($title); } $batch->execute(); # Construct the HTML $outText = '<div class="mw-templatesUsedExplanation">'; if ($preview) { $outText .= wfMsgExt('templatesusedpreview', array('parse'), count($templates)); } elseif ($section) { $outText .= wfMsgExt('templatesusedsection', array('parse'), count($templates)); } else { $outText .= wfMsgExt('templatesused', array('parse'), count($templates)); } $outText .= "</div><ul>\n"; usort($templates, array('Title', 'compare')); foreach ($templates as $titleObj) { $r = $titleObj->getRestrictions('edit'); if (in_array('sysop', $r)) { $protected = wfMsgExt('template-protected', array('parseinline')); } elseif (in_array('autoconfirmed', $r)) { $protected = wfMsgExt('template-semiprotected', array('parseinline')); } else { $protected = ''; } if ($titleObj->quickUserCan('edit')) { $editLink = self::link($titleObj, wfMsg('editlink'), array(), array('action' => 'edit')); } else { $editLink = self::link($titleObj, wfMsg('viewsourcelink'), array(), array('action' => 'edit')); } $outText .= '<li>' . self::link($titleObj) . ' (' . $editLink . ') ' . $protected . '</li>'; } $outText .= '</ul>'; } wfProfileOut(__METHOD__); return $outText; }
static function bulkLoad($rows) { // Preload subthreads $top_thread_ids = array(); $all_thread_rows = $rows; $pageIds = array(); $linkBatch = new LinkBatch(); $userIds = array(); $loadEditorsFor = array(); $dbr = wfGetDB(DB_SLAVE); if (!is_array(self::$replyCacheById)) { self::$replyCacheById = array(); } // Build a list of threads for which to pull replies, and page IDs to pull data for. // Also, pre-initialise the reply cache. foreach ($rows as $row) { if ($row->thread_ancestor) { $top_thread_ids[] = $row->thread_ancestor; } else { $top_thread_ids[] = $row->thread_id; } // Grab page data while we're here. if ($row->thread_root) { $pageIds[] = $row->thread_root; } if ($row->thread_summary_page) { $pageIds[] = $row->thread_summary_page; } if (!isset(self::$replyCacheById[$row->thread_id])) { self::$replyCacheById[$row->thread_id] = array(); } } $all_thread_ids = $top_thread_ids; // Pull replies to the threads provided, and as above, pull page IDs to pull data for, // pre-initialise the reply cache, and stash the row object for later use. if (count($top_thread_ids)) { $res = $dbr->select('thread', '*', array('thread_ancestor' => $top_thread_ids, 'thread_type != ' . $dbr->addQuotes(Threads::TYPE_DELETED)), __METHOD__); foreach ($res as $row) { // Grab page data while we're here. if ($row->thread_root) { $pageIds[] = $row->thread_root; } if ($row->thread_summary_page) { $pageIds[] = $row->thread_summary_page; } $all_thread_rows[] = $row; $all_thread_ids[$row->thread_id] = $row->thread_id; } } // Pull thread reactions if (count($all_thread_ids)) { $res = $dbr->select('thread_reaction', '*', array('tr_thread' => $all_thread_ids), __METHOD__); foreach ($res as $row) { $thread_id = $row->tr_thread; $user = $row->tr_user_text; $info = array('type' => $row->tr_type, 'user-id' => $row->tr_user, 'user-name' => $row->tr_user_text, 'value' => $row->tr_value); $type = $info['type']; $user = $info['user-name']; if (!isset(self::$reactionCacheById[$thread_id])) { self::$reactionCacheById[$thread_id] = array(); } if (!isset(self::$reactionCacheById[$thread_id][$type])) { self::$reactionCacheById[$thread_id][$type] = array(); } self::$reactionCacheById[$thread_id][$type][$user] = $info; } } // Preload page data (restrictions, and preload Article object with everything from // the page table. Also, precache the title and article objects for pulling later. $articlesById = array(); if (count($pageIds)) { // Pull restriction info. Needs to come first because otherwise it's done per // page by loadPageData. $restrictionRows = array_fill_keys($pageIds, array()); $res = $dbr->select('page_restrictions', '*', array('pr_page' => $pageIds), __METHOD__); foreach ($res as $row) { $restrictionRows[$row->pr_page][] = $row; } $res = $dbr->select('page', '*', array('page_id' => $pageIds), __METHOD__); foreach ($res as $row) { $t = Title::newFromRow($row); if (isset($restrictionRows[$t->getArticleId()])) { $t->loadRestrictionsFromRows($restrictionRows[$t->getArticleId()], $row->page_restrictions); } $article = new Article($t); $article->loadPageData($row); self::$titleCacheById[$t->getArticleId()] = $t; $articlesById[$article->getId()] = $article; if (count(self::$titleCacheById) > 10000) { self::$titleCacheById = array(); } } } // For every thread we have a row object for, load a Thread object, add the user and // user talk pages to a link batch, cache the relevant user id/name pair, and // populate the reply cache. foreach ($all_thread_rows as $row) { $thread = Thread::newFromRow($row, null); if (isset($articlesById[$thread->rootId])) { $thread->root = $articlesById[$thread->rootId]; } // User cache data $t = Title::makeTitleSafe(NS_USER, $row->thread_author_name); $linkBatch->addObj($t); $t = Title::makeTitleSafe(NS_USER_TALK, $row->thread_author_name); $linkBatch->addObj($t); User::$idCacheByName[$row->thread_author_name] = $row->thread_author_id; $userIds[$row->thread_author_id] = true; if ($row->thread_editedness > Threads::EDITED_BY_AUTHOR) { $loadEditorsFor[$row->thread_root] = $thread; $thread->setEditors(array()); } } // Pull list of users who have edited if (count($loadEditorsFor)) { $res = $dbr->select('revision', array('rev_user_text', 'rev_page'), array('rev_page' => array_keys($loadEditorsFor), 'rev_parent_id != ' . $dbr->addQuotes(0)), __METHOD__); foreach ($res as $row) { $pageid = $row->rev_page; $editor = $row->rev_user_text; $t = $loadEditorsFor[$pageid]; $t->addEditor($editor); } } // Pull link batch data. $linkBatch->execute(); $threads = array(); // Fill and return an array with the threads that were actually requested. foreach ($rows as $row) { $threads[$row->thread_id] = Threads::$cache_by_id[$row->thread_id]; } return $threads; }
/** * Print out a list of linked titles * * $titles can be an array of strings or Title objects; the former * is preferred, since Titles are very memory-heavy * * @param $titles array of strings, or Title objects * @param $output String */ private function showTitles($titles, &$output) { $talk = $this->msg('talkpagelinktext')->escaped(); // Do a batch existence check $batch = new LinkBatch(); foreach ($titles as $title) { if (!$title instanceof Title) { $title = Title::newFromText($title); } if ($title instanceof Title) { $batch->addObj($title); $batch->addObj($title->getTalkPage()); } } $batch->execute(); // Print out the list $output .= "<ul>\n"; foreach ($titles as $title) { if (!$title instanceof Title) { $title = Title::newFromText($title); } if ($title instanceof Title) { $output .= "<li>" . Linker::link($title) . ' (' . Linker::link($title->getTalkPage(), $talk) . ")</li>\n"; } } $output .= "</ul>\n"; }
/** * 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]; }
/** * Return a HTML representation of the image gallery * * For each image in the gallery, display * - a thumbnail * - the image name * - the additional text provided when adding the image * - the size of the image * * @return string */ function toHTML() { if ($this->mPerRow > 0) { $maxwidth = $this->mPerRow * ($this->mWidths + $this->getAllPadding()); $oldStyle = isset($this->mAttribs['style']) ? $this->mAttribs['style'] : ''; # _width is ignored by any sane browser. IE6 doesn't know max-width # so it uses _width instead $this->mAttribs['style'] = "max-width: {$maxwidth}px;_width: {$maxwidth}px;" . $oldStyle; } $attribs = Sanitizer::mergeAttributes(['class' => 'gallery mw-gallery-' . $this->mMode], $this->mAttribs); $modules = $this->getModules(); if ($this->mParser) { $this->mParser->getOutput()->addModules($modules); $this->mParser->getOutput()->addModuleStyles('mediawiki.page.gallery.styles'); } else { $this->getOutput()->addModules($modules); $this->getOutput()->addModuleStyles('mediawiki.page.gallery.styles'); } $output = Xml::openElement('ul', $attribs); if ($this->mCaption) { $output .= "\n\t<li class='gallerycaption'>{$this->mCaption}</li>"; } if ($this->mShowFilename) { // Preload LinkCache info for when generating links // of the filename below $lb = new LinkBatch(); foreach ($this->mImages as $img) { $lb->addObj($img[0]); } $lb->execute(); } $lang = $this->getRenderLang(); # Output each image... foreach ($this->mImages as $pair) { /** @var Title $nt */ $nt = $pair[0]; $text = $pair[1]; # "text" means "caption" here $alt = $pair[2]; $link = $pair[3]; $descQuery = false; if ($nt->getNamespace() === NS_FILE) { # Get the file... if ($this->mParser instanceof Parser) { # Give extensions a chance to select the file revision for us $options = []; Hooks::run('BeforeParserFetchFileAndTitle', [$this->mParser, $nt, &$options, &$descQuery]); # Fetch and register the file (file title may be different via hooks) list($img, $nt) = $this->mParser->fetchFileAndTitle($nt, $options); } else { $img = wfFindFile($nt); } } else { $img = false; } $params = $this->getThumbParams($img); // $pair[4] is per image handler options $transformOptions = $params + $pair[4]; $thumb = false; if (!$img) { # We're dealing with a non-image, spit out the name and be done with it. $thumbhtml = "\n\t\t\t" . '<div class="thumb" style="height: ' . ($this->getThumbPadding() + $this->mHeights) . 'px;">' . htmlspecialchars($nt->getText()) . '</div>'; if ($this->mParser instanceof Parser) { $this->mParser->addTrackingCategory('broken-file-category'); } } elseif ($this->mHideBadImages && wfIsBadImage($nt->getDBkey(), $this->getContextTitle())) { # The image is blacklisted, just show it as a text link. $thumbhtml = "\n\t\t\t" . '<div class="thumb" style="height: ' . ($this->getThumbPadding() + $this->mHeights) . 'px;">' . Linker::linkKnown($nt, htmlspecialchars($nt->getText())) . '</div>'; } else { $thumb = $img->transform($transformOptions); if (!$thumb) { # Error generating thumbnail. $thumbhtml = "\n\t\t\t" . '<div class="thumb" style="height: ' . ($this->getThumbPadding() + $this->mHeights) . 'px;">' . htmlspecialchars($img->getLastError()) . '</div>'; } else { /** @var MediaTransformOutput $thumb */ $vpad = $this->getVPad($this->mHeights, $thumb->getHeight()); $imageParameters = ['desc-link' => true, 'desc-query' => $descQuery, 'alt' => $alt, 'custom-url-link' => $link]; // In the absence of both alt text and caption, fall back on // providing screen readers with the filename as alt text if ($alt == '' && $text == '') { $imageParameters['alt'] = $nt->getText(); } $this->adjustImageParameters($thumb, $imageParameters); Linker::processResponsiveImages($img, $thumb, $transformOptions); # Set both fixed width and min-height. $thumbhtml = "\n\t\t\t" . '<div class="thumb" style="width: ' . $this->getThumbDivWidth($thumb->getWidth()) . 'px;">' . '<div style="margin:' . $vpad . 'px auto;">' . $thumb->toHtml($imageParameters) . '</div></div>'; // Call parser transform hook /** @var MediaHandler $handler */ $handler = $img->getHandler(); if ($this->mParser && $handler) { $handler->parserTransformHook($this->mParser, $img); } } } // @todo Code is incomplete. // $linkTarget = Title::newFromText( $wgContLang->getNsText( MWNamespace::getUser() ) . // ":{$ut}" ); // $ul = Linker::link( $linkTarget, $ut ); if ($this->mShowBytes) { if ($img) { $fileSize = htmlspecialchars($lang->formatSize($img->getSize())); } else { $fileSize = $this->msg('filemissing')->escaped(); } $fileSize = "{$fileSize}<br />\n"; } else { $fileSize = ''; } $textlink = $this->mShowFilename ? Linker::linkKnown($nt, htmlspecialchars($lang->truncate($nt->getText(), $this->mCaptionLength))) . "<br />\n" : ''; $galleryText = $textlink . $text . $fileSize; $galleryText = $this->wrapGalleryText($galleryText, $thumb); # Weird double wrapping (the extra div inside the li) needed due to FF2 bug # Can be safely removed if FF2 falls completely out of existence $output .= "\n\t\t" . '<li class="gallerybox" style="width: ' . $this->getGBWidth($thumb) . 'px">' . '<div style="width: ' . $this->getGBWidth($thumb) . 'px">' . $thumbhtml . $galleryText . "\n\t\t</div></li>"; } $output .= "\n</ul>"; return $output; }
function wfPolyglotGetLanguages($title) { global $wgPolyglotLanguages; if (!$wgPolyglotLanguages) { return null; } $n = $title->getDBkey(); $ns = $title->getNamespace(); $titles = array(); $batch = new LinkBatch(); foreach ($wgPolyglotLanguages as $lang) { $obj = Title::makeTitle($ns, $n . '/' . $lang); $batch->addObj($obj); $titles[] = array($obj, $lang); } $batch->execute(); $links = array(); foreach ($titles as $parts) { list($t, $lang) = $parts; if ($t->exists()) { $links[$lang] = $t->getFullText(); } } return $links; }
/** * Print out a list of linked titles * * $titles can be an array of strings or Title objects; the former * is preferred, since Titles are very memory-heavy * * @param array $titles Array of strings, or Title objects * @param string $output */ private function showTitles($titles, &$output) { $talk = $this->msg('talkpagelinktext')->escaped(); // Do a batch existence check $batch = new LinkBatch(); if (count($titles) >= 100) { $output = $this->msg('watchlistedit-too-many')->parse(); return; } foreach ($titles as $title) { if (!$title instanceof Title) { $title = Title::newFromText($title); } if ($title instanceof Title) { $batch->addObj($title); $batch->addObj($title->getTalkPage()); } } $batch->execute(); // Print out the list $output .= "<ul>\n"; foreach ($titles as $title) { if (!$title instanceof Title) { $title = Title::newFromText($title); } if ($title instanceof Title) { $output .= '<li>' . Linker::link($title) . ' ' . $this->msg('parentheses')->rawParams(Linker::link($title->getTalkPage(), $talk))->escaped() . "</li>\n"; } } $output .= "</ul>\n"; }
/** * Constructor */ function wfSpecialRecentchanges($par, $specialPage) { global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; global $wgRCShowWatchingUsers, $wgShowUpdatedMarker; global $wgAllowCategorizedRecentChanges; $fname = 'wfSpecialRecentchanges'; # Get query parameters $feedFormat = $wgRequest->getVal('feed'); /* Checkbox values can't be true by default, because * we cannot differentiate between unset and not set at all */ $defaults = array('days' => $wgUser->getDefaultOption('rcdays'), 'limit' => $wgUser->getDefaultOption('rclimit'), 'hideminor' => false, 'hidebots' => true, 'hideanons' => false, 'hideliu' => false, 'hidepatrolled' => false, 'hidemyself' => false, 'from' => '', 'namespace' => null, 'invert' => false, 'categories_any' => false); extract($defaults); $days = $wgUser->getOption('rcdays', $defaults['days']); $days = $wgRequest->getInt('days', $days); $limit = $wgUser->getOption('rclimit', $defaults['limit']); # list( $limit, $offset ) = wfCheckLimits( 100, 'rclimit' ); $limit = $wgRequest->getInt('limit', $limit); /* order of selection: url > preferences > default */ $hideminor = $wgRequest->getBool('hideminor', $wgUser->getOption('hideminor') ? true : $defaults['hideminor']); # As a feed, use limited settings only if ($feedFormat) { global $wgFeedLimit; if ($limit > $wgFeedLimit) { $limit = $wgFeedLimit; } } else { $namespace = $wgRequest->getIntOrNull('namespace'); $invert = $wgRequest->getBool('invert', $defaults['invert']); $hidebots = $wgRequest->getBool('hidebots', $defaults['hidebots']); $hideanons = $wgRequest->getBool('hideanons', $defaults['hideanons']); $hideliu = $wgRequest->getBool('hideliu', $defaults['hideliu']); $hidepatrolled = $wgRequest->getBool('hidepatrolled', $defaults['hidepatrolled']); $hidemyself = $wgRequest->getBool('hidemyself', $defaults['hidemyself']); $from = $wgRequest->getVal('from', $defaults['from']); # Get query parameters from path if ($par) { $bits = preg_split('/\\s*,\\s*/', trim($par)); foreach ($bits as $bit) { if ('hidebots' == $bit) { $hidebots = 1; } if ('bots' == $bit) { $hidebots = 0; } if ('hideminor' == $bit) { $hideminor = 1; } if ('minor' == $bit) { $hideminor = 0; } if ('hideliu' == $bit) { $hideliu = 1; } if ('hidepatrolled' == $bit) { $hidepatrolled = 1; } if ('hideanons' == $bit) { $hideanons = 1; } if ('hidemyself' == $bit) { $hidemyself = 1; } if (is_numeric($bit)) { $limit = $bit; } $m = array(); if (preg_match('/^limit=(\\d+)$/', $bit, $m)) { $limit = $m[1]; } if (preg_match('/^days=(\\d+)$/', $bit, $m)) { $days = $m[1]; } } } } if ($limit < 0 || $limit > 5000) { $limit = $defaults['limit']; } # Database connection and caching $dbr = wfGetDB(DB_SLAVE); list($recentchanges, $watchlist) = $dbr->tableNamesN('recentchanges', 'watchlist'); $cutoff_unixtime = time() - $days * 86400; $cutoff_unixtime = $cutoff_unixtime - $cutoff_unixtime % 86400; $cutoff = $dbr->timestamp($cutoff_unixtime); if (preg_match('/^[0-9]{14}$/', $from) and $from > wfTimestamp(TS_MW, $cutoff)) { $cutoff = $dbr->timestamp($from); } else { $from = $defaults['from']; } # 10 seconds server-side caching max $wgOut->setSquidMaxage(10); # Get last modified date, for client caching # Don't use this if we are using the patrol feature, patrol changes don't update the timestamp $lastmod = $dbr->selectField('recentchanges', 'MAX(rc_timestamp)', false, $fname); if ($feedFormat || !$wgUseRCPatrol) { if ($lastmod && $wgOut->checkLastModified($lastmod)) { # Client cache fresh and headers sent, nothing more to do. return; } } # It makes no sense to hide both anons and logged-in users # Where this occurs, force anons to be shown if ($hideanons && $hideliu) { $hideanons = false; } # Form WHERE fragments for all the options $hidem = $hideminor ? 'AND rc_minor = 0' : ''; $hidem .= $hidebots ? ' AND rc_bot = 0' : ''; $hidem .= $hideliu ? ' AND rc_user = 0' : ''; $hidem .= $wgUseRCPatrol && $hidepatrolled ? ' AND rc_patrolled = 0' : ''; $hidem .= $hideanons ? ' AND rc_user != 0' : ''; if ($hidemyself) { if ($wgUser->getID()) { $hidem .= ' AND rc_user != ' . $wgUser->getID(); } else { $hidem .= ' AND rc_user_text != ' . $dbr->addQuotes($wgUser->getName()); } } # Namespace filtering $hidem .= is_null($namespace) ? '' : ' AND rc_namespace' . ($invert ? '!=' : '=') . $namespace; // This is the big thing! $uid = $wgUser->getID(); // Perform query $forceclause = $dbr->useIndexClause("rc_timestamp"); $sql2 = "SELECT * FROM {$recentchanges} {$forceclause}" . ($uid ? "LEFT OUTER JOIN {$watchlist} ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace " : "") . "WHERE rc_timestamp >= '{$cutoff}' {$hidem} " . "ORDER BY rc_timestamp DESC"; $sql2 = $dbr->limitResult($sql2, $limit, 0); $res = $dbr->query($sql2, $fname); // Fetch results, prepare a batch link existence check query $rows = array(); $batch = new LinkBatch(); while ($row = $dbr->fetchObject($res)) { $rows[] = $row; if (!$feedFormat) { // User page link $title = Title::makeTitleSafe(NS_USER, $row->rc_user_text); $batch->addObj($title); // User talk $title = Title::makeTitleSafe(NS_USER_TALK, $row->rc_user_text); $batch->addObj($title); } } $dbr->freeResult($res); if ($feedFormat) { rcOutputFeed($rows, $feedFormat, $limit, $hideminor, $lastmod); } else { # Web output... // Run existence checks $batch->execute(); $any = $wgRequest->getBool('categories_any', $defaults['categories_any']); // Output header if (!$specialPage->including()) { $wgOut->addWikiText(wfMsgForContentNoTrans("recentchangestext")); // Dump everything here $nondefaults = array(); wfAppendToArrayIfNotDefault('days', $days, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('limit', $limit, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hideminor', $hideminor, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hidebots', $hidebots, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hideanons', $hideanons, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hideliu', $hideliu, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hidepatrolled', $hidepatrolled, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('hidemyself', $hidemyself, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('from', $from, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('namespace', $namespace, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('invert', $invert, $defaults, $nondefaults); wfAppendToArrayIfNotDefault('categories_any', $any, $defaults, $nondefaults); // Add end of the texts $wgOut->addHTML('<div class="rcoptions">' . rcOptionsPanel($defaults, $nondefaults) . "\n"); $wgOut->addHTML(rcNamespaceForm($namespace, $invert, $nondefaults, $any) . '</div>' . "\n"); } // And now for the content $list = ChangesList::newFromUser($wgUser); if ($wgAllowCategorizedRecentChanges) { $categories = trim($wgRequest->getVal('categories', "")); $categories = str_replace("|", "\n", $categories); $categories = explode("\n", $categories); rcFilterByCategories($rows, $categories, $any); } $s = $list->beginRecentChangesList(); $counter = 1; foreach ($rows as $obj) { if ($limit == 0) { break; } if (!($hideminor && $obj->rc_minor) && !($hidepatrolled && $obj->rc_patrolled)) { $rc = RecentChange::newFromRow($obj); $rc->counter = $counter++; if ($wgShowUpdatedMarker && !empty($obj->wl_notificationtimestamp) && $obj->rc_timestamp >= $obj->wl_notificationtimestamp) { $rc->notificationtimestamp = true; } else { $rc->notificationtimestamp = false; } if ($wgRCShowWatchingUsers && $wgUser->getOption('shownumberswatching')) { $sql3 = "SELECT COUNT(*) AS n FROM {$watchlist} WHERE wl_title='" . $dbr->strencode($obj->rc_title) . "' AND wl_namespace={$obj->rc_namespace}"; $res3 = $dbr->query($sql3, 'wfSpecialRecentChanges'); $x = $dbr->fetchObject($res3); $rc->numberofWatchingusers = $x->n; } else { $rc->numberofWatchingusers = 0; } $s .= $list->recentChangesLine($rc, !empty($obj->wl_user)); --$limit; } } $s .= $list->endRecentChangesList(); $wgOut->addHTML($s); } }
protected function showHistory() { $this->checkReadOnly(); $out = $this->getOutput(); if ($this->mAllowed) { $out->addModules('mediawiki.special.undelete'); } $out->wrapWikiMsg("<div class='mw-undelete-pagetitle'>\n\$1\n</div>\n", array('undeletepagetitle', wfEscapeWikiText($this->mTargetObj->getPrefixedText()))); $archive = new PageArchive($this->mTargetObj, $this->getConfig()); Hooks::run('UndeleteForm::showHistory', array(&$archive, $this->mTargetObj)); /* $text = $archive->getLastRevisionText(); if( is_null( $text ) ) { $out->addWikiMsg( 'nohistory' ); return; } */ $out->addHTML('<div class="mw-undelete-history">'); if ($this->mAllowed) { $out->addWikiMsg('undeletehistory'); $out->addWikiMsg('undeleterevdel'); } else { $out->addWikiMsg('undeletehistorynoadmin'); } $out->addHTML('</div>'); # List all stored revisions $revisions = $archive->listRevisions(); $files = $archive->listFiles(); $haveRevisions = $revisions && $revisions->numRows() > 0; $haveFiles = $files && $files->numRows() > 0; # Batch existence check on user and talk pages if ($haveRevisions) { $batch = new LinkBatch(); foreach ($revisions as $row) { $batch->addObj(Title::makeTitleSafe(NS_USER, $row->ar_user_text)); $batch->addObj(Title::makeTitleSafe(NS_USER_TALK, $row->ar_user_text)); } $batch->execute(); $revisions->seek(0); } if ($haveFiles) { $batch = new LinkBatch(); foreach ($files as $row) { $batch->addObj(Title::makeTitleSafe(NS_USER, $row->fa_user_text)); $batch->addObj(Title::makeTitleSafe(NS_USER_TALK, $row->fa_user_text)); } $batch->execute(); $files->seek(0); } if ($this->mAllowed) { $action = $this->getPageTitle()->getLocalURL(array('action' => 'submit')); # Start the form here $top = Xml::openElement('form', array('method' => 'post', 'action' => $action, 'id' => 'undelete')); $out->addHTML($top); } # Show relevant lines from the deletion log: $deleteLogPage = new LogPage('delete'); $out->addHTML(Xml::element('h2', null, $deleteLogPage->getName()->text()) . "\n"); LogEventsList::showLogExtract($out, 'delete', $this->mTargetObj); # Show relevant lines from the suppression log: $suppressLogPage = new LogPage('suppress'); if ($this->getUser()->isAllowed('suppressionlog')) { $out->addHTML(Xml::element('h2', null, $suppressLogPage->getName()->text()) . "\n"); LogEventsList::showLogExtract($out, 'suppress', $this->mTargetObj); } if ($this->mAllowed && ($haveRevisions || $haveFiles)) { # Format the user-visible controls (comment field, submission button) # in a nice little table if ($this->getUser()->isAllowed('suppressrevision')) { $unsuppressBox = "<tr>\n\t\t\t\t\t\t<td> </td>\n\t\t\t\t\t\t<td class='mw-input'>" . Xml::checkLabel($this->msg('revdelete-unsuppress')->text(), 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress) . "</td>\n\t\t\t\t\t</tr>"; } else { $unsuppressBox = ''; } $table = Xml::fieldset($this->msg('undelete-fieldset-title')->text()) . Xml::openElement('table', array('id' => 'mw-undelete-table')) . "<tr>\n\t\t\t\t\t<td colspan='2' class='mw-undelete-extrahelp'>" . $this->msg('undeleteextrahelp')->parseAsBlock() . "</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td class='mw-label'>" . Xml::label($this->msg('undeletecomment')->text(), 'wpComment') . "</td>\n\t\t\t\t<td class='mw-input'>" . Xml::input('wpComment', 50, $this->mComment, array('id' => 'wpComment', 'autofocus' => '')) . "</td>\n\t\t\t</tr>\n\t\t\t<tr>\n\t\t\t\t<td> </td>\n\t\t\t\t<td class='mw-submit'>" . Xml::submitButton($this->msg('undeletebtn')->text(), array('name' => 'restore', 'id' => 'mw-undelete-submit')) . ' ' . Xml::submitButton($this->msg('undeleteinvert')->text(), array('name' => 'invert', 'id' => 'mw-undelete-invert')) . "</td>\n\t\t\t</tr>" . $unsuppressBox . Xml::closeElement('table') . Xml::closeElement('fieldset'); $out->addHTML($table); } $out->addHTML(Xml::element('h2', null, $this->msg('history')->text()) . "\n"); if ($haveRevisions) { # The page's stored (deleted) history: $out->addHTML('<ul>'); $remaining = $revisions->numRows(); $earliestLiveTime = $this->mTargetObj->getEarliestRevTime(); foreach ($revisions as $row) { $remaining--; $out->addHTML($this->formatRevisionRow($row, $earliestLiveTime, $remaining)); } $revisions->free(); $out->addHTML('</ul>'); } else { $out->addWikiMsg('nohistory'); } if ($haveFiles) { $out->addHTML(Xml::element('h2', null, $this->msg('filehist')->text()) . "\n"); $out->addHTML('<ul>'); foreach ($files as $row) { $out->addHTML($this->formatFileRow($row)); } $files->free(); $out->addHTML('</ul>'); } if ($this->mAllowed) { # Slip in the hidden controls here $misc = Html::hidden('target', $this->mTarget); $misc .= Html::hidden('wpEditToken', $this->getUser()->getEditToken()); $misc .= Xml::closeElement('form'); $out->addHTML($misc); } return true; }