(bug 44010) Pass context to UserGetLanguageObject
[lhc/web/wiklou.git] / includes / context / RequestContext.php
index 7ca184a..96d27b0 100644 (file)
@@ -28,7 +28,6 @@
  * Group all the pieces relevant to the context of a request into one instance
  */
 class RequestContext implements IContextSource {
-
        /**
         * @var WebRequest
         */
@@ -39,6 +38,11 @@ class RequestContext implements IContextSource {
         */
        private $title;
 
+       /**
+        * @var WikiPage
+        */
+       private $wikipage;
+
        /**
         * @var OutputPage
         */
@@ -62,7 +66,7 @@ class RequestContext implements IContextSource {
        /**
         * Set the WebRequest object
         *
-        * @param $r WebRequest object
+        * @param WebRequest $r
         */
        public function setRequest( WebRequest $r ) {
                $this->request = $r;
@@ -84,10 +88,12 @@ class RequestContext implements IContextSource {
        /**
         * Set the Title object
         *
-        * @param $t Title object
+        * @param Title $t
         */
        public function setTitle( Title $t ) {
                $this->title = $t;
+               // Erase the WikiPage so a new one with the new title gets created.
+               $this->wikipage = null;
        }
 
        /**
@@ -103,6 +109,66 @@ class RequestContext implements IContextSource {
                return $this->title;
        }
 
+       /**
+        * Check whether a WikiPage object can be get with getWikiPage().
+        * Callers should expect that an exception is thrown from getWikiPage()
+        * if this method returns false.
+        *
+        * @since 1.19
+        * @return bool
+        */
+       public function canUseWikiPage() {
+               if ( $this->wikipage !== null ) {
+                       # If there's a WikiPage object set, we can for sure get it
+                       return true;
+               }
+               $title = $this->getTitle();
+               if ( $title === null ) {
+                       # No Title, no WikiPage
+                       return false;
+               } else {
+                       # Only namespaces whose pages are stored in the database can have WikiPage
+                       return $title->canExist();
+               }
+       }
+
+       /**
+        * Set the WikiPage object
+        *
+        * @since 1.19
+        * @param WikiPage $p
+        */
+       public function setWikiPage( WikiPage $p ) {
+               $contextTitle = $this->getTitle();
+               $pageTitle = $p->getTitle();
+               if ( !$contextTitle || !$pageTitle->equals( $contextTitle ) ) {
+                       $this->setTitle( $pageTitle );
+               }
+               // Defer this to the end since setTitle sets it to null.
+               $this->wikipage = $p;
+       }
+
+       /**
+        * Get the WikiPage object.
+        * May throw an exception if there's no Title object set or the Title object
+        * belongs to a special namespace that doesn't have WikiPage, so use first
+        * canUseWikiPage() to check whether this method can be called safely.
+        *
+        * @since 1.19
+        * @throws MWException
+        * @return WikiPage
+        */
+       public function getWikiPage() {
+               if ( $this->wikipage === null ) {
+                       $title = $this->getTitle();
+                       if ( $title === null ) {
+                               throw new MWException( __METHOD__ . ' called without Title object set' );
+                       }
+                       $this->wikipage = WikiPage::factory( $title );
+               }
+               return $this->wikipage;
+       }
+
        /**
         * @param $o OutputPage
         */
@@ -113,7 +179,7 @@ class RequestContext implements IContextSource {
        /**
         * Get the OutputPage object
         *
-        * @return OutputPage object
+        * @return OutputPage
         */
        public function getOutput() {
                if ( $this->output === null ) {
@@ -125,7 +191,7 @@ class RequestContext implements IContextSource {
        /**
         * Set the User object
         *
-        * @param $u User
+        * @param User $u
         */
        public function setUser( User $u ) {
                $this->user = $u;
@@ -146,15 +212,17 @@ class RequestContext implements IContextSource {
        /**
         * Accepts a language code and ensures it's sane. Outputs a cleaned up language
         * code and replaces with $wgLanguageCode if not sane.
+        * @param string $code Language code
+        * @return string
         */
-       private static function sanitizeLangCode( $code ) {
+       public static function sanitizeLangCode( $code ) {
                global $wgLanguageCode;
 
                // BCP 47 - letter case MUST NOT carry meaning
                $code = strtolower( $code );
 
                # Validate $code
-               if( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) {
+               if ( empty( $code ) || !Language::isValidCode( $code ) || ( $code === 'qqq' ) ) {
                        wfDebug( "Invalid user language code\n" );
                        $code = $wgLanguageCode;
                }
@@ -166,16 +234,19 @@ class RequestContext implements IContextSource {
         * Set the Language object
         *
         * @deprecated 1.19 Use setLanguage instead
-        * @param $l Mixed Language instance or language code
+        * @param Language|string $l Language instance or language code
         */
        public function setLang( $l ) {
+               wfDeprecated( __METHOD__, '1.19' );
                $this->setLanguage( $l );
        }
 
        /**
         * Set the Language object
         *
-        * @param $l Mixed Language instance or language code
+        * @param Language|string $l Language instance or language code
+        * @throws MWException
+        * @since 1.19
         */
        public function setLanguage( $l ) {
                if ( $l instanceof Language ) {
@@ -194,39 +265,52 @@ class RequestContext implements IContextSource {
         * @return Language
         */
        public function getLang() {
+               wfDeprecated( __METHOD__, '1.19' );
                return $this->getLanguage();
        }
 
        /**
-        * Get the Language object
+        * Get the Language object.
+        * Initialization of user or request objects can depend on this.
         *
         * @return Language
+        * @since 1.19
         */
        public function getLanguage() {
+               if ( isset( $this->recursion ) ) {
+                       throw new MWException( 'Recursion detected' );
+               }
+
                if ( $this->lang === null ) {
+                       $this->recursion = true;
+
                        global $wgLanguageCode, $wgContLang;
-                       $code = $this->getRequest()->getVal(
-                               'uselang',
-                               $this->getUser()->getOption( 'language' )
-                       );
+
+                       $request = $this->getRequest();
+                       $user = $this->getUser();
+
+                       $code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
                        $code = self::sanitizeLangCode( $code );
 
-                       wfRunHooks( 'UserGetLanguageObject', array( $this->getUser(), &$code ) );
+                       wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) );
 
-                       if( $code === $wgLanguageCode ) {
+                       if ( $code === $wgLanguageCode ) {
                                $this->lang = $wgContLang;
                        } else {
                                $obj = Language::factory( $code );
                                $this->lang = $obj;
                        }
+
+                       unset( $this->recursion );
                }
+
                return $this->lang;
        }
 
        /**
         * Set the Skin object
         *
-        * @param $s Skin
+        * @param Skin $s
         */
        public function setSkin( Skin $s ) {
                $this->skin = clone $s;
@@ -241,19 +325,35 @@ class RequestContext implements IContextSource {
        public function getSkin() {
                if ( $this->skin === null ) {
                        wfProfileIn( __METHOD__ . '-createskin' );
-                       
-                       global $wgHiddenPrefs;
-                       if( !in_array( 'skin', $wgHiddenPrefs ) ) {
-                               # get the user skin
-                               $userSkin = $this->getUser()->getOption( 'skin' );
-                               $userSkin = $this->getRequest()->getVal( 'useskin', $userSkin );
-                       } else {
-                               # if we're not allowing users to override, then use the default
-                               global $wgDefaultSkin;
-                               $userSkin = $wgDefaultSkin;
+
+                       $skin = null;
+                       wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) );
+
+                       // If the hook worked try to set a skin from it
+                       if ( $skin instanceof Skin ) {
+                               $this->skin = $skin;
+                       } elseif ( is_string( $skin ) ) {
+                               $this->skin = Skin::newFromKey( $skin );
                        }
 
-                       $this->skin = Skin::newFromKey( $userSkin );
+                       // If this is still null (the hook didn't run or didn't work)
+                       // then go through the normal processing to load a skin
+                       if ( $this->skin === null ) {
+                               global $wgHiddenPrefs;
+                               if ( !in_array( 'skin', $wgHiddenPrefs ) ) {
+                                       # get the user skin
+                                       $userSkin = $this->getUser()->getOption( 'skin' );
+                                       $userSkin = $this->getRequest()->getVal( 'useskin', $userSkin );
+                               } else {
+                                       # if we're not allowing users to override, then use the default
+                                       global $wgDefaultSkin;
+                                       $userSkin = $wgDefaultSkin;
+                               }
+
+                               $this->skin = Skin::newFromKey( $userSkin );
+                       }
+
+                       // After all that set a context on whatever skin got created
                        $this->skin->setContext( $this );
                        wfProfileOut( __METHOD__ . '-createskin' );
                }
@@ -266,7 +366,7 @@ class RequestContext implements IContextSource {
         * Get a Message object with context set
         * Parameters are the same as wfMessage()
         *
-        * @return Message object
+        * @return Message
         */
        public function msg() {
                $args = func_get_args();
@@ -278,7 +378,7 @@ class RequestContext implements IContextSource {
        /**
         * Get the RequestContext object associated with the main request
         *
-        * @return RequestContext object
+        * @return RequestContext
         */
        public static function getMain() {
                static $instance = null;
@@ -298,11 +398,11 @@ class RequestContext implements IContextSource {
         *   language or a uselang param in the fauxrequest data may change the lang
         * - Skin will be based on the anonymous user, should be the wiki's default skin
         *
-        * @param $title Title Title to use for the extraneous request
-        * @param $request Mixed A WebRequest or data to use for a FauxRequest
+        * @param Title $title Title to use for the extraneous request
+        * @param WebRequest|array $request A WebRequest or data to use for a FauxRequest
         * @return RequestContext
         */
-       public static function newExtraneousContext( Title $title, $request=array() ) {
+       public static function newExtraneousContext( Title $title, $request = array() ) {
                $context = new self;
                $context->setTitle( $title );
                if ( $request instanceof WebRequest ) {
@@ -313,6 +413,4 @@ class RequestContext implements IContextSource {
                $context->user = User::newFromName( '127.0.0.1', false );
                return $context;
        }
-
 }
-