* and does not rely on global state or the database.
*/
class Title implements LinkTarget {
- /** @var HashBagOStuff */
+ /** @var MapCacheLRU */
static private $titleCache = null;
/**
public static function newFromTextThrow( $text, $defaultNamespace = NS_MAIN ) {
if ( is_object( $text ) ) {
throw new MWException( '$text must be a string, given an object' );
+ } elseif ( $text === null ) {
+ // Legacy code relies on MalformedTitleException being thrown in this case
+ // (happens when URL with no title in it is parsed). TODO fix
+ throw new MalformedTitleException( 'title-invalid-empty' );
}
$titleCache = self::getTitleCache();
}
/**
- * @return HashBagOStuff
+ * @return MapCacheLRU
*/
private static function getTitleCache() {
if ( self::$titleCache == null ) {
- self::$titleCache = new HashBagOStuff( [ 'maxKeys' => self::CACHE_MAX ] );
+ self::$titleCache = new MapCacheLRU( self::CACHE_MAX );
}
return self::$titleCache;
}
public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
$canonicalNamespace = false
) {
- global $wgContLang;
-
if ( $canonicalNamespace ) {
$namespace = MWNamespace::getCanonicalName( $ns );
} else {
- $namespace = $wgContLang->getNsText( $ns );
+ $namespace = MediaWikiServices::getInstance()->getContentLanguage()->getNsText( $ns );
}
$name = $namespace == '' ? $title : "$namespace:$title";
if ( strval( $interwiki ) != '' ) {
* @return string Namespace text
*/
public function getSubjectNsText() {
- global $wgContLang;
- return $wgContLang->getNsText( MWNamespace::getSubject( $this->mNamespace ) );
+ return MediaWikiServices::getInstance()->getContentLanguage()->
+ getNsText( MWNamespace::getSubject( $this->mNamespace ) );
}
/**
* @return string Namespace text
*/
public function getTalkNsText() {
- global $wgContLang;
- return $wgContLang->getNsText( MWNamespace::getTalk( $this->mNamespace ) );
+ return MediaWikiServices::getInstance()->getContentLanguage()->
+ getNsText( MWNamespace::getTalk( $this->mNamespace ) );
}
/**
*/
public function isSiteConfigPage() {
return (
- NS_MEDIAWIKI == $this->mNamespace
- && (
- $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JSON )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
- )
+ $this->isSiteCssConfigPage()
+ || $this->isSiteJsonConfigPage()
+ || $this->isSiteJsConfigPage()
);
}
*/
public function isUserConfigPage() {
return (
- NS_USER == $this->mNamespace
- && $this->isSubpage()
- && (
- $this->hasContentModel( CONTENT_MODEL_CSS )
- || $this->hasContentModel( CONTENT_MODEL_JSON )
- || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
- )
+ $this->isUserCssConfigPage()
+ || $this->isUserJsonConfigPage()
+ || $this->isUserJsConfigPage()
);
}
return $this->isUserJsConfigPage();
}
+ /**
+ * Is this a sitewide CSS "config" page?
+ *
+ * @return bool
+ * @since 1.32
+ */
+ public function isSiteCssConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_CSS )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -4 ) === '.css'
+ )
+ );
+ }
+
+ /**
+ * Is this a sitewide JSON "config" page?
+ *
+ * @return bool
+ * @since 1.32
+ */
+ public function isSiteJsonConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_JSON )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -5 ) === '.json'
+ )
+ );
+ }
+
+ /**
+ * Is this a sitewide JS "config" page?
+ *
+ * @return bool
+ * @since 1.31
+ */
+ public function isSiteJsConfigPage() {
+ return (
+ NS_MEDIAWIKI == $this->mNamespace
+ && (
+ $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT )
+ // paranoia - a MediaWiki: namespace page with mismatching extension and content
+ // model is probably by mistake and might get handled incorrectly (see e.g. T112937)
+ || substr( $this->getDBkey(), -3 ) === '.js'
+ )
+ );
+ }
+
/**
* Is this a talk page of some sort?
*
* @return string The prefixed text
*/
private function prefix( $name ) {
- global $wgContLang;
-
$p = '';
if ( $this->isExternal() ) {
$p = $this->mInterwiki . ':';
if ( $nsText === false ) {
// See T165149. Awkward, but better than erroneously linking to the main namespace.
- $nsText = $wgContLang->getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
+ $nsText = MediaWikiServices::getInstance()->getContentLanguage()->
+ getNsText( NS_SPECIAL ) . ":Badtitle/NS{$this->mNamespace}";
}
$p .= $nsText . ':';
$titleRef = $this;
Hooks::run( 'GetLocalURL::Article', [ &$titleRef, &$url ] );
} else {
- global $wgVariantArticlePath, $wgActionPaths, $wgContLang;
+ global $wgVariantArticlePath, $wgActionPaths;
$url = false;
$matches = [];
if ( $url === false
&& $wgVariantArticlePath
&& preg_match( '/^variant=([^&]*)$/', $query, $matches )
- && $this->getPageLanguage()->equals( $wgContLang )
+ && $this->getPageLanguage()->equals(
+ MediaWikiServices::getInstance()->getContentLanguage() )
&& $this->getPageLanguage()->hasVariants()
) {
$variant = urldecode( $matches[1] );
return $errors;
}
+ /**
+ * Check sitewide CSS/JSON/JS permissions
+ *
+ * @param string $action The action to check
+ * @param User $user User to check
+ * @param array $errors List of current errors
+ * @param string $rigor Same format as Title::getUserPermissionsErrors()
+ * @param bool $short Short circuit on first error
+ *
+ * @return array List of errors
+ */
+ private function checkSiteConfigPermissions( $action, $user, $errors, $rigor, $short ) {
+ if ( $action != 'patrol' ) {
+ $error = null;
+ // Sitewide CSS/JSON/JS changes, like all NS_MEDIAWIKI changes, also require the
+ // editinterface right. That's implemented as a restriction so no check needed here.
+ if ( $this->isSiteCssConfigPage() && !$user->isAllowed( 'editsitecss' ) ) {
+ $error = [ 'sitecssprotected', $action ];
+ } elseif ( $this->isSiteJsonConfigPage() && !$user->isAllowed( 'editsitejson' ) ) {
+ $error = [ 'sitejsonprotected', $action ];
+ } elseif ( $this->isSiteJsConfigPage() && !$user->isAllowed( 'editsitejs' ) ) {
+ $error = [ 'sitejsprotected', $action ];
+ }
+
+ if ( $error ) {
+ if ( $user->isAllowed( 'editinterface' ) ) {
+ // Most users / site admins will probably find out about the new, more restrictive
+ // permissions by failing to edit something. Give them more info.
+ // TODO remove this a few release cycles after 1.32
+ $error = [ 'interfaceadmin-info', wfMessage( $error[0], $error[1] ) ];
+ }
+ $errors[] = $error;
+ }
+ }
+
+ return $errors;
+ }
+
/**
* Check CSS/JSON/JS sub-page permissions
*
'checkReadPermissions',
'checkUserBlock', // for wgBlockDisablesLogin
];
- # Don't call checkSpecialsAndNSPermissions or checkUserConfigPermissions
- # here as it will lead to duplicate error messages. This is okay to do
- # since anywhere that checks for create will also check for edit, and
- # those checks are called for edit.
+ # Don't call checkSpecialsAndNSPermissions, checkSiteConfigPermissions
+ # or checkUserConfigPermissions here as it will lead to duplicate
+ # error messages. This is okay to do since anywhere that checks for
+ # create will also check for edit, and those checks are called for edit.
} elseif ( $action == 'create' ) {
$checks = [
'checkQuickPermissions',
'checkQuickPermissions',
'checkPermissionHooks',
'checkSpecialsAndNSPermissions',
+ 'checkSiteConfigPermissions',
'checkUserConfigPermissions',
'checkPageRestrictions',
'checkCascadingSourcesRestrictions',
* @return string Containing capitalized title
*/
public static function capitalize( $text, $ns = NS_MAIN ) {
- global $wgContLang;
-
if ( MWNamespace::isCapitalized( $ns ) ) {
- return $wgContLang->ucfirst( $text );
+ return MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $text );
} else {
return $text;
}
* $parent => $currentarticle
*/
public function getParentCategories() {
- global $wgContLang;
-
$data = [];
$titleKey = $this->getArticleID();
);
if ( $res->numRows() > 0 ) {
+ $contLang = MediaWikiServices::getInstance()->getContentLanguage();
foreach ( $res as $row ) {
- // $data[] = Title::newFromText($wgContLang->getNsText ( NS_CATEGORY ).':'.$row->cl_to);
- $data[$wgContLang->getNsText( NS_CATEGORY ) . ':' . $row->cl_to] = $this->getFullText();
+ // $data[] = Title::newFromText( $contLang->getNsText ( NS_CATEGORY ).':'.$row->cl_to);
+ $data[$contLang->getNsText( NS_CATEGORY ) . ':' . $row->cl_to] =
+ $this->getFullText();
}
}
return $data;
// message content will be displayed, same for language subpages-
// Use always content language to avoid loading hundreds of languages
// to get the link color.
- global $wgContLang;
+ $contLang = MediaWikiServices::getInstance()->getContentLanguage();
list( $name, ) = MessageCache::singleton()->figureMessage(
- $wgContLang->lcfirst( $this->getText() )
+ $contLang->lcfirst( $this->getText() )
);
- $message = wfMessage( $name )->inLanguage( $wgContLang )->useDatabase( false );
+ $message = wfMessage( $name )->inLanguage( $contLang )->useDatabase( false );
return $message->exists();
}
* @return string|bool
*/
public function getDefaultMessageText() {
- global $wgContLang;
-
if ( $this->getNamespace() != NS_MEDIAWIKI ) { // Just in case
return false;
}
list( $name, $lang ) = MessageCache::singleton()->figureMessage(
- $wgContLang->lcfirst( $this->getText() )
+ MediaWikiServices::getInstance()->getContentLanguage()->lcfirst( $this->getText() )
);
$message = wfMessage( $name )->inLanguage( $lang )->useDatabase( false );
* @return string XML 'id' name
*/
public function getNamespaceKey( $prepend = 'nstab-' ) {
- global $wgContLang;
// Gets the subject namespace of this title
$subjectNS = MWNamespace::getSubject( $this->getNamespace() );
// Prefer canonical namespace name for HTML IDs
$namespaceKey = $this->getSubjectNsText();
}
// Makes namespace key lowercase
- $namespaceKey = $wgContLang->lc( $namespaceKey );
+ $namespaceKey = MediaWikiServices::getInstance()->getContentLanguage()->lc( $namespaceKey );
// Uses main
if ( $namespaceKey == '' ) {
$namespaceKey = 'main';
/**
* Get the language in which the content of this page is written in
- * wikitext. Defaults to $wgContLang, but in certain cases it can be
+ * wikitext. Defaults to content language, but in certain cases it can be
* e.g. $wgLang (such as special pages, which are in the user language).
*
* @since 1.18
/**
* Get the language in which the content of this page is written when
- * viewed by user. Defaults to $wgContLang, but in certain cases it can be
+ * viewed by user. Defaults to content language, but in certain cases it can be
* e.g. $wgLang (such as special pages, which are in the user language).
*
* @since 1.20