Merge "Split editcascadeprotected permission from protect permission"
[lhc/web/wiklou.git] / includes / Title.php
index 95588a2..ef806a5 100644 (file)
@@ -21,6 +21,8 @@
  *
  * @file
  */
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Represents a title within MediaWiki.
@@ -156,42 +158,6 @@ class Title implements LinkTarget {
        private $mIsBigDeletion = null;
        // @}
 
-       /**
-        * B/C kludge: provide a TitleParser for use by Title.
-        * Ideally, Title would have no methods that need this.
-        * Avoid usage of this singleton by using TitleValue
-        * and the associated services when possible.
-        *
-        * @return MediaWikiTitleCodec
-        */
-       private static function getMediaWikiTitleCodec() {
-               global $wgContLang, $wgLocalInterwikis;
-
-               static $titleCodec = null;
-               static $titleCodecFingerprint = null;
-
-               // $wgContLang and $wgLocalInterwikis may change (especially while testing),
-               // make sure we are using the right one. To detect changes over the course
-               // of a request, we remember a fingerprint of the config used to create the
-               // codec singleton, and re-create it if the fingerprint doesn't match.
-               $fingerprint = spl_object_hash( $wgContLang ) . '|' . implode( '+', $wgLocalInterwikis );
-
-               if ( $fingerprint !== $titleCodecFingerprint ) {
-                       $titleCodec = null;
-               }
-
-               if ( !$titleCodec ) {
-                       $titleCodec = new MediaWikiTitleCodec(
-                               $wgContLang,
-                               GenderCache::singleton(),
-                               $wgLocalInterwikis
-                       );
-                       $titleCodecFingerprint = $fingerprint;
-               }
-
-               return $titleCodec;
-       }
-
        /**
         * B/C kludge: provide a TitleParser for use by Title.
         * Ideally, Title would have no methods that need this.
@@ -201,11 +167,12 @@ class Title implements LinkTarget {
         * @return TitleFormatter
         */
        private static function getTitleFormatter() {
-               // NOTE: we know that getMediaWikiTitleCodec() returns a MediaWikiTitleCodec,
-               //      which implements TitleFormatter.
-               return self::getMediaWikiTitleCodec();
+               return MediaWikiServices::getInstance()->getTitleFormatter();
        }
 
+       /**
+        * @access protected
+        */
        function __construct() {
        }
 
@@ -248,10 +215,16 @@ class Title implements LinkTarget {
         * @return Title
         */
        public static function newFromLinkTarget( LinkTarget $linkTarget ) {
+               if ( $linkTarget instanceof Title ) {
+                       // Special case if it's already a Title object
+                       return $linkTarget;
+               }
                return self::makeTitle(
                        $linkTarget->getNamespace(),
                        $linkTarget->getText(),
-                       $linkTarget->getFragment() );
+                       $linkTarget->getFragment(),
+                       $linkTarget->getInterwiki()
+               );
        }
 
        /**
@@ -866,7 +839,9 @@ class Title implements LinkTarget {
                                $this->mTitleValue = new TitleValue(
                                        $this->getNamespace(),
                                        $this->getDBkey(),
-                                       $this->getFragment() );
+                                       $this->getFragment(),
+                                       $this->getInterwiki()
+                               );
                        } catch ( InvalidArgumentException $ex ) {
                                wfDebug( __METHOD__ . ': Can\'t create a TitleValue for [[' .
                                        $this->getPrefixedText() . ']]: ' . $ex->getMessage() . "\n" );
@@ -1372,7 +1347,8 @@ class Title implements LinkTarget {
         * specified fragment before setting, so it assumes you're passing it with
         * an initial "#".
         *
-        * Deprecated for public use, use Title::makeTitle() with fragment parameter.
+        * Deprecated for public use, use Title::makeTitle() with fragment parameter,
+        * or Title::createFragmentTarget().
         * Still in active use privately.
         *
         * @private
@@ -1382,6 +1358,23 @@ class Title implements LinkTarget {
                $this->mFragment = strtr( substr( $fragment, 1 ), '_', ' ' );
        }
 
+       /**
+        * Creates a new Title for a different fragment of the same page.
+        *
+        * @since 1.27
+        * @param string $fragment
+        * @return Title
+        */
+       public function createFragmentTarget( $fragment ) {
+               return self::makeTitle(
+                       $this->getNamespace(),
+                       $this->getText(),
+                       $fragment,
+                       $this->getInterwiki()
+               );
+
+       }
+
        /**
         * Prefix some arbitrary text with the namespace or interwiki prefix
         * of this object
@@ -2129,7 +2122,9 @@ class Title implements LinkTarget {
                        }
                        if ( !$user->isAllowed( $right ) ) {
                                $errors[] = [ 'protectedpagetext', $right, $action ];
-                       } elseif ( $this->mCascadeRestriction && !$user->isAllowed( 'protect' ) ) {
+                       } elseif ( $this->mCascadeRestriction &&
+                               !$user->isAllowedAny( 'editcascadeprotected', 'protect' ) )
+                       {
                                $errors[] = [ 'protectedpagetext', 'protect', $action ];
                        }
                }
@@ -2170,7 +2165,9 @@ class Title implements LinkTarget {
                                        if ( $right == 'autoconfirmed' ) {
                                                $right = 'editsemiprotected';
                                        }
-                                       if ( $right != '' && !$user->isAllowedAll( 'protect', $right ) ) {
+                                       if ( $right != '' && !$user->isAllowed( $right ) &&
+                                               !$user->isAllowedAny( 'editcascadeprotected', 'protect' ) )
+                                       {
                                                $pages = '';
                                                foreach ( $cascadingSources as $page ) {
                                                        $pages .= '* [[:' . $page->getPrefixedText() . "]]\n";
@@ -3305,9 +3302,11 @@ class Title implements LinkTarget {
                // @note: splitTitleString() is a temporary hack to allow MediaWikiTitleCodec to share
                //        the parsing code with Title, while avoiding massive refactoring.
                // @todo: get rid of secureAndSplit, refactor parsing code.
-               $titleParser = self::getMediaWikiTitleCodec();
+               // @note: getTitleParser() returns a TitleParser implementation which does not have a
+               //        splitTitleString method, but the only implementation (MediaWikiTitleCodec) does
+               $titleCodec = MediaWikiServices::getInstance()->getTitleParser();
                // MalformedTitleException can be thrown here
-               $parts = $titleParser->splitTitleString( $dbkey, $this->getDefaultNamespace() );
+               $parts = $titleCodec->splitTitleString( $dbkey, $this->getDefaultNamespace() );
 
                # Fill fields
                $this->setFragment( '#' . $parts['fragment'] );
@@ -4411,7 +4410,8 @@ class Title implements LinkTarget {
                        $this->mNotificationTimestamp = [];
                }
 
-               $watchedItem = WatchedItemStore::getDefaultInstance()->getWatchedItem( $user, $this );
+               $store = MediaWikiServices::getInstance()->getWatchedItemStore();
+               $watchedItem = $store->getWatchedItem( $user, $this );
                if ( $watchedItem ) {
                        $this->mNotificationTimestamp[$uid] = $watchedItem->getNotificationTimestamp();
                } else {