r92990 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92989‎ | r92990 | r92991 >
Date:17:38, 24 July 2011
Author:reedy
Status:reverted
Tags:
Comment:
Merge r87108, Merge r70764
Modified paths:
  • /branches/iwtransclusion/phase3v3/includes/Article.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/EditPage.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/Linker.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/OutputPage.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/Title.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/db/Database.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/parser/Parser.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/includes/parser/ParserOutput.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/languages/messages/MessagesEn.php (modified) (history)
  • /branches/iwtransclusion/phase3v3/maintenance/archives/patch-globaltemplatelinks.sql (modified) (history)
  • /branches/iwtransclusion/phase3v3/maintenance/language/messages.inc (modified) (history)

Diff [purge]

Index: branches/iwtransclusion/phase3v3/maintenance/archives/patch-globaltemplatelinks.sql
@@ -17,15 +17,19 @@
1818 -- Needed for display purposes
1919 gtl_from_title varchar(255) binary NOT NULL,
2020
21 - -- The wiki ID of the wiki that hosts the transcluded page
22 - gtl_to_wiki varchar(64) NOT NULL,
 21+ -- The interwiki prefix of the wiki that hosts the transcluded page
 22+ gtl_to_prefix varchar(32) NOT NULL,
2323
2424 -- The namespace of the transcluded page on that wiki
2525 gtl_to_namespace int NOT NULL,
2626
 27+ -- The namespace name of transcluded page
 28+ -- Needed for display purposes, since the local namespace ID doesn't necessarily match a distant one
 29+ gtl_to_namespacetext varchar(255) NOT NULL,
 30+
2731 -- The title of the transcluded page on that wiki
2832 gtl_to_title varchar(255) binary NOT NULL
2933 ) /*$wgDBTableOptions*/;
3034
31 -CREATE UNIQUE INDEX /*i*/gtl_to_from ON /*_*/globaltemplatelinks (gtl_to_wiki, gtl_to_namespace, gtl_to_title, gtl_from_wiki, gtl_from_page);
32 -CREATE UNIQUE INDEX /*i*/gtl_from_to ON /*_*/globaltemplatelinks (gtl_from_wiki, gtl_from_page, gtl_to_wiki, gtl_to_namespace, gtl_to_title);
 35+CREATE UNIQUE INDEX /*i*/gtl_to_from ON /*_*/globaltemplatelinks (gtl_to_prefix, gtl_to_namespace, gtl_to_title, gtl_from_wiki, gtl_from_page);
 36+CREATE UNIQUE INDEX /*i*/gtl_from_to ON /*_*/globaltemplatelinks (gtl_from_wiki, gtl_from_page, gtl_to_prefix, gtl_to_namespace, gtl_to_title);
Index: branches/iwtransclusion/phase3v3/maintenance/language/messages.inc
@@ -639,6 +639,9 @@
640640 'templatesused',
641641 'templatesusedpreview',
642642 'templatesusedsection',
 643+ 'distanttemplatesused',
 644+ 'distanttemplatesusedpreview',
 645+ 'distanttemplatesusedsection',
