27 use Wikimedia\Assert\Assert;
199 return MediaWikiServices::getInstance()->getTitleFormatter();
211 return MediaWikiServices::getInstance()->getInterwikiLookup();
230 $t->mDbkeyform = $key;
233 $t->secureAndSplit();
269 if ( $linkTarget instanceof
Title ) {
271 if ( $forceClone === self::NEW_CLONE ) {
272 return clone $linkTarget;
318 if ( $text !==
null && !is_string( $text ) && !is_int( $text ) ) {
319 throw new InvalidArgumentException(
'$text must be a string.' );
321 if ( $text ===
null ) {
354 if ( is_object( $text ) ) {
355 throw new MWException(
'$text must be a string, given an object' );
356 } elseif ( $text ===
null ) {
368 if ( $defaultNamespace ==
NS_MAIN ) {
376 $filteredText = Sanitizer::decodeCharReferencesAndNormalize( $text );
379 $t->mDbkeyform = strtr( $filteredText,
' ',
'_' );
380 $t->mDefaultNamespace = (int)$defaultNamespace;
382 $t->secureAndSplit();
383 if ( $defaultNamespace ==
NS_MAIN ) {
407 # For compatibility with old buggy URLs. "+" is usually not valid in titles,
408 # but some URLs used it as a space replacement and they still come
409 # from some external search tools.
410 if ( strpos( self::legalChars(),
'+' ) ===
false ) {
411 $url = strtr( $url,
'+',
' ' );
414 $t->mDbkeyform = strtr( $url,
' ',
'_' );
417 $t->secureAndSplit();
428 if ( self::$titleCache ===
null ) {
429 self::$titleCache =
new MapCacheLRU( self::CACHE_MAX );
445 'page_namespace',
'page_title',
'page_id',
446 'page_len',
'page_is_redirect',
'page_latest',
450 $fields[] =
'page_content_model';
454 $fields[] =
'page_lang';
470 $row =
wfGetDB( $index )->selectRow(
472 self::getSelectFields(),
473 [
'page_id' => $id ],
477 if ( $row !==
false ) {
493 if ( !count( $ids ) ) {
500 self::getSelectFields(),
501 [
'page_id' => $ids ],
506 foreach (
$res as $row ) {
520 $t->loadFromRow( $row );
532 if ( isset( $row->page_id ) ) {
533 $this->mArticleID = (int)$row->page_id;
535 if ( isset( $row->page_len ) ) {
536 $this->mLength = (int)$row->page_len;
538 if ( isset( $row->page_is_redirect ) ) {
539 $this->mRedirect = (bool)$row->page_is_redirect;
541 if ( isset( $row->page_latest ) ) {
542 $this->mLatestID = (int)$row->page_latest;
544 if ( isset( $row->page_content_model ) ) {
549 if ( isset( $row->page_lang ) ) {
550 $this->mDbPageLanguage = (string)$row->page_lang;
552 if ( isset( $row->page_restrictions ) ) {
553 $this->mOldRestrictions = $row->page_restrictions;
556 $this->mArticleID = 0;
558 $this->mRedirect =
false;
559 $this->mLatestID = 0;
588 $t->mInterwiki = $interwiki;
589 $t->mFragment = $fragment;
590 $t->mNamespace = $ns = (int)$ns;
591 $t->mDbkeyform = strtr(
$title,
' ',
'_' );
592 $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
594 $t->mTextform = strtr(
$title,
'_',
' ' );
617 if ( !MediaWikiServices::getInstance()->getNamespaceInfo()->
exists( $ns ) ) {
625 $t->secureAndSplit();
651 $msg = $localizer->msg(
'mainpage' );
679 [
'page_namespace',
'page_title' ],
680 [
'page_id' => $id ],
683 if (
$s ===
false ) {
710 $length = strlen( $byteClass );
712 $x0 = $x1 = $x2 =
'';
714 $d0 = $d1 = $d2 =
'';
716 $ord0 = $ord1 = $ord2 = 0;
718 $r0 = $r1 = $r2 =
'';
722 $allowUnicode =
false;
723 for ( $pos = 0; $pos < $length; $pos++ ) {
734 $inChar = $byteClass[$pos];
735 if ( $inChar ==
'\\' ) {
736 if ( preg_match(
'/x([0-9a-fA-F]{2})/A', $byteClass, $m, 0, $pos + 1 ) ) {
737 $x0 = $inChar . $m[0];
738 $d0 = chr( hexdec( $m[1] ) );
739 $pos += strlen( $m[0] );
740 } elseif ( preg_match(
'/[0-7]{3}/A', $byteClass, $m, 0, $pos + 1 ) ) {
741 $x0 = $inChar . $m[0];
742 $d0 = chr( octdec( $m[0] ) );
743 $pos += strlen( $m[0] );
744 } elseif ( $pos + 1 >= $length ) {
747 $d0 = $byteClass[$pos + 1];
756 if ( $ord0 < 32 || $ord0 == 0x7f ) {
757 $r0 = sprintf(
'\x%02x', $ord0 );
758 } elseif ( $ord0 >= 0x80 ) {
760 $r0 = sprintf(
'\x%02x', $ord0 );
761 $allowUnicode =
true;
763 } elseif ( strpos(
'-\\[]^', $d0 ) !==
false ) {
769 if ( $x0 !==
'' && $x1 ===
'-' && $x2 !==
'' ) {
771 if ( $ord2 > $ord0 ) {
773 } elseif ( $ord0 >= 0x80 ) {
775 $allowUnicode =
true;
776 if ( $ord2 < 0x80 ) {
785 $x0 = $x1 = $d0 = $d1 = $r0 = $r1 =
'';
786 } elseif ( $ord2 < 0x80 ) {
791 if ( $ord1 < 0x80 ) {
794 if ( $ord0 < 0x80 ) {
797 if ( $allowUnicode ) {
798 $out .=
'\u0080-\uFFFF';
815 $canonicalNamespace =
false
817 if ( $canonicalNamespace ) {
818 $namespace = MediaWikiServices::getInstance()->getNamespaceInfo()->
819 getCanonicalName( $ns );
821 $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
823 $name = $namespace ==
'' ?
$title :
"$namespace:$title";
824 if ( strval( $interwiki ) !=
'' ) {
825 $name =
"$interwiki:$name";
827 if ( strval( $fragment ) !=
'' ) {
828 $name .=
'#' . $fragment;
864 $services = MediaWikiServices::getInstance();
865 if ( !$services->getNamespaceInfo()->exists( $this->mNamespace ) ) {
870 $services->getTitleParser()->parseTitle( $this->mDbkeyform, $this->mNamespace );
883 }
catch ( InvalidArgumentException $ex ) {
901 return $iw->isLocal();
913 return $this->mInterwiki !==
'';
973 if ( $this->mTitleValue ===
null ) {
981 }
catch ( InvalidArgumentException $ex ) {
982 wfDebug( __METHOD__ .
': Can\'t create a TitleValue for [[' .
1024 if ( !is_null( $this->mUserCaseDBKey ) ) {
1050 if ( $this->mForcedContentModel ) {
1051 if ( !$this->mContentModel ) {
1052 throw new RuntimeException(
'Got out of sync; an empty model is being forced' );
1061 ( !$this->mContentModel || $flags & self::GAID_FOR_UPDATE ) &&
1064 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1065 $linkCache->addLinkObj( $this ); # in
case we already had an article ID
1069 if ( !$this->mContentModel ) {
1100 if ( (
string)$model ===
'' ) {
1101 throw new InvalidArgumentException(
"Missing CONTENT_MODEL_* constant" );
1104 $this->mContentModel = $model;
1105 $this->mForcedContentModel =
true;
1114 if ( !$this->mForcedContentModel ) {
1115 $this->mContentModel = ( $model === false ) ?
false : (
string)$model;
1128 $nsText = MediaWikiServices::getInstance()->getNamespaceInfo()->
1129 getCanonicalName( $this->mNamespace );
1130 if ( $nsText !==
false ) {
1137 return $formatter->getNamespaceName( $this->mNamespace, $this->mDbkeyform );
1138 }
catch ( InvalidArgumentException $ex ) {
1139 wfDebug( __METHOD__ .
': ' . $ex->getMessage() .
"\n" );
1150 $services = MediaWikiServices::getInstance();
1151 return $services->getContentLanguage()->
1152 getNsText( $services->getNamespaceInfo()->getSubject( $this->mNamespace ) );
1161 $services = MediaWikiServices::getInstance();
1162 return $services->getContentLanguage()->
1163 getNsText( $services->getNamespaceInfo()->getTalk( $this->mNamespace ) );
1178 return MediaWikiServices::getInstance()->getNamespaceInfo()->canHaveTalkPage( $this );
1187 return $this->mNamespace >=
NS_MAIN;
1199 $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
1201 $nsInfo->isWatchable( $this->mNamespace );
1221 list( $thisName, ) =
1222 MediaWikiServices::getInstance()->getSpecialPageFactory()->
1223 resolveAlias( $this->mDbkeyform );
1224 if ( $name == $thisName ) {
1239 $spFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
1240 list( $canonicalName, $par ) = $spFactory->resolveAlias( $this->mDbkeyform );
1241 if ( $canonicalName ) {
1242 $localName = $spFactory->getLocalNameFor( $canonicalName, $par );
1243 if ( $localName != $this->mDbkeyform ) {
1262 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1263 equals( $this->mNamespace, $ns );
1274 if ( count( $namespaces ) > 0 && is_array( $namespaces[0] ) ) {
1275 $namespaces = $namespaces[0];
1278 foreach ( $namespaces as $ns ) {
1301 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1302 subjectEquals( $this->mNamespace, $ns );
1313 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1314 isContent( $this->mNamespace );
1325 !MediaWikiServices::getInstance()->getNamespaceInfo()->
1333 Hooks::run(
'TitleIsMovable', [ $this, &$result ] );
1348 return $this->
equals( self::newMainPage() );
1357 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1359 ? strpos( $this->
getText(),
'/' ) !== false
1372 strpos( $this->
getText(),
'Conversiontable/' ) === 0;
1427 $subpage = explode(
'/', $this->mTextform );
1428 $subpage = $subpage[count( $subpage ) - 1];
1429 $lastdot = strrpos( $subpage,
'.' );
1430 if ( $lastdot ===
false ) {
1431 return $subpage; # Never happens: only called
for names ending in
'.css'/
'.json'/
'.js'
1433 return substr( $subpage, 0, $lastdot );
1491 || substr( $this->mDbkeyform, -4 ) ===
'.css'
1509 || substr( $this->mDbkeyform, -5 ) ===
'.json'
1527 || substr( $this->mDbkeyform, -3 ) ===
'.js'
1554 return MediaWikiServices::getInstance()->getNamespaceInfo()->
1555 isTalk( $this->mNamespace );
1575 $talkNS = MediaWikiServices::getInstance()->getNamespaceInfo()->getTalk( $this->mNamespace );
1576 if ( $this->mNamespace == $talkNS ) {
1616 $subjectNS = MediaWikiServices::getInstance()->getNamespaceInfo()
1617 ->getSubject( $this->mNamespace );
1618 if ( $this->mNamespace == $subjectNS ) {
1641 if ( $this->
getText() ==
'' ) {
1643 $method .
': called on empty title ' . $this->
getFullText() .
', returning '
1652 $method .
': called on interwiki title ' . $this->
getFullText() .
', returning '
1676 throw new MWException(
'Special pages cannot have other pages' );
1682 throw new MWException(
"{$this->getPrefixedText()} does not have an other page" );
1718 return $this->mFragment !==
'';
1733 if ( $interwiki && !$interwiki->isLocal() ) {
1734 return '#' . Sanitizer::escapeIdForExternalInterwiki( $this->mFragment );
1738 return '#' . Sanitizer::escapeIdForLink( $this->mFragment );
1754 $this->mFragment = strtr( substr( $fragment, 1 ),
'_',
' ' );
1783 $p = $this->mInterwiki .
':';
1786 if ( $this->mNamespace != 0 ) {
1789 if ( $nsText ===
false ) {
1791 $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
1795 $p .= $nsText .
':';
1807 $s = $this->
prefix( $this->mDbkeyform );
1808 $s = strtr(
$s,
' ',
'_' );
1819 if ( $this->prefixedText ===
null ) {
1820 $s = $this->
prefix( $this->mTextform );
1821 $s = strtr(
$s,
'_',
' ' );
1822 $this->prefixedText =
$s;
1867 !MediaWikiServices::getInstance()->getNamespaceInfo()->
1869 || strtok( $this->
getText(),
'/' ) ===
false
1874 return strtok( $this->
getText(),
'/' );
1891 Assert::postcondition(
1893 'makeTitleSafe() should always return a Title for the text returned by getRootText().'
1915 !MediaWikiServices::getInstance()->getNamespaceInfo()->
1921 $lastSlashPos = strrpos( $text,
'/' );
1923 if ( $lastSlashPos ===
false ) {
1927 return substr( $text, 0, $lastSlashPos );
1944 Assert::postcondition(
1946 'makeTitleSafe() should always return a Title for the text returned by getBaseText().'
1964 !MediaWikiServices::getInstance()->getNamespaceInfo()->
1969 $parts = explode(
'/', $this->mTextform );
1970 return $parts[count( $parts ) - 1];
1989 $this->
getText() .
'/' . $text,
2012 $s = $this->
prefix( $this->mDbkeyform );
2031 if ( $query2 !==
false ) {
2032 wfDeprecated(
"Title::get{Canonical,Full,Link,Local,Internal}URL " .
2033 "method called with a second parameter is deprecated. Add your " .
2034 "parameter to an array passed as the first parameter.",
"1.19" );
2036 if ( is_array( $query ) ) {
2040 if ( is_string( $query2 ) ) {
2071 # Hand off all the decisions on urls to getLocalURL
2074 # Expand the url to make it a full url. Note that getLocalURL has the
2075 # potential to output full urls for a variety of reasons, so we use
2076 # wfExpandUrl instead of simply prepending $wgServer
2079 # Finally, add the fragment.
2083 Hooks::run(
'GetFullURL', [ &$titleRef, &$url, $query ] );
2111 return $target->getFullURL( $query,
false, $proto );
2145 if ( $namespace !=
'' ) {
2146 # Can this actually happen? Interwikis shouldn't be parsed.
2147 # Yes! It can in interwiki transclusion. But... it probably shouldn't.
2150 $url = $interwiki->getURL( $namespace . $this->mDbkeyform );
2154 if ( $query ==
'' ) {
2158 Hooks::run(
'GetLocalURL::Article', [ &$titleRef, &$url ] );
2167 && preg_match(
'/^(.*&|)action=([^&]*)(&(.*)|)$/', $query,
$matches )
2169 $action = urldecode(
$matches[2] );
2170 if ( isset( $articlePaths[$action] ) ) {
2175 $url = str_replace(
'$1', $dbkey, $articlePaths[$action] );
2176 if ( $query !=
'' ) {
2184 && preg_match(
'/^variant=([^&]*)$/', $query,
$matches )
2186 MediaWikiServices::getInstance()->getContentLanguage() )
2189 $variant = urldecode(
$matches[1] );
2194 $url = str_replace(
'$1', $dbkey, $url );
2198 if ( $url ===
false ) {
2199 if ( $query ==
'-' ) {
2202 $url =
"{$wgScript}?title={$dbkey}&{$query}";
2207 Hooks::run(
'GetLocalURL::Internal', [ &$titleRef, &$url, $query ] );
2211 if (
$wgRequest->getVal(
'action' ) ==
'render' ) {
2222 Hooks::run(
'GetLocalURL', [ &$titleRef, &$url, $query ] );
2243 public function getLinkURL( $query =
'', $query2 =
false, $proto =
false ) {
2244 if ( $this->
isExternal() || $proto !==
false ) {
2245 $ret = $this->
getFullURL( $query, $query2, $proto );
2275 Hooks::run(
'GetInternalURL', [ &$titleRef, &$url, $query ] );
2297 Hooks::run(
'GetCanonicalURL', [ &$titleRef, &$url, $query ] );
2336 return $this->
userCan( $action, $user,
false );
2354 public function userCan( $action, $user =
null, $rigor = PermissionManager::RIGOR_SECURE ) {
2355 if ( !$user instanceof
User ) {
2361 if ( $rigor ===
true ) {
2362 $rigor = PermissionManager::RIGOR_SECURE;
2363 } elseif ( $rigor ===
false ) {
2364 $rigor = PermissionManager::RIGOR_QUICK;
2367 return MediaWikiServices::getInstance()->getPermissionManager()
2368 ->userCan( $action, $user, $this, $rigor );
2393 $action, $user, $rigor = PermissionManager::RIGOR_SECURE, $ignoreErrors = []
2396 if ( $rigor ===
true ) {
2397 $rigor = PermissionManager::RIGOR_SECURE;
2398 } elseif ( $rigor ===
false ) {
2399 $rigor = PermissionManager::RIGOR_QUICK;
2402 return MediaWikiServices::getInstance()->getPermissionManager()
2403 ->getPermissionErrors( $action, $user, $this, $rigor, $ignoreErrors );
2417 # Remove the create restriction for existing titles
2418 $types = array_diff( $types, [
'create' ] );
2420 # Only the create and upload restrictions apply to non-existing titles
2421 $types = array_intersect( $types, [
'create',
'upload' ] );
2438 if ( $this->mNamespace !=
NS_FILE ) {
2439 # Remove the upload restriction for non-file titles
2440 $types = array_diff( $types, [
'upload' ] );
2443 Hooks::run(
'TitleGetRestrictionTypes', [ $this, &$types ] );
2445 wfDebug( __METHOD__ .
': applicable restrictions to [[' .
2446 $this->
getPrefixedText() .
']] are {' . implode(
',', $types ) .
"}\n" );
2460 if ( $protection ) {
2461 if ( $protection[
'permission'] ==
'sysop' ) {
2462 $protection[
'permission'] =
'editprotected';
2464 if ( $protection[
'permission'] ==
'autoconfirmed' ) {
2465 $protection[
'permission'] =
'editsemiprotected';
2483 if ( $this->mNamespace < 0 ) {
2492 if ( $this->mTitleProtection ===
null ) {
2495 $commentQuery = $commentStore->getJoin(
'pt_reason' );
2497 [
'protected_titles' ] + $commentQuery[
'tables'],
2499 'user' =>
'pt_user',
2500 'expiry' =>
'pt_expiry',
2501 'permission' =>
'pt_create_perm'
2502 ] + $commentQuery[
'fields'],
2503 [
'pt_namespace' => $this->mNamespace,
'pt_title' => $this->mDbkeyform ],
2506 $commentQuery[
'joins']
2512 $this->mTitleProtection = [
2513 'user' => $row[
'user'],
2514 'expiry' =>
$dbr->decodeExpiry( $row[
'expiry'] ),
2515 'permission' => $row[
'permission'],
2516 'reason' => $commentStore->getComment(
'pt_reason', $row )->text,
2519 $this->mTitleProtection =
false;
2533 [
'pt_namespace' => $this->mNamespace,
'pt_title' => $this->mDbkeyform ],
2536 $this->mTitleProtection =
false;
2551 if ( !$restrictions || !$semi ) {
2557 foreach ( array_keys( $semi,
'autoconfirmed' ) as $key ) {
2558 $semi[$key] =
'editsemiprotected';
2560 foreach ( array_keys( $restrictions,
'autoconfirmed' ) as $key ) {
2561 $restrictions[$key] =
'editsemiprotected';
2564 return !array_diff( $restrictions, $semi );
2579 # Special pages have inherent protection
2584 # Check regular protection levels
2585 foreach ( $restrictionTypes as
$type ) {
2586 if ( $action ==
$type || $action ==
'' ) {
2589 if ( in_array( $level, $r ) && $level !=
'' ) {
2611 $permissionManager = MediaWikiServices::getInstance()->getPermissionManager();
2613 if ( !$permissionManager->userHasRight( $user, $right ) ) {
2628 return ( $sources > 0 );
2641 return $getPages ? $this->mCascadeSources !== null : $this->mHasCascadingRestrictions !==
null;
2658 $pagerestrictions = [];
2660 if ( $this->mCascadeSources !==
null && $getPages ) {
2662 } elseif ( $this->mHasCascadingRestrictions !==
null && !$getPages ) {
2668 if ( $this->mNamespace ==
NS_FILE ) {
2669 $tables = [
'imagelinks',
'page_restrictions' ];
2676 $tables = [
'templatelinks',
'page_restrictions' ];
2686 $cols = [
'pr_page',
'page_namespace',
'page_title',
2687 'pr_expiry',
'pr_type',
'pr_level' ];
2688 $where_clauses[] =
'page_id=pr_page';
2691 $cols = [
'pr_expiry' ];
2694 $res =
$dbr->select( $tables, $cols, $where_clauses, __METHOD__ );
2696 $sources = $getPages ? [] :
false;
2699 foreach (
$res as $row ) {
2700 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
2701 if ( $expiry > $now ) {
2703 $page_id = $row->pr_page;
2704 $page_ns = $row->page_namespace;
2705 $page_title = $row->page_title;
2707 # Add groups needed for each restriction type if its not already there
2708 # Make sure this restriction type still exists
2710 if ( !isset( $pagerestrictions[$row->pr_type] ) ) {
2711 $pagerestrictions[$row->pr_type] = [];
2715 isset( $pagerestrictions[$row->pr_type] )
2716 && !in_array( $row->pr_level, $pagerestrictions[$row->pr_type] )
2718 $pagerestrictions[$row->pr_type][] = $row->pr_level;
2727 $this->mCascadeSources = $sources;
2728 $this->mCascadingRestrictions = $pagerestrictions;
2730 $this->mHasCascadingRestrictions = $sources;
2733 return [ $sources, $pagerestrictions ];
2757 if ( !$this->mRestrictionsLoaded ) {
2760 return $this->mRestrictions[$action] ?? [];
2771 if ( !$this->mRestrictionsLoaded ) {
2785 if ( !$this->mRestrictionsLoaded ) {
2788 return $this->mRestrictionsExpiry[$action] ??
false;
2797 if ( !$this->mRestrictionsLoaded ) {
2823 foreach ( $restrictionTypes as
$type ) {
2824 $this->mRestrictions[
$type] = [];
2825 $this->mRestrictionsExpiry[
$type] =
'infinity';
2828 $this->mCascadeRestriction =
false;
2830 # Backwards-compatibility: also load the restrictions from the page record (old format).
2831 if ( $oldFashionedRestrictions !==
null ) {
2832 $this->mOldRestrictions = $oldFashionedRestrictions;
2835 if ( $this->mOldRestrictions ===
false ) {
2836 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
2837 $linkCache->addLinkObj( $this ); # in
case we already had an article ID
2838 $this->mOldRestrictions = $linkCache->getGoodLinkFieldObj( $this,
'restrictions' );
2841 if ( $this->mOldRestrictions !=
'' ) {
2842 foreach ( explode(
':', trim( $this->mOldRestrictions ) ) as $restrict ) {
2843 $temp = explode(
'=', trim( $restrict ) );
2844 if ( count( $temp ) == 1 ) {
2846 $this->mRestrictions[
'edit'] = explode(
',', trim( $temp[0] ) );
2847 $this->mRestrictions[
'move'] = explode(
',', trim( $temp[0] ) );
2849 $restriction = trim( $temp[1] );
2850 if ( $restriction !=
'' ) {
2851 $this->mRestrictions[$temp[0]] = explode(
',', $restriction );
2857 if ( count( $rows ) ) {
2858 # Current system - load second to make them override.
2861 # Cycle through all the restrictions.
2862 foreach ( $rows as $row ) {
2864 if ( !in_array( $row->pr_type, $restrictionTypes ) ) {
2868 $expiry =
$dbr->decodeExpiry( $row->pr_expiry );
2871 if ( !$expiry || $expiry > $now ) {
2872 $this->mRestrictionsExpiry[$row->pr_type] = $expiry;
2873 $this->mRestrictions[$row->pr_type] = explode(
',', trim( $row->pr_level ) );
2875 $this->mCascadeRestriction |= $row->pr_cascade;
2880 $this->mRestrictionsLoaded =
true;
2895 if ( $this->mRestrictionsLoaded && !$readLatest ) {
2901 $fname = __METHOD__;
2902 $loadRestrictionsFromDb =
function (
IDatabase $dbr ) use ( $fname, $id ) {
2903 return iterator_to_array(
2905 'page_restrictions',
2906 [
'pr_type',
'pr_expiry',
'pr_level',
'pr_cascade' ],
2907 [
'pr_page' => $id ],
2913 if ( $readLatest ) {
2915 $rows = $loadRestrictionsFromDb(
$dbr );
2917 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
2918 $rows =
$cache->getWithSetCallback(
2920 $cache->makeKey(
'page-restrictions',
'v1', $id, $this->getLatestRevID() ),
2922 function ( $curValue, &$ttl, array &$setOpts ) use ( $loadRestrictionsFromDb ) {
2925 $setOpts += Database::getCacheSetOptions(
$dbr );
2926 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
2927 if ( $lb->hasOrMadeRecentMasterChanges() ) {
2929 $ttl = WANObjectCache::TTL_UNCACHEABLE;
2932 return $loadRestrictionsFromDb(
$dbr );
2941 if ( $title_protection ) {
2945 if ( !$expiry || $expiry > $now ) {
2947 $this->mRestrictionsExpiry[
'create'] = $expiry;
2948 $this->mRestrictions[
'create'] =
2949 explode(
',', trim( $title_protection[
'permission'] ) );
2951 $this->mTitleProtection =
false;
2954 $this->mRestrictionsExpiry[
'create'] =
'infinity';
2956 $this->mRestrictionsLoaded =
true;
2965 $this->mRestrictionsLoaded =
false;
2966 $this->mTitleProtection =
null;
2983 $config = MediaWikiServices::getInstance()->getMainConfig();
2985 'page_restrictions',
2989 [
'LIMIT' => $config->get(
'UpdateRowsPerQuery' ) ]
2992 $dbw->
delete(
'page_restrictions', [
'pr_id' => $ids ], $fname );
3017 !MediaWikiServices::getInstance()->getNamespaceInfo()->
3024 # We dynamically add a member variable for the purpose of this method
3025 # alone to cache the result. There's no point in having it hanging
3026 # around uninitialized in every Title object; therefore we only add it
3027 # if needed and don't declare it statically.
3028 if ( $this->mHasSubpages ===
null ) {
3029 $this->mHasSubpages =
false;
3032 $this->mHasSubpages = (bool)$subpages->current();
3048 !MediaWikiServices::getInstance()->getNamespaceInfo()->
3056 $conds[] =
'page_title ' .
$dbr->buildLike( $this->mDbkeyform .
'/',
$dbr->anyString() );
3058 if ( $limit > -1 ) {
3059 $options[
'LIMIT'] = $limit;
3062 $dbr->select(
'page',
3063 [
'page_id',
'page_namespace',
'page_title',
'page_is_redirect' ],
3077 if ( $this->mNamespace < 0 ) {
3082 $n =
$dbr->selectField(
'archive',
'COUNT(*)',
3083 [
'ar_namespace' => $this->mNamespace,
'ar_title' => $this->mDbkeyform ],
3086 if ( $this->mNamespace ==
NS_FILE ) {
3087 $n +=
$dbr->selectField(
'filearchive',
'COUNT(*)',
3088 [
'fa_name' => $this->mDbkeyform ],
3102 if ( $this->mNamespace < 0 ) {
3106 $deleted = (bool)
$dbr->selectField(
'archive',
'1',
3107 [
'ar_namespace' => $this->mNamespace,
'ar_title' => $this->mDbkeyform ],
3110 if ( !$deleted && $this->mNamespace ==
NS_FILE ) {
3111 $deleted = (bool)
$dbr->selectField(
'filearchive',
'1',
3112 [
'fa_name' => $this->mDbkeyform ],
3127 if ( $this->mNamespace < 0 ) {
3128 $this->mArticleID = 0;
3133 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3134 if ( $flags & self::GAID_FOR_UPDATE ) {
3135 $oldUpdate = $linkCache->forUpdate(
true );
3136 $linkCache->clearLink( $this );
3137 $this->mArticleID = $linkCache->addLinkObj( $this );
3138 $linkCache->forUpdate( $oldUpdate );
3141 } elseif ( $this->mArticleID == -1 ) {
3142 $this->mArticleID = $linkCache->addLinkObj( $this );
3157 $this->mRedirect = (bool)$this->
loadFieldFromDB(
'page_is_redirect', $flags );
3159 if ( $this->mRedirect !==
null ) {
3162 $this->mRedirect =
false;
3167 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3168 $linkCache->addLinkObj( $this );
3171 $this->mRedirect = (bool)$linkCache->getGoodLinkFieldObj( $this,
'redirect' );
3188 if ( $this->mLength != -1 ) {
3195 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3196 $linkCache->addLinkObj( $this );
3199 $this->mLength = (int)$linkCache->getGoodLinkFieldObj( $this,
'length' );
3213 $this->mLatestID = (int)$this->
loadFieldFromDB(
'page_latest', $flags );
3215 if ( $this->mLatestID !==
false ) {
3218 $this->mLatestID = 0;
3223 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3224 $linkCache->addLinkObj( $this );
3227 $this->mLatestID = (int)$linkCache->getGoodLinkFieldObj( $this,
'revision' );
3244 if ( $id ===
false ) {
3245 $this->mArticleID = -1;
3247 $this->mArticleID = (int)$id;
3249 $this->mRestrictionsLoaded =
false;
3250 $this->mRestrictions = [];
3251 $this->mOldRestrictions =
false;
3252 $this->mRedirect =
null;
3253 $this->mLength = -1;
3254 $this->mLatestID =
false;
3255 $this->mContentModel =
false;
3256 $this->mForcedContentModel =
false;
3257 $this->mEstimateRevisions =
null;
3258 $this->mPageLanguage =
null;
3259 $this->mDbPageLanguage =
false;
3260 $this->mIsBigDeletion =
null;
3262 MediaWikiServices::getInstance()->getLinkCache()->clearLink( $this );
3266 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3267 $linkCache->clear();
3281 $services = MediaWikiServices::getInstance();
3282 if ( $services->getNamespaceInfo()->isCapitalized( $ns ) ) {
3283 return $services->getContentLanguage()->ucfirst( $text );
3308 $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
3309 '@phan-var MediaWikiTitleCodec $titleCodec';
3311 $parts = $titleCodec->splitTitleString( $this->mDbkeyform, $this->mDefaultNamespace );
3315 $this->mInterwiki = $parts[
'interwiki'];
3316 $this->mLocalInterwiki = $parts[
'local_interwiki'];
3317 $this->mNamespace = $parts[
'namespace'];
3318 $this->mUserCaseDBKey = $parts[
'user_case_dbkey'];
3320 $this->mDbkeyform = $parts[
'dbkey'];
3321 $this->mUrlform =
wfUrlencode( $this->mDbkeyform );
3322 $this->mTextform = strtr( $this->mDbkeyform,
'_',
' ' );
3324 # We already know that some pages won't be in the database!
3326 $this->mArticleID = 0;
3344 public function getLinksTo( $options = [], $table =
'pagelinks', $prefix =
'pl' ) {
3345 if ( count( $options ) > 0 ) {
3353 self::getSelectFields(),
3355 "{$prefix}_from=page_id",
3356 "{$prefix}_namespace" => $this->mNamespace,
3357 "{$prefix}_title" => $this->mDbkeyform ],
3363 if (
$res->numRows() ) {
3364 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3365 foreach (
$res as $row ) {
3366 $titleObj =
self::makeTitle( $row->page_namespace, $row->page_title );
3368 $linkCache->addGoodLinkObjFromRow( $titleObj, $row );
3369 $retVal[] = $titleObj;
3387 return $this->
getLinksTo( $options,
'templatelinks',
'tl' );
3402 public function getLinksFrom( $options = [], $table =
'pagelinks', $prefix =
'pl' ) {
3405 # If the page doesn't exist; there can't be any link from this page
3412 $blNamespace =
"{$prefix}_namespace";
3413 $blTitle =
"{$prefix}_title";
3417 [ $table,
'nestpage' => $pageQuery[
'tables'] ],
3419 [ $blNamespace, $blTitle ],
3420 $pageQuery[
'fields']
3422 [
"{$prefix}_from" => $id ],
3427 [
"page_namespace=$blNamespace",
"page_title=$blTitle" ]
3428 ] ] + $pageQuery[
'joins']
3432 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
3433 foreach (
$res as $row ) {
3434 if ( $row->page_id ) {
3438 $linkCache->addBadLinkObj( $titleObj );
3440 $retVal[] = $titleObj;
3457 return $this->
getLinksFrom( $options,
'templatelinks',
'tl' );
3470 # All links from article ID 0 are false positives
3476 [
'page',
'pagelinks' ],
3477 [
'pl_namespace',
'pl_title' ],
3480 'page_namespace IS NULL'
3486 [
'pl_namespace=page_namespace',
'pl_title=page_title' ]
3492 foreach (
$res as $row ) {
3511 if ( $pageLang->hasVariants() ) {
3512 $variants = $pageLang->getVariants();
3513 foreach ( $variants as $vCode ) {
3520 $urls[] = $this->
getInternalURL(
'action=raw&ctype=text/javascript' );
3522 $urls[] = $this->
getInternalURL(
'action=raw&ctype=application/json' );
3527 Hooks::run(
'TitleSquidURLs', [ $this, &$urls ] );
3556 if ( !( $nt instanceof
Title ) ) {
3559 return [ [
'badtitletext' ] ];
3562 $mp = MediaWikiServices::getInstance()->getMovePageFactory()->newMovePage( $this, $nt );
3563 $errors = $mp->isValidMove()->getErrorsArray();
3567 $mp->checkPermissions( $wgUser, $reason )->getErrorsArray()
3571 return $errors ?:
true;
3587 public function moveTo( &$nt, $auth =
true, $reason =
'', $createRedirect =
true,
3588 array $changeTags = []
3594 $mp = MediaWikiServices::getInstance()->getMovePageFactory()->newMovePage( $this, $nt );
3595 $method = $auth ?
'moveIfAllowed' :
'move';
3597 $status = $mp->$method( $wgUser, $reason, $createRedirect, $changeTags );
3601 return $status->getErrorsArray();
3620 public function moveSubpages( $nt, $auth =
true, $reason =
'', $createRedirect =
true,
3621 array $changeTags = []
3628 $method = $auth ?
'moveSubpagesIfAllowed' :
'moveSubpages';
3630 $result = $mp->$method( $wgUser, $reason, $createRedirect, $changeTags );
3632 if ( !$result->isOK() ) {
3633 return $result->getErrorsArray();
3637 foreach ( $result->getValue() as $key =>
$status ) {
3640 $retval[$key] =
$status->getValue();
3642 $retval[$key] =
$status->getErrorsArray();
3661 $fields = [
'page_is_redirect',
'page_latest',
'page_id' ];
3663 $fields[] =
'page_content_model';
3666 $row = $dbw->selectRow(
'page',
3672 # Cache some fields we may want
3673 $this->mArticleID = $row ? intval( $row->page_id ) : 0;
3674 $this->mRedirect = $row ? (bool)$row->page_is_redirect :
false;
3675 $this->mLatestID = $row ? intval( $row->page_latest ) :
false;
3676 $this->mContentModel = $row && isset( $row->page_content_model )
3677 ? strval( $row->page_content_model )
3680 if ( !$this->mRedirect ) {
3683 # Does the article have a history?
3684 $row = $dbw->selectField( [
'page',
'revision' ],
3686 [
'page_namespace' => $this->mNamespace,
3687 'page_title' => $this->mDbkeyform,
3689 'page_latest != rev_id'
3694 # Return true if there was no history
3695 return ( $row ===
false );
3709 # Is it an existing file?
3710 if ( $nt->getNamespace() ==
NS_FILE ) {
3711 $file = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()
3713 $file->load( File::READ_LATEST );
3714 if (
$file->exists() ) {
3715 wfDebug( __METHOD__ .
": file exists\n" );
3719 # Is it a redirect with no history?
3720 if ( !$nt->isSingleRevRedirect() ) {
3721 wfDebug( __METHOD__ .
": not a one-rev redirect\n" );
3724 # Get the article text
3726 if ( !is_object( $rev ) ) {
3730 # Does the redirect point to the source?
3731 # Or is it a broken self-redirect, usually caused by namespace collisions?
3734 if ( $redirTitle ) {
3736 $redirTitle->getPrefixedDBkey() != $nt->getPrefixedDBkey() ) {
3737 wfDebug( __METHOD__ .
": redirect points to other page\n" );
3743 # Fail safe (not a redirect after all. strange.)
3744 wfDebug( __METHOD__ .
": failsafe: database sais " . $nt->getPrefixedDBkey() .
3745 " is a redirect, but it doesn't contain a valid redirect.\n" );
3762 if ( $titleKey === 0 ) {
3771 [
'cl_from' => $titleKey ],
3775 if (
$res->numRows() > 0 ) {
3776 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
3777 foreach (
$res as $row ) {
3779 $data[$contLang->getNsText(
NS_CATEGORY ) .
':' . $row->cl_to] =
3797 foreach ( $parents as $parent => $current ) {
3798 if ( array_key_exists( $parent, $children ) ) {
3799 # Circular reference
3800 $stack[$parent] = [];
3804 $stack[$parent] = $nt->getParentCategoryTree( $children + [ $parent => 1 ] );
3820 if ( $this->mArticleID > 0 ) {
3836 $rl = MediaWikiServices::getInstance()->getRevisionLookup();
3837 $rev = $rl->getRevisionById( $revId, $flags );
3842 $oldRev = ( $dir ===
'next' )
3843 ? $rl->getNextRevision( $rev, $flags )
3844 : $rl->getPreviousRevision( $rev, $flags );
3846 return $oldRev ? $oldRev->getId() :
false;
3885 $row =
wfGetDB( $index )->selectRow(
3887 [
'rev_page' => $pageId ],
3891 'ORDER BY' =>
'rev_timestamp ASC, rev_id ASC',
3892 'IGNORE INDEX' => [
'revision' =>
'rev_timestamp' ],
3899 return new Revision( $row, 0, $this );
3913 return $rev ? $rev->getTimestamp() :
null;
3923 return (
bool)
$dbr->selectField(
'page',
'page_is_new', $this->
pageCond(), __METHOD__ );
3938 if ( $this->mIsBigDeletion ===
null ) {
3941 $revCount =
$dbr->selectRowCount(
3961 if ( !$this->
exists() ) {
3965 if ( $this->mEstimateRevisions ===
null ) {
3967 $this->mEstimateRevisions =
$dbr->estimateRowCount(
'revision',
'*',
3984 if ( !( $old instanceof
Revision ) ) {
3987 if ( !( $new instanceof
Revision ) ) {
3990 if ( !$old || !$new ) {
3996 'rev_timestamp > ' .
$dbr->addQuotes(
$dbr->timestamp( $old->getTimestamp() ) ),
3997 'rev_timestamp < ' .
$dbr->addQuotes(
$dbr->timestamp( $new->getTimestamp() ) )
3999 if ( $max !==
null ) {
4000 return $dbr->selectRowCount(
'revision',
'1',
4003 [
'LIMIT' => $max + 1 ]
4006 return (
int)
$dbr->selectField(
'revision',
'count(*)', $conds, __METHOD__ );
4027 if ( !( $old instanceof
Revision ) ) {
4030 if ( !( $new instanceof
Revision ) ) {
4036 if ( !$old || !$new ) {
4042 $options = (array)$options;
4043 if ( in_array(
'include_old', $options ) ) {
4046 if ( in_array(
'include_new', $options ) ) {
4049 if ( in_array(
'include_both', $options ) ) {
4054 if ( $old->getId() === $new->getId() ) {
4055 return ( $old_cmp ===
'>' && $new_cmp ===
'<' ) ?
4057 [ $old->getUserText( RevisionRecord::RAW ) ];
4058 } elseif ( $old->getId() === $new->getParentId() ) {
4059 if ( $old_cmp ===
'>=' && $new_cmp ===
'<=' ) {
4060 $authors[] = $oldUserText = $old->getUserText( RevisionRecord::RAW );
4061 $newUserText = $new->getUserText( RevisionRecord::RAW );
4062 if ( $oldUserText != $newUserText ) {
4063 $authors[] = $newUserText;
4065 } elseif ( $old_cmp ===
'>=' ) {
4066 $authors[] = $old->getUserText( RevisionRecord::RAW );
4067 } elseif ( $new_cmp ===
'<=' ) {
4068 $authors[] = $new->getUserText( RevisionRecord::RAW );
4074 $authors =
$dbr->selectFieldValues(
4079 "rev_timestamp $old_cmp " .
$dbr->addQuotes(
$dbr->timestamp( $old->getTimestamp() ) ),
4080 "rev_timestamp $new_cmp " .
$dbr->addQuotes(
$dbr->timestamp( $new->getTimestamp() ) )
4082 [
'DISTINCT',
'LIMIT' => $limit + 1 ],
4104 return $authors ? count( $authors ) : 0;
4115 return $this->mInterwiki ===
$title->getInterwiki()
4116 && $this->mNamespace ==
$title->getNamespace()
4117 && $this->mDbkeyform ===
$title->getDBkey();
4127 return $this->mInterwiki ===
$title->mInterwiki
4128 && $this->mNamespace ==
$title->mNamespace
4129 && strpos( $this->mDbkeyform,
$title->mDbkeyform .
'/' ) === 0;
4144 Hooks::run(
'TitleExists', [ $this, &$exists ] );
4177 Hooks::run(
'TitleIsAlwaysKnown', [ $this, &$isKnown ] );
4179 if ( !is_null( $isKnown ) ) {
4187 $services = MediaWikiServices::getInstance();
4188 switch ( $this->mNamespace ) {
4192 return (
bool)$services->getRepoGroup()->findFile( $this );
4195 return $services->getSpecialPageFactory()->exists( $this->mDbkeyform );
4198 return $this->mDbkeyform ==
'';
4237 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
4239 $contLang->lcfirst( $this->getText() )
4241 $message =
wfMessage( $name )->inLanguage( $contLang )->useDatabase(
false );
4242 return $message->exists();
4291 MediaWikiServices::getInstance()->getContentLanguage()->lcfirst( $this->
getText() )
4293 $message =
wfMessage( $name )->inLanguage(
$lang )->useDatabase(
false );
4295 if ( $message->exists() ) {
4296 return $message->plain();
4311 } elseif ( $this->mArticleID === 0 ) {
4316 $dbw->onTransactionPreCommitOrIdle(
4317 function () use ( $dbw ) {
4319 $this,
null,
null, $dbw->getDomainID() );
4329 function (
IDatabase $dbw, $fname ) use ( $conds, $purgeTime ) {
4330 $dbTimestamp = $dbw->
timestamp( $purgeTime ?: time() );
4333 [
'page_touched' => $dbTimestamp ],
4334 $conds + [
'page_touched < ' . $dbw->
addQuotes( $dbTimestamp ) ],
4337 MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
4356 [
'causeAction' =>
'page-touch' ]
4362 [
'causeAction' =>
'category-touch' ]
4376 if ( $db ===
null ) {
4379 $touched = $db->selectField(
'page',
'page_touched', $this->
pageCond(), __METHOD__ );
4397 $uid = $user->getId();
4402 if ( array_key_exists( $uid, $this->mNotificationTimestamp ) ) {
4403 return $this->mNotificationTimestamp[$uid];
4406 if ( count( $this->mNotificationTimestamp ) >= self::CACHE_MAX ) {
4407 $this->mNotificationTimestamp = [];
4410 $store = MediaWikiServices::getInstance()->getWatchedItemStore();
4411 $watchedItem = $store->getWatchedItem( $user, $this );
4412 if ( $watchedItem ) {
4413 $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
4415 $this->mNotificationTimestamp[$uid] =
false;
4418 return $this->mNotificationTimestamp[$uid];
4429 $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
4430 $subjectNS = $nsInfo->getSubject( $this->mNamespace );
4432 $namespaceKey = $nsInfo->getCanonicalName( $subjectNS );
4433 if ( $namespaceKey ===
false ) {
4438 $namespaceKey = MediaWikiServices::getInstance()->getContentLanguage()->lc( $namespaceKey );
4440 if ( $namespaceKey ==
'' ) {
4441 $namespaceKey =
'main';
4444 if ( $namespaceKey ==
'file' ) {
4445 $namespaceKey =
'image';
4447 return $prepend . $namespaceKey;
4468 $where[] =
'rd_interwiki = ' .
$dbr->addQuotes(
'' ) .
' OR rd_interwiki IS NULL';
4470 if ( !is_null( $ns ) ) {
4471 $where[
'page_namespace'] = $ns;
4475 [
'redirect',
'page' ],
4476 [
'page_namespace',
'page_title' ],
4481 foreach (
$res as $row ) {
4497 if ( $this->
isSpecial(
'Userlogout' ) ) {
4501 foreach ( $wgInvalidRedirectTargets as $target ) {
4529 MediaWikiServices::getInstance()->getNamespaceInfo()->getContentNamespaces();
4531 return !in_array( $this->mNamespace, $bannedNamespaces );
4545 $unprefixed = $this->
getText();
4551 Hooks::run(
'GetDefaultSortkey', [ $this, &$unprefixed ] );
4552 if ( $prefix !==
'' ) {
4553 # Separate with a line feed, so the unprefixed part is only used as
4554 # a tiebreaker when two pages have the exact same prefix.
4555 # In UCA, tab is the only character that can sort above LF
4556 # so we strip both of them from the original prefix.
4557 $prefix = strtr( $prefix,
"\n\t",
' ' );
4558 return "$prefix\n$unprefixed";
4576 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
4577 $linkCache->addLinkObj( $this );
4578 $this->mDbPageLanguage = $linkCache->getGoodLinkFieldObj( $this,
'lang' );
4601 if ( $dbPageLanguage ) {
4605 if ( !$this->mPageLanguage || $this->mPageLanguage[1] !==
$wgLanguageCode ) {
4613 $langObj = $contentHandler->getPageLanguage( $this );
4636 $variant =
$wgLang->getPreferredVariant();
4637 if (
$wgLang->getCode() !== $variant ) {
4646 if ( $dbPageLanguage ) {
4648 $variant = $pageLang->getPreferredVariant();
4649 if ( $pageLang->getCode() !== $variant ) {
4660 $pageLang = $contentHandler->getPageViewLanguage( $this );
4680 if ( $msg->exists() ) {
4681 $html = $msg->parseAsBlock();
4683 if ( trim( $html ) !==
'' ) {
4684 $notices[$editnotice_ns] = Html::rawElement(
4688 'mw-editnotice-namespace',
4689 Sanitizer::escapeClass(
"mw-$editnotice_ns" )
4697 MediaWikiServices::getInstance()->getNamespaceInfo()->
4701 $editnotice_base = $editnotice_ns;
4702 foreach ( explode(
'/', $this->mDbkeyform ) as $part ) {
4703 $editnotice_base .=
'-' . $part;
4705 if ( $msg->exists() ) {
4706 $html = $msg->parseAsBlock();
4707 if ( trim( $html ) !==
'' ) {
4708 $notices[$editnotice_base] = Html::rawElement(
4712 'mw-editnotice-base',
4713 Sanitizer::escapeClass(
"mw-$editnotice_base" )
4722 $editnoticeText = $editnotice_ns .
'-' . strtr( $this->mDbkeyform,
'/',
'-' );
4724 if ( $msg->exists() ) {
4725 $html = $msg->parseAsBlock();
4726 if ( trim( $html ) !==
'' ) {
4727 $notices[$editnoticeText] = Html::rawElement(
4731 'mw-editnotice-page',
4732 Sanitizer::escapeClass(
"mw-$editnoticeText" )
4740 Hooks::run(
'TitleGetEditNotices', [ $this, $oldid, &$notices ] );
4749 if ( !in_array( $field, self::getSelectFields(),
true ) ) {
4756 return wfGetDB( $index )->selectField(
4776 'mDefaultNamespace',
4781 $this->mArticleID = ( $this->mNamespace >= 0 ) ? -1 : 0;
4782 $this->mUrlform =
wfUrlencode( $this->mDbkeyform );
4783 $this->mTextform = strtr( $this->mDbkeyform,
'_',
' ' );