X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2FTitle.php;h=cec0067f37d317509f405b971e7b7f383e66371b;hb=eda718909ccadbeda0df126f49a78336471190c1;hp=9d2f4c9abe9d954c685456fc6d3396d10f4a2f75;hpb=f4aba377e31ad1fc0287ded2fd5d4f4dc3d5317a;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Title.php b/includes/Title.php index 9d2f4c9abe..cec0067f37 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -13,7 +13,11 @@ if ( !class_exists( 'UtfNormal' ) ) { require_once( dirname( __FILE__ ) . '/normal/UtfNormal.php' ); } -define ( 'GAID_FOR_UPDATE', 1 ); +/** + * @deprecated This used to be a define, but was moved to + * Title::GAID_FOR_UPDATE in 1.17. This will probably be removed in 1.18 + */ +define( 'GAID_FOR_UPDATE', Title::GAID_FOR_UPDATE ); /** * Represents a title within MediaWiki. @@ -27,7 +31,6 @@ class Title { /** @name Static cache variables */ // @{ static private $titleCache = array(); - static private $interwikiCache = array(); // @} /** @@ -37,6 +40,12 @@ class Title { */ const CACHE_MAX = 1000; + /** + * Used to be GAID_FOR_UPDATE define. Used with getArticleId() and friends + * to use the master DB + */ + const GAID_FOR_UPDATE = 1; + /** * @name Private member variables @@ -93,10 +102,11 @@ class Title { public static function newFromDBkey( $key ) { $t = new Title(); $t->mDbkeyform = $key; - if ( $t->secureAndSplit() ) + if ( $t->secureAndSplit() ) { return $t; - else + } else { return null; + } } /** @@ -129,7 +139,7 @@ class Title { } /** - * Convert things like é ā or 〗 into normalized(bug 14952) text + * Convert things like é ā or 〗 into normalized (bug 14952) text */ $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text ); @@ -193,11 +203,11 @@ class Title { * Create a new Title from an article ID * * @param $id \type{\int} the page_id corresponding to the Title to create - * @param $flags \type{\int} use GAID_FOR_UPDATE to use master + * @param $flags \type{\int} use Title::GAID_FOR_UPDATE to use master * @return \type{Title} the new object, or NULL on an error */ public static function newFromID( $id, $flags = 0 ) { - $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); + $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); $row = $db->selectRow( 'page', '*', array( 'page_id' => $id ), __METHOD__ ); if ( $row !== false ) { $title = Title::newFromRow( $row ); @@ -219,8 +229,15 @@ class Title { } $dbr = wfGetDB( DB_SLAVE ); - $res = $dbr->select( 'page', array( '*' ), - array( 'page_id' => $ids ), __METHOD__ ); + $res = $dbr->select( + 'page', + array( + 'page_namespace', 'page_title', 'page_id', + 'page_len', 'page_is_redirect', 'page_latest', + ), + array( 'page_id' => $ids ), + __METHOD__ + ); $titles = array(); foreach ( $res as $row ) { @@ -345,11 +362,13 @@ class Title { public static function newFromRedirectArray( $text ) { global $wgMaxRedirects; // are redirects disabled? - if ( $wgMaxRedirects < 1 ) + if ( $wgMaxRedirects < 1 ) { return null; + } $title = self::newFromRedirectInternal( $text ); - if ( is_null( $title ) ) + if ( is_null( $title ) ) { return null; + } // recursive check to follow double redirects $recurse = $wgMaxRedirects; $titles = array( $title ); @@ -421,11 +440,15 @@ class Title { public static function nameOf( $id ) { $dbr = wfGetDB( DB_SLAVE ); - $s = $dbr->selectRow( 'page', + $s = $dbr->selectRow( + 'page', array( 'page_namespace', 'page_title' ), array( 'page_id' => $id ), - __METHOD__ ); - if ( $s === false ) { return null; } + __METHOD__ + ); + if ( $s === false ) { + return null; + } $n = self::makeName( $s->page_namespace, $s->page_title ); return $n; @@ -515,8 +538,9 @@ class Title { * @return \type{\bool} TRUE if this is transcludable */ public function isTrans() { - if ( $this->mInterwiki == '' ) + if ( $this->mInterwiki == '' ) { return false; + } return Interwiki::fetch( $this->mInterwiki )->isTranscludable(); } @@ -528,8 +552,9 @@ class Title { * @return \type{\string} the DB name */ public function getTransWikiID() { - if ( $this->mInterwiki == '' ) + if ( $this->mInterwiki == '' ) { return false; + } return Interwiki::fetch( $this->mInterwiki )->getWikiID(); } @@ -738,8 +763,9 @@ class Title { $parts = explode( '/', $this->getText() ); # Don't discard the real title if there's no subpage involved - if ( count( $parts ) > 1 ) - unset( $parts[ count( $parts ) - 1 ] ); + if ( count( $parts ) > 1 ) { + unset( $parts[count( $parts ) - 1] ); + } return implode( '/', $parts ); } @@ -753,7 +779,7 @@ class Title { return( $this->mTextform ); } $parts = explode( '/', $this->mTextform ); - return( $parts[ count( $parts ) - 1 ] ); + return( $parts[count( $parts ) - 1] ); } /** @@ -789,7 +815,7 @@ class Title { * @return \type{\string} the URL */ public function getFullURL( $query = '', $variant = false ) { - global $wgContLang, $wgServer, $wgRequest; + global $wgServer, $wgRequest; if ( is_array( $query ) ) { $query = wfArrayToCGI( $query ); @@ -805,7 +831,7 @@ class Title { $url = $wgServer . $url; } } else { - $baseUrl = $interwiki->getURL( ); + $baseUrl = $interwiki->getURL(); $namespace = wfUrlencode( $this->getNsText() ); if ( $namespace != '' ) { @@ -837,19 +863,12 @@ class Title { */ public function getLocalURL( $query = '', $variant = false ) { global $wgArticlePath, $wgScript, $wgServer, $wgRequest; - global $wgVariantArticlePath, $wgContLang, $wgUser; + global $wgVariantArticlePath, $wgContLang; if ( is_array( $query ) ) { $query = wfArrayToCGI( $query ); } - // internal links should point to same variant as current page (only anonymous users) - if ( !$variant && $wgContLang->hasVariants() && !$wgUser->isLoggedIn() ) { - $pref = $wgContLang->getPreferredVariant( false ); - if ( $pref != $wgContLang->getCode() ) - $variant = $pref; - } - if ( $this->isExternal() ) { $url = $this->getFullURL(); if ( $query ) { @@ -883,7 +902,9 @@ class Title { $action = urldecode( $matches[2] ); if ( isset( $wgActionPaths[$action] ) ) { $query = $matches[1]; - if ( isset( $matches[4] ) ) $query .= $matches[4]; + if ( isset( $matches[4] ) ) { + $query .= $matches[4]; + } $url = str_replace( '$1', $dbkey, $wgActionPaths[$action] ); if ( $query != '' ) { $url = wfAppendQuery( $url, $query ); @@ -983,7 +1004,9 @@ class Title { * interwiki link */ public function getEditURL() { - if ( $this->mInterwiki != '' ) { return ''; } + if ( $this->mInterwiki != '' ) { + return ''; + } $s = $this->getLocalURL( 'action=edit' ); return $s; @@ -1004,7 +1027,9 @@ class Title { * * @return \type{\bool} */ - public function isExternal() { return ( $this->mInterwiki != '' ); } + public function isExternal() { + return ( $this->mInterwiki != '' ); + } /** * Is this page "semi-protected" - the *only* protection is autoconfirm? @@ -1017,8 +1042,9 @@ class Title { $restrictions = $this->getRestrictions( $action ); if ( count( $restrictions ) > 0 ) { foreach ( $restrictions as $restriction ) { - if ( strtolower( $restriction ) != 'autoconfirmed' ) + if ( strtolower( $restriction ) != 'autoconfirmed' ) { return false; + } } } else { # Not protected @@ -1044,8 +1070,9 @@ class Title { $restrictionTypes = $this->getRestrictionTypes(); # Special pages have inherent protection - if( $this->getNamespace() == NS_SPECIAL ) + if( $this->getNamespace() == NS_SPECIAL ) { return true; + } # Check regular protection levels foreach ( $restrictionTypes as $type ) { @@ -1068,8 +1095,11 @@ class Title { * @return \type{\bool} */ public function isConversionTable() { - if($this->getNamespace() == NS_MEDIAWIKI - && strpos( $this->getText(), 'Conversiontable' ) !== false ) { + if( + $this->getNamespace() == NS_MEDIAWIKI && + strpos( $this->getText(), 'Conversiontable' ) !== false + ) + { return true; } @@ -1119,10 +1149,11 @@ class Title { */ public function isNamespaceProtected() { global $wgNamespaceProtection, $wgUser; - if ( isset( $wgNamespaceProtection[ $this->mNamespace ] ) ) { - foreach ( (array)$wgNamespaceProtection[ $this->mNamespace ] as $right ) { - if ( $right != '' && !$wgUser->isAllowed( $right ) ) + if ( isset( $wgNamespaceProtection[$this->mNamespace] ) ) { + foreach ( (array)$wgNamespaceProtection[$this->mNamespace] as $right ) { + if ( $right != '' && !$wgUser->isAllowed( $right ) ) { return true; + } } } return false; @@ -1152,14 +1183,6 @@ class Title { * @return \type{\array} Array of arrays of the arguments to wfMsg to explain permissions problems. */ public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) { - if ( !StubObject::isRealObject( $user ) ) { - // Since StubObject is always used on globals, we can - // unstub $wgUser here and set $user = $wgUser - global $wgUser; - $wgUser->_unstub( '', 5 ); - $user = $wgUser; - } - $errors = $this->getUserPermissionsErrorsInternal( $action, $user, $doExpensiveQueries ); // Remove the errors being ignored. @@ -1189,7 +1212,7 @@ class Title { if ( $action == 'create' ) { if ( ( $this->isTalkPage() && !$user->isAllowed( 'createtalk' ) ) || ( !$this->isTalkPage() && !$user->isAllowed( 'createpage' ) ) ) { - $errors[] = $user->isAnon() ? array ( 'nocreatetext' ) : array ( 'nocreate-loggedin' ); + $errors[] = $user->isAnon() ? array( 'nocreatetext' ) : array( 'nocreate-loggedin' ); } } elseif ( $action == 'move' ) { if ( !$user->isAllowed( 'move-rootuserpages' ) @@ -1216,23 +1239,21 @@ class Title { } if ( $user->isAnon() && ( $userCanMove || $autoconfirmedCanMove ) ) { // custom message if logged-in users without any special rights can move - $errors[] = array ( 'movenologintext' ); + $errors[] = array( 'movenologintext' ); } else { - $errors[] = array ( 'movenotallowed' ); + $errors[] = array( 'movenotallowed' ); } } } elseif ( $action == 'move-target' ) { if ( !$user->isAllowed( 'move' ) ) { // User can't move anything - $errors[] = array ( 'movenotallowed' ); + $errors[] = array( 'movenotallowed' ); } elseif ( !$user->isAllowed( 'move-rootuserpages' ) && $this->mNamespace == NS_USER && !$this->isSubpage() ) { // Show user page-specific message only if the user can move other pages $errors[] = array( 'cant-move-to-user-page' ); } } elseif ( !$user->isAllowed( $action ) ) { - $return = null; - // We avoid expensive display logic for quickUserCan's and such $groups = false; if ( !$short ) { @@ -1248,7 +1269,7 @@ class Title { count( $groups ) ); } else { - $return = array( "badaccess-group0" ); + $return = array( 'badaccess-group0' ); } $errors[] = $return; } @@ -1287,6 +1308,7 @@ class Title { */ private function checkPermissionHooks( $action, $user, $errors, $doExpensiveQueries, $short ) { // Use getUserPermissionsErrors instead + $result = ''; if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) { return $result ? array() : array( array( 'badaccess-group0' ) ); } @@ -1457,9 +1479,7 @@ class Title { return $errors; } - global $wgContLang; - global $wgLang; - global $wgEmailConfirmToEdit; + global $wgContLang, $wgLang, $wgEmailConfirmToEdit; if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' ) { $errors[] = array( 'confirmedittext' ); @@ -1497,7 +1517,7 @@ class Title { if ( !strpos( $option, ':' ) ) continue; - list ( $show, $value ) = explode( ":", $option ); + list( $show, $value ) = explode( ':', $option ); if ( $value == 'infinite' || $value == 'indefinite' ) { $blockExpiry = $show; @@ -1532,14 +1552,16 @@ class Title { wfProfileIn( __METHOD__ ); $errors = array(); - $checks = array( 'checkQuickPermissions', + $checks = array( + 'checkQuickPermissions', 'checkPermissionHooks', 'checkSpecialsAndNSPermissions', 'checkCSSandJSPermissions', 'checkPageRestrictions', 'checkCascadingSourcesRestrictions', 'checkActionPermissions', - 'checkUserBlock' ); + 'checkUserBlock' + ); while( count( $checks ) > 0 && !( $short && count( $errors ) > 0 ) ) { @@ -1607,8 +1629,7 @@ class Title { if ( $encodedExpiry != 'infinity' ) { $expiry_description = ' (' . wfMsgForContent( 'protect-expiring', $wgContLang->timeanddate( $expiry ), $wgContLang->date( $expiry ) , $wgContLang->time( $expiry ) ) . ')'; - } - else { + } else { $expiry_description .= ' (' . wfMsgForContent( 'protect-expiry-indefinite' ) . ')'; } @@ -1650,9 +1671,11 @@ class Title { public function deleteTitleProtection() { $dbw = wfGetDB( DB_MASTER ); - $dbw->delete( 'protected_titles', + $dbw->delete( + 'protected_titles', array( 'pt_namespace' => $this->getNamespace(), 'pt_title' => $this->getDBkey() ), - __METHOD__ ); + __METHOD__ + ); } /** @@ -1707,8 +1730,9 @@ class Title { } # Shortcut for public wikis, allows skipping quite a bit of code - if ( $useShortcut ) + if ( $useShortcut ) { return true; + } if ( $wgUser->isAllowed( 'read' ) ) { return true; @@ -1744,8 +1768,9 @@ class Title { * a colon for main-namespace pages */ if ( $this->getNamespace() == NS_MAIN ) { - if ( in_array( ':' . $name, $wgWhitelistRead ) ) + if ( in_array( ':' . $name, $wgWhitelistRead ) ) { return true; + } } /** @@ -1761,8 +1786,9 @@ class Title { } $pure = SpecialPage::getTitleFor( $name )->getPrefixedText(); - if ( in_array( $pure, $wgWhitelistRead, true ) ) + if ( in_array( $pure, $wgWhitelistRead, true ) ) { return true; + } } } @@ -1809,8 +1835,9 @@ class Title { } $subpages = $this->getSubpages( 1 ); - if ( $subpages instanceof TitleArray ) + if ( $subpages instanceof TitleArray ) { return $this->mHasSubpages = (bool)$subpages->count(); + } return $this->mHasSubpages = false; } @@ -1822,15 +1849,17 @@ class Title { * doesn't allow subpages */ public function getSubpages( $limit = -1 ) { - if ( !MWNamespace::hasSubpages( $this->getNamespace() ) ) + if ( !MWNamespace::hasSubpages( $this->getNamespace() ) ) { return array(); + } $dbr = wfGetDB( DB_SLAVE ); $conds['page_namespace'] = $this->getNamespace(); $conds[] = 'page_title ' . $dbr->buildLike( $this->getDBkey() . '/', $dbr->anyString() ); $options = array(); - if ( $limit > -1 ) + if ( $limit > -1 ) { $options['LIMIT'] = $limit; + } return $this->mSubpages = TitleArray::newFromResult( $dbr->select( 'page', array( 'page_id', 'page_namespace', 'page_title', 'page_is_redirect' ), @@ -1869,7 +1898,9 @@ class Title { public function isValidCssJsSubpage() { if ( $this->isCssJsSubpage() ) { $name = $this->getSkinFromCssJsSubpage(); - if ( $name == 'common' ) return true; + if ( $name == 'common' ) { + return true; + } $skinNames = Skin::getSkinNames(); return array_key_exists( $name, $skinNames ); } else { @@ -1918,6 +1949,7 @@ class Title { return ( ( $wgUser->isAllowed( 'editusercssjs' ) && $wgUser->isAllowed( 'editusercss' ) ) || preg_match( '/^' . preg_quote( $wgUser->getName(), '/' ) . '\//', $this->mTextform ) ); } + /** * Protect js subpages of user pages: can $wgUser edit * this page? @@ -1966,18 +1998,20 @@ class Title { $dbr = wfGetDB( DB_SLAVE ); if ( $this->getNamespace() == NS_FILE ) { - $tables = array ( 'imagelinks', 'page_restrictions' ); + $tables = array( 'imagelinks', 'page_restrictions' ); $where_clauses = array( 'il_to' => $this->getDBkey(), 'il_from=pr_page', - 'pr_cascade' => 1 ); + 'pr_cascade' => 1 + ); } else { - $tables = array ( 'templatelinks', 'page_restrictions' ); + $tables = array( 'templatelinks', 'page_restrictions' ); $where_clauses = array( 'tl_namespace' => $this->getNamespace(), 'tl_title' => $this->getDBkey(), 'tl_from=pr_page', - 'pr_cascade' => 1 ); + 'pr_cascade' => 1 + ); } if ( $getPages ) { @@ -2060,9 +2094,8 @@ class Title { */ private function loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions = null ) { $rows = array(); - $dbr = wfGetDB( DB_SLAVE ); - while ( $row = $dbr->fetchObject( $res ) ) { + foreach ( $res as $row ) { $rows[] = $row; } @@ -2162,7 +2195,7 @@ class Title { $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'page_restrictions', '*', - array ( 'pr_page' => $this->getArticleId() ), __METHOD__ ); + array( 'pr_page' => $this->getArticleId() ), __METHOD__ ); $this->loadRestrictionsFromResultWrapper( $res, $oldFashionedRestrictions ); } else { @@ -2192,13 +2225,17 @@ class Title { */ static function purgeExpiredRestrictions() { $dbw = wfGetDB( DB_MASTER ); - $dbw->delete( 'page_restrictions', + $dbw->delete( + 'page_restrictions', array( 'pr_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), - __METHOD__ ); + __METHOD__ + ); - $dbw->delete( 'protected_titles', + $dbw->delete( + 'protected_titles', array( 'pt_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) ), - __METHOD__ ); + __METHOD__ + ); } /** @@ -2280,7 +2317,7 @@ class Title { * Get the article ID for this Title from the link cache, * adding it if necessary * - * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select + * @param $flags \type{\int} a bit field; may be Title::GAID_FOR_UPDATE to select * for update * @return \type{\int} the ID */ @@ -2289,7 +2326,7 @@ class Title { return $this->mArticleID = 0; } $linkCache = LinkCache::singleton(); - if ( $flags & GAID_FOR_UPDATE ) { + if ( $flags & self::GAID_FOR_UPDATE ) { $oldUpdate = $linkCache->forUpdate( true ); $linkCache->clearLink( $this ); $this->mArticleID = $linkCache->addLinkObj( $this ); @@ -2306,12 +2343,13 @@ class Title { * Is this an article that is a redirect page? * Uses link cache, adding it if necessary * - * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update + * @param $flags \type{\int} a bit field; may be Title::GAID_FOR_UPDATE to select for update * @return \type{\bool} */ public function isRedirect( $flags = 0 ) { - if ( !is_null( $this->mRedirect ) ) + if ( !is_null( $this->mRedirect ) ) { return $this->mRedirect; + } # Calling getArticleID() loads the field from cache as needed if ( !$this->getArticleID( $flags ) ) { return $this->mRedirect = false; @@ -2326,12 +2364,13 @@ class Title { * What is the length of this page? * Uses link cache, adding it if necessary * - * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update + * @param $flags \type{\int} a bit field; may be Title::GAID_FOR_UPDATE to select for update * @return \type{\bool} */ public function getLength( $flags = 0 ) { - if ( $this->mLength != -1 ) + if ( $this->mLength != -1 ) { return $this->mLength; + } # Calling getArticleID() loads the field from cache as needed if ( !$this->getArticleID( $flags ) ) { return $this->mLength = 0; @@ -2345,12 +2384,13 @@ class Title { /** * What is the page_latest field for this page? * - * @param $flags \type{\int} a bit field; may be GAID_FOR_UPDATE to select for update + * @param $flags \type{\int} a bit field; may be Title::GAID_FOR_UPDATE to select for update * @return \type{\int} or 0 if the page doesn't exist */ public function getLatestRevID( $flags = 0 ) { - if ( $this->mLatestID !== false ) + if ( $this->mLatestID !== false ) { return intval( $this->mLatestID ); + } # Calling getArticleID() loads the field from cache as needed if ( !$this->getArticleID( $flags ) ) { return $this->mLatestID = 0; @@ -2365,6 +2405,10 @@ class Title { * This clears some fields in this object, and clears any associated * keys in the "bad links" section of the link cache. * + * - This is called from Article::insertNewArticle() to allow + * loading of the new page_id. It's also called from + * Article::doDeleteArticle() + * * @param $newid \type{\int} the new Article ID */ public function resetArticleID( $newid ) { @@ -2393,7 +2437,8 @@ class Title { return; } $dbw = wfGetDB( DB_MASTER ); - $success = $dbw->update( 'page', + $success = $dbw->update( + 'page', array( 'page_touched' => $dbw->timestamp() ), $this->pageCond(), __METHOD__ @@ -2458,10 +2503,11 @@ class Title { public static function capitalize( $text, $ns = NS_MAIN ) { global $wgContLang; - if ( MWNamespace::isCapitalized( $ns ) ) + if ( MWNamespace::isCapitalized( $ns ) ) { return $wgContLang->ucfirst( $text ); - else + } else { return $text; + } } /** @@ -2531,10 +2577,11 @@ class Title { $this->mNamespace = $ns; # For Talk:X pages, check if X has a "namespace" prefix if ( $ns == NS_TALK && preg_match( $prefixRegexp, $dbkey, $x ) ) { - if ( $wgContLang->getNsIndex( $x[1] ) ) + if ( $wgContLang->getNsIndex( $x[1] ) ) { return false; # Disallow Talk:File:x type titles... - else if ( Interwiki::isValidInterwiki( $x[1] ) ) + } else if ( Interwiki::isValidInterwiki( $x[1] ) ) { return false; # Disallow Talk:Interwiki:x type titles... + } } } elseif ( Interwiki::isValidInterwiki( $p ) ) { if ( !$firstPass ) { @@ -2638,7 +2685,7 @@ class Title { * site might be case-sensitive. */ $this->mUserCaseDBKey = $dbkey; - if ( $this->mInterwiki == '' ) { + if ( $this->mInterwiki == '' ) { $dbkey = self::capitalize( $dbkey, $this->mNamespace ); } @@ -2691,7 +2738,7 @@ class Title { /** * Get a Title object associated with the talk page of this article * - * @return \type{Title} the object for the talk page + * @return Title the object for the talk page */ public function getTalkPage() { return Title::makeTitle( MWNamespace::getTalk( $this->getNamespace() ), $this->getDBkey() ); @@ -2701,7 +2748,7 @@ class Title { * Get a title object associated with the subject page of this * talk page * - * @return \type{Title} the object for the subject page + * @return Title the object for the subject page */ public function getSubjectPage() { // Is this the same title? @@ -2733,14 +2780,16 @@ class Title { $db = wfGetDB( DB_SLAVE ); } - $res = $db->select( array( 'page', $table ), + $res = $db->select( + array( 'page', $table ), array( 'page_namespace', 'page_title', 'page_id', 'page_len', 'page_is_redirect', 'page_latest' ), array( "{$prefix}_from=page_id", "{$prefix}_namespace" => $this->getNamespace(), "{$prefix}_title" => $this->getDBkey() ), __METHOD__, - $options ); + $options + ); $retVal = array(); if ( $db->numRows( $res ) ) { @@ -2751,7 +2800,6 @@ class Title { } } } - $db->freeResult( $res ); return $retVal; } @@ -2955,8 +3003,9 @@ class Title { $errors[] = array( 'cantmove-titleprotected' ); } } - if ( empty( $errors ) ) + if ( empty( $errors ) ) { return true; + } return $errors; } @@ -2972,6 +3021,8 @@ class Title { * @return \type{\mixed} true on success, getUserPermissionsErrors()-like array on failure */ public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) { + global $wgContLang; + $err = $this->isValidMoveOperation( $nt, $auth, $reason ); if ( is_array( $err ) ) { return $err; @@ -3004,24 +3055,19 @@ class Title { } $redirid = $this->getArticleID(); - // Category memberships include a sort key which may be customized. - // If it's left as the default (the page title), we need to update - // the sort key to match the new title. - // - // Be careful to avoid resetting cl_timestamp, which may disturb - // time-based lists on some sites. - // - // Warning -- if the sort key is *explicitly* set to the old title, - // we can't actually distinguish it from a default here, and it'll - // be set to the new title even though it really shouldn't. - // It'll get corrected on the next edit, but resetting cl_timestamp. + // Refresh the sortkey for this row. Be careful to avoid resetting + // cl_timestamp, which may disturb time-based lists on some sites. + $prefix = $dbw->selectField( + 'categorylinks', + 'cl_sortkey_prefix', + array( 'cl_from' => $pageid ), + __METHOD__ + ); $dbw->update( 'categorylinks', array( - 'cl_sortkey' => $nt->getPrefixedText(), + 'cl_sortkey' => $wgContLang->convertToSortkey( $nt->getCategorySortkey( $prefix ) ), 'cl_timestamp=cl_timestamp' ), - array( - 'cl_from' => $pageid, - 'cl_sortkey' => $this->getPrefixedText() ), + array( 'cl_from' => $pageid ), __METHOD__ ); if ( $protected ) { @@ -3042,7 +3088,9 @@ class Title { # Update the protection log $log = new LogPage( 'protect' ); $comment = wfMsgForContent( 'prot_1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() ); - if ( $reason ) $comment .= wfMsgForContent( 'colon-separator' ) . $reason; + if ( $reason ) { + $comment .= wfMsgForContent( 'colon-separator' ) . $reason; + } $log->addEntry( 'move_prot', $nt, $comment, array( $this->getPrefixedText() ) ); // FIXME: $params? } @@ -3078,12 +3126,12 @@ class Title { # Nothing special $u = false; } - if ( $u ) + if ( $u ) { $u->doUpdate(); + } # Update message cache for interface messages - if ( $nt->getNamespace() == NS_MEDIAWIKI ) { - global $wgMessageCache; - + global $wgMessageCache; + if ( $this->getNamespace() == NS_MEDIAWIKI ) { # @bug 17860: old article can be deleted, if this the case, # delete it from message cache if ( $this->getArticleID() === 0 ) { @@ -3092,7 +3140,8 @@ class Title { $oldarticle = new Article( $this ); $wgMessageCache->replace( $this->getDBkey(), $oldarticle->getContent() ); } - + } + if ( $nt->getNamespace() == NS_MEDIAWIKI ) { $newarticle = new Article( $nt ); $wgMessageCache->replace( $nt->getDBkey(), $newarticle->getContent() ); } @@ -3142,8 +3191,9 @@ class Title { if ( !$dbw->cascadingDeletes() ) { $dbw->delete( 'revision', array( 'rev_page' => $newid ), __METHOD__ ); global $wgUseTrackbacks; - if ( $wgUseTrackbacks ) + if ( $wgUseTrackbacks ) { $dbw->delete( 'trackbacks', array( 'tb_page' => $newid ), __METHOD__ ); + } $dbw->delete( 'pagelinks', array( 'pl_from' => $newid ), __METHOD__ ); $dbw->delete( 'imagelinks', array( 'il_from' => $newid ), __METHOD__ ); $dbw->delete( 'categorylinks', array( 'cl_from' => $newid ), __METHOD__ ); @@ -3230,7 +3280,7 @@ class Title { * Ignored if the user doesn't have the suppressredirect right */ private function moveToNewTitle( &$nt, $reason = '', $createRedirect = true ) { - global $wgUseSquid, $wgUser, $wgContLang; + global $wgUser, $wgContLang; $comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() ); if ( $reason ) { @@ -3309,7 +3359,6 @@ class Title { # Purge old title from squid # The new title, and links to the new title, are purged in Article::onArticleCreate() $this->purgeSquid(); - } /** @@ -3326,15 +3375,18 @@ class Title { public function moveSubpages( $nt, $auth = true, $reason = '', $createRedirect = true ) { global $wgMaximumMovedPages; // Check permissions - if ( !$this->userCan( 'move-subpages' ) ) + if ( !$this->userCan( 'move-subpages' ) ) { return array( 'cant-move-subpages' ); + } // Do the source and target namespaces support subpages? - if ( !MWNamespace::hasSubpages( $this->getNamespace() ) ) + if ( !MWNamespace::hasSubpages( $this->getNamespace() ) ) { return array( 'namespace-nosubpages', MWNamespace::getCanonicalName( $this->getNamespace() ) ); - if ( !MWNamespace::hasSubpages( $nt->getNamespace() ) ) + } + if ( !MWNamespace::hasSubpages( $nt->getNamespace() ) ) { return array( 'namespace-nosubpages', MWNamespace::getCanonicalName( $nt->getNamespace() ) ); + } $subpages = $this->getSubpages( $wgMaximumMovedPages + 1 ); $retval = array(); @@ -3353,9 +3405,11 @@ class Title { // $this and $nt if ( $oldSubpage->getArticleId() == $this->getArticleId() || $oldSubpage->getArticleID() == $nt->getArticleId() ) + { // When moving a page to a subpage of itself, // don't move it twice continue; + } $newPageName = preg_replace( '#^' . preg_quote( $this->getDBkey(), '#' ) . '#', StringUtils::escapeRegexReplacement( $nt->getDBkey() ), # bug 21234 @@ -3424,7 +3478,6 @@ class Title { * @return \type{\bool} TRUE or FALSE */ public function isValidMoveTarget( $nt ) { - $dbw = wfGetDB( DB_MASTER ); # Is it an existing file? if ( $nt->getNamespace() == NS_FILE ) { $file = wfLocalFile( $nt ); @@ -3490,14 +3543,13 @@ class Title { . " ORDER BY cl_sortkey"; $res = $dbr->query( $sql ); + $data = array(); if ( $dbr->numRows( $res ) > 0 ) { - foreach ( $res as $row ) + foreach ( $res as $row ) { // $data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$row->cl_to); $data[$wgContLang->getNSText( NS_CATEGORY ) . ':' . $row->cl_to] = $this->getFullText(); - $dbr->freeResult( $res ); - } else { - $data = array(); + } } return $data; } @@ -3524,10 +3576,9 @@ class Title { } } } - return $stack; - } else { - return array(); } + + return $stack; } @@ -3550,11 +3601,11 @@ class Title { * Get the revision ID of the previous revision * * @param $revId \type{\int} Revision ID. Get the revision that was before this one. - * @param $flags \type{\int} GAID_FOR_UPDATE + * @param $flags \type{\int} Title::GAID_FOR_UPDATE * @return \twotypes{\int,\bool} Old revision ID, or FALSE if none exists */ public function getPreviousRevisionID( $revId, $flags = 0 ) { - $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); + $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); return $db->selectField( 'revision', 'rev_id', array( 'rev_page' => $this->getArticleId( $flags ), @@ -3569,11 +3620,11 @@ class Title { * Get the revision ID of the next revision * * @param $revId \type{\int} Revision ID. Get the revision that was after this one. - * @param $flags \type{\int} GAID_FOR_UPDATE + * @param $flags \type{\int} Title::GAID_FOR_UPDATE * @return \twotypes{\int,\bool} Next revision ID, or FALSE if none exists */ public function getNextRevisionID( $revId, $flags = 0 ) { - $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); + $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); return $db->selectField( 'revision', 'rev_id', array( 'rev_page' => $this->getArticleId( $flags ), @@ -3587,13 +3638,15 @@ class Title { /** * Get the first revision of the page * - * @param $flags \type{\int} GAID_FOR_UPDATE + * @param $flags \type{\int} Title::GAID_FOR_UPDATE * @return Revision (or NULL if page doesn't exist) */ public function getFirstRevision( $flags = 0 ) { - $db = ( $flags & GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); + $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE ); $pageId = $this->getArticleId( $flags ); - if ( !$pageId ) return null; + if ( !$pageId ) { + return null; + } $row = $db->selectRow( 'revision', '*', array( 'rev_page' => $pageId ), __METHOD__, @@ -3720,21 +3773,21 @@ class Title { return true; // any interwiki link might be viewable, for all we know } switch( $this->mNamespace ) { - case NS_MEDIA: - case NS_FILE: - return (bool)wfFindFile( $this ); // file exists, possibly in a foreign repo - case NS_SPECIAL: - return SpecialPage::exists( $this->getDBkey() ); // valid special page - case NS_MAIN: - return $this->mDbkeyform == ''; // selflink, possibly with fragment - case NS_MEDIAWIKI: - // If the page is form Mediawiki:message/lang, calling wfMsgWeirdKey causes - // the full l10n of that language to be loaded. That takes much memory and - // isn't needed. So we strip the language part away. - list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 ); - return (bool)wfMsgWeirdKey( $basename ); // known system message - default: - return false; + case NS_MEDIA: + case NS_FILE: + return (bool)wfFindFile( $this ); // file exists, possibly in a foreign repo + case NS_SPECIAL: + return SpecialPage::exists( $this->getDBkey() ); // valid special page + case NS_MAIN: + return $this->mDbkeyform == ''; // selflink, possibly with fragment + case NS_MEDIAWIKI: + // If the page is form Mediawiki:message/lang, calling wfMsgWeirdKey causes + // the full l10n of that language to be loaded. That takes much memory and + // isn't needed. So we strip the language part away. + list( $basename, /* rest */ ) = explode( '/', $this->mDbkeyform, 2 ); + return (bool)wfMsgWeirdKey( $basename ); // known system message + default: + return false; } } @@ -3747,7 +3800,7 @@ class Title { * @return \type{\bool} */ public function isKnown() { - return $this->exists() || $this->isAlwaysKnown(); + return $this->isAlwaysKnown() || $this->exists(); } /** @@ -3756,8 +3809,9 @@ class Title { * @return Boolean */ public function hasSourceText() { - if ( $this->exists() ) + if ( $this->exists() ) { return true; + } if ( $this->mNamespace == NS_MEDIAWIKI ) { // If the page doesn't exist but is a known system message, default @@ -3773,11 +3827,11 @@ class Title { } /** - * Is this in a namespace that allows actual pages? - * - * @return \type{\bool} - * @internal note -- uses hardcoded namespace index instead of constants - */ + * Is this in a namespace that allows actual pages? + * + * @return \type{\bool} + * @internal note -- uses hardcoded namespace index instead of constants + */ public function canExist() { return $this->mNamespace >= 0 && $this->mNamespace != NS_MEDIA; } @@ -3818,7 +3872,9 @@ class Title { public function getNotificationTimestamp( $user = null ) { global $wgUser, $wgShowUpdatedMarker; // Assume current user if none given - if ( !$user ) $user = $wgUser; + if ( !$user ) { + $user = $wgUser; + } // Check cache first $uid = $user->getId(); if ( isset( $this->mNotificationTimestamp[$uid] ) ) { @@ -3919,7 +3975,7 @@ class Title { * * @return boolean */ - public function isSpecialPage( ) { + public function isSpecialPage() { return $this->getNamespace() == NS_SPECIAL; } @@ -3985,7 +4041,9 @@ class Title { 'rd_title' => $this->getDBkey(), 'rd_from = page_id' ); - if ( !is_null( $ns ) ) $where['page_namespace'] = $ns; + if ( !is_null( $ns ) ) { + $where['page_namespace'] = $ns; + } $res = $dbr->select( array( 'redirect', 'page' ), @@ -3994,7 +4052,6 @@ class Title { __METHOD__ ); - foreach ( $res as $row ) { $redirs[] = self::newFromRow( $row ); } @@ -4042,8 +4099,7 @@ class Title { * @return Boolean */ public function canUseNoindex() { - global $wgArticleRobotPolicies, $wgContentNamespaces, - $wgExemptFromUserRobotsControl; + global $wgContentNamespaces, $wgExemptFromUserRobotsControl; $bannedNamespaces = is_null( $wgExemptFromUserRobotsControl ) ? $wgContentNamespaces @@ -4070,4 +4126,25 @@ class Title { return $types; } + + /** + * Returns the raw sort key to be used for categories, with the specified + * prefix. This will be fed to Language::convertToSortkey() to get a + * binary sortkey that can be used for actual sorting. + * + * @param $prefix string The prefix to be used, specified using + * {{defaultsort:}} or like [[Category:Foo|prefix]]. Empty for no + * prefix. + * @return string + */ + public function getCategorySortkey( $prefix = '' ) { + $unprefixed = $this->getText(); + if ( $prefix !== '' ) { + # Separate with a null byte, so the unprefixed part is only used as + # a tiebreaker when two pages have the exact same prefix -- null + # sorts before everything else (hopefully). + return "$prefix\0$unprefixed"; + } + return $unprefixed; + } }