643646 'template-protected',
644647 'template-semiprotected',
645648 'hiddencategories',
Index: branches/iwtransclusion/phase3v3/includes/Article.php
@@ -1627,6 +1627,594 @@
16281628 }
16291629
16301630 /**
 1631+ * Back-end article deletion
 1632+ * Deletes the article with database consistency, writes logs, purges caches
 1633+ *
 1634+ * @param $reason string delete reason for deletion log
 1635+ * @param suppress bitfield
 1636+ * Revision::DELETED_TEXT
 1637+ * Revision::DELETED_COMMENT
 1638+ * Revision::DELETED_USER
 1639+ * Revision::DELETED_RESTRICTED
 1640+ * @param $id int article ID
 1641+ * @param $commit boolean defaults to true, triggers transaction end
 1642+ * @return boolean true if successful
 1643+ */
 1644+ public function doDeleteArticle( $reason, $suppress = false, $id = 0, $commit = true ) {
 1645+ global $wgDeferredUpdateList, $wgUseTrackbacks, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
 1646+
 1647+ wfDebug( __METHOD__ . "\n" );
 1648+
 1649+ if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$wgUser, &$reason, &$error ) ) ) {
 1650+ return false;
 1651+ }
 1652+ $dbw = wfGetDB( DB_MASTER );
 1653+ $t = $this->mTitle->getDBkey();
 1654+ $id = $id ? $id : $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE );
 1655+
 1656+ if ( $t === '' || $id == 0 ) {
 1657+ return false;
 1658+ }
 1659+
 1660+ $u = new SiteStatsUpdate( 0, 1, - (int)$this->isCountable( $this->getRawText() ), -1 );
 1661+ array_push( $wgDeferredUpdateList, $u );
 1662+
 1663+ // Bitfields to further suppress the content
 1664+ if ( $suppress ) {
 1665+ $bitfield = 0;
 1666+ // This should be 15...
 1667+ $bitfield |= Revision::DELETED_TEXT;
 1668+ $bitfield |= Revision::DELETED_COMMENT;
 1669+ $bitfield |= Revision::DELETED_USER;
 1670+ $bitfield |= Revision::DELETED_RESTRICTED;
 1671+ } else {
 1672+ $bitfield = 'rev_deleted';
 1673+ }
 1674+
 1675+ $dbw->begin();
 1676+ // For now, shunt the revision data into the archive table.
 1677+ // Text is *not* removed from the text table; bulk storage
 1678+ // is left intact to avoid breaking block-compression or
 1679+ // immutable storage schemes.
 1680+ //
 1681+ // For backwards compatibility, note that some older archive
 1682+ // table entries will have ar_text and ar_flags fields still.
 1683+ //
 1684+ // In the future, we may keep revisions and mark them with
 1685+ // the rev_deleted field, which is reserved for this purpose.
 1686+ $dbw->insertSelect( 'archive', array( 'page', 'revision' ),
 1687+ array(
 1688+ 'ar_namespace' => 'page_namespace',
 1689+ 'ar_title' => 'page_title',
 1690+ 'ar_comment' => 'rev_comment',
 1691+ 'ar_user' => 'rev_user',
 1692+ 'ar_user_text' => 'rev_user_text',
 1693+ 'ar_timestamp' => 'rev_timestamp',
 1694+ 'ar_minor_edit' => 'rev_minor_edit',
 1695+ 'ar_rev_id' => 'rev_id',
 1696+ 'ar_text_id' => 'rev_text_id',
 1697+ 'ar_text' => '\'\'', // Be explicit to appease
 1698+ 'ar_flags' => '\'\'', // MySQL's "strict mode"...
 1699+ 'ar_len' => 'rev_len',
 1700+ 'ar_page_id' => 'page_id',
 1701+ 'ar_deleted' => $bitfield
 1702+ ), array(
 1703+ 'page_id' => $id,
 1704+ 'page_id = rev_page'
 1705+ ), __METHOD__
 1706+ );
 1707+
 1708+ # Delete restrictions for it
 1709+ $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ );
 1710+
 1711+ # Now that it's safely backed up, delete it
 1712+ $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ );
 1713+ $ok = ( $dbw->affectedRows() > 0 ); // getArticleId() uses slave, could be laggy
 1714+
 1715+ if ( !$ok ) {
 1716+ $dbw->rollback();
 1717+ return false;
 1718+ }
 1719+
 1720+ # Fix category table counts
 1721+ $cats = array();
 1722+ $res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ );
 1723+
 1724+ foreach ( $res as $row ) {
 1725+ $cats [] = $row->cl_to;
 1726+ }
 1727+
 1728+ $this->updateCategoryCounts( array(), $cats );
 1729+
 1730+ # If using cascading deletes, we can skip some explicit deletes
 1731+ if ( !$dbw->cascadingDeletes() ) {
 1732+ $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ );
 1733+
 1734+ if ( $wgUseTrackbacks )
 1735+ $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ );
 1736+
 1737+ # Delete outgoing links
 1738+ $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) );
 1739+ $dbw->delete( 'imagelinks', array( 'il_from' => $id ) );
 1740+ $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) );
 1741+ $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) );
 1742+ $dbw->delete( 'externallinks', array( 'el_from' => $id ) );
 1743+ $dbw->delete( 'langlinks', array( 'll_from' => $id ) );
 1744+ $dbw->delete( 'iwlinks', array( 'iwl_from' => $id ) );
 1745+ $dbw->delete( 'redirect', array( 'rd_from' => $id ) );
 1746+
 1747+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 1748+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 1749+ $dbw2->delete( 'globaltemplatelinks',
 1750+ array( 'gtl_from_wiki' => wfWikiID( ),
 1751+ 'gtl_from_page' => $id )
 1752+ );
 1753+ }
 1754+ }
 1755+
 1756+ # If using cleanup triggers, we can skip some manual deletes
 1757+ if ( !$dbw->cleanupTriggers() ) {
 1758+ # Clean up recentchanges entries...
 1759+ $dbw->delete( 'recentchanges',
 1760+ array( 'rc_type != ' . RC_LOG,
 1761+ 'rc_namespace' => $this->mTitle->getNamespace(),
 1762+ 'rc_title' => $this->mTitle->getDBkey() ),
 1763+ __METHOD__ );
 1764+ $dbw->delete( 'recentchanges',
 1765+ array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ),
 1766+ __METHOD__ );
 1767+ }
 1768+
 1769+ # Clear caches
 1770+ Article::onArticleDelete( $this->mTitle );
 1771+
 1772+ # Clear the cached article id so the interface doesn't act like we exist
 1773+ $this->mTitle->resetArticleID( 0 );
 1774+
 1775+ # Log the deletion, if the page was suppressed, log it at Oversight instead
 1776+ $logtype = $suppress ? 'suppress' : 'delete';
 1777+ $log = new LogPage( $logtype );
 1778+
 1779+ # Make sure logging got through
 1780+ $log->addEntry( 'delete', $this->mTitle, $reason, array() );
 1781+
 1782+ if ( $commit ) {
 1783+ $dbw->commit();
 1784+ }
 1785+
 1786+ wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$wgUser, $reason, $id ) );
 1787+ return true;
 1788+ }
 1789+
 1790+ /**
 1791+ * Roll back the most recent consecutive set of edits to a page
 1792+ * from the same user; fails if there are no eligible edits to
 1793+ * roll back to, e.g. user is the sole contributor. This function
 1794+ * performs permissions checks on $wgUser, then calls commitRollback()
 1795+ * to do the dirty work
 1796+ *
 1797+ * @param $fromP String: Name of the user whose edits to rollback.
 1798+ * @param $summary String: Custom summary. Set to default summary if empty.
 1799+ * @param $token String: Rollback token.
 1800+ * @param $bot Boolean: If true, mark all reverted edits as bot.
 1801+ *
 1802+ * @param $resultDetails Array: contains result-specific array of additional values
 1803+ * 'alreadyrolled' : 'current' (rev)
 1804+ * success : 'summary' (str), 'current' (rev), 'target' (rev)
 1805+ *
 1806+ * @return array of errors, each error formatted as
 1807+ * array(messagekey, param1, param2, ...).
 1808+ * On success, the array is empty. This array can also be passed to
 1809+ * OutputPage::showPermissionsErrorPage().
 1810+ */
 1811+ public function doRollback( $fromP, $summary, $token, $bot, &$resultDetails ) {
 1812+ global $wgUser;
 1813+
 1814+ $resultDetails = null;
 1815+
 1816+ # Check permissions
 1817+ $editErrors = $this->mTitle->getUserPermissionsErrors( 'edit', $wgUser );
 1818+ $rollbackErrors = $this->mTitle->getUserPermissionsErrors( 'rollback', $wgUser );
 1819+ $errors = array_merge( $editErrors, wfArrayDiff2( $rollbackErrors, $editErrors ) );
 1820+
 1821+ if ( !$wgUser->matchEditToken( $token, array( $this->mTitle->getPrefixedText(), $fromP ) ) ) {
 1822+ $errors[] = array( 'sessionfailure' );
 1823+ }
 1824+
 1825+ if ( $wgUser->pingLimiter( 'rollback' ) || $wgUser->pingLimiter() ) {
 1826+ $errors[] = array( 'actionthrottledtext' );
 1827+ }
 1828+
 1829+ # If there were errors, bail out now
 1830+ if ( !empty( $errors ) ) {
 1831+ return $errors;
 1832+ }
 1833+
 1834+ return $this->commitRollback( $fromP, $summary, $bot, $resultDetails );
 1835+ }
 1836+
 1837+ /**
 1838+ * Backend implementation of doRollback(), please refer there for parameter
 1839+ * and return value documentation
 1840+ *
 1841+ * NOTE: This function does NOT check ANY permissions, it just commits the
 1842+ * rollback to the DB Therefore, you should only call this function direct-
 1843+ * ly if you want to use custom permissions checks. If you don't, use
 1844+ * doRollback() instead.
 1845+ */
 1846+ public function commitRollback( $fromP, $summary, $bot, &$resultDetails ) {
 1847+ global $wgUseRCPatrol, $wgUser, $wgLang;
 1848+
 1849+ $dbw = wfGetDB( DB_MASTER );
 1850+
 1851+ if ( wfReadOnly() ) {
 1852+ return array( array( 'readonlytext' ) );
 1853+ }
 1854+
 1855+ # Get the last editor
 1856+ $current = Revision::newFromTitle( $this->mTitle );
 1857+ if ( is_null( $current ) ) {
 1858+ # Something wrong... no page?
 1859+ return array( array( 'notanarticle' ) );
 1860+ }
 1861+
 1862+ $from = str_replace( '_', ' ', $fromP );
 1863+ # User name given should match up with the top revision.
 1864+ # If the user was deleted then $from should be empty.
 1865+ if ( $from != $current->getUserText() ) {
 1866+ $resultDetails = array( 'current' => $current );
 1867+ return array( array( 'alreadyrolled',
 1868+ htmlspecialchars( $this->mTitle->getPrefixedText() ),
 1869+ htmlspecialchars( $fromP ),
 1870+ htmlspecialchars( $current->getUserText() )
 1871+ ) );
 1872+ }
 1873+
 1874+ # Get the last edit not by this guy...
 1875+ # Note: these may not be public values
 1876+ $user = intval( $current->getRawUser() );
 1877+ $user_text = $dbw->addQuotes( $current->getRawUserText() );
 1878+ $s = $dbw->selectRow( 'revision',
 1879+ array( 'rev_id', 'rev_timestamp', 'rev_deleted' ),
 1880+ array( 'rev_page' => $current->getPage(),
 1881+ "rev_user != {$user} OR rev_user_text != {$user_text}"
 1882+ ), __METHOD__,
 1883+ array( 'USE INDEX' => 'page_timestamp',
 1884+ 'ORDER BY' => 'rev_timestamp DESC' )
 1885+ );
 1886+ if ( $s === false ) {
 1887+ # No one else ever edited this page
 1888+ return array( array( 'cantrollback' ) );
 1889+ } else if ( $s->rev_deleted & Revision::DELETED_TEXT || $s->rev_deleted & Revision::DELETED_USER ) {
 1890+ # Only admins can see this text
 1891+ return array( array( 'notvisiblerev' ) );
 1892+ }
 1893+
 1894+ $set = array();
 1895+ if ( $bot && $wgUser->isAllowed( 'markbotedits' ) ) {
 1896+ # Mark all reverted edits as bot
 1897+ $set['rc_bot'] = 1;
 1898+ }
 1899+
 1900+ if ( $wgUseRCPatrol ) {
 1901+ # Mark all reverted edits as patrolled
 1902+ $set['rc_patrolled'] = 1;
 1903+ }
 1904+
 1905+ if ( count( $set ) ) {
 1906+ $dbw->update( 'recentchanges', $set,
 1907+ array( /* WHERE */
 1908+ 'rc_cur_id' => $current->getPage(),
 1909+ 'rc_user_text' => $current->getUserText(),
 1910+ "rc_timestamp > '{$s->rev_timestamp}'",
 1911+ ), __METHOD__
 1912+ );
 1913+ }
 1914+
 1915+ # Generate the edit summary if necessary
 1916+ $target = Revision::newFromId( $s->rev_id );
 1917+ if ( empty( $summary ) ) {
 1918+ if ( $from == '' ) { // no public user name
 1919+ $summary = wfMsgForContent( 'revertpage-nouser' );
 1920+ } else {
 1921+ $summary = wfMsgForContent( 'revertpage' );
 1922+ }
 1923+ }
 1924+
 1925+ # Allow the custom summary to use the same args as the default message
 1926+ $args = array(
 1927+ $target->getUserText(), $from, $s->rev_id,
 1928+ $wgLang->timeanddate( wfTimestamp( TS_MW, $s->rev_timestamp ), true ),
 1929+ $current->getId(), $wgLang->timeanddate( $current->getTimestamp() )
 1930+ );
 1931+ $summary = wfMsgReplaceArgs( $summary, $args );
 1932+
 1933+ # Save
 1934+ $flags = EDIT_UPDATE;
 1935+
 1936+ if ( $wgUser->isAllowed( 'minoredit' ) ) {
 1937+ $flags |= EDIT_MINOR;
 1938+ }
 1939+
 1940+ if ( $bot && ( $wgUser->isAllowedAny( 'markbotedits', 'bot' ) ) ) {
 1941+ $flags |= EDIT_FORCE_BOT;
 1942+ }
 1943+
 1944+ # Actually store the edit
 1945+ $status = $this->doEdit( $target->getText(), $summary, $flags, $target->getId() );
 1946+ if ( !empty( $status->value['revision'] ) ) {
 1947+ $revId = $status->value['revision']->getId();
 1948+ } else {
 1949+ $revId = false;
 1950+ }
 1951+
 1952+ wfRunHooks( 'ArticleRollbackComplete', array( $this, $wgUser, $target, $current ) );
 1953+
 1954+ $resultDetails = array(
 1955+ 'summary' => $summary,
 1956+ 'current' => $current,
 1957+ 'target' => $target,
 1958+ 'newid' => $revId
 1959+ );
 1960+
 1961+ return array();
 1962+ }
 1963+
 1964+ /**
 1965+ * User interface for rollback operations
 1966+ */
 1967+ public function rollback() {
 1968+ global $wgUser, $wgOut, $wgRequest;
 1969+
 1970+ $details = null;
 1971+
 1972+ $result = $this->doRollback(
 1973+ $wgRequest->getVal( 'from' ),
 1974+ $wgRequest->getText( 'summary' ),
 1975+ $wgRequest->getVal( 'token' ),
 1976+ $wgRequest->getBool( 'bot' ),
 1977+ $details
 1978+ );
 1979+
 1980+ if ( in_array( array( 'actionthrottledtext' ), $result ) ) {
 1981+ $wgOut->rateLimited();
 1982+ return;
 1983+ }
 1984+
 1985+ if ( isset( $result[0][0] ) && ( $result[0][0] == 'alreadyrolled' || $result[0][0] == 'cantrollback' ) ) {
 1986+ $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) );
 1987+ $errArray = $result[0];
 1988+ $errMsg = array_shift( $errArray );
 1989+ $wgOut->addWikiMsgArray( $errMsg, $errArray );
 1990+
 1991+ if ( isset( $details['current'] ) ) {
 1992+ $current = $details['current'];
 1993+
 1994+ if ( $current->getComment() != '' ) {
 1995+ $wgOut->addWikiMsgArray( 'editcomment', array(
 1996+ Linker::formatComment( $current->getComment() ) ), array( 'replaceafter' ) );
 1997+ }
 1998+ }
 1999+
 2000+ return;
 2001+ }
 2002+
 2003+ # Display permissions errors before read-only message -- there's no
 2004+ # point in misleading the user into thinking the inability to rollback
 2005+ # is only temporary.
 2006+ if ( !empty( $result ) && $result !== array( array( 'readonlytext' ) ) ) {
 2007+ # array_diff is completely broken for arrays of arrays, sigh.
 2008+ # Remove any 'readonlytext' error manually.
 2009+ $out = array();
 2010+ foreach ( $result as $error ) {
 2011+ if ( $error != array( 'readonlytext' ) ) {
 2012+ $out [] = $error;
 2013+ }
 2014+ }
 2015+ $wgOut->showPermissionsErrorPage( $out );
 2016+
 2017+ return;
 2018+ }
 2019+
 2020+ if ( $result == array( array( 'readonlytext' ) ) ) {
 2021+ $wgOut->readOnlyPage();
 2022+
 2023+ return;
 2024+ }
 2025+
 2026+ $current = $details['current'];
 2027+ $target = $details['target'];
 2028+ $newId = $details['newid'];
 2029+ $wgOut->setPageTitle( wfMsg( 'actioncomplete' ) );
 2030+ $wgOut->setRobotPolicy( 'noindex,nofollow' );
 2031+
 2032+ if ( $current->getUserText() === '' ) {
 2033+ $old = wfMsg( 'rev-deleted-user' );
 2034+ } else {
 2035+ $old = Linker::userLink( $current->getUser(), $current->getUserText() )
 2036+ . Linker::userToolLinks( $current->getUser(), $current->getUserText() );
 2037+ }
 2038+
 2039+ $new = Linker::userLink( $target->getUser(), $target->getUserText() )
 2040+ . Linker::userToolLinks( $target->getUser(), $target->getUserText() );
 2041+ $wgOut->addHTML( wfMsgExt( 'rollback-success', array( 'parse', 'replaceafter' ), $old, $new ) );
 2042+ $wgOut->returnToMain( false, $this->mTitle );
 2043+
 2044+ if ( !$wgRequest->getBool( 'hidediff', false ) && !$wgUser->getBoolOption( 'norollbackdiff', false ) ) {
 2045+ $de = new DifferenceEngine( $this->mTitle, $current->getId(), $newId, false, true );
 2046+ $de->showDiff( '', '' );
 2047+ }
 2048+ }
 2049+
 2050+ /**
 2051+ * Do standard deferred updates after page view
 2052+ */
 2053+ public function viewUpdates() {
 2054+ global $wgDeferredUpdateList, $wgDisableCounters, $wgUser;
 2055+ if ( wfReadOnly() ) {
 2056+ return;
 2057+ }
 2058+
 2059+ # Don't update page view counters on views from bot users (bug 14044)
 2060+ if ( !$wgDisableCounters && !$wgUser->isAllowed( 'bot' ) && $this->getID() ) {
 2061+ $wgDeferredUpdateList[] = new ViewCountUpdate( $this->getID() );
 2062+ $wgDeferredUpdateList[] = new SiteStatsUpdate( 1, 0, 0 );
 2063+ }
 2064+
 2065+ # Update newtalk / watchlist notification status
 2066+ $wgUser->clearNotification( $this->mTitle );
 2067+ }
 2068+
 2069+ /**
 2070+ * Prepare text which is about to be saved.
 2071+ * Returns a stdclass with source, pst and output members
 2072+ */
 2073+ public function prepareTextForEdit( $text, $revid = null, User $user = null ) {
 2074+ if ( $this->mPreparedEdit && $this->mPreparedEdit->newText == $text && $this->mPreparedEdit->revid == $revid ) {
 2075+ // Already prepared
 2076+ return $this->mPreparedEdit;
 2077+ }
 2078+
 2079+ global $wgParser;
 2080+
 2081+ if( $user === null ) {
 2082+ global $wgUser;
 2083+ $user = $wgUser;
 2084+ }
 2085+ $popts = ParserOptions::newFromUser( $user );
 2086+ wfRunHooks( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
 2087+
 2088+ $edit = (object)array();
 2089+ $edit->revid = $revid;
 2090+ $edit->newText = $text;
 2091+ $edit->pst = $this->preSaveTransform( $text, $user, $popts );
 2092+ $edit->popts = $this->getParserOptions();
 2093+ $edit->output = $wgParser->parse( $edit->pst, $this->mTitle, $edit->popts, true, true, $revid );
 2094+ $edit->oldText = $this->getRawText();
 2095+
 2096+ $this->mPreparedEdit = $edit;
 2097+
 2098+ return $edit;
 2099+ }
 2100+
 2101+ /**
 2102+ * Do standard deferred updates after page edit.
 2103+ * Update links tables, site stats, search index and message cache.
 2104+ * Purges pages that include this page if the text was changed here.
 2105+ * Every 100th edit, prune the recent changes table.
 2106+ *
 2107+ * @private
 2108+ * @param $text String: New text of the article
 2109+ * @param $summary String: Edit summary
 2110+ * @param $minoredit Boolean: Minor edit
 2111+ * @param $timestamp_of_pagechange String timestamp associated with the page change
 2112+ * @param $newid Integer: rev_id value of the new revision
 2113+ * @param $changed Boolean: Whether or not the content actually changed
 2114+ * @param $user User object: User doing the edit
 2115+ */
 2116+ public function editUpdates( $text, $summary, $minoredit, $timestamp_of_pagechange, $newid, $changed = true, User $user = null ) {
 2117+ global $wgDeferredUpdateList, $wgUser, $wgEnableParserCache;
 2118+
 2119+ wfProfileIn( __METHOD__ );
 2120+
 2121+ # Parse the text
 2122+ # Be careful not to double-PST: $text is usually already PST-ed once
 2123+ if ( !$this->mPreparedEdit || $this->mPreparedEdit->output->getFlag( 'vary-revision' ) ) {
 2124+ wfDebug( __METHOD__ . ": No prepared edit or vary-revision is set...\n" );
 2125+ $editInfo = $this->prepareTextForEdit( $text, $newid, $user );
 2126+ } else {
 2127+ wfDebug( __METHOD__ . ": No vary-revision, using prepared edit...\n" );
 2128+ $editInfo = $this->mPreparedEdit;
 2129+ }
 2130+
 2131+ # Save it to the parser cache
 2132+ if ( $wgEnableParserCache ) {
 2133+ $parserCache = ParserCache::singleton();
 2134+ $parserCache->save( $editInfo->output, $this, $editInfo->popts );
 2135+ }
 2136+
 2137+ # Update the links tables
 2138+ $u = new LinksUpdate( $this->mTitle, $editInfo->output );
 2139+ $u->doUpdate();
 2140+
 2141+ wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $changed ) );
 2142+
 2143+ if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
 2144+ if ( 0 == mt_rand( 0, 99 ) ) {
 2145+ // Flush old entries from the `recentchanges` table; we do this on
 2146+ // random requests so as to avoid an increase in writes for no good reason
 2147+ global $wgRCMaxAge;
 2148+
 2149+ $dbw = wfGetDB( DB_MASTER );
 2150+ $cutoff = $dbw->timestamp( time() - $wgRCMaxAge );
 2151+ $dbw->delete(
 2152+ 'recentchanges',
 2153+ array( "rc_timestamp < '$cutoff'" ),
 2154+ __METHOD__
 2155+ );
 2156+ }
 2157+ }
 2158+
 2159+ $id = $this->getID();
 2160+ $title = $this->mTitle->getPrefixedDBkey();
 2161+ $shortTitle = $this->mTitle->getDBkey();
 2162+
 2163+ if ( 0 == $id ) {
 2164+ wfProfileOut( __METHOD__ );
 2165+ return;
 2166+ }
 2167+
 2168+ $u = new SiteStatsUpdate( 0, 1, $this->mGoodAdjustment, $this->mTotalAdjustment );
 2169+ array_push( $wgDeferredUpdateList, $u );
 2170+ $u = new SearchUpdate( $id, $title, $text );
 2171+ array_push( $wgDeferredUpdateList, $u );
 2172+
 2173+ # If this is another user's talk page, update newtalk
 2174+ # Don't do this if $changed = false otherwise some idiot can null-edit a
 2175+ # load of user talk pages and piss people off, nor if it's a minor edit
 2176+ # by a properly-flagged bot.
 2177+ if ( $this->mTitle->getNamespace() == NS_USER_TALK && $shortTitle != $wgUser->getTitleKey() && $changed
 2178+ && !( $minoredit && $wgUser->isAllowed( 'nominornewtalk' ) )
 2179+ ) {
 2180+ if ( wfRunHooks( 'ArticleEditUpdateNewTalk', array( &$this ) ) ) {
 2181+ $other = User::newFromName( $shortTitle, false );
 2182+ if ( !$other ) {
 2183+ wfDebug( __METHOD__ . ": invalid username\n" );
 2184+ } elseif ( User::isIP( $shortTitle ) ) {
 2185+ // An anonymous user
 2186+ $other->setNewtalk( true );
 2187+ } elseif ( $other->isLoggedIn() ) {
 2188+ $other->setNewtalk( true );
 2189+ } else {
 2190+ wfDebug( __METHOD__ . ": don't need to notify a nonexistent user\n" );
 2191+ }
 2192+ }
 2193+ }
 2194+
 2195+ if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) {
 2196+ MessageCache::singleton()->replace( $shortTitle, $text );
 2197+ }
 2198+
 2199+ wfProfileOut( __METHOD__ );
 2200+ }
 2201+
 2202+ /**
 2203+ * Perform article updates on a special page creation.
 2204+ *
 2205+ * @param $rev Revision object
 2206+ *
 2207+ * @todo This is a shitty interface function. Kill it and replace the
 2208+ * other shitty functions like editUpdates and such so it's not needed
 2209+ * anymore.
 2210+ */
 2211+ public function createUpdates( $rev ) {
 2212+ $this->mGoodAdjustment = $this->isCountable( $rev->getText() );
 2213+ $this->mTotalAdjustment = 1;
 2214+ $this->editUpdates( $rev->getText(), $rev->getComment(),
 2215+ $rev->isMinor(), wfTimestamp(), $rev->getId(), true );
 2216+ }
 2217+
 2218+ /**
16312219 * Generate the navigation links when browsing through an article revisions
16322220 * It shows the information as:
16332221 * Revision as of \<date\>; view current revision
@@ -1894,6 +2482,166 @@
18952483 }
18962484
18972485 /**
 2486+ * Return a list of templates used by this article.
 2487+ * Uses the templatelinks table
 2488+ *
 2489+ * @return Array of Title objects
 2490+ */
 2491+ public function getUsedTemplates() {
 2492+ $result = array();
 2493+ $id = $this->mTitle->getArticleID();
 2494+
 2495+ if ( $id == 0 ) {
 2496+ return array();
 2497+ }
 2498+
 2499+ $dbr = wfGetDB( DB_SLAVE );
 2500+ $res = $dbr->select( array( 'templatelinks' ),
 2501+ array( 'tl_namespace', 'tl_title' ),
 2502+ array( 'tl_from' => $id ),
 2503+ __METHOD__ );
 2504+
 2505+ if ( $res !== false ) {
 2506+ foreach ( $res as $row ) {
 2507+ $result[] = Title::makeTitle( $row->tl_namespace, $row->tl_title );
 2508+ }
 2509+ }
 2510+
 2511+ return $result;
 2512+ }
 2513+
 2514+ /**
 2515+ * Return a list of distant templates used by this article.
 2516+ * Uses the globaltemplatelinks table
 2517+ *
 2518+ * @return Array of Title objects
 2519+ */
 2520+ public function getUsedDistantTemplates() {
 2521+ global $wgGlobalDatabase;
 2522+
 2523+ $result = array();
 2524+
 2525+ if ( $wgGlobalDatabase ) {
 2526+ $id = $this->mTitle->getArticleID();
 2527+
 2528+ if ( $id == 0 ) {
 2529+ return array();
 2530+ }
 2531+
 2532+ $dbr = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase );
 2533+ $res = $dbr->select( array( 'globaltemplatelinks' ),
 2534+ array( 'gtl_to_prefix', 'gtl_to_namespace', 'gtl_to_title' ),
 2535+ array( 'gtl_from_wiki' => wfWikiID( ), 'gtl_from_page' => $id ),
 2536+ __METHOD__ );
 2537+
 2538+ if ( $res !== false ) {
 2539+ foreach ( $res as $row ) {
 2540+ $result[] = Title::makeTitle( $row->gtl_to_namespace, $row->gtl_to_title, null, $row->gtl_to_prefix );
 2541+ }
 2542+ }
 2543+
 2544+ $dbr->freeResult( $res );
 2545+ }
 2546+
 2547+ return $result;
 2548+ }
 2549+
 2550+ /**
 2551+ * Returns a list of hidden categories this page is a member of.
 2552+ * Uses the page_props and categorylinks tables.
 2553+ *
 2554+ * @return Array of Title objects
 2555+ */
 2556+ public function getHiddenCategories() {
 2557+ $result = array();
 2558+ $id = $this->mTitle->getArticleID();
 2559+
 2560+ if ( $id == 0 ) {
 2561+ return array();
 2562+ }
 2563+
 2564+ $dbr = wfGetDB( DB_SLAVE );
 2565+ $res = $dbr->select( array( 'categorylinks', 'page_props', 'page' ),
 2566+ array( 'cl_to' ),
 2567+ array( 'cl_from' => $id, 'pp_page=page_id', 'pp_propname' => 'hiddencat',
 2568+ 'page_namespace' => NS_CATEGORY, 'page_title=cl_to' ),
 2569+ __METHOD__ );
 2570+
 2571+ if ( $res !== false ) {
 2572+ foreach ( $res as $row ) {
 2573+ $result[] = Title::makeTitle( NS_CATEGORY, $row->cl_to );
 2574+ }
 2575+ }
 2576+
 2577+ return $result;
 2578+ }
 2579+
 2580+ /**
 2581+ * Return an applicable autosummary if one exists for the given edit.
 2582+ * @param $oldtext String: the previous text of the page.
 2583+ * @param $newtext String: The submitted text of the page.
 2584+ * @param $flags Int bitmask: a bitmask of flags submitted for the edit.
 2585+ * @return string An appropriate autosummary, or an empty string.
 2586+ */
 2587+ public static function getAutosummary( $oldtext, $newtext, $flags ) {
 2588+ global $wgContLang;
 2589+
 2590+ # Decide what kind of autosummary is needed.
 2591+
 2592+ # Redirect autosummaries
 2593+ $ot = Title::newFromRedirect( $oldtext );
 2594+ $rt = Title::newFromRedirect( $newtext );
 2595+
 2596+ if ( is_object( $rt ) && ( !is_object( $ot ) || !$rt->equals( $ot ) || $ot->getFragment() != $rt->getFragment() ) ) {
 2597+ return wfMsgForContent( 'autoredircomment', $rt->getFullText() );
 2598+ }
 2599+
 2600+ # New page autosummaries
 2601+ if ( $flags & EDIT_NEW && strlen( $newtext ) ) {
 2602+ # If they're making a new article, give its text, truncated, in the summary.
 2603+
 2604+ $truncatedtext = $wgContLang->truncate(
 2605+ str_replace( "\n", ' ', $newtext ),
 2606+ max( 0, 200 - strlen( wfMsgForContent( 'autosumm-new' ) ) ) );
 2607+
 2608+ return wfMsgForContent( 'autosumm-new', $truncatedtext );
 2609+ }
 2610+
 2611+ # Blanking autosummaries
 2612+ if ( $oldtext != '' && $newtext == '' ) {
 2613+ return wfMsgForContent( 'autosumm-blank' );
 2614+ } elseif ( strlen( $oldtext ) > 10 * strlen( $newtext ) && strlen( $newtext ) < 500 ) {
 2615+ # Removing more than 90% of the article
 2616+
 2617+ $truncatedtext = $wgContLang->truncate(
 2618+ $newtext,
 2619+ max( 0, 200 - strlen( wfMsgForContent( 'autosumm-replace' ) ) ) );
 2620+
 2621+ return wfMsgForContent( 'autosumm-replace', $truncatedtext );
 2622+ }
 2623+
 2624+ # If we reach this point, there's no applicable autosummary for our case, so our
 2625+ # autosummary is empty.
 2626+ return '';
 2627+ }
 2628+
 2629+ /**
 2630+ * Add the primary page-view wikitext to the output buffer
 2631+ * Saves the text into the parser cache if possible.
 2632+ * Updates templatelinks if it is out of date.
 2633+ *
 2634+ * @param $text String
 2635+ * @param $cache Boolean
 2636+ * @param $parserOptions mixed ParserOptions object, or boolean false
 2637+ */
 2638+ public function outputWikiText( $text, $cache = true, $parserOptions = false ) {
 2639+ global $wgOut;
 2640+
 2641+ $this->mParserOutput = $this->getOutputFromWikitext( $text, $cache, $parserOptions );
 2642+ $wgOut->addParserOutput( $this->mParserOutput );
 2643+ }
 2644+
 2645+ /**
18982646 * This does all the heavy lifting for outputWikitext, except it returns the parser
18992647 * output instead of sending it straight to $wgOut. Makes things nice and simple for,
19002648 * say, embedding thread pages within a discussion system (LiquidThreads)
Index: branches/iwtransclusion/phase3v3/includes/parser/Parser.php
@@ -3051,7 +3051,7 @@
30523052 * @private
30533053 */
30543054 function braceSubstitution( $piece, $frame ) {
3055 - global $wgContLang, $wgNonincludableNamespaces;
 3055+ global $wgContLang, $wgNonincludableNamespaces, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
30563056 wfProfileIn( __METHOD__ );
30573057 wfProfileIn( __METHOD__.'-setup' );
30583058
@@ -3266,11 +3266,15 @@
32673267 $text = "[[:$titleText]]";
32683268 $found = true;
32693269 }
3270 - } elseif ( $title->isTrans() ) {
 3270+ } elseif ( $wgEnableInterwikiTranscluding && $title->isTrans() ) {
32713271 // TODO: Work by Peter17 in progress
32723272
32733273 $text = Interwiki::interwikiTransclude( $title );
32743274
 3275+ if ( $wgEnableInterwikiTemplatesTracking ) {
 3276+ $this->registerDistantTemplate( $title );
 3277+ }
 3278+
32753279 if ( $text !== false ) {
32763280 # Preprocess it like a template
32773281 $text = $this->preprocessToDom( $text, self::PTD_FOR_INCLUSION );
@@ -3429,6 +3433,17 @@
34303434 * @param Title $title
34313435 * @return mixed string or false
34323436 */
 3437+ function registerDistantTemplate( $title ) {
 3438+ $stuff = Parser::distantTemplateCallback( $title, $this );
 3439+ $text = $stuff['text'];
 3440+ $finalTitle = isset( $stuff['finalTitle'] ) ? $stuff['finalTitle'] : $title;
 3441+ if ( isset( $stuff['deps'] ) ) {
 3442+ foreach ( $stuff['deps'] as $dep ) {
 3443+ $this->mOutput->addDistantTemplate( $dep['title'], $dep['page_id'], $dep['rev_id'] );
 3444+ }
 3445+ }
 3446+ }
 3447+
34333448 function fetchTemplate( $title ) {
34343449 $rv = $this->fetchTemplateAndTitle( $title );
34353450 return $rv[0];
Index: branches/iwtransclusion/phase3v3/includes/parser/ParserOutput.php
@@ -306,6 +306,31 @@
307307 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning
308308 }
309309
 310+ function addDistantTemplate( $title, $page_id, $rev_id ) {
 311+ $prefix = $title->getInterwiki();
 312+ if ( $prefix !=='' ) {
 313+ $ns = $title->getNamespace();
 314+ $dbk = $title->getDBkey();
 315+
 316+ if ( !isset( $this->mDistantTemplates[$prefix] ) ) {
 317+ $this->mDistantTemplates[$prefix] = array();
 318+ }
 319+ if ( !isset( $this->mDistantTemplates[$prefix][$ns] ) ) {
 320+ $this->mDistantTemplates[$prefix][$ns] = array();
 321+ }
 322+ $this->mDistantTemplates[$prefix][$ns][$dbk] = $page_id;
 323+
 324+ // For versioning
 325+ if ( !isset( $this->mDistantTemplateIds[$prefix] ) ) {
 326+ $this->mDistantTemplateIds[$prefix] = array();
 327+ }
 328+ if ( !isset( $this->mDistantTemplateIds[$prefix][$ns] ) ) {
 329+ $this->mDistantTemplateIds[$prefix][$ns] = array();
 330+ }
 331+ $this->mDistantTemplateIds[$prefix][$ns][$dbk] = $rev_id;
 332+ }
 333+ }
 334+
310335 /**
311336 * @param $title Title object, must be an interwiki link
312337 * @throws MWException if given invalid input
Index: branches/iwtransclusion/phase3v3/includes/Linker.php
@@ -1646,6 +1646,48 @@
16471647 }
16481648
16491649 /**
 1650+ * Returns HTML for the "templates used on this page" list.
 1651+ *
 1652+ * @param $templates Array of templates from Article::getUsedTemplate
 1653+ * or similar
 1654+ * @param $preview Boolean: whether this is for a preview
 1655+ * @param $section Boolean: whether this is for a section edit
 1656+ * @return String: HTML output
 1657+ */
 1658+ public function formatDistantTemplates( $templates, $preview = false, $section = false ) {
 1659+ wfProfileIn( __METHOD__ );
 1660+
 1661+ $outText = '';
 1662+ if ( count( $templates ) > 0 ) {
 1663+ # Do a batch existence check
 1664+ $batch = new LinkBatch;
 1665+ foreach( $templates as $title ) {
 1666+ $batch->addObj( $title );
 1667+ }
 1668+ $batch->execute();
 1669+
 1670+ # Construct the HTML
 1671+ $outText = '<div class="mw-templatesUsedExplanation">';
 1672+ if ( $preview ) {
 1673+ $outText .= wfMsgExt( 'distanttemplatesusedpreview', array( 'parse' ), count( $templates ) );
 1674+ } elseif ( $section ) {
 1675+ $outText .= wfMsgExt( 'distanttemplatesusedsection', array( 'parse' ), count( $templates ) );
 1676+ } else {
 1677+ $outText .= wfMsgExt( 'distanttemplatesused', array( 'parse' ), count( $templates ) );
 1678+ }
 1679+ $outText .= "</div><ul>\n";
 1680+
 1681+ usort( $templates, array( 'Title', 'compare' ) );
 1682+ foreach ( $templates as $titleObj ) {
 1683+ $outText .= '<li>' . $this->link( $titleObj ) . '</li>';
 1684+ }
 1685+ $outText .= '</ul>';
 1686+ }
 1687+ wfProfileOut( __METHOD__ );
 1688+ return $outText;
 1689+ }
 1690+
 1691+ /**
16501692 * Returns HTML for the "hidden categories on this page" list.
16511693 *
16521694 * @param $hiddencats Array of hidden categories from Article::getHiddenCategories
Index: branches/iwtransclusion/phase3v3/includes/db/Database.php
@@ -1777,6 +1777,31 @@
17781778 return false;
17791779 }
17801780 }
 1781+
 1782+ /**
 1783+ * Build a partial where clause from a 3-d array
 1784+ * The keys on each level may be either integers or strings.
 1785+ *
 1786+ * @param $data Array: organized as 3-d array(baseKeyVal => array(middleKeyVal => array(subKeyVal => <ignored>, ...), ...), ...)
 1787+ * @param $baseKey String: field name to match the base-level keys to (eg 'gtl_to_prefix')
 1788+ * @param $middleKey String: field name to match the middle-level keys to (eg 'gtl_to_namespace')
 1789+ * @param $subKey String: field name to match the sub-level keys to (eg 'gtl_to_title')
 1790+ * @return Mixed: string SQL fragment, or false if no items in array.
 1791+ */
 1792+ function makeWhereFrom3d( $data, $baseKey, $middleKey, $subKey ) {
 1793+ $conds = array();
 1794+ foreach ( $data as $base => $subdata ) {
 1795+ foreach ( $subdata as $middle => $sub ) {
 1796+ if ( count( $sub ) ) {
 1797+ $conds[] = $this->makeList(
 1798+ array( $baseKey => $base,
 1799+ $middleKey => $middle,
 1800+ $subKey => array_keys( $sub ) ),
 1801+ LIST_AND
 1802+ );
 1803+ }
 1804+ }
 1805+ }
17811806
17821807 /**
17831808 * Bitwise operations
Property changes on: branches/iwtransclusion/phase3v3/includes/db/Database.php
___________________________________________________________________
Modified: svn:mergeinfo
17841809 Merged /branches/iwtransclusion/phase3/includes/db/Database.php:r70764
17851810 Merged /branches/iwtransclusion/phase3v2/includes/db/Database.php:r87108
Index: branches/iwtransclusion/phase3v3/includes/EditPage.php
@@ -1319,8 +1319,8 @@
13201320 * @param $formCallback Callback that takes an OutputPage parameter; will be called
13211321 * during form output near the top, for captchas and the like.
13221322 */
1323 - function showEditForm( $formCallback = null ) {
1324 - global $wgOut, $wgUser;
 1323+ function showEditForm( $formCallback=null ) {
 1324+ global $wgOut, $wgUser, $wgTitle, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
13251325
13261326 wfProfileIn( __METHOD__ );
13271327
@@ -1365,6 +1365,9 @@
13661366
13671367 $templates = $this->getTemplates();
13681368 $formattedtemplates = Linker::formatTemplates( $templates, $this->preview, $this->section != '');
 1369+
 1370+ $distantTemplates = $this->getDistantTemplates();
 1371+ $formattedDistantTemplates = $sk->formatDistantTemplates( $distantTemplates, $this->preview, $this->section != '' );
13691372
13701373 $hiddencats = $this->mArticle->getHiddenCategories();
13711374 $formattedhiddencats = Linker::formatHiddenCategories( $hiddencats );
@@ -1464,6 +1467,21 @@
14651468 <div class='templatesUsed'>
14661469 {$formattedtemplates}
14671470 </div>
 1471+HTML
 1472+);
 1473+
 1474+ if ( $wgEnableInterwikiTranscluding && $wgEnableInterwikiTemplatesTracking ) {
 1475+ $wgOut->addHTML( <<<HTML
 1476+{$this->editFormTextAfterTools}
 1477+<div class='distantTemplatesUsed'>
 1478+{$formattedDistantTemplates}
 1479+</div>
 1480+HTML
 1481+);
 1482+ }
 1483+
 1484+ $wgOut->addHTML( <<<HTML
 1485+{$this->editFormTextAfterTools}
14681486 <div class='hiddencats'>
14691487 {$formattedhiddencats}
14701488 </div>
@@ -2119,6 +2137,28 @@
21202138 return $this->mArticle->getUsedTemplates();
21212139 }
21222140 }
 2141+
 2142+ function getDistantTemplates() {
 2143+ global $wgEnableInterwikiTemplatesTracking;
 2144+ if ( !$wgEnableInterwikiTemplatesTracking ) {
 2145+ return array( );
 2146+ }
 2147+ if ( $this->preview || $this->section != '' ) {
 2148+ $templates = array();
 2149+ if ( !isset( $this->mParserOutput ) ) return $templates;
 2150+ $templatesList = $this->mParserOutput->getDistantTemplates();
 2151+ foreach( $templatesList as $prefix => $templatesbyns ) {
 2152+ foreach( $templatesbyns as $ns => $template ) {
 2153+ foreach( array_keys( $template ) as $dbk ) {
 2154+ $templates[] = Title::makeTitle( $ns, $dbk, null, $prefix );
 2155+ }
 2156+ }
 2157+ }
 2158+ return $templates;
 2159+ } else {
 2160+ return $this->mArticle->getUsedDistantTemplates();
 2161+ }
 2162+ }
21232163
21242164 /**
21252165 * Call the stock "user is blocked" page
Index: branches/iwtransclusion/phase3v3/includes/OutputPage.php
@@ -2095,6 +2095,9 @@
20962096 * @param $action String: action that was denied or null if unknown
20972097 */
20982098 public function readOnlyPage( $source = null, $protected = false, $reasons = array(), $action = null ) {
 2099+ global $wgUser, $wgEnableInterwikiTranscluding, $wgEnableInterwikiTemplatesTracking;
 2100+ $skin = $wgUser->getSkin();
 2101+
20992102 $this->setRobotPolicy( 'noindex,nofollow' );
21002103 $this->setArticleRelated( false );
21012104
@@ -2140,6 +2143,12 @@
21412144 $templates
21422145 </div>
21432146 " );
 2147+ if ( $wgEnableInterwikiTranscluding && $wgEnableInterwikiTemplatesTracking ) {
 2148+ $this->addHTML( "<div class='distantTemplatesUsed'>
 2149+{$skin->formatDistantTemplates( $article->getUsedDistantTemplates( ) )}
 2150+</div>
 2151+" );
 2152+ }
21442153 }
21452154
21462155 # If the title doesn't exist, it's fairly pointless to print a return
Property changes on: branches/iwtransclusion/phase3v3/includes/OutputPage.php
___________________________________________________________________
Modified: svn:mergeinfo
21472156 Merged /branches/iwtransclusion/phase3/includes/OutputPage.php:r70764
21482157 Merged /branches/iwtransclusion/phase3v2/includes/OutputPage.php:r87108
Index: branches/iwtransclusion/phase3v3/includes/Title.php
@@ -21,6 +21,7 @@
2222 */
2323
2424 /**
 25+
2526 * Represents a title within MediaWiki.
2627 * Optionally may contain an interwiki designation or namespace.
2728 * @note This class can fetch various kinds of data from the database;
@@ -41,13 +42,7 @@
4243 */
4344 const CACHE_MAX = 1000;
4445
45 - /**
46 - * Used to be GAID_FOR_UPDATE define. Used with getArticleID() and friends
47 - * to use the master DB
48 - */
49 - const GAID_FOR_UPDATE = 1;
5046
51 -
5247 /**
5348 * @name Private member variables
5449 * Please use the accessor functions instead.
@@ -73,11 +68,11 @@
7469 var $mCascadeSources; ///< Where are the cascading restrictions coming from on this page?
7570 var $mRestrictionsLoaded = false; ///< Boolean for initialisation on demand
7671 var $mPrefixedText; ///< Text form including namespace/interwiki, initialised on demand
77 - var $mTitleProtection; ///< Cached value for getTitleProtection (create protection)
 72+ var $mTitleProtection; ///< Cached value of getTitleProtection
7873 # Don't change the following default, NS_MAIN is hardcoded in several
7974 # places. See bug 696.
8075 var $mDefaultNamespace = NS_MAIN; // /< Namespace index when there is no namespace
81 - # Zero except in {{transclusion}} tags
 76+ # Zero except in {{transclusion}} tags
8277 var $mWatched = null; // /< Is $wgUser watching this page? null if unfilled, accessed through userIsWatching()
8378 var $mLength = -1; // /< The page length, 0 for special pages
8479 var $mRedirect = null; // /< Is the article at this title a redirect?
@@ -88,16 +83,17 @@
8984
9085 /**
9186 * Constructor
 87+ * @private
9288 */
93 - /*protected*/ function __construct() { }
 89+ /* private */ function __construct() { }
9490
9591 /**
9692 * Create a new Title from a prefixed DB key
9793 *
98 - * @param $key String the database key, which has underscores
 94+ * @param $key \type{\string} The database key, which has underscores
9995 * instead of spaces, possibly including namespace and
10096 * interwiki prefixes
101 - * @return Title, or NULL on an error
 97+ * @return \type{Title} the new object, or NULL on an error
10298 */
10399 public static function newFromDBkey( $key ) {
104100 $t = new Title();
@@ -113,13 +109,13 @@
114110 * Create a new Title from text, such as what one would find in a link. De-
115111 * codes any HTML entities in the text.
116112 *
117 - * @param $text String the link text; spaces, prefixes, and an
 113+ * @param $text string The link text; spaces, prefixes, and an
118114 * initial ':' indicating the main namespace are accepted.
119 - * @param $defaultNamespace Int the namespace to use if none is speci-
 115+ * @param $defaultNamespace int The namespace to use if none is speci-
120116 * fied by a prefix. If you want to force a specific namespace even if
121117 * $text might begin with a namespace prefix, use makeTitle() or
122118 * makeTitleSafe().
123 - * @return Title, or null on an error.
 119+ * @return Title The new object, or null on an error.
124120 */
125121 public static function newFromText( $text, $defaultNamespace = NS_MAIN ) {
126122 if ( is_object( $text ) ) {
@@ -138,7 +134,9 @@
139135 return Title::$titleCache[$text];
140136 }
141137
142 - # Convert things like &eacute; &#257; or &#x3017; into normalized (bug 14952) text
 138+ /**
 139+ * Convert things like &eacute; &#257; or &#x3017; into normalized(bug 14952) text
 140+ */
143141 $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
144142
145143 $t = new Title();
@@ -175,8 +173,8 @@
176174 * Create a new Title from URL-encoded text. Ensures that
177175 * the given title's length does not exceed the maximum.
178176 *
179 - * @param $url String the title, as might be taken from a URL
180 - * @return Title the new object, or NULL on an error
 177+ * @param $url \type{\string} the title, as might be taken from a URL
 178+ * @return \type{Title} the new object, or NULL on an error
181179 */
182180 public static function newFromURL( $url ) {
183181 global $wgLegalTitleChars;
@@ -200,12 +198,12 @@
201199 /**
202200 * Create a new Title from an article ID
203201 *
204 - * @param $id Int the page_id corresponding to the Title to create
205 - * @param $flags Int use Title::GAID_FOR_UPDATE to use master
206 - * @return Title the new object, or NULL on an error
 202+ * @param $id \type{\int} the page_id corresponding to the Title to create
 203+ * @param $flags \type{\int} use GAID_FOR_UPDATE to use master
 204+ * @return \type{Title} the new object, or NULL on an error
207205 */
208206 public static function newFromID( $id, $flags = 0 ) {
209 - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
 207+ $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
210208 $row = $db->selectRow( 'page', '*', array( 'page_id' => $id ), __METHOD__ );
211209 if ( $row !== false ) {
212210 $title = Title::newFromRow( $row );
@@ -218,15 +216,15 @@
219217 /**
220218 * Make an array of titles from an array of IDs
221219 *
222 - * @param $ids Array of Int Array of IDs
223 - * @return Array of Titles
 220+ * @param $ids \type{\arrayof{\int}} Array of IDs
 221+ * @return \type{\arrayof{Title}} Array of Titles
224222 */
225223 public static function newFromIDs( $ids ) {
226224 if ( !count( $ids ) ) {
227225 return array();
228226 }
229227 $dbr = wfGetDB( DB_SLAVE );
230 -
 228+
231229 $res = $dbr->select(
232230 'page',
233231 array(
@@ -247,8 +245,8 @@
248246 /**
249247 * Make a Title object from a DB row
250248 *
251 - * @param $row Object database row (needs at least page_title,page_namespace)
252 - * @return Title corresponding Title
 249+ * @param $row \type{Row} (needs at least page_title,page_namespace)
 250+ * @return \type{Title} corresponding Title
253251 */
254252 public static function newFromRow( $row ) {
255253 $t = self::makeTitle( $row->page_namespace, $row->page_title );
@@ -288,11 +286,11 @@
289287 * For convenience, spaces are converted to underscores so that
290288 * eg user_text fields can be used directly.
291289 *
292 - * @param $ns Int the namespace of the article
293 - * @param $title String the unprefixed database key form
294 - * @param $fragment String the link fragment (after the "#")
295 - * @param $interwiki String the interwiki prefix
296 - * @return Title the new object
 290+ * @param $ns \type{\int} the namespace of the article
 291+ * @param $title \type{\string} the unprefixed database key form
 292+ * @param $fragment \type{\string} The link fragment (after the "#")
 293+ * @param $interwiki \type{\string} The interwiki prefix
 294+ * @return \type{Title} the new object
297295 */
298296 public static function &makeTitle( $ns, $title, $fragment = '', $interwiki = '' ) {
299297 $t = new Title();
@@ -311,11 +309,11 @@
312310 * The parameters will be checked for validity, which is a bit slower
313311 * than makeTitle() but safer for user-provided data.
314312 *
315 - * @param $ns Int the namespace of the article
316 - * @param $title String database key form
317 - * @param $fragment String the link fragment (after the "#")
318 - * @param $interwiki String interwiki prefix
319 - * @return Title the new object, or NULL on an error
 313+ * @param $ns \type{\int} the namespace of the article
 314+ * @param $title \type{\string} the database key form
 315+ * @param $fragment \type{\string} The link fragment (after the "#")
 316+ * @param $interwiki \type{\string} The interwiki prefix
 317+ * @return \type{Title} the new object, or NULL on an error
320318 */
321319 public static function makeTitleSafe( $ns, $title, $fragment = '', $interwiki = '' ) {
322320 $t = new Title();
@@ -330,7 +328,7 @@
331329 /**
332330 * Create a new Title for the Main Page
333331 *
334 - * @return Title the new object
 332+ * @return \type{Title} the new object
335333 */
336334 public static function newMainPage() {
337335 $title = Title::newFromText( wfMsgForContent( 'mainpage' ) );
@@ -347,8 +345,8 @@
348346 * This will only return the very next target, useful for
349347 * the redirect table and other checks that don't need full recursion
350348 *
351 - * @param $text String: Text with possible redirect
352 - * @return Title: The corresponding Title
 349+ * @param $text \type{\string} Text with possible redirect
 350+ * @return \type{Title} The corresponding Title
353351 */
354352 public static function newFromRedirect( $text ) {
355353 return self::newFromRedirectInternal( $text );
@@ -360,8 +358,8 @@
361359 * This will recurse down $wgMaxRedirects times or until a non-redirect target is hit
362360 * in order to provide (hopefully) the Title of the final destination instead of another redirect
363361 *
364 - * @param $text String Text with possible redirect
365 - * @return Title
 362+ * @param $text \type{\string} Text with possible redirect
 363+ * @return \type{Title} The corresponding Title
366364 */
367365 public static function newFromRedirectRecurse( $text ) {
368366 $titles = self::newFromRedirectArray( $text );
@@ -374,11 +372,15 @@
375373 * The last element in the array is the final destination after all redirects
376374 * have been resolved (up to $wgMaxRedirects times)
377375 *
378 - * @param $text String Text with possible redirect
379 - * @return Array of Titles, with the destination last
 376+ * @param $text \type{\string} Text with possible redirect
 377+ * @return \type{\array} Array of Titles, with the destination last
380378 */
381379 public static function newFromRedirectArray( $text ) {
382380 global $wgMaxRedirects;
 381+ // are redirects disabled?
 382+ if ( $wgMaxRedirects < 1 ) {
 383+ return null;
 384+ }
383385 $title = self::newFromRedirectInternal( $text );
384386 if ( is_null( $title ) ) {
385387 return null;
@@ -409,15 +411,10 @@
410412 * Really extract the redirect destination
411413 * Do not call this function directly, use one of the newFromRedirect* functions above
412414 *
413 - * @param $text String Text with possible redirect
414 - * @return Title
 415+ * @param $text \type{\string} Text with possible redirect
 416+ * @return \type{Title} The corresponding Title
415417 */
416418 protected static function newFromRedirectInternal( $text ) {
417 - global $wgMaxRedirects;
418 - if ( $wgMaxRedirects < 1 ) {
419 - //redirects are disabled, so quit early
420 - return null;
421 - }
422419 $redir = MagicWord::get( 'redirect' );
423420 $text = trim( $text );
424421 if ( $redir->matchStartAndRemove( $text ) ) {
@@ -430,7 +427,9 @@
431428 // and URL-decode links
432429 if ( strpos( $m[1], '%' ) !== false ) {
433430 // Match behavior of inline link parsing here;
434 - $m[1] = rawurldecode( ltrim( $m[1], ':' ) );
 431+ // don't interpret + as " " most of the time!
 432+ // It might be safe to just use rawurldecode instead, though.
 433+ $m[1] = urldecode( ltrim( $m[1], ':' ) );
435434 }
436435 $title = Title::newFromText( $m[1] );
437436 // If the title is a redirect to bad special pages or is invalid, return null
@@ -450,8 +449,9 @@
451450 /**
452451 * Get the prefixed DB key associated with an ID
453452 *
454 - * @param $id Int the page_id of the article
455 - * @return Title an object representing the article, or NULL if no such article was found
 453+ * @param $id \type{\int} the page_id of the article
 454+ * @return \type{Title} an object representing the article, or NULL
 455+ * if no such article was found
456456 */
457457 public static function nameOf( $id ) {
458458 $dbr = wfGetDB( DB_SLAVE );
@@ -473,7 +473,7 @@
474474 /**
475475 * Get a regex character class describing the legal characters in a link
476476 *
477 - * @return String the list of characters, not delimited
 477+ * @return \type{\string} the list of characters, not delimited
478478 */
479479 public static function legalChars() {
480480 global $wgLegalTitleChars;
@@ -484,9 +484,10 @@
485485 * Get a string representation of a title suitable for
486486 * including in a search index
487487 *
488 - * @param $ns Int a namespace index
489 - * @param $title String text-form main part
490 - * @return String a stripped-down title string ready for the search index
 488+ * @param $ns \type{\int} a namespace index
 489+ * @param $title \type{\string} text-form main part
 490+ * @return \type{\string} a stripped-down title string ready for the
 491+ * search index
491492 */
492493 public static function indexTitle( $ns, $title ) {
493494 global $wgContLang;
@@ -511,11 +512,11 @@
512513 /**
513514 * Make a prefixed DB key from a DB key and a namespace index
514515 *
515 - * @param $ns Int numerical representation of the namespace
516 - * @param $title String the DB key form the title
517 - * @param $fragment String The link fragment (after the "#")
518 - * @param $interwiki String The interwiki prefix
519 - * @return String the prefixed form of the title
 516+ * @param $ns \type{\int} numerical representation of the namespace
 517+ * @param $title \type{\string} the DB key form the title
 518+ * @param $fragment \type{\string} The link fragment (after the "#")
 519+ * @param $interwiki \type{\string} The interwiki prefix
 520+ * @return \type{\string} the prefixed form of the title
520521 */
521522 public static function makeName( $ns, $title, $fragment = '', $interwiki = '' ) {
522523 global $wgContLang;
@@ -535,7 +536,8 @@
536537 * Determine whether the object refers to a page within
537538 * this project.
538539 *
539 - * @return Bool TRUE if this is an in-project interwiki link or a wikilink, FALSE otherwise
 540+ * @return \type{\bool} TRUE if this is an in-project interwiki link
 541+ * or a wikilink, FALSE otherwise
540542 */
541543 public function isLocal() {
542544 if ( $this->mInterwiki != '' ) {
@@ -549,7 +551,7 @@
550552 * Determine whether the object refers to a page within
551553 * this project and is transcludable.
552554 *
553 - * @return Bool TRUE if this is transcludable
 555+ * @return \type{\bool} TRUE if this is transcludable
554556 */
555557 public function isTrans() {
556558 if ( $this->mInterwiki == '' ) {
@@ -558,11 +560,25 @@
559561
560562 return Interwiki::fetch( $this->mInterwiki )->isTranscludable();
561563 }
 564+
 565+ /**
 566+ * Returns the API URL of the distant wiki
 567+ * which owns the object.
 568+ *
 569+ * @return \type{\string} the API URL
 570+ */
 571+ public function getTransAPI() {
 572+ if ( $this->mInterwiki == '' )
 573+ return false;
562574
 575+ return Interwiki::fetch( $this->mInterwiki )->getAPI();
 576+ }
 577+
563578 /**
564 - * Returns the DB name of the distant wiki which owns the object.
 579+ * Returns the DB name of the distant wiki
 580+ * which owns the object.
565581 *
566 - * @return String the DB name
 582+ * @return \type{\string} the DB name
567583 */
568584 public function getTransWikiID() {
569585 if ( $this->mInterwiki == '' ) {
@@ -594,35 +610,35 @@
595611 /**
596612 * Get the text form (spaces not underscores) of the main part
597613 *
598 - * @return String Main part of the title
 614+ * @return \type{\string} Main part of the title
599615 */
600616 public function getText() { return $this->mTextform; }
601617
602618 /**
603619 * Get the URL-encoded form of the main part
604620 *
605 - * @return String Main part of the title, URL-encoded
 621+ * @return \type{\string} Main part of the title, URL-encoded
606622 */
607623 public function getPartialURL() { return $this->mUrlform; }
608624
609625 /**
610626 * Get the main part with underscores
611627 *
612 - * @return String: Main part of the title, with underscores
 628+ * @return \type{\string} Main part of the title, with underscores
613629 */
614630 public function getDBkey() { return $this->mDbkeyform; }
615631
616632 /**
617 - * Get the namespace index, i.e. one of the NS_xxxx constants.
 633+ * Get the namespace index, i.e.\ one of the NS_xxxx constants.
618634 *
619 - * @return Integer: Namespace index
 635+ * @return \type{\int} Namespace index
620636 */
621637 public function getNamespace() { return $this->mNamespace; }
622638
623639 /**
624640 * Get the namespace text
625641 *
626 - * @return String: Namespace text
 642+ * @return \type{\string} Namespace text
627643 */
628644 public function getNsText() {
629645 global $wgContLang;
@@ -638,20 +654,13 @@
639655 return MWNamespace::getCanonicalName( $this->mNamespace );
640656 }
641657 }
642 -
643 - if ( $wgContLang->needsGenderDistinction() &&
644 - MWNamespace::hasGenderDistinction( $this->mNamespace ) ) {
645 - $gender = GenderCache::singleton()->getGenderOf( $this->getText(), __METHOD__ );
646 - return $wgContLang->getGenderNsText( $this->mNamespace, $gender );
647 - }
648 -
649658 return $wgContLang->getNsText( $this->mNamespace );
650659 }
651660
652661 /**
653662 * Get the DB key with the initial letter case as specified by the user
654663 *
655 - * @return String DB key
 664+ * @return \type{\string} DB key
656665 */
657666 function getUserCaseDBKey() {
658667 return $this->mUserCaseDBKey;
@@ -660,7 +669,7 @@
661670 /**
662671 * Get the namespace text of the subject (rather than talk) page
663672 *
664 - * @return String Namespace text
 673+ * @return \type{\string} Namespace text
665674 */
666675 public function getSubjectNsText() {
667676 global $wgContLang;
@@ -670,7 +679,7 @@
671680 /**
672681 * Get the namespace text of the talk page
673682 *
674 - * @return String Namespace text
 683+ * @return \type{\string} Namespace text
675684 */
676685 public function getTalkNsText() {
677686 global $wgContLang;
@@ -680,7 +689,7 @@
681690 /**
682691 * Could this title have a corresponding talk page?
683692 *
684 - * @return Bool TRUE or FALSE
 693+ * @return \type{\bool} TRUE or FALSE
685694 */
686695 public function canTalk() {
687696 return( MWNamespace::canTalk( $this->mNamespace ) );
@@ -689,20 +698,20 @@
690699 /**
691700 * Get the interwiki prefix (or null string)
692701 *
693 - * @return String Interwiki prefix
 702+ * @return \type{\string} Interwiki prefix
694703 */
695704 public function getInterwiki() { return $this->mInterwiki; }
696705
697706 /**
698707 * Get the Title fragment (i.e.\ the bit after the #) in text form
699708 *
700 - * @return String Title fragment
 709+ * @return \type{\string} Title fragment
701710 */
702711 public function getFragment() { return $this->mFragment; }
703712
704713 /**
705714 * Get the fragment in URL form, including the "#" character if there is one
706 - * @return String Fragment in URL form
 715+ * @return \type{\string} Fragment in URL form
707716 */
708717 public function getFragmentForURL() {
709718 if ( $this->mFragment == '' ) {
@@ -715,14 +724,14 @@
716725 /**
717726 * Get the default namespace index, for when there is no namespace
718727 *
719 - * @return Int Default namespace index
 728+ * @return \type{\int} Default namespace index
720729 */
721730 public function getDefaultNamespace() { return $this->mDefaultNamespace; }
722731
723732 /**
724733 * Get title for search index
725734 *
726 - * @return String a stripped-down title string ready for the
 735+ * @return \type{\string} a stripped-down title string ready for the
727736 * search index
728737 */
729738 public function getIndexTitle() {
@@ -732,7 +741,7 @@
733742 /**
734743 * Get the prefixed database key form
735744 *
736 - * @return String the prefixed title, with underscores and
 745+ * @return \type{\string} the prefixed title, with underscores and
737746 * any interwiki and namespace prefixes
738747 */
739748 public function getPrefixedDBkey() {
@@ -745,7 +754,7 @@
746755 * Get the prefixed title with spaces.
747756 * This is the form usually used for display
748757 *
749 - * @return String the prefixed title, with spaces
 758+ * @return \type{\string} the prefixed title, with spaces
750759 */
751760 public function getPrefixedText() {
752761 // @todo FIXME: Bad usage of empty() ?
@@ -775,7 +784,8 @@
776785 * Get the prefixed title with spaces, plus any fragment
777786 * (part beginning with '#')
778787 *
779 - * @return String the prefixed title, with spaces and the fragment, including '#'
 788+ * @return \type{\string} the prefixed title, with spaces and
 789+ * the fragment, including '#'
780790 */
781791 public function getFullText() {
782792 $text = $this->getPrefixedText();
@@ -788,7 +798,7 @@
789799 /**
790800 * Get the base page name, i.e. the leftmost part before any slashes
791801 *
792 - * @return String Base name
 802+ * @return \type{\string} Base name
793803 */
794804 public function getBaseText() {
795805 if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
@@ -806,7 +816,7 @@
807817 /**
808818 * Get the lowest-level subpage name, i.e. the rightmost part after any slashes
809819 *
810 - * @return String Subpage name
 820+ * @return \type{\string} Subpage name
811821 */
812822 public function getSubpageText() {
813823 if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
@@ -819,7 +829,7 @@
820830 /**
821831 * Get a URL-encoded form of the subpage text
822832 *
823 - * @return String URL-encoded subpage name
 833+ * @return \type{\string} URL-encoded subpage name
824834 */
825835 public function getSubpageUrlForm() {
826836 $text = $this->getSubpageText();
@@ -830,7 +840,7 @@
831841 /**
832842 * Get a URL-encoded title (not an actual URL) including interwiki
833843 *
834 - * @return String the URL-encoded form
 844+ * @return \type{\string} the URL-encoded form
835845 */
836846 public function getPrefixedURL() {
837847 $s = $this->prefix( $this->mDbkeyform );
@@ -845,8 +855,8 @@
846856 * @param $query \twotypes{\string,\array} an optional query string, not used for interwiki
847857 * links. Can be specified as an associative array as well, e.g.,
848858 * array( 'action' => 'edit' ) (keys and values will be URL-escaped).
849 - * @param $variant String language variant of url (for sr, zh..)
850 - * @return String the URL
 859+ * @param $variant \type{\string} language variant of url (for sr, zh..)
 860+ * @return \type{\string} the URL
851861 */
852862 public function getFullURL( $query = '', $variant = false ) {
853863 global $wgServer, $wgRequest;
@@ -892,17 +902,25 @@
893903 * $wgArticlePath will be used. Can be specified as an associative array
894904 * as well, e.g., array( 'action' => 'edit' ) (keys and values will be
895905 * URL-escaped).
896 - * @param $variant String language variant of url (for sr, zh..)
897 - * @return String the URL
 906+ * @param $variant \type{\string} language variant of url (for sr, zh..)
 907+ * @return \type{\string} the URL
898908 */
899909 public function getLocalURL( $query = '', $variant = false ) {
900910 global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
901 - global $wgVariantArticlePath, $wgContLang;
 911+ global $wgVariantArticlePath, $wgContLang, $wgUser;
902912
903913 if ( is_array( $query ) ) {
904914 $query = wfArrayToCGI( $query );
905915 }
906916
 917+ // internal links should point to same variant as current page (only anonymous users)
 918+ if ( !$variant && $wgContLang->hasVariants() && !$wgUser->isLoggedIn() ) {
 919+ $pref = $wgContLang->getPreferredVariant( false );
 920+ if ( $pref != $wgContLang->getCode() ) {
 921+ $variant = $pref;
 922+ }
 923+ }
 924+
907925 if ( $this->isExternal() ) {
908926 $url = $this->getFullURL();
909927 if ( $query ) {
@@ -974,12 +992,12 @@
975993 * The result obviously should not be URL-escaped, but does need to be
976994 * HTML-escaped if it's being output in HTML.
977995 *
978 - * @param $query Array of Strings An associative array of key => value pairs for the
 996+ * @param $query \type{\arrayof{\string}} An associative array of key => value pairs for the
979997 * query string. Keys and values will be escaped.
980 - * @param $variant String language variant of URL (for sr, zh..). Ignored
 998+ * @param $variant \type{\string} Language variant of URL (for sr, zh..). Ignored
981999 * for external links. Default is "false" (same variant as current page,
9821000 * for anonymous users).
983 - * @return String the URL
 1001+ * @return \type{\string} the URL
9841002 */
9851003 public function getLinkUrl( $query = array(), $variant = false ) {
9861004 wfProfileIn( __METHOD__ );
@@ -998,8 +1016,8 @@
9991017 * Get an HTML-escaped version of the URL form, suitable for
10001018 * using in a link, without a server name or fragment
10011019 *
1002 - * @param $query String an optional query string
1003 - * @return String the URL
 1020+ * @param $query \type{\string} an optional query string
 1021+ * @return \type{\string} the URL
10041022 */
10051023 public function escapeLocalURL( $query = '' ) {
10061024 return htmlspecialchars( $this->getLocalURL( $query ) );
@@ -1009,8 +1027,8 @@
10101028 * Get an HTML-escaped version of the URL form, suitable for
10111029 * using in a link, including the server name and fragment
10121030 *
1013 - * @param $query String an optional query string
1014 - * @return String the URL
 1031+ * @param $query \type{\string} an optional query string
 1032+ * @return \type{\string} the URL
10151033 */
10161034 public function escapeFullURL( $query = '' ) {
10171035 return htmlspecialchars( $this->getFullURL( $query ) );
@@ -1021,14 +1039,13 @@
10221040 * - Used in various Squid-related code, in case we have a different
10231041 * internal hostname for the server from the exposed one.
10241042 *
1025 - * @param $query String an optional query string
1026 - * @param $variant String language variant of url (for sr, zh..)
1027 - * @return String the URL
 1043+ * @param $query \type{\string} an optional query string
 1044+ * @param $variant \type{\string} language variant of url (for sr, zh..)
 1045+ * @return \type{\string} the URL
10281046 */
10291047 public function getInternalURL( $query = '', $variant = false ) {
1030 - global $wgInternalServer, $wgServer;
1031 - $server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
1032 - $url = $server . $this->getLocalURL( $query, $variant );
 1048+ global $wgInternalServer;
 1049+ $url = $wgInternalServer . $this->getLocalURL( $query, $variant );
10331050 wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
10341051 return $url;
10351052 }
@@ -1036,7 +1053,7 @@
10371054 /**
10381055 * Get the edit URL for this Title
10391056 *
1040 - * @return String the URL, or a null string if this is an
 1057+ * @return \type{\string} the URL, or a null string if this is an
10411058 * interwiki link
10421059 */
10431060 public function getEditURL() {
@@ -1052,7 +1069,7 @@
10531070 * Get the HTML-escaped displayable text form.
10541071 * Used for the title field in <a> tags.
10551072 *
1056 - * @return String the text, including any prefixes
 1073+ * @return \type{\string} the text, including any prefixes
10571074 */
10581075 public function getEscapedText() {
10591076 return htmlspecialchars( $this->getPrefixedText() );
@@ -1061,7 +1078,7 @@
10621079 /**
10631080 * Is this Title interwiki?
10641081 *
1065 - * @return Bool
 1082+ * @return \type{\bool}
10661083 */
10671084 public function isExternal() {
10681085 return ( $this->mInterwiki != '' );
@@ -1070,8 +1087,8 @@
10711088 /**
10721089 * Is this page "semi-protected" - the *only* protection is autoconfirm?
10731090 *
1074 - * @param $action String Action to check (default: edit)
1075 - * @return Bool
 1091+ * @param $action \type{\string} Action to check (default: edit)
 1092+ * @return \type{\bool}
10761093 */
10771094 public function isSemiProtected( $action = 'edit' ) {
10781095 if ( $this->exists() ) {
@@ -1096,9 +1113,9 @@
10971114 /**
10981115 * Does the title correspond to a protected article?
10991116 *
1100 - * @param $action String the action the page is protected from,
 1117+ * @param $action \type{\string} the action the page is protected from,
11011118 * by default checks all actions.
1102 - * @return Bool
 1119+ * @return \type{\bool}
11031120 */
11041121 public function isProtected( $action = '' ) {
11051122 global $wgRestrictionLevels;
@@ -1128,7 +1145,7 @@
11291146 /**
11301147 * Is this a conversion table for the LanguageConverter?
11311148 *
1132 - * @return Bool
 1149+ * @return \type{\bool}
11331150 */
11341151 public function isConversionTable() {
11351152 if(
@@ -1145,7 +1162,7 @@
11461163 /**
11471164 * Is $wgUser watching this page?
11481165 *
1149 - * @return Bool
 1166+ * @return \type{\bool}
11501167 */
11511168 public function userIsWatching() {
11521169 global $wgUser;
@@ -1170,26 +1187,25 @@
11711188 *
11721189 * May provide false positives, but should never provide a false negative.
11731190 *
1174 - * @param $action String action that permission needs to be checked for
1175 - * @return Bool
 1191+ * @param $action \type{\string} action that permission needs to be checked for
 1192+ * @return \type{\bool}
11761193 */
11771194 public function quickUserCan( $action ) {
11781195 return $this->userCan( $action, false );
11791196 }
11801197
11811198 /**
1182 - * Determines if $user is unable to edit this page because it has been protected
 1199+ * Determines if $wgUser is unable to edit this page because it has been protected
11831200 * by $wgNamespaceProtection.
11841201 *
11851202 * @param $user User object to check permissions
11861203 * @return Bool
11871204 */
1188 - public function isNamespaceProtected( User $user ) {
1189 - global $wgNamespaceProtection;
1190 -
 1205+ public function isNamespaceProtected() {
 1206+ global $wgNamespaceProtection, $wgUser;
11911207 if ( isset( $wgNamespaceProtection[$this->mNamespace] ) ) {
11921208 foreach ( (array)$wgNamespaceProtection[$this->mNamespace] as $right ) {
1193 - if ( $right != '' && !$user->isAllowed( $right ) ) {
 1209+ if ( $right != '' && !$wgUser->isAllowed( $right ) ) {
11941210 return true;
11951211 }
11961212 }
@@ -1200,9 +1216,9 @@
12011217 /**
12021218 * Can $wgUser perform $action on this page?
12031219 *
1204 - * @param $action String action that permission needs to be checked for
1205 - * @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries.
1206 - * @return Bool
 1220+ * @param $action \type{\string} action that permission needs to be checked for
 1221+ * @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
 1222+ * @return \type{\bool}
12071223 */
12081224 public function userCan( $action, $doExpensiveQueries = true ) {
12091225 global $wgUser;
@@ -1222,6 +1238,14 @@
12231239 * @return Array of arguments to wfMsg to explain permissions problems.
12241240 */
12251241 public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) {
 1242+ if ( !StubObject::isRealObject( $user ) ) {
 1243+ // Since StubObject is always used on globals, we can
 1244+ // unstub $wgUser here and set $user = $wgUser
 1245+ global $wgUser;
 1246+ $wgUser->_unstub( '', 5 );
 1247+ $user = $wgUser;
 1248+ }
 1249+
12261250 $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries );
12271251
12281252 // Remove the errors being ignored.
@@ -1292,6 +1316,8 @@
12931317 $errors[] = array( 'cant-move-to-user-page' );
12941318 }
12951319 } elseif ( !$user->isAllowed( $action, $ns ) ) {
 1320+ $return = null;
 1321+
12961322 // We avoid expensive display logic for quickUserCan's and such
12971323 $groups = false;
12981324 if ( !$short ) {
@@ -1342,18 +1368,10 @@
13431369
13441370 /**
13451371 * Check various permission hooks
1346 - *
1347 - * @param $action String the action to check
1348 - * @param $user User user to check
1349 - * @param $errors Array list of current errors
1350 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1351 - * @param $short Boolean short circuit on first error
1352 - *
1353 - * @return Array list of errors
 1372+ * @see checkQuickPermissions for parameter information
13541373 */
13551374 private function checkPermissionHooks( $action, $user, $errors, $doExpensiveQueries, $short ) {
13561375 // Use getUserPermissionsErrors instead
1357 - $result = '';
13581376 if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
13591377 return $result ? array() : array( array( 'badaccess-group0' ) );
13601378 }
@@ -1372,14 +1390,7 @@
13731391
13741392 /**
13751393 * Check permissions on special pages & namespaces
1376 - *
1377 - * @param $action String the action to check
1378 - * @param $user User user to check
1379 - * @param $errors Array list of current errors
1380 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1381 - * @param $short Boolean short circuit on first error
1382 - *
1383 - * @return Array list of errors
 1394+ * @see checkQuickPermissions for parameter information
13841395 */
13851396 private function checkSpecialsAndNSPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
13861397 # Only 'createaccount' and 'execute' can be performed on
@@ -1390,7 +1401,7 @@
13911402 }
13921403
13931404 # Check $wgNamespaceProtection for restricted namespaces
1394 - if ( $this->isNamespaceProtected( $user ) ) {
 1405+ if ( $this->isNamespaceProtected() ) {
13951406 $ns = $this->mNamespace == NS_MAIN ?
13961407 wfMsg( 'nstab-main' ) : $this->getNsText();
13971408 $errors[] = $this->mNamespace == NS_MEDIAWIKI ?
@@ -1402,14 +1413,7 @@
14031414
14041415 /**
14051416 * Check CSS/JS sub-page permissions
1406 - *
1407 - * @param $action String the action to check
1408 - * @param $user User user to check
1409 - * @param $errors Array list of current errors
1410 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1411 - * @param $short Boolean short circuit on first error
1412 - *
1413 - * @return Array list of errors
 1417+ * @see checkQuickPermissions for parameter information
14141418 */
14151419 private function checkCSSandJSPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
14161420 # Protect css/js subpages of user pages
@@ -1431,14 +1435,7 @@
14321436 * Check against page_restrictions table requirements on this
14331437 * page. The user must possess all required rights for this
14341438 * action.
1435 - *
1436 - * @param $action String the action to check
1437 - * @param $user User user to check
1438 - * @param $errors Array list of current errors
1439 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1440 - * @param $short Boolean short circuit on first error
1441 - *
1442 - * @return Array list of errors
 1439+ * @see checkQuickPermissions for parameter information
14431440 */
14441441 private function checkPageRestrictions( $action, $user, $errors, $doExpensiveQueries, $short ) {
14451442 foreach ( $this->getRestrictions( $action ) as $right ) {
@@ -1465,14 +1462,7 @@
14661463
14671464 /**
14681465 * Check restrictions on cascading pages.
1469 - *
1470 - * @param $action String the action to check
1471 - * @param $user User to check
1472 - * @param $errors Array list of current errors
1473 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1474 - * @param $short Boolean short circuit on first error
1475 - *
1476 - * @return Array list of errors
 1466+ * @see checkQuickPermissions for parameter information
14771467 */
14781468 private function checkCascadingSourcesRestrictions( $action, $user, $errors, $doExpensiveQueries, $short ) {
14791469 if ( $doExpensiveQueries && !$this->isCssJsSubpage() ) {
@@ -1504,14 +1494,7 @@
15051495
15061496 /**
15071497 * Check action permissions not already checked in checkQuickPermissions
1508 - *
1509 - * @param $action String the action to check
1510 - * @param $user User to check
1511 - * @param $errors Array list of current errors
1512 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1513 - * @param $short Boolean short circuit on first error
1514 - *
1515 - * @return Array list of errors
 1498+ * @see checkQuickPermissions for parameter information
15161499 */
15171500 private function checkActionPermissions( $action, $user, $errors, $doExpensiveQueries, $short ) {
15181501 if ( $action == 'protect' ) {
@@ -1552,14 +1535,7 @@
15531536
15541537 /**
15551538 * Check that the user isn't blocked from editting.
1556 - *
1557 - * @param $action String the action to check
1558 - * @param $user User to check
1559 - * @param $errors Array list of current errors
1560 - * @param $doExpensiveQueries Boolean whether or not to perform expensive queries
1561 - * @param $short Boolean short circuit on first error
1562 - *
1563 - * @return Array list of errors
 1539+ * @see checkQuickPermissions for parameter information
15641540 */
15651541 private function checkUserBlock( $action, $user, $errors, $doExpensiveQueries, $short ) {
15661542 if( !$doExpensiveQueries ) {
@@ -1572,14 +1548,8 @@
15731549 $errors[] = array( 'confirmedittext' );
15741550 }
15751551
1576 - if ( in_array( $action, array( 'read', 'createaccount', 'unblock' ) ) ){
1577 - // Edit blocks should not affect reading.
1578 - // Account creation blocks handled at userlogin.
1579 - // Unblocking handled in SpecialUnblock
1580 - } elseif( ( $action == 'edit' || $action == 'create' ) && !$user->isBlockedFrom( $this ) ){
1581 - // Don't block the user from editing their own talk page unless they've been
1582 - // explicitly blocked from that too.
1583 - } elseif( $user->isBlocked() && $user->mBlock->prevents( $action ) !== false ) {
 1552+ // Edit blocks should not affect reading. Account creation blocks handled at userlogin.
 1553+ if ( $action != 'read' && $action != 'createaccount' && $user->isBlockedFrom( $this ) ) {
15841554 $block = $user->mBlock;
15851555
15861556 // This is from OutputPage::blockedPage
@@ -1599,16 +1569,29 @@
16001570 }
16011571
16021572 $link = '[[' . $wgContLang->getNsText( NS_USER ) . ":{$name}|{$name}]]";
1603 - $blockid = $block->getId();
 1573+ $blockid = $block->mId;
16041574 $blockExpiry = $user->mBlock->mExpiry;
16051575 $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $user->mBlock->mTimestamp ), true );
16061576 if ( $blockExpiry == 'infinity' ) {
1607 - $blockExpiry = wfMessage( 'infiniteblock' )->text();
 1577+ // Entry in database (table ipblocks) is 'infinity' but 'ipboptions' uses 'infinite' or 'indefinite'
 1578+ $scBlockExpiryOptions = wfMsg( 'ipboptions' );
 1579+
 1580+ foreach ( explode( ',', $scBlockExpiryOptions ) as $option ) {
 1581+ if ( !strpos( $option, ':' ) )
 1582+ continue;
 1583+
 1584+ list( $show, $value ) = explode( ':', $option );
 1585+
 1586+ if ( $value == 'infinite' || $value == 'indefinite' ) {
 1587+ $blockExpiry = $show;
 1588+ break;
 1589+ }
 1590+ }
16081591 } else {
16091592 $blockExpiry = $wgLang->timeanddate( wfTimestamp( TS_MW, $blockExpiry ), true );
16101593 }
16111594
1612 - $intended = strval( $user->mBlock->getTarget() );
 1595+ $intended = $user->mBlock->mAddress;
16131596
16141597 $errors[] = array( ( $block->mAuto ? 'autoblockedtext' : 'blockedtext' ), $link, $reason, $ip, $name,
16151598 $blockid, $blockExpiry, $intended, $blockTimestamp );
@@ -1622,11 +1605,11 @@
16231606 * which checks ONLY that previously checked by userCan (i.e. it leaves out
16241607 * checks on wfReadOnly() and blocks)
16251608 *
1626 - * @param $action String action that permission needs to be checked for
1627 - * @param $user User to check
1628 - * @param $doExpensiveQueries Bool Set this to false to avoid doing unnecessary queries.
1629 - * @param $short Bool Set this to true to stop after the first permission error.
1630 - * @return Array of arrays of the arguments to wfMsg to explain permissions problems.
 1609+ * @param $action \type{\string} action that permission needs to be checked for
 1610+ * @param $user \type{User} user to check
 1611+ * @param $doExpensiveQueries \type{\bool} Set this to false to avoid doing unnecessary queries.
 1612+ * @param $short \type{\bool} Set this to true to stop after the first permission error.
 1613+ * @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems.
16311614 */
16321615 protected function getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries = true, $short = false ) {
16331616 wfProfileIn( __METHOD__ );
@@ -1655,9 +1638,8 @@
16561639
16571640 /**
16581641 * Is this title subject to title protection?
1659 - * Title protection is the one applied against creation of such title.
16601642 *
1661 - * @return Mixed An associative array representing any existent title
 1643+ * @return \type{\mixed} An associative array representing any existent title
16621644 * protection, or false if there's none.
16631645 */
16641646 private function getTitleProtection() {
@@ -1686,9 +1668,9 @@
16871669 /**
16881670 * Update the title protection status
16891671 *
1690 - * @param $create_perm String Permission required for creation
1691 - * @param $reason String Reason for protection
1692 - * @param $expiry String Expiry timestamp
 1672+ * @param $create_perm \type{\string} Permission required for creation
 1673+ * @param $reason \type{\string} Reason for protection
 1674+ * @param $expiry \type{\string} Expiry timestamp
16931675 * @return boolean true
16941676 */
16951677 public function updateTitleProtection( $create_perm, $reason, $expiry ) {
@@ -1704,10 +1686,10 @@
17051687
17061688 $dbw = wfGetDB( DB_MASTER );
17071689
1708 - $encodedExpiry = $dbw->encodeExpiry( $expiry );
 1690+ $encodedExpiry = Block::encodeExpiry( $expiry, $dbw );
17091691
17101692 $expiry_description = '';
1711 - if ( $encodedExpiry != $dbw->getInfinity() ) {
 1693+ if ( $encodedExpiry != 'infinity' ) {
17121694 $expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ),
17131695 $wgContLang->date( $expiry ) , $wgContLang->time( $expiry ) ) . ')';
17141696 } else {
@@ -1716,23 +1698,21 @@
17171699
17181700 # Update protection table
17191701 if ( $create_perm != '' ) {
1720 - $this->mTitleProtection = array(
 1702+ $dbw->replace( 'protected_titles', array( array( 'pt_namespace', 'pt_title' ) ),
 1703+ array(
17211704 'pt_namespace' => $namespace,
17221705 'pt_title' => $title,
17231706 'pt_create_perm' => $create_perm,
1724 - 'pt_timestamp' => $dbw->encodeExpiry( wfTimestampNow() ),
 1707+ 'pt_timestamp' => Block::encodeExpiry( wfTimestampNow(), $dbw ),
17251708 'pt_expiry' => $encodedExpiry,
17261709 'pt_user' => $wgUser->getId(),
17271710 'pt_reason' => $reason,
1728 - );
1729 - $dbw->replace( 'protected_titles', array( array( 'pt_namespace', 'pt_title' ) ),
1730 - $this->mTitleProtection, __METHOD__ );
 1711+ ), __METHOD__
 1712+ );
17311713 } else {
17321714 $dbw->delete( 'protected_titles', array( 'pt_namespace' => $namespace,
17331715 'pt_title' => $title ), __METHOD__ );
1734 - $this->mTitleProtection = false;
17351716 }
1736 -
17371717 # Update the protection log
17381718 if ( $dbw->affectedRows() ) {
17391719 $log = new LogPage( 'protect' );
@@ -1759,14 +1739,13 @@
17601740 array( 'pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey() ),
17611741 __METHOD__
17621742 );
1763 - $this->mTitleProtection = false;
17641743 }
17651744
17661745 /**
17671746 * Would anybody with sufficient privileges be able to move this page?
17681747 * Some pages just aren't movable.
17691748 *
1770 - * @return Bool TRUE or FALSE
 1749+ * @return \type{\bool} TRUE or FALSE
17711750 */
17721751 public function isMovable() {
17731752 return MWNamespace::isMovable( $this->getNamespace() ) && $this->getInterwiki() == '';
@@ -1775,7 +1754,7 @@
17761755 /**
17771756 * Can $wgUser read this page?
17781757 *
1779 - * @return Bool
 1758+ * @return \type{\bool}
17801759 * @todo fold these checks into userCan()
17811760 */
17821761 public function userCanRead() {
@@ -1823,36 +1802,47 @@
18241803 } else {
18251804 global $wgWhitelistRead;
18261805
1827 - # Always grant access to the login page.
1828 - # Even anons need to be able to log in.
1829 - if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'ChangePassword' ) ) {
 1806+ /**
 1807+ * Always grant access to the login page.
 1808+ * Even anons need to be able to log in.
 1809+ */
 1810+ if ( $this->isSpecial( 'Userlogin' ) || $this->isSpecial( 'Resetpass' ) ) {
18301811 return true;
18311812 }
18321813
1833 - # Bail out if there isn't whitelist
 1814+ /**
 1815+ * Bail out if there isn't whitelist
 1816+ */
18341817 if ( !is_array( $wgWhitelistRead ) ) {
18351818 return false;
18361819 }
18371820
1838 - # Check for explicit whitelisting
 1821+ /**
 1822+ * Check for explicit whitelisting
 1823+ */
18391824 $name = $this->getPrefixedText();
18401825 $dbName = $this->getPrefixedDBKey();
18411826 // Check with and without underscores
18421827 if ( in_array( $name, $wgWhitelistRead, true ) || in_array( $dbName, $wgWhitelistRead, true ) )
18431828 return true;
18441829
1845 - # Old settings might have the title prefixed with
1846 - # a colon for main-namespace pages
 1830+ /**
 1831+ * Old settings might have the title prefixed with
 1832+ * a colon for main-namespace pages
 1833+ */
18471834 if ( $this->getNamespace() == NS_MAIN ) {
18481835 if ( in_array( ':' . $name, $wgWhitelistRead ) ) {
18491836 return true;
18501837 }
18511838 }
18521839
1853 - # If it's a special page, ditch the subpage bit and check again
 1840+ /**
 1841+ * If it's a special page, ditch the subpage bit
 1842+ * and check again
 1843+ */
18541844 if ( $this->getNamespace() == NS_SPECIAL ) {
18551845 $name = $this->getDBkey();
1856 - list( $name, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $name );
 1846+ list( $name, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $name );
18571847 if ( $name === false ) {
18581848 # Invalid special page, but we show standard login required message
18591849 return false;
@@ -1869,22 +1859,9 @@
18701860 }
18711861
18721862 /**
1873 - * Is this the mainpage?
1874 - * @note Title::newFromText seams to be sufficiently optimized by the title
1875 - * cache that we don't need to over-optimize by doing direct comparisons and
1876 - * acidentally creating new bugs where $title->equals( Title::newFromText() )
1877 - * ends up reporting something differently than $title->isMainPage();
1878 - *
1879 - * @return Bool
1880 - */
1881 - public function isMainPage() {
1882 - return $this->equals( Title::newMainPage() );
1883 - }
1884 -
1885 - /**
18861863 * Is this a talk page of some sort?
18871864 *
1888 - * @return Bool
 1865+ * @return \type{\bool}
18891866 */
18901867 public function isTalkPage() {
18911868 return MWNamespace::isTalk( $this->getNamespace() );
@@ -1893,7 +1870,7 @@
18941871 /**
18951872 * Is this a subpage?
18961873 *
1897 - * @return Bool
 1874+ * @return \type{\bool}
18981875 */
18991876 public function isSubpage() {
19001877 return MWNamespace::hasSubpages( $this->mNamespace )
@@ -1904,7 +1881,7 @@
19051882 /**
19061883 * Does this have subpages? (Warning, usually requires an extra DB query.)
19071884 *
1908 - * @return Bool
 1885+ * @return \type{\bool}
19091886 */
19101887 public function hasSubpages() {
19111888 if ( !MWNamespace::hasSubpages( $this->mNamespace ) ) {
@@ -1930,7 +1907,7 @@
19311908 /**
19321909 * Get all subpages of this page.
19331910 *
1934 - * @param $limit Int maximum number of subpages to fetch; -1 for no limit
 1911+ * @param $limit Maximum number of subpages to fetch; -1 for no limit
19351912 * @return mixed TitleArray, or empty array if this page's namespace
19361913 * doesn't allow subpages
19371914 */
@@ -1960,7 +1937,7 @@
19611938 * Could this page contain custom CSS or JavaScript, based
19621939 * on the title?
19631940 *
1964 - * @return Bool
 1941+ * @return \type{\bool}
19651942 */
19661943 public function isCssOrJsPage() {
19671944 return $this->mNamespace == NS_MEDIAWIKI
@@ -1969,7 +1946,7 @@
19701947
19711948 /**
19721949 * Is this a .css or .js subpage of a user page?
1973 - * @return Bool
 1950+ * @return \type{\bool}
19741951 */
19751952 public function isCssJsSubpage() {
19761953 return ( NS_USER == $this->mNamespace and preg_match( "/\\/.*\\.(?:css|js)$/", $this->mTextform ) );
@@ -1977,12 +1954,21 @@
19781955
19791956 /**
19801957 * Is this a *valid* .css or .js subpage of a user page?
 1958+ * Check that the corresponding skin exists
19811959 *
1982 - * @return Bool
1983 - * @deprecated since 1.17
 1960+ * @return \type{\bool}
19841961 */
19851962 public function isValidCssJsSubpage() {
1986 - return $this->isCssJsSubpage();
 1963+ if ( $this->isCssJsSubpage() ) {
 1964+ $name = $this->getSkinFromCssJsSubpage();
 1965+ if ( $name == 'common' ) {
 1966+ return true;
 1967+ }
 1968+ $skinNames = Skin::getSkinNames();
 1969+ return array_key_exists( $name, $skinNames );
 1970+ } else {
 1971+ return false;
 1972+ }
19871973 }
19881974
19891975 /**
@@ -1999,7 +1985,7 @@
20001986 /**
20011987 * Is this a .css subpage of a user page?
20021988 *
2003 - * @return Bool
 1989+ * @return \type{\bool}
20041990 */
20051991 public function isCssSubpage() {
20061992 return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.css$/", $this->mTextform ) );
@@ -2008,7 +1994,7 @@
20091995 /**
20101996 * Is this a .js subpage of a user page?
20111997 *
2012 - * @return Bool
 1998+ * @return \type{\bool}
20131999 */
20142000 public function isJsSubpage() {
20152001 return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.js$/", $this->mTextform ) );
@@ -2045,7 +2031,7 @@
20462032 /**
20472033 * Cascading protection: Return true if cascading restrictions apply to this page, false if not.
20482034 *
2049 - * @return Bool If the page is subject to cascading restrictions.
 2035+ * @return \type{\bool} If the page is subject to cascading restrictions.
20502036 */
20512037 public function isCascadeProtected() {
20522038 list( $sources, /* $restrictions */ ) = $this->getCascadeProtectionSources( false );
@@ -2055,15 +2041,15 @@
20562042 /**
20572043 * Cascading protection: Get the source of any cascading restrictions on this page.
20582044 *
2059 - * @param $getPages Bool Whether or not to retrieve the actual pages
 2045+ * @param $getPages \type{\bool} Whether or not to retrieve the actual pages
20602046 * that the restrictions have come from.
2061 - * @return Mixed Array of Title objects of the pages from which cascading restrictions
2062 - * have come, false for none, or true if such restrictions exist, but $getPages
2063 - * was not set. The restriction array is an array of each type, each of which
2064 - * contains a array of unique groups.
 2047+ * @return \type{\arrayof{mixed title array, restriction array}} Array of the Title
 2048+ * objects of the pages from which cascading restrictions have come,
 2049+ * false for none, or true if such restrictions exist, but $getPages was not set.
 2050+ * The restriction array is an array of each type, each of which contains a
 2051+ * array of unique groups.
20652052 */
20662053 public function getCascadeProtectionSources( $getPages = true ) {
2067 - global $wgContLang;
20682054 $pagerestrictions = array();
20692055
20702056 if ( isset( $this->mCascadeSources ) && $getPages ) {
@@ -2109,7 +2095,7 @@
21102096 $purgeExpired = false;
21112097
21122098 foreach ( $res as $row ) {
2113 - $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
 2099+ $expiry = Block::decodeExpiry( $row->pr_expiry );
21142100 if ( $expiry > $now ) {
21152101 if ( $getPages ) {
21162102 $page_id = $row->pr_page;
@@ -2139,6 +2125,8 @@
21402126 Title::purgeExpiredRestrictions();
21412127 }
21422128
 2129+ wfProfileOut( __METHOD__ );
 2130+
21432131 if ( $getPages ) {
21442132 $this->mCascadeSources = $sources;
21452133 $this->mCascadingRestrictions = $pagerestrictions;
@@ -2146,7 +2134,6 @@
21472135 $this->mHasCascadingRestrictions = $sources;
21482136 }
21492137
2150 - wfProfileOut( __METHOD__ );
21512138 return array( $sources, $pagerestrictions );
21522139 }
21532140
@@ -2166,14 +2153,15 @@
21672154 /**
21682155 * Loads a string into mRestrictions array
21692156 *
2170 - * @param $res Resource restrictions as an SQL result.
2171 - * @param $oldFashionedRestrictions String comma-separated list of page
 2157+ * @param $res \type{Resource} restrictions as an SQL result.
 2158+ * @param $oldFashionedRestrictions string comma-separated list of page
21722159 * restrictions from page table (pre 1.10)
21732160 */
21742161 private function loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions = null ) {
21752162 $rows = array();
 2163+ $dbr = wfGetDB( DB_SLAVE );
21762164
2177 - foreach ( $res as $row ) {
 2165+ while ( $row = $dbr->fetchObject( $res ) ) {
21782166 $rows[] = $row;
21792167 }
21802168
@@ -2182,22 +2170,20 @@
21832171
21842172 /**
21852173 * Compiles list of active page restrictions from both page table (pre 1.10)
2186 - * and page_restrictions table for this existing page.
2187 - * Public for usage by LiquidThreads.
 2174+ * and page_restrictions table
21882175 *
21892176 * @param $rows array of db result objects
21902177 * @param $oldFashionedRestrictions string comma-separated list of page
21912178 * restrictions from page table (pre 1.10)
21922179 */
21932180 public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
2194 - global $wgContLang;
21952181 $dbr = wfGetDB( DB_SLAVE );
21962182
21972183 $restrictionTypes = $this->getRestrictionTypes();
21982184
21992185 foreach ( $restrictionTypes as $type ) {
22002186 $this->mRestrictions[$type] = array();
2201 - $this->mRestrictionsExpiry[$type] = $wgContLang->formatExpiry( '', TS_MW );
 2187+ $this->mRestrictionsExpiry[$type] = Block::decodeExpiry( '' );
22022188 }
22032189
22042190 $this->mCascadeRestriction = false;
@@ -2231,16 +2217,17 @@
22322218 $now = wfTimestampNow();
22332219 $purgeExpired = false;
22342220
2235 - # Cycle through all the restrictions.
22362221 foreach ( $rows as $row ) {
 2222+ # Cycle through all the restrictions.
22372223
22382224 // Don't take care of restrictions types that aren't allowed
 2225+
22392226 if ( !in_array( $row->pr_type, $restrictionTypes ) )
22402227 continue;
22412228
22422229 // This code should be refactored, now that it's being used more generally,
22432230 // But I don't really see any harm in leaving it in Block for now -werdna
2244 - $expiry = $wgContLang->formatExpiry( $row->pr_expiry, TS_MW );
 2231+ $expiry = Block::decodeExpiry( $row->pr_expiry );
22452232
22462233 // Only apply the restrictions if they haven't expired!
22472234 if ( !$expiry || $expiry > $now ) {
@@ -2265,21 +2252,16 @@
22662253 /**
22672254 * Load restrictions from the page_restrictions table
22682255 *
2269 - * @param $oldFashionedRestrictions String comma-separated list of page
 2256+ * @param $oldFashionedRestrictions string comma-separated list of page
22702257 * restrictions from page table (pre 1.10)
22712258 */
22722259 public function loadRestrictions( $oldFashionedRestrictions = null ) {
2273 - global $wgContLang;
22742260 if ( !$this->mRestrictionsLoaded ) {
22752261 if ( $this->exists() ) {
22762262 $dbr = wfGetDB( DB_SLAVE );
22772263
2278 - $res = $dbr->select(
2279 - 'page_restrictions',
2280 - '*',
2281 - array( 'pr_page' => $this->getArticleId() ),
2282 - __METHOD__
2283 - );
 2264+ $res = $dbr->select( 'page_restrictions', '*',
 2265+ array( 'pr_page' => $this->getArticleId() ), __METHOD__ );
22842266
22852267 $this->loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions );
22862268 } else {
@@ -2287,7 +2269,7 @@
22882270
22892271 if ( $title_protection ) {
22902272 $now = wfTimestampNow();
2291 - $expiry = $wgContLang->formatExpiry( $title_protection['pt_expiry'], TS_MW );
 2273+ $expiry = Block::decodeExpiry( $title_protection['pt_expiry'] );
22922274
22932275 if ( !$expiry || $expiry > $now ) {
22942276 // Apply the restrictions
@@ -2295,10 +2277,9 @@
22962278 $this->mRestrictions['create'] = explode( ',', trim( $title_protection['pt_create_perm'] ) );
22972279 } else { // Get rid of the old restrictions
22982280 Title::purgeExpiredRestrictions();
2299 - $this->mTitleProtection = false;
23002281 }
23012282 } else {
2302 - $this->mRestrictionsExpiry['create'] = $wgContLang->formatExpiry( '', TS_MW );
 2283+ $this->mRestrictionsExpiry['create'] = Block::decodeExpiry( '' );
23032284 }
23042285 $this->mRestrictionsLoaded = true;
23052286 }
@@ -2326,8 +2307,8 @@
23272308 /**
23282309 * Accessor/initialisation for mRestrictions
23292310 *
2330 - * @param $action String action that permission needs to be checked for
2331 - * @return Array of Strings the array of groups allowed to edit this article
 2311+ * @param $action \type{\string} action that permission needs to be checked for
 2312+ * @return \type{\arrayof{\string}} the array of groups allowed to edit this article
23322313 */
23332314 public function getRestrictions( $action ) {
23342315 if ( !$this->mRestrictionsLoaded ) {
@@ -2341,7 +2322,7 @@
23422323 /**
23432324 * Get the expiry time for the restriction against a given action
23442325 *
2345 - * @return String|Bool 14-char timestamp, or 'infinity' if the page is protected forever
 2326+ * @return 14-char timestamp, or 'infinity' if the page is protected forever
23462327 * or not protected at all, or false if the action is not recognised.
23472328 */
23482329 public function getRestrictionExpiry( $action ) {
@@ -2419,16 +2400,16 @@
24202401 * Get the article ID for this Title from the link cache,
24212402 * adding it if necessary
24222403 *
2423 - * @param $flags Int a bit field; may be Title::GAID_FOR_UPDATE to select
 2404+ * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select
24242405 * for update
2425 - * @return Int the ID
 2406+ * @return \type{\int} the ID
24262407 */
24272408 public function getArticleID( $flags = 0 ) {
24282409 if ( $this->getNamespace() < 0 ) {
24292410 return $this->mArticleID = 0;
24302411 }
24312412 $linkCache = LinkCache::singleton();
2432 - if ( $flags & self::GAID_FOR_UPDATE ) {
 2413+ if ( $flags & GAID_FOR_UPDATE ) {
24332414 $oldUpdate = $linkCache->forUpdate( true );
24342415 $linkCache->clearLink( $this );
24352416 $this->mArticleID = $linkCache->addLinkObj( $this );
@@ -2445,8 +2426,8 @@
24462427 * Is this an article that is a redirect page?
24472428 * Uses link cache, adding it if necessary
24482429 *
2449 - * @param $flags Int a bit field; may be Title::GAID_FOR_UPDATE to select for update
2450 - * @return Bool
 2430+ * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
 2431+ * @return \type{\bool}
24512432 */
24522433 public function isRedirect( $flags = 0 ) {
24532434 if ( !is_null( $this->mRedirect ) ) {
@@ -2466,8 +2447,8 @@
24672448 * What is the length of this page?
24682449 * Uses link cache, adding it if necessary
24692450 *
2470 - * @param $flags Int a bit field; may be Title::GAID_FOR_UPDATE to select for update
2471 - * @return Int
 2451+ * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
 2452+ * @return \type{\bool}
24722453 */
24732454 public function getLength( $flags = 0 ) {
24742455 if ( $this->mLength != -1 ) {
@@ -2486,8 +2467,8 @@
24872468 /**
24882469 * What is the page_latest field for this page?
24892470 *
2490 - * @param $flags Int a bit field; may be Title::GAID_FOR_UPDATE to select for update
2491 - * @return Int or 0 if the page doesn't exist
 2471+ * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update
 2472+ * @return \type{\int} or 0 if the page doesn't exist
24922473 */
24932474 public function getLatestRevID( $flags = 0 ) {
24942475 if ( $this->mLatestID !== false ) {
@@ -2507,11 +2488,7 @@
25082489 * This clears some fields in this object, and clears any associated
25092490 * keys in the "bad links" section of the link cache.
25102491 *
2511 - * - This is called from Article::doEdit() and Article::insertOn() to allow
2512 - * loading of the new page_id. It's also called from
2513 - * Article::doDeleteArticle()
2514 - *
2515 - * @param $newid Int the new Article ID
 2492+ * @param $newid \type{\int} the new Article ID
25162493 */
25172494 public function resetArticleID( $newid ) {
25182495 $linkCache = LinkCache::singleton();
@@ -2532,7 +2509,7 @@
25332510 /**
25342511 * Updates page_touched for this page; called from LinksUpdate.php
25352512 *
2536 - * @return Bool true if the update succeded
 2513+ * @return \type{\bool} true if the update succeded
25372514 */
25382515 public function invalidateCache() {
25392516 if ( wfReadOnly() ) {
@@ -2553,16 +2530,15 @@
25542531 * Prefix some arbitrary text with the namespace or interwiki prefix
25552532 * of this object
25562533 *
2557 - * @param $name String the text
2558 - * @return String the prefixed text
 2534+ * @param $name \type{\string} the text
 2535+ * @return \type{\string} the prefixed text
25592536 * @private
25602537 */
2561 - private function prefix( $name ) {
 2538+ /* private */ function prefix( $name ) {
25622539 $p = '';
25632540 if ( $this->mInterwiki != '' ) {
25642541 $p = $this->mInterwiki . ':';
25652542 }
2566 -
25672543 if ( 0 != $this->mNamespace ) {
25682544 $p .= $this->getNsText() . ':';
25692545 }
@@ -2574,7 +2550,7 @@
25752551 * Note that this doesn't pick up many things that could be wrong with titles, but that
25762552 * replacing this regex with something valid will make many titles valid.
25772553 *
2578 - * @return String regex string
 2554+ * @return string regex string
25792555 */
25802556 static function getTitleInvalidRegex() {
25812557 static $rxTc = false;
@@ -2599,7 +2575,7 @@
26002576 /**
26012577 * Capitalize a text string for a title if it belongs to a namespace that capitalizes
26022578 *
2603 - * @param $text String containing title to capitalize
 2579+ * @param $text string containing title to capitalize
26042580 * @param $ns int namespace index, defaults to NS_MAIN
26052581 * @return String containing capitalized title
26062582 */
@@ -2622,12 +2598,14 @@
26232599 * namespace prefixes, sets the other forms, and canonicalizes
26242600 * everything.
26252601 *
2626 - * @return Bool true on success
 2602+ * @return \type{\bool} true on success
26272603 */
26282604 private function secureAndSplit() {
26292605 global $wgContLang, $wgLocalInterwiki;
26302606
26312607 # Initialisation
 2608+ $rxTc = self::getTitleInvalidRegex();
 2609+
26322610 $this->mInterwiki = $this->mFragment = '';
26332611 $this->mNamespace = $this->mDefaultNamespace; # Usually NS_MAIN
26342612
@@ -2642,6 +2620,7 @@
26432621 # Note: use of the /u option on preg_replace here will cause
26442622 # input with invalid UTF-8 sequences to be nullified out in PHP 5.2.x,
26452623 # conveniently disabling them.
 2624+ #
26462625 $dbkey = preg_replace( '/[ _\xA0\x{1680}\x{180E}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}]+/u', '_', $dbkey );
26472626 $dbkey = trim( $dbkey, '_' );
26482627
@@ -2678,11 +2657,9 @@
26792658 # For Talk:X pages, check if X has a "namespace" prefix
26802659 if ( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) {
26812660 if ( $wgContLang->getNsIndex( $x[1] ) ) {
2682 - # Disallow Talk:File:x type titles...
2683 - return false;
 2661+ return false; # Disallow Talk:File:x type titles...
26842662 } elseif ( Interwiki::isValidInterwiki( $x[1] ) ) {
2685 - # Disallow Talk:Interwiki:x type titles...
2686 - return false;
 2663+ return false; # Disallow Talk:Interwiki:x type titles...
26872664 }
26882665 }
26892666 } elseif ( Interwiki::isValidInterwiki( $p ) ) {
@@ -2697,9 +2674,7 @@
26982675 $this->mInterwiki = $wgContLang->lc( $p );
26992676
27002677 # Redundant interwiki prefix to the local wiki
2701 - if ( $wgLocalInterwiki !== false
2702 - && 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) )
2703 - {
 2678+ if ( 0 == strcasecmp( $this->mInterwiki, $wgLocalInterwiki ) ) {
27042679 if ( $dbkey == '' ) {
27052680 # Can't have an empty self-link
27062681 return false;
@@ -2724,12 +2699,13 @@
27252700 } while ( true );
27262701
27272702 # We already know that some pages won't be in the database!
 2703+ #
27282704 if ( $this->mInterwiki != '' || NS_SPECIAL == $this->mNamespace ) {
27292705 $this->mArticleID = 0;
27302706 }
27312707 $fragment = strstr( $dbkey, '#' );
27322708 if ( false !== $fragment ) {
2733 - $this->setFragment( $fragment );
 2709+ $this->setFragment( preg_replace( '/^#_*/', '#', $fragment ) );
27342710 $dbkey = substr( $dbkey, 0, strlen( $dbkey ) - strlen( $fragment ) );
27352711 # remove whitespace again: prevents "Foo_bar_#"
27362712 # becoming "Foo_bar_"
@@ -2737,65 +2713,79 @@
27382714 }
27392715
27402716 # Reject illegal characters.
2741 - $rxTc = self::getTitleInvalidRegex();
 2717+ #
27422718 if ( preg_match( $rxTc, $dbkey ) ) {
27432719 return false;
27442720 }
27452721
2746 - # Pages with "/./" or "/../" appearing in the URLs will often be un-
2747 - # reachable due to the way web browsers deal with 'relative' URLs.
2748 - # Also, they conflict with subpage syntax. Forbid them explicitly.
 2722+ /**
 2723+ * Pages with "/./" or "/../" appearing in the URLs will often be un-
 2724+ * reachable due to the way web browsers deal with 'relative' URLs.
 2725+ * Also, they conflict with subpage syntax. Forbid them explicitly.
 2726+ */
27492727 if ( strpos( $dbkey, '.' ) !== false &&
2750 - ( $dbkey === '.' || $dbkey === '..' ||
2751 - strpos( $dbkey, './' ) === 0 ||
2752 - strpos( $dbkey, '../' ) === 0 ||
2753 - strpos( $dbkey, '/./' ) !== false ||
2754 - strpos( $dbkey, '/../' ) !== false ||
2755 - substr( $dbkey, -2 ) == '/.' ||
2756 - substr( $dbkey, -3 ) == '/..' ) )
 2728+ ( $dbkey === '.' || $dbkey === '..' ||
 2729+ strpos( $dbkey, './' ) === 0 ||
 2730+ strpos( $dbkey, '../' ) === 0 ||
 2731+ strpos( $dbkey, '/./' ) !== false ||
 2732+ strpos( $dbkey, '/../' ) !== false ||
 2733+ substr( $dbkey, -2 ) == '/.' ||
 2734+ substr( $dbkey, -3 ) == '/..' ) )
27572735 {
27582736 return false;
27592737 }
27602738
2761 - # Magic tilde sequences? Nu-uh!
 2739+ /**
 2740+ * Magic tilde sequences? Nu-uh!
 2741+ */
27622742 if ( strpos( $dbkey, '~~~' ) !== false ) {
27632743 return false;
27642744 }
27652745
2766 - # Limit the size of titles to 255 bytes. This is typically the size of the
2767 - # underlying database field. We make an exception for special pages, which
2768 - # don't need to be stored in the database, and may edge over 255 bytes due
2769 - # to subpage syntax for long titles, e.g. [[Special:Block/Long name]]
 2746+ /**
 2747+ * Limit the size of titles to 255 bytes.
 2748+ * This is typically the size of the underlying database field.
 2749+ * We make an exception for special pages, which don't need to be stored
 2750+ * in the database, and may edge over 255 bytes due to subpage syntax
 2751+ * for long titles, e.g. [[Special:Block/Long name]]
 2752+ */
27702753 if ( ( $this->mNamespace != NS_SPECIAL && strlen( $dbkey ) > 255 ) ||
27712754 strlen( $dbkey ) > 512 )
27722755 {
27732756 return false;
27742757 }
27752758
2776 - # Normally, all wiki links are forced to have an initial capital letter so [[foo]]
2777 - # and [[Foo]] point to the same place. Don't force it for interwikis, since the
2778 - # other site might be case-sensitive.
 2759+ /**
 2760+ * Normally, all wiki links are forced to have
 2761+ * an initial capital letter so [[foo]] and [[Foo]]
 2762+ * point to the same place.
 2763+ *
 2764+ * Don't force it for interwikis, since the other
 2765+ * site might be case-sensitive.
 2766+ */
27792767 $this->mUserCaseDBKey = $dbkey;
27802768 if ( $this->mInterwiki == '' ) {
27812769 $dbkey = self::capitalize( $dbkey, $this->mNamespace );
27822770 }
27832771
2784 - # Can't make a link to a namespace alone... "empty" local links can only be
2785 - # self-links with a fragment identifier.
2786 - if ( $dbkey == '' && $this->mInterwiki == '' && $this->mNamespace != NS_MAIN ) {
 2772+ /**
 2773+ * Can't make a link to a namespace alone...
 2774+ * "empty" local links can only be self-links
 2775+ * with a fragment identifier.
 2776+ */
 2777+ if ( $dbkey == '' &&
 2778+ $this->mInterwiki == '' &&
 2779+ $this->mNamespace != NS_MAIN ) {
27872780 return false;
27882781 }
2789 -
27902782 // Allow IPv6 usernames to start with '::' by canonicalizing IPv6 titles.
27912783 // IP names are not allowed for accounts, and can only be referring to
27922784 // edits from the IP. Given '::' abbreviations and caps/lowercaps,
27932785 // there are numerous ways to present the same IP. Having sp:contribs scan
27942786 // them all is silly and having some show the edits and others not is
27952787 // inconsistent. Same for talk/userpages. Keep them normalized instead.
2796 - $dbkey = ( $this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK )
2797 - ? IP::sanitizeIP( $dbkey )
2798 - : $dbkey;
2799 -
 2788+ $dbkey = ( $this->mNamespace == NS_USER || $this->mNamespace == NS_USER_TALK ) ?
 2789+ IP::sanitizeIP( $dbkey ) : $dbkey;
28002790 // Any remaining initial :s are illegal.
28012791 if ( $dbkey !== '' && ':' == $dbkey { 0 } ) {
28022792 return false;
@@ -2818,7 +2808,7 @@
28192809 * Deprecated for public use, use Title::makeTitle() with fragment parameter.
28202810 * Still in active use privately.
28212811 *
2822 - * @param $fragment String text
 2812+ * @param $fragment \type{\string} text
28232813 */
28242814 public function setFragment( $fragment ) {
28252815 $this->mFragment = str_replace( '_', ' ', substr( $fragment, 1 ) );
@@ -2831,7 +2821,7 @@
28322822 /**
28332823 * Get a Title object associated with the talk page of this article
28342824 *
2835 - * @return Title the object for the talk page
 2825+ * @return \type{Title} the object for the talk page
28362826 */
28372827 public function getTalkPage() {
28382828 return Title::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() );
@@ -2841,7 +2831,7 @@
28422832 * Get a title object associated with the subject page of this
28432833 * talk page
28442834 *
2845 - * @return Title the object for the subject page
 2835+ * @return \type{Title} the object for the subject page
28462836 */
28472837 public function getSubjectPage() {
28482838 // Is this the same title?
@@ -2862,7 +2852,7 @@
28632853 * @param $options Array: may be FOR UPDATE
28642854 * @param $table String: table name
28652855 * @param $prefix String: fields prefix
2866 - * @return Array of Title objects linking here
 2856+ * @return \type{\arrayof{Title}} the Title objects linking here
28672857 */
28682858 public function getLinksTo( $options = array(), $table = 'pagelinks', $prefix = 'pl' ) {
28692859 $linkCache = LinkCache::singleton();
@@ -2887,13 +2877,13 @@
28882878 $retVal = array();
28892879 if ( $db->numRows( $res ) ) {
28902880 foreach ( $res as $row ) {
2891 - $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title );
2892 - if ( $titleObj ) {
 2881+ if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
28932882 $linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect, $row->page_latest );
28942883 $retVal[] = $titleObj;
28952884 }
28962885 }
28972886 }
 2887+ $db->freeResult( $res );
28982888 return $retVal;
28992889 }
29002890
@@ -2905,7 +2895,7 @@
29062896 * On heavily-used templates it will max out the memory.
29072897 *
29082898 * @param $options Array: may be FOR UPDATE
2909 - * @return Array of Title the Title objects linking here
 2899+ * @return \type{\arrayof{Title}} the Title objects linking here
29102900 */
29112901 public function getTemplateLinksTo( $options = array() ) {
29122902 return $this->getLinksTo( $options, 'templatelinks', 'tl' );
@@ -2915,7 +2905,7 @@
29162906 * Get an array of Title objects referring to non-existent articles linked from this page
29172907 *
29182908 * @todo check if needed (used only in SpecialBrokenRedirects.php, and should use redirect table in this case)
2919 - * @return Array of Title the Title objects
 2909+ * @return \type{\arrayof{Title}} the Title objects
29202910 */
29212911 public function getBrokenLinksFrom() {
29222912 if ( $this->getArticleId() == 0 ) {
@@ -2952,7 +2942,7 @@
29532943 * Get a list of URLs to purge from the Squid cache when this
29542944 * page changes
29552945 *
2956 - * @return Array of String the URLs
 2946+ * @return \type{\arrayof{\string}} the URLs
29572947 */
29582948 public function getSquidURLs() {
29592949 global $wgContLang;
@@ -2988,8 +2978,8 @@
29892979 /**
29902980 * Move this page without authentication
29912981 *
2992 - * @param $nt Title the new page Title
2993 - * @return Mixed true on success, getUserPermissionsErrors()-like array on failure
 2982+ * @param $nt \type{Title} the new page Title
 2983+ * @return \type{\mixed} true on success, getUserPermissionsErrors()-like array on failure
29942984 */
29952985 public function moveNoAuth( &$nt ) {
29962986 return $this->moveTo( $nt, false );
@@ -2999,11 +2989,11 @@
30002990 * Check whether a given move operation would be valid.
30012991 * Returns true if ok, or a getUserPermissionsErrors()-like array otherwise
30022992 *
3003 - * @param $nt Title the new title
3004 - * @param $auth Bool indicates whether $wgUser's permissions
 2993+ * @param $nt \type{Title} the new title
 2994+ * @param $auth \type{\bool} indicates whether $wgUser's permissions
30052995 * should be checked
3006 - * @param $reason String is the log summary of the move, used for spam checking
3007 - * @return Mixed True on success, getUserPermissionsErrors()-like array on failure
 2996+ * @param $reason \type{\string} is the log summary of the move, used for spam checking
 2997+ * @return \type{\mixed} True on success, getUserPermissionsErrors()-like array on failure
30082998 */
30092999 public function isValidMoveOperation( &$nt, $auth = true, $reason = '' ) {
30103000 global $wgUser;
@@ -3035,13 +3025,28 @@
30363026 }
30373027 if ( ( $this->getDBkey() == '' ) ||
30383028 ( !$oldid ) ||
3039 - ( $nt->getDBkey() == '' ) ) {
 3029+ ( $nt->getDBkey() == '' ) ) {
30403030 $errors[] = array( 'badarticleerror' );
30413031 }
30423032
30433033 // Image-specific checks
30443034 if ( $this->getNamespace() == NS_FILE ) {
3045 - $errors = array_merge( $errors, $this->validateFileMoveOperation( $nt ) );
 3035+ if ( $nt->getNamespace() != NS_FILE ) {
 3036+ $errors[] = array( 'imagenocrossnamespace' );
 3037+ }
 3038+ $file = wfLocalFile( $this );
 3039+ if ( $file->exists() ) {
 3040+ if ( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
 3041+ $errors[] = array( 'imageinvalidfilename' );
 3042+ }
 3043+ if ( !File::checkExtensionCompatibility( $file, $nt->getDBkey() ) ) {
 3044+ $errors[] = array( 'imagetypemismatch' );
 3045+ }
 3046+ }
 3047+ $destfile = wfLocalFile( $nt );
 3048+ if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destfile->exists() && wfFindFile( $nt ) ) {
 3049+ $errors[] = array( 'file-exists-sharedrepo' );
 3050+ }
30463051 }
30473052
30483053 if ( $nt->getNamespace() == NS_FILE && $this->getNamespace() != NS_FILE ) {
@@ -3089,56 +3094,25 @@
30903095 }
30913096
30923097 /**
3093 - * Check if the requested move target is a valid file move target
3094 - * @param Title $nt Target title
3095 - * @return array List of errors
3096 - */
3097 - protected function validateFileMoveOperation( $nt ) {
3098 - global $wgUser;
3099 -
3100 - $errors = array();
3101 -
3102 - if ( $nt->getNamespace() != NS_FILE ) {
3103 - $errors[] = array( 'imagenocrossnamespace' );
3104 - }
3105 -
3106 - $file = wfLocalFile( $this );
3107 - if ( $file->exists() ) {
3108 - if ( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
3109 - $errors[] = array( 'imageinvalidfilename' );
3110 - }
3111 - if ( !File::checkExtensionCompatibility( $file, $nt->getDBkey() ) ) {
3112 - $errors[] = array( 'imagetypemismatch' );
3113 - }
3114 - }
3115 -
3116 - $destFile = wfLocalFile( $nt );
3117 - if ( !$wgUser->isAllowed( 'reupload-shared' ) && !$destFile->exists() && wfFindFile( $nt ) ) {
3118 - $errors[] = array( 'file-exists-sharedrepo' );
3119 - }
3120 -
3121 - return $errors;
3122 - }
3123 -
3124 - /**
31253098 * Move a title to a new location
31263099 *
3127 - * @param $nt Title the new title
3128 - * @param $auth Bool indicates whether $wgUser's permissions
 3100+ * @param $nt \type{Title} the new title
 3101+ * @param $auth \type{\bool} indicates whether $wgUser's permissions
31293102 * should be checked
3130 - * @param $reason String the reason for the move
3131 - * @param $createRedirect Bool Whether to create a redirect from the old title to the new title.
 3103+ * @param $reason \type{\string} The reason for the move
 3104+ * @param $createRedirect \type{\bool} Whether to create a redirect from the old title to the new title.
31323105 * Ignored if the user doesn't have the suppressredirect right.
3133 - * @return Mixed true on success, getUserPermissionsErrors()-like array on failure
 3106+ * @return \type{\mixed} true on success, getUserPermissionsErrors()-like array on failure
31343107 */
31353108 public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) {
 3109+ global $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
 3110+
31363111 $err = $this->isValidMoveOperation( $nt, $auth, $reason );
31373112 if ( is_array( $err ) ) {
31383113 return $err;
31393114 }
31403115
3141 - // If it is a file, move it first. It is done before all other moving stuff is
3142 - // done because it's hard to revert
 3116+ // If it is a file, move it first. It is done before all other moving stuff is done because it's hard to revert
31433117 $dbw = wfGetDB( DB_MASTER );
31443118 if ( $this->getNamespace() == NS_FILE ) {
31453119 $file = wfLocalFile( $this );
@@ -3153,39 +3127,43 @@
31543128 $dbw->begin(); # If $file was a LocalFile, its transaction would have closed our own.
31553129 $pageid = $this->getArticleID( self::GAID_FOR_UPDATE );
31563130 $protected = $this->isProtected();
3157 - $pageCountChange = ( $createRedirect ? 1 : 0 ) - ( $nt->exists() ? 1 : 0 );
 3131+ if ( $nt->exists() ) {
 3132+ $err = $this->moveOverExistingRedirect( $nt, $reason, $createRedirect );
 3133+ $pageCountChange = ( $createRedirect ? 0 : -1 );
 3134+ } else { # Target didn't exist, do normal move.
 3135+ $err = $this->moveToNewTitle( $nt, $reason, $createRedirect );
 3136+ $pageCountChange = ( $createRedirect ? 1 : 0 );
 3137+ }
31583138
3159 - // Do the actual move
3160 - $err = $this->moveToInternal( $nt, $reason, $createRedirect );
31613139 if ( is_array( $err ) ) {
31623140 # @todo FIXME: What about the File we have already moved?
31633141 $dbw->rollback();
31643142 return $err;
31653143 }
3166 -
31673144 $redirid = $this->getArticleID();
31683145
31693146 // Refresh the sortkey for this row. Be careful to avoid resetting
31703147 // cl_timestamp, which may disturb time-based lists on some sites.
3171 - $prefixes = $dbw->select(
 3148+ $prefix = $dbw->selectField(
31723149 'categorylinks',
3173 - array( 'cl_sortkey_prefix', 'cl_to' ),
 3150+ 'cl_sortkey_prefix',
31743151 array( 'cl_from' => $pageid ),
31753152 __METHOD__
31763153 );
3177 - foreach ( $prefixes as $prefixRow ) {
3178 - $prefix = $prefixRow->cl_sortkey_prefix;
3179 - $catTo = $prefixRow->cl_to;
3180 - $dbw->update( 'categorylinks',
3181 - array(
3182 - 'cl_sortkey' => Collation::singleton()->getSortKey(
3183 - $nt->getCategorySortkey( $prefix ) ),
3184 - 'cl_timestamp=cl_timestamp' ),
3185 - array(
3186 - 'cl_from' => $pageid,
3187 - 'cl_to' => $catTo ),
3188 - __METHOD__
3189 - );
 3154+ $dbw->update( 'categorylinks',
 3155+ array(
 3156+ 'cl_sortkey' => $wgContLang->convertToSortkey( $nt->getCategorySortkey( $prefix ) ),
 3157+ 'cl_timestamp=cl_timestamp' ),
 3158+ array( 'cl_from' => $pageid ),
 3159+ __METHOD__ );
 3160+
 3161+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 3162+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 3163+ $dbw2->update( 'globaltemplatelinks',
 3164+ array( 'gtl_from_namespace' => $nt->getNsText(),
 3165+ 'gtl_from_title' => $nt->getText() ),
 3166+ array ( 'gtl_from_page' => $pageid ),
 3167+ __METHOD__ );
31903168 }
31913169
31923170 if ( $protected ) {
@@ -3251,19 +3229,20 @@
32523230 $u->doUpdate();
32533231 }
32543232 # Update message cache for interface messages
3255 - if ( $this->getNamespace() == NS_MEDIAWIKI ) {
 3233+ if ( $nt->getNamespace() == NS_MEDIAWIKI ) {
 3234+ global $wgMessageCache;
 3235+
32563236 # @bug 17860: old article can be deleted, if this the case,
32573237 # delete it from message cache
32583238 if ( $this->getArticleID() === 0 ) {
3259 - MessageCache::singleton()->replace( $this->getDBkey(), false );
 3239+ $wgMessageCache->replace( $this->getDBkey(), false );
32603240 } else {
32613241 $oldarticle = new Article( $this );
3262 - MessageCache::singleton()->replace( $this->getDBkey(), $oldarticle->getContent() );
 3242+ $wgMessageCache->replace( $this->getDBkey(), $oldarticle->getContent() );
32633243 }
3264 - }
3265 - if ( $nt->getNamespace() == NS_MEDIAWIKI ) {
 3244+
32663245 $newarticle = new Article( $nt );
3267 - MessageCache::singleton()->replace( $nt->getDBkey(), $newarticle->getContent() );
 3246+ $wgMessageCache->replace( $nt->getDBkey(), $newarticle->getContent() );
32683247 }
32693248
32703249 global $wgUser;
@@ -3272,80 +3251,78 @@
32733252 }
32743253
32753254 /**
3276 - * Move page to a title which is either a redirect to the
3277 - * source page or nonexistent
 3255+ * Move page to a title which is at present a redirect to the
 3256+ * source page
32783257 *
3279 - * @param $nt Title the page to move to, which should be a redirect or nonexistent
3280 - * @param $reason String The reason for the move
3281 - * @param $createRedirect Bool Whether to leave a redirect at the old title. Ignored
3282 - * if the user doesn't have the suppressredirect right
 3258+ * @param $nt \type{Title} the page to move to, which should currently
 3259+ * be a redirect
 3260+ * @param $reason \type{\string} The reason for the move
 3261+ * @param $createRedirect \type{\bool} Whether to leave a redirect at the old title.
 3262+ * Ignored if the user doesn't have the suppressredirect right
32833263 */
3284 - private function moveToInternal( &$nt, $reason = '', $createRedirect = true ) {
3285 - global $wgUser, $wgContLang;
 3264+ private function moveOverExistingRedirect( &$nt, $reason = '', $createRedirect = true ) {
 3265+ global $wgUseSquid, $wgUser, $wgContLang, $wgEnableInterwikiTemplatesTracking, $wgGlobalDatabase;
32863266
3287 - $moveOverRedirect = $nt->exists();
 3267+ $comment = wfMsgForContent( '1movedto2_redir', $this->getPrefixedText(), $nt->getPrefixedText() );
32883268
3289 - $commentMsg = ( $moveOverRedirect ? '1movedto2_redir' : '1movedto2' );
3290 - $comment = wfMsgForContent( $commentMsg, $this->getPrefixedText(), $nt->getPrefixedText() );
3291 -
32923269 if ( $reason ) {
32933270 $comment .= wfMsgForContent( 'colon-separator' ) . $reason;
32943271 }
3295 - # Truncate for whole multibyte characters.
3296 - $comment = $wgContLang->truncate( $comment, 255 );
 3272+ # Truncate for whole multibyte characters. +5 bytes for ellipsis
 3273+ $comment = $wgContLang->truncate( $comment, 250 );
32973274
 3275+ $now = wfTimestampNow();
 3276+ $newid = $nt->getArticleID();
32983277 $oldid = $this->getArticleID();
32993278 $latest = $this->getLatestRevID();
33003279
3301 - $oldns = $this->getNamespace();
3302 - $olddbk = $this->getDBkey();
3303 -
33043280 $dbw = wfGetDB( DB_MASTER );
33053281
3306 - if ( $moveOverRedirect ) {
3307 - $rcts = $dbw->timestamp( $nt->getEarliestRevTime() );
 3282+ $rcts = $dbw->timestamp( $nt->getEarliestRevTime() );
 3283+ $newns = $nt->getNamespace();
 3284+ $newdbk = $nt->getDBkey();
33083285
3309 - $newid = $nt->getArticleID();
3310 - $newns = $nt->getNamespace();
3311 - $newdbk = $nt->getDBkey();
3312 -
3313 - # Delete the old redirect. We don't save it to history since
3314 - # by definition if we've got here it's rather uninteresting.
3315 - # We have to remove it so that the next step doesn't trigger
3316 - # a conflict on the unique namespace+title index...
3317 - $dbw->delete( 'page', array( 'page_id' => $newid ), __METHOD__ );
3318 - if ( !$dbw->cascadingDeletes() ) {
3319 - $dbw->delete( 'revision', array( 'rev_page' => $newid ), __METHOD__ );
3320 - global $wgUseTrackbacks;
3321 - if ( $wgUseTrackbacks ) {
3322 - $dbw->delete( 'trackbacks', array( 'tb_page' => $newid ), __METHOD__ );
3323 - }
3324 - $dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), __METHOD__ );
3325 - $dbw->delete( 'imagelinks', array( 'il_from' => $newid ), __METHOD__ );
3326 - $dbw->delete( 'categorylinks', array( 'cl_from' => $newid ), __METHOD__ );
3327 - $dbw->delete( 'templatelinks', array( 'tl_from' => $newid ), __METHOD__ );
3328 - $dbw->delete( 'externallinks', array( 'el_from' => $newid ), __METHOD__ );
3329 - $dbw->delete( 'langlinks', array( 'll_from' => $newid ), __METHOD__ );
3330 - $dbw->delete( 'redirect', array( 'rd_from' => $newid ), __METHOD__ );
 3286+ # Delete the old redirect. We don't save it to history since
 3287+ # by definition if we've got here it's rather uninteresting.
 3288+ # We have to remove it so that the next step doesn't trigger
 3289+ # a conflict on the unique namespace+title index...
 3290+ $dbw->delete( 'page', array( 'page_id' => $newid ), __METHOD__ );
 3291+ if ( !$dbw->cascadingDeletes() ) {
 3292+ $dbw->delete( 'revision', array( 'rev_page' => $newid ), __METHOD__ );
 3293+ global $wgUseTrackbacks;
 3294+ if ( $wgUseTrackbacks ) {
 3295+ $dbw->delete( 'trackbacks', array( 'tb_page' => $newid ), __METHOD__ );
33313296 }
3332 - // If the target page was recently created, it may have an entry in recentchanges still
3333 - $dbw->delete( 'recentchanges',
3334 - array( 'rc_timestamp' => $rcts, 'rc_namespace' => $newns, 'rc_title' => $newdbk, 'rc_new' => 1 ),
3335 - __METHOD__
3336 - );
 3297+ $dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), __METHOD__ );
 3298+ $dbw->delete( 'imagelinks', array( 'il_from' => $newid ), __METHOD__ );
 3299+ $dbw->delete( 'categorylinks', array( 'cl_from' => $newid ), __METHOD__ );
 3300+ $dbw->delete( 'templatelinks', array( 'tl_from' => $newid ), __METHOD__ );
 3301+ $dbw->delete( 'externallinks', array( 'el_from' => $newid ), __METHOD__ );
 3302+ $dbw->delete( 'langlinks', array( 'll_from' => $newid ), __METHOD__ );
 3303+ $dbw->delete( 'redirect', array( 'rd_from' => $newid ), __METHOD__ );
 3304+
 3305+ if ( $wgEnableInterwikiTemplatesTracking && $wgGlobalDatabase ) {
 3306+ $dbw2 = wfGetDB( DB_MASTER, array(), $wgGlobalDatabase );
 3307+ $dbw2->delete( 'globaltemplatelinks',
 3308+ array( 'gtl_from_wiki' => wfWikiID( ),
 3309+ 'gtl_from_page' => $newid ),
 3310+ __METHOD__ );
 3311+ }
33373312 }
 3313+ // If the redirect was recently created, it may have an entry in recentchanges still
 3314+ $dbw->delete( 'recentchanges',
 3315+ array( 'rc_timestamp' => $rcts, 'rc_namespace' => $newns, 'rc_title' => $newdbk, 'rc_new' => 1 ),
 3316+ __METHOD__
 3317+ );
33383318
33393319 # Save a null revision in the page's history notifying of the move
33403320 $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
3341 - if ( !is_object( $nullRevision ) ) {
3342 - throw new MWException( 'No valid null revision produced in ' . __METHOD__ );
3343 - }
33443321 $nullRevId = $nullRevision->insertOn( $dbw );
33453322
33463323 # Change the name of the target page:
33473324 $dbw->update( 'page',
33483325 /* SET */ array(
3349 - 'page_touched' => $dbw->timestamp(),
 3326+ 'page_touched' => $dbw->timestamp( $now ),
33503327 'page_namespace' => $nt->getNamespace(),
33513328 'page_title' => $nt->getDBkey(),
33523329 'page_latest' => $nullRevId,
@@ -3384,34 +3361,110 @@
33853362 __METHOD__ );
33863363 $redirectSuppressed = false;
33873364 } else {
3388 - // Get rid of old new page entries in Special:NewPages and RC.
3389 - // Needs to be before $this->resetArticleID( 0 ).
3390 - $dbw->delete( 'recentchanges', array(
3391 - 'rc_timestamp' => $dbw->timestamp( $this->getEarliestRevTime() ),
3392 - 'rc_namespace' => $oldns,
3393 - 'rc_title' => $olddbk,
3394 - 'rc_new' => 1
3395 - ),
3396 - __METHOD__
3397 - );
3398 -
33993365 $this->resetArticleID( 0 );
34003366 $redirectSuppressed = true;
34013367 }
34023368
34033369 # Log the move
34043370 $log = new LogPage( 'move' );
3405 - $logType = ( $moveOverRedirect ? 'move_redir' : 'move' );
3406 - $log->addEntry( $logType, $this, $reason, array( 1 => $nt->getPrefixedText(), 2 => $redirectSuppressed ) );
 3371+ $log->addEntry( 'move_redir', $this, $reason, array( 1 => $nt->getPrefixedText(), 2 => $redirectSuppressed ) );
34073372
3408 - # Purge caches for old and new titles
3409 - if ( $moveOverRedirect ) {
3410 - # A simple purge is enough when moving over a redirect
3411 - $nt->purgeSquid();
 3373+ # Purge squid
 3374+ if ( $wgUseSquid ) {
 3375+ $urls = array_merge( $nt->getSquidURLs(), $this->getSquidURLs() );
 3376+ $u = new SquidUpdate( $urls );
 3377+ $u->doUpdate();
 3378+ }
 3379+
 3380+ }
 3381+
 3382+ /**
 3383+ * Move page to non-existing title.
 3384+ *
 3385+ * @param $nt \type{Title} the new Title
 3386+ * @param $reason \type{\string} The reason for the move
 3387+ * @param $createRedirect \type{\bool} Whether to create a redirect from the old title to the new title
 3388+ * Ignored if the user doesn't have the suppressredirect right
 3389+ */
 3390+ private function moveToNewTitle( &$nt, $reason = '', $createRedirect = true ) {
 3391+ global $wgUser, $wgContLang;
 3392+
 3393+ $comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
 3394+ if ( $reason ) {
 3395+ $comment .= wfMsgExt( 'colon-separator',
 3396+ array( 'escapenoentities', 'content' ) );
 3397+ $comment .= $reason;
 3398+ }
 3399+ # Truncate for whole multibyte characters. +5 bytes for ellipsis
 3400+ $comment = $wgContLang->truncate( $comment, 250 );
 3401+
 3402+ $newid = $nt->getArticleID();
 3403+ $oldid = $this->getArticleID();
 3404+ $latest = $this->getLatestRevId();
 3405+
 3406+ $dbw = wfGetDB( DB_MASTER );
 3407+ $now = $dbw->timestamp();
 3408+
 3409+ # Save a null revision in the page's history notifying of the move
 3410+ $nullRevision = Revision::newNullRevision( $dbw, $oldid, $comment, true );
 3411+ if ( !is_object( $nullRevision ) ) {
 3412+ throw new MWException( 'No valid null revision produced in ' . __METHOD__ );
 3413+ }
 3414+ $nullRevId = $nullRevision->insertOn( $dbw );
 3415+
 3416+ $article = new Article( $this );
 3417+ wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) );
 3418+
 3419+ # Rename page entry
 3420+ $dbw->update( 'page',
 3421+ /* SET */ array(
 3422+ 'page_touched' => $now,
 3423+ 'page_namespace' => $nt->getNamespace(),
 3424+ 'page_title' => $nt->getDBkey(),
 3425+ 'page_latest' => $nullRevId,
 3426+ ),
 3427+ /* WHERE */ array( 'page_id' => $oldid ),
 3428+ __METHOD__
 3429+ );
 3430+ $nt->resetArticleID( $oldid );
 3431+
 3432+ if ( $createRedirect || !$wgUser->isAllowed( 'suppressredirect' ) ) {
 3433+ # Insert redirect
 3434+ $mwRedir = MagicWord::get( 'redirect' );
 3435+ $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
 3436+ $redirectArticle = new Article( $this );
 3437+ $newid = $redirectArticle->insertOn( $dbw );
 3438+ $redirectRevision = new Revision( array(
 3439+ 'page' => $newid,
 3440+ 'comment' => $comment,
 3441+ 'text' => $redirectText ) );
 3442+ $redirectRevision->insertOn( $dbw );
 3443+ $redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
 3444+
 3445+ wfRunHooks( 'NewRevisionFromEditComplete', array( $redirectArticle, $redirectRevision, false, $wgUser ) );
 3446+
 3447+ # Record the just-created redirect's linking to the page
 3448+ $dbw->insert( 'pagelinks',
 3449+ array(
 3450+ 'pl_from' => $newid,
 3451+ 'pl_namespace' => $nt->getNamespace(),
 3452+ 'pl_title' => $nt->getDBkey() ),
 3453+ __METHOD__ );
 3454+ $redirectSuppressed = false;
34123455 } else {
3413 - # Purge caches as per article creation, including any pages that link to this title
3414 - Article::onArticleCreate( $nt );
 3456+ $this->resetArticleID( 0 );
 3457+ $redirectSuppressed = true;
34153458 }
 3459+
 3460+ # Log the move
 3461+ $log = new LogPage( 'move' );
 3462+ $log->addEntry( 'move', $this, $reason, array( 1 => $nt->getPrefixedText(), 2 => $redirectSuppressed ) );
 3463+
 3464+ # Purge caches as per article creation
 3465+ Article::onArticleCreate( $nt );
 3466+
 3467+ # Purge old title from squid
 3468+ # The new title, and links to the new title, are purged in Article::onArticleCreate()
34163469 $this->purgeSquid();
34173470 }
34183471
@@ -3421,11 +3474,10 @@
34223475 * @param $nt Title Move target
34233476 * @param $auth bool Whether $wgUser's permissions should be checked
34243477 * @param $reason string The reason for the move
3425 - * @param $createRedirect bool Whether to create redirects from the old subpages to
3426 - * the new ones Ignored if the user doesn't have the 'suppressredirect' right
 3478+ * @param $createRedirect bool Whether to create redirects from the old subpages to the new ones
 3479+ * Ignored if the user doesn't have the 'suppressredirect' right
34273480 * @return mixed array with old page titles as keys, and strings (new page titles) or
3428 - * arrays (errors) as values, or an error array with numeric indices if no pages
3429 - * were moved
 3481+ * arrays (errors) as values, or an error array with numeric indices if no pages were moved
34303482 */
34313483 public function moveSubpages( $nt, $auth = true, $reason = '', $createRedirect = true ) {
34323484 global $wgMaximumMovedPages;
@@ -3492,7 +3544,7 @@
34933545 * Checks if this page is just a one-rev redirect.
34943546 * Adds lock, so don't use just for light purposes.
34953547 *
3496 - * @return Bool
 3548+ * @return \type{\bool}
34973549 */
34983550 public function isSingleRevRedirect() {
34993551 $dbw = wfGetDB( DB_MASTER );
@@ -3529,8 +3581,8 @@
35303582 * Checks if $this can be moved to a given Title
35313583 * - Selects for update, so don't call it unless you mean business
35323584 *
3533 - * @param $nt Title the new title to check
3534 - * @return Bool
 3585+ * @param $nt \type{Title} the new title to check
 3586+ * @return \type{\bool} TRUE or FALSE
35353587 */
35363588 public function isValidMoveTarget( $nt ) {
35373589 # Is it an existing file?
@@ -3571,7 +3623,7 @@
35723624 /**
35733625 * Can this title be added to a user's watchlist?
35743626 *
3575 - * @return Bool TRUE or FALSE
 3627+ * @return \type{\bool} TRUE or FALSE
35763628 */
35773629 public function isWatchable() {
35783630 return !$this->isExternal() && MWNamespace::isWatchable( $this->getNamespace() );
@@ -3581,35 +3633,31 @@
35823634 * Get categories to which this Title belongs and return an array of
35833635 * categories' names.
35843636 *
3585 - * @return Array of parents in the form:
3586 - * $parent => $currentarticle
 3637+ * @return \type{\array} array an array of parents in the form:
 3638+ * $parent => $currentarticle
35873639 */
35883640 public function getParentCategories() {
35893641 global $wgContLang;
35903642
3591 - $data = array();
3592 -
3593 - $titleKey = $this->getArticleId();
3594 -
3595 - if ( $titleKey === 0 ) {
3596 - return $data;
3597 - }
3598 -
 3643+ $titlekey = $this->getArticleId();
35993644 $dbr = wfGetDB( DB_SLAVE );
 3645+ $categorylinks = $dbr->tableName( 'categorylinks' );
36003646
3601 - $res = $dbr->select( 'categorylinks', '*',
3602 - array(
3603 - 'cl_from' => $titleKey,
3604 - ),
3605 - __METHOD__,
3606 - array()
3607 - );
 3647+ # NEW SQL
 3648+ $sql = "SELECT * FROM $categorylinks"
 3649+ . " WHERE cl_from='$titlekey'"
 3650+ . " AND cl_from <> '0'"
 3651+ . " ORDER BY cl_sortkey";
36083652
 3653+ $res = $dbr->query( $sql );
 3654+
36093655 if ( $dbr->numRows( $res ) > 0 ) {
3610 - foreach ( $res as $row ) {
 3656+ foreach ( $res as $row )
36113657 // $data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$row->cl_to);
36123658 $data[$wgContLang->getNSText( NS_CATEGORY ) . ':' . $row->cl_to] = $this->getFullText();
3613 - }
 3659+ $dbr->freeResult( $res );
 3660+ } else {
 3661+ $data = array();
36143662 }
36153663 return $data;
36163664 }
@@ -3617,8 +3665,8 @@
36183666 /**
36193667 * Get a tree of parent categories
36203668 *
3621 - * @param $children Array with the children in the keys, to check for circular refs
3622 - * @return Array Tree of parent categories
 3669+ * @param $children \type{\array} an array with the children in the keys, to check for circular refs
 3670+ * @return \type{\array} Tree of parent categories
36233671 */
36243672 public function getParentCategoryTree( $children = array() ) {
36253673 $stack = array();
@@ -3636,16 +3684,18 @@
36373685 }
36383686 }
36393687 }
 3688+ return $stack;
 3689+ } else {
 3690+ return array();
36403691 }
3641 -
3642 - return $stack;
36433692 }
36443693
 3694+
36453695 /**
36463696 * Get an associative array for selecting this title from
36473697 * the "page" table
36483698 *
3649 - * @return Array suitable for the $where parameter of DB::select()
 3699+ * @return \type{\array} Selection array
36503700 */
36513701 public function pageCond() {
36523702 if ( $this->mArticleID > 0 ) {
@@ -3659,12 +3709,12 @@
36603710 /**
36613711 * Get the revision ID of the previous revision
36623712 *
3663 - * @param $revId Int Revision ID. Get the revision that was before this one.
3664 - * @param $flags Int Title::GAID_FOR_UPDATE
3665 - * @return Int|Bool Old revision ID, or FALSE if none exists
 3713+ * @param $revId \type{\int} Revision ID. Get the revision that was before this one.
 3714+ * @param $flags \type{\int} GAID_FOR_UPDATE
 3715+ * @return \twotypes{\int,\bool} Old revision ID, or FALSE if none exists
36663716 */
36673717 public function getPreviousRevisionID( $revId, $flags = 0 ) {
3668 - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
 3718+ $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
36693719 return $db->selectField( 'revision', 'rev_id',
36703720 array(
36713721 'rev_page' => $this->getArticleId( $flags ),
@@ -3678,12 +3728,12 @@
36793729 /**
36803730 * Get the revision ID of the next revision
36813731 *
3682 - * @param $revId Int Revision ID. Get the revision that was after this one.
3683 - * @param $flags Int Title::GAID_FOR_UPDATE
3684 - * @return Int|Bool Next revision ID, or FALSE if none exists
 3732+ * @param $revId \type{\int} Revision ID. Get the revision that was after this one.
 3733+ * @param $flags \type{\int} GAID_FOR_UPDATE
 3734+ * @return \twotypes{\int,\bool} Next revision ID, or FALSE if none exists
36853735 */
36863736 public function getNextRevisionID( $revId, $flags = 0 ) {
3687 - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
 3737+ $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
36883738 return $db->selectField( 'revision', 'rev_id',
36893739 array(
36903740 'rev_page' => $this->getArticleId( $flags ),
@@ -3697,37 +3747,28 @@
36983748 /**
36993749 * Get the first revision of the page
37003750 *
3701 - * @param $flags Int Title::GAID_FOR_UPDATE
3702 - * @return Revision|Null if page doesn't exist
 3751+ * @param $flags \type{\int} GAID_FOR_UPDATE
 3752+ * @return Revision (or NULL if page doesn't exist)
37033753 */
37043754 public function getFirstRevision( $flags = 0 ) {
 3755+ $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
37053756 $pageId = $this->getArticleId( $flags );
3706 - if ( $pageId ) {
3707 - $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
3708 - $row = $db->selectRow( 'revision', '*',
3709 - array( 'rev_page' => $pageId ),
3710 - __METHOD__,
3711 - array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 )
3712 - );
3713 - if ( $row ) {
3714 - return new Revision( $row );
3715 - }
 3757+ if ( !$pageId ) {
 3758+ return null;
37163759 }
3717 - return null;
 3760+ $row = $db->selectRow( 'revision', '*',
 3761+ array( 'rev_page' => $pageId ),
 3762+ __METHOD__,
 3763+ array( 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 1 )
 3764+ );
 3765+ if ( !$row ) {
 3766+ return null;
 3767+ } else {
 3768+ return new Revision( $row );
 3769+ }
37183770 }
37193771
37203772 /**
3721 - * Get the oldest revision timestamp of this page
3722 - *
3723 - * @param $flags Int Title::GAID_FOR_UPDATE
3724 - * @return String: MW timestamp
3725 - */
3726 - public function getEarliestRevTime( $flags = 0 ) {
3727 - $rev = $this->getFirstRevision( $flags );
3728 - return $rev ? $rev->getTimestamp() : null;
3729 - }
3730 -
3731 - /**
37323773 * Check if this is a new page
37333774 *
37343775 * @return bool
@@ -3738,70 +3779,45 @@
37393780 }
37403781
37413782 /**
3742 - * Get the number of revisions between the given revision.
3743 - * Used for diffs and other things that really need it.
 3783+ * Get the oldest revision timestamp of this page
37443784 *
3745 - * @param $old int|Revision Old revision or rev ID (first before range)
3746 - * @param $new int|Revision New revision or rev ID (first after range)
3747 - * @return Int Number of revisions between these revisions.
 3785+ * @return String: MW timestamp
37483786 */
3749 - public function countRevisionsBetween( $old, $new ) {
3750 - if ( !( $old instanceof Revision ) ) {
3751 - $old = Revision::newFromTitle( $this, (int)$old );
3752 - }
3753 - if ( !( $new instanceof Revision ) ) {
3754 - $new = Revision::newFromTitle( $this, (int)$new );
3755 - }
3756 - if ( !$old || !$new ) {
3757 - return 0; // nothing to compare
3758 - }
 3787+ public function getEarliestRevTime() {
37593788 $dbr = wfGetDB( DB_SLAVE );
3760 - return (int)$dbr->selectField( 'revision', 'count(*)',
3761 - array(
3762 - 'rev_page' => $this->getArticleId(),
3763 - 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
3764 - 'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) )
3765 - ),
3766 - __METHOD__
3767 - );
 3789+ if ( $this->exists() ) {
 3790+ $min = $dbr->selectField( 'revision',
 3791+ 'MIN(rev_timestamp)',
 3792+ array( 'rev_page' => $this->getArticleId() ),
 3793+ __METHOD__ );
 3794+ return wfTimestampOrNull( TS_MW, $min );
 3795+ }
 3796+ return null;
37683797 }
37693798
37703799 /**
3771 - * Get the number of authors between the given revision IDs.
 3800+ * Get the number of revisions between the given revision IDs.
37723801 * Used for diffs and other things that really need it.
37733802 *
3774 - * @param $old int|Revision Old revision or rev ID (first before range)
3775 - * @param $new int|Revision New revision or rev ID (first after range)
3776 - * @param $limit Int Maximum number of authors
3777 - * @return Int Number of revision authors between these revisions.
 3803+ * @param $old \type{\int} Revision ID.
 3804+ * @param $new \type{\int} Revision ID.
 3805+ * @return \type{\int} Number of revisions between these IDs.
37783806 */
3779 - public function countAuthorsBetween( $old, $new, $limit ) {
3780 - if ( !( $old instanceof Revision ) ) {
3781 - $old = Revision::newFromTitle( $this, (int)$old );
3782 - }
3783 - if ( !( $new instanceof Revision ) ) {
3784 - $new = Revision::newFromTitle( $this, (int)$new );
3785 - }
3786 - if ( !$old || !$new ) {
3787 - return 0; // nothing to compare
3788 - }
 3807+ public function countRevisionsBetween( $old, $new ) {
37893808 $dbr = wfGetDB( DB_SLAVE );
3790 - $res = $dbr->select( 'revision', 'DISTINCT rev_user_text',
3791 - array(
3792 - 'rev_page' => $this->getArticleID(),
3793 - 'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
3794 - 'rev_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $new->getTimestamp() ) )
3795 - ), __METHOD__,
3796 - array( 'LIMIT' => $limit + 1 ) // add one so caller knows it was truncated
 3809+ return (int)$dbr->selectField( 'revision', 'count(*)',
 3810+ 'rev_page = ' . intval( $this->getArticleId() ) .
 3811+ ' AND rev_id > ' . intval( $old ) .
 3812+ ' AND rev_id < ' . intval( $new ),
 3813+ __METHOD__
37973814 );
3798 - return (int)$dbr->numRows( $res );
37993815 }
38003816
38013817 /**
38023818 * Compare with another title.
38033819 *
3804 - * @param $title Title
3805 - * @return Bool
 3820+ * @param $title \type{Title}
 3821+ * @return \type{\bool} TRUE or FALSE
38063822 */
38073823 public function equals( Title $title ) {
38083824 // Note: === is necessary for proper matching of number-like titles.
@@ -3812,10 +3828,7 @@
38133829
38143830 /**
38153831 * Callback for usort() to do title sorts by (namespace, title)
3816 - *
3817 - * @param $a Title
3818 - * @param $b Title
3819 - *
 3832+ *
38203833 * @return Integer: result of string comparison, or namespace comparison
38213834 */
38223835 public static function compare( $a, $b ) {
@@ -3829,7 +3842,7 @@
38303843 /**
38313844 * Return a string representation of this title
38323845 *
3833 - * @return String representation of this title
 3846+ * @return \type{\string} String representation of this title
38343847 */
38353848 public function __toString() {
38363849 return $this->getPrefixedText();
@@ -3842,7 +3855,7 @@
38433856 * If you want to know if a title can be meaningfully viewed, you should
38443857 * probably call the isKnown() method instead.
38453858 *
3846 - * @return Bool
 3859+ * @return \type{\bool}
38473860 */
38483861 public function exists() {
38493862 return $this->getArticleId() != 0;
@@ -3862,28 +3875,28 @@
38633876 * existing code, but we might want to add an optional parameter to skip
38643877 * it and any other expensive checks.)
38653878 *
3866 - * @return Bool
 3879+ * @return \type{\bool}
38673880 */
38683881 public function isAlwaysKnown() {
38693882 if ( $this->mInterwiki != '' ) {
38703883 return true; // any interwiki link might be viewable, for all we know
38713884 }
38723885 switch( $this->mNamespace ) {
3873 - case NS_MEDIA:
3874 - case NS_FILE:
3875 - // file exists, possibly in a foreign repo
3876 - return (bool)wfFindFile( $this );
3877 - case NS_SPECIAL:
3878 - // valid special page
3879 - return SpecialPageFactory::exists( $this->getDBkey() );
3880 - case NS_MAIN:
3881 - // selflink, possibly with fragment
3882 - return $this->mDbkeyform == '';
3883 - case NS_MEDIAWIKI:
3884 - // known system message
3885 - return $this->getDefaultMessageText() !== false;
3886 - default:
3887 - return false;
 3886+ case NS_MEDIA:
 3887+ case NS_FILE:
 3888+ return (bool)wfFindFile( $this ); // file exists, possibly in a foreign repo
 3889+ case NS_SPECIAL:
 3890+ return SpecialPage::exists( $this->getDBkey() ); // valid special page
 3891+ case NS_MAIN:
 3892+ return $this->mDbkeyform == ''; // selflink, possibly with fragment
 3893+ case NS_MEDIAWIKI:
 3894+ // If the page is form Mediawiki:message/lang, calling wfMsgWeirdKey causes
 3895+ // the full l10n of that language to be loaded. That takes much memory and
 3896+ // isn't needed. So we strip the language part away.
 3897+ list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 );
 3898+ return (bool)wfMsgWeirdKey( $basename ); // known system message
 3899+ default:
 3900+ return false;
38883901 }
38893902 }
38903903
@@ -3893,10 +3906,10 @@
38943907 * links to the title should be rendered as "bluelinks" (as opposed to
38953908 * "redlinks" to non-existent pages).
38963909 *
3897 - * @return Bool
 3910+ * @return \type{\bool}
38983911 */
38993912 public function isKnown() {
3900 - return $this->isAlwaysKnown() || $this->exists();
 3913+ return $this->exists() || $this->isAlwaysKnown();
39013914 }
39023915
39033916 /**
@@ -3912,38 +3925,20 @@
39133926 if ( $this->mNamespace == NS_MEDIAWIKI ) {
39143927 // If the page doesn't exist but is a known system message, default
39153928 // message content will be displayed, same for language subpages
3916 - return $this->getDefaultMessageText() !== false;
 3929+ // Also, if the page is form Mediawiki:message/lang, calling wfMsgWeirdKey
 3930+ // causes the full l10n of that language to be loaded. That takes much
 3931+ // memory and isn't needed. So we strip the language part away.
 3932+ list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 );
 3933+ return (bool)wfMsgWeirdKey( $basename );
39173934 }
39183935
39193936 return false;
39203937 }
39213938
39223939 /**
3923 - * Get the default message text or false if the message doesn't exist
3924 - *
3925 - * @return String or false
3926 - */
3927 - public function getDefaultMessageText() {
3928 - global $wgContLang;
3929 -
3930 - if ( $this->getNamespace() != NS_MEDIAWIKI ) { // Just in case
3931 - return false;
3932 - }
3933 -
3934 - list( $name, $lang ) = MessageCache::singleton()->figureMessage( $wgContLang->lcfirst( $this->getText() ) );
3935 - $message = wfMessage( $name )->inLanguage( $lang )->useDatabase( false );
3936 -
3937 - if ( $message->exists() ) {
3938 - return $message->plain();
3939 - } else {
3940 - return false;
3941 - }
3942 - }
3943 -
3944 - /**
39453940 * Is this in a namespace that allows actual pages?
39463941 *
3947 - * @return Bool
 3942+ * @return \type{\bool}
39483943 * @internal note -- uses hardcoded namespace index instead of constants
39493944 */
39503945 public function canExist() {
@@ -3969,7 +3964,7 @@
39703965 * Get the last touched timestamp
39713966 *
39723967 * @param $db DatabaseBase: optional db
3973 - * @return String last-touched timestamp
 3968+ * @return \type{\string} Last touched timestamp
39743969 */
39753970 public function getTouched( $db = null ) {
39763971 $db = isset( $db ) ? $db : wfGetDB( DB_SLAVE );
@@ -3981,7 +3976,7 @@
39823977 * Get the timestamp when this page was updated since the user last saw it.
39833978 *
39843979 * @param $user User
3985 - * @return String|Null
 3980+ * @return Mixed: string/null
39863981 */
39873982 public function getNotificationTimestamp( $user = null ) {
39883983 global $wgUser, $wgShowUpdatedMarker;
@@ -3991,8 +3986,7 @@
39923987 }
39933988 // Check cache first
39943989 $uid = $user->getId();
3995 - // avoid isset here, as it'll return false for null entries
3996 - if ( array_key_exists( $uid, $this->mNotificationTimestamp ) ) {
 3990+ if ( isset( $this->mNotificationTimestamp[$uid] ) ) {
39973991 return $this->mNotificationTimestamp[$uid];
39983992 }
39993993 if ( !$uid || !$wgShowUpdatedMarker ) {
@@ -4017,7 +4011,7 @@
40184012 /**
40194013 * Get the trackback URL for this page
40204014 *
4021 - * @return String Trackback URL
 4015+ * @return \type{\string} Trackback URL
40224016 */
40234017 public function trackbackURL() {
40244018 global $wgScriptPath, $wgServer, $wgScriptExtension;
@@ -4029,7 +4023,7 @@
40304024 /**
40314025 * Get the trackback RDF for this page
40324026 *
4033 - * @return String Trackback RDF
 4027+ * @return \type{\string} Trackback RDF
40344028 */
40354029 public function trackbackRDF() {
40364030 $url = htmlspecialchars( $this->getFullURL() );
@@ -4043,8 +4037,8 @@
40444038 // Spec: http://www.sixapart.com/pronet/docs/trackback_spec
40454039 return "<!--
40464040 <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"
4047 - xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
4048 - xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
 4041+ xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
 4042+ xmlns:trackback=\"http://madskills.com/public/xml/rss/module/trackback/\">
40494043 <rdf:Description
40504044 rdf:about=\"$url\"
40514045 dc:identifier=\"$url\"
@@ -4058,7 +4052,7 @@
40594053 * Generate strings used for xml 'id' names in monobook tabs
40604054 *
40614055 * @param $prepend string defaults to 'nstab-'
4062 - * @return String XML 'id' name
 4056+ * @return \type{\string} XML 'id' name
40634057 */
40644058 public function getNamespaceKey( $prepend = 'nstab-' ) {
40654059 global $wgContLang;
@@ -4097,12 +4091,12 @@
40984092 /**
40994093 * Returns true if this title resolves to the named special page
41004094 *
4101 - * @param $name String The special page name
 4095+ * @param $name \type{\string} The special page name
41024096 * @return boolean
41034097 */
41044098 public function isSpecial( $name ) {
41054099 if ( $this->getNamespace() == NS_SPECIAL ) {
4106 - list( $thisName, /* $subpage */ ) = SpecialPageFactory::resolveAlias( $this->getDBkey() );
 4100+ list( $thisName, /* $subpage */ ) = SpecialPage::resolveAliasWithSubpage( $this->getDBkey() );
41074101 if ( $name == $thisName ) {
41084102 return true;
41094103 }
@@ -4111,16 +4105,16 @@
41124106 }
41134107
41144108 /**
4115 - * If the Title refers to a special page alias which is not the local default, resolve
4116 - * the alias, and localise the name as necessary. Otherwise, return $this
 4109+ * If the Title refers to a special page alias which is not the local default,
41174110 *
4118 - * @return Title
 4111+ * @return \type{Title} A new Title which points to the local default.
 4112+ * Otherwise, returns $this.
41194113 */
41204114 public function fixSpecialName() {
41214115 if ( $this->getNamespace() == NS_SPECIAL ) {
4122 - list( $canonicalName, /*...*/ ) = SpecialPageFactory::resolveAlias( $this->mDbkeyform );
 4116+ $canonicalName = SpecialPage::resolveAlias( $this->mDbkeyform );
41234117 if ( $canonicalName ) {
4124 - $localName = SpecialPageFactory::getLocalNameFor( $canonicalName );
 4118+ $localName = SpecialPage::getLocalNameFor( $canonicalName );
41254119 if ( $localName != $this->mDbkeyform ) {
41264120 return Title::makeTitle( NS_SPECIAL, $localName );
41274121 }
@@ -4134,7 +4128,7 @@
41354129 * In other words, is this a content page, for the purposes of calculating
41364130 * statistics, etc?
41374131 *
4138 - * @return Boolean
 4132+ * @return \type{\bool}
41394133 */
41404134 public function isContentPage() {
41414135 return MWNamespace::isContent( $this->getNamespace() );
@@ -4143,8 +4137,9 @@
41444138 /**
41454139 * Get all extant redirects to this Title
41464140 *
4147 - * @param $ns Int|Null Single namespace to consider; NULL to consider all namespaces
4148 - * @return Array of Title redirects to this title
 4141+ * @param $ns \twotypes{\int,\null} Single namespace to consider;
 4142+ * NULL to consider all namespaces
 4143+ * @return \type{\arrayof{Title}} Redirects to this title
41494144 */
41504145 public function getRedirectsHere( $ns = null ) {
41514146 $redirs = array();
@@ -4166,6 +4161,7 @@
41674162 __METHOD__
41684163 );
41694164
 4165+
41704166 foreach ( $res as $row ) {
41714167 $redirs[] = self::newFromRow( $row );
41724168 }
@@ -4175,7 +4171,7 @@
41764172 /**
41774173 * Check if this Title is a valid redirect target
41784174 *
4179 - * @return Bool
 4175+ * @return \type{\bool}
41804176 */
41814177 public function isValidRedirectTarget() {
41824178 global $wgInvalidRedirectTargets;
@@ -4207,7 +4203,8 @@
42084204 }
42094205
42104206 /**
4211 - * Whether the magic words __INDEX__ and __NOINDEX__ function for this page.
 4207+ * Whether the magic words __INDEX__ and __NOINDEX__ function for
 4208+ * this page.
42124209 *
42134210 * @return Boolean
42144211 */
@@ -4228,47 +4225,21 @@
42294226 * @return array applicable restriction types
42304227 */
42314228 public function getRestrictionTypes() {
4232 - if ( $this->getNamespace() == NS_SPECIAL ) {
4233 - return array();
4234 - }
 4229+ global $wgRestrictionTypes;
 4230+ $types = $this->exists() ? $wgRestrictionTypes : array( 'create' );
42354231
4236 - $types = self::getFilteredRestrictionTypes( $this->exists() );
4237 -
4238 - if ( $this->getNamespace() != NS_FILE ) {
4239 - # Remove the upload restriction for non-file titles
4240 - $types = array_diff( $types, array( 'upload' ) );
 4232+ if ( $this->getNamespace() == NS_FILE ) {
 4233+ $types[] = 'upload';
42414234 }
42424235
42434236 wfRunHooks( 'TitleGetRestrictionTypes', array( $this, &$types ) );
42444237
4245 - wfDebug( __METHOD__ . ': applicable restriction types for ' .
4246 - $this->getPrefixedText() . ' are ' . implode( ',', $types ) . "\n" );
4247 -
42484238 return $types;
42494239 }
4250 - /**
4251 - * Get a filtered list of all restriction types supported by this wiki.
4252 - * @param bool $exists True to get all restriction types that apply to
4253 - * titles that do exist, False for all restriction types that apply to
4254 - * titles that do not exist
4255 - * @return array
4256 - */
4257 - public static function getFilteredRestrictionTypes( $exists = true ) {
4258 - global $wgRestrictionTypes;
4259 - $types = $wgRestrictionTypes;
4260 - if ( $exists ) {
4261 - # Remove the create restriction for existing titles
4262 - $types = array_diff( $types, array( 'create' ) );
4263 - } else {
4264 - # Only the create and upload restrictions apply to non-existing titles
4265 - $types = array_intersect( $types, array( 'create', 'upload' ) );
4266 - }
4267 - return $types;
4268 - }
42694240
42704241 /**
42714242 * Returns the raw sort key to be used for categories, with the specified
4272 - * prefix. This will be fed to Collation::getSortKey() to get a
 4243+ * prefix. This will be fed to Language::convertToSortkey() to get a
42734244 * binary sortkey that can be used for actual sorting.
42744245 *
42754246 * @param $prefix string The prefix to be used, specified using
@@ -4285,12 +4256,10 @@
42864257 // in order to re-sort existing category relations.
42874258 wfRunHooks( 'GetDefaultSortkey', array( $this, &$unprefixed ) );
42884259 if ( $prefix !== '' ) {
4289 - # Separate with a line feed, so the unprefixed part is only used as
4290 - # a tiebreaker when two pages have the exact same prefix.
4291 - # In UCA, tab is the only character that can sort above LF
4292 - # so we strip both of them from the original prefix.
4293 - $prefix = strtr( $prefix, "\n\t", ' ' );
4294 - return "$prefix\n$unprefixed";
 4260+ # Separate with a null byte, so the unprefixed part is only used as
 4261+ # a tiebreaker when two pages have the exact same prefix -- null
 4262+ # sorts before everything else (hopefully).
 4263+ return "$prefix\0$unprefixed";
42954264 }
42964265 return $unprefixed;
42974266 }
@@ -4326,37 +4295,3 @@
43274296 return wfGetLangObj( $pageLang );
43284297 }
43294298 }
4330 -
4331 -/**
4332 - * A BadTitle is generated in MediaWiki::parseTitle() if the title is invalid; the
4333 - * software uses this to display an error page. Internally it's basically a Title
4334 - * for an empty special page
4335 - */
4336 -class BadTitle extends Title {
4337 - public function __construct(){
4338 - $this->mTextform = '';
4339 - $this->mUrlform = '';
4340 - $this->mDbkeyform = '';
4341 - $this->mNamespace = NS_SPECIAL; // Stops talk page link, etc, being shown
4342 - }
4343 -
4344 - public function exists(){
4345 - return false;
4346 - }
4347 -
4348 - public function getPrefixedText(){
4349 - return '';
4350 - }
4351 -
4352 - public function getText(){
4353 - return '';
4354 - }
4355 -
4356 - public function getPrefixedURL(){
4357 - return '';
4358 - }
4359 -
4360 - public function getPrefixedDBKey(){
4361 - return '';
4362 - }
4363 -}
Property changes on: branches/iwtransclusion/phase3v3/includes/Title.php
___________________________________________________________________
Modified: svn:mergeinfo
43644299 Merged /branches/iwtransclusion/phase3v2/includes/Title.php:r87108
43654300 Merged /branches/iwtransclusion/phase3/includes/Title.php:r70764
Index: branches/iwtransclusion/phase3v3/languages/messages/MessagesEn.php
@@ -1399,6 +1399,9 @@
14001400 'templatesused' => '{{PLURAL:$1|Template|Templates}} used on this page:',
14011401 'templatesusedpreview' => '{{PLURAL:$1|Template|Templates}} used in this preview:',
14021402 'templatesusedsection' => '{{PLURAL:$1|Template|Templates}} used in this section:',
 1403+'distanttemplatesused' => 'Distant {{PLURAL:$1|template|templates}} used on this page:',
 1404+'distanttemplatesusedpreview' => 'Distant {{PLURAL:$1|template|templates}} used in this preview:',
 1405+'distanttemplatesusedsection' => 'Distant {{PLURAL:$1|template|templates}} used in this section:',
14031406 'template-protected' => '(protected)',
14041407 'template-semiprotected' => '(semi-protected)',
14051408 'hiddencategories' => 'This page is a member of {{PLURAL:$1|1 hidden category|$1 hidden categories}}:',

Follow-up revisions

RevisionCommit summaryAuthorDate
r92991Revert r92990reedy17:44, 24 July 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r70764Fix remarks about r70576; display the distant templates below the edit textareapeter1714:46, 9 August 2010
r87108Merge r70764reedy00:40, 29 April 2011

Status & tagging log