Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.31% covered (success)
92.31%
24 / 26
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
StubGlobalUser
96.00% covered (success)
96.00%
24 / 25
83.33% covered (warning)
83.33%
5 / 6
11
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 _newObject
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 setUser
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getRealUser
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 _unstub
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 __destruct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\StubObject;
22
23use InvalidArgumentException;
24use MediaWiki\User\User;
25
26/**
27 * Stub object for the global user ($wgUser) that makes it possible to change the
28 * relevant underlying object while still ensuring that deprecation warnings will
29 * be emitted upon method calls.
30 *
31 * @internal Will be removed in 1.38
32 *
33 * @since 1.37
34 * @author Danny712
35 */
36class StubGlobalUser extends StubObject {
37
38    /** @var bool */
39    public static $destructorDeprecationDisarmed = false;
40
41    /** @var User */
42    public $realUser;
43
44    /**
45     * @param User $realUser
46     */
47    public function __construct( User $realUser ) {
48        parent::__construct( 'wgUser' );
49        $this->realUser = $realUser;
50    }
51
52    /**
53     * @return User
54     */
55    // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
56    public function _newObject() {
57        // Based on MediaWiki\StubObject\DeprecatedGlobal::_newObject
58        /*
59         * Put the caller offset for wfDeprecated as 6, as
60         * that gives the function that uses this object, since:
61         *
62         * 1 = this function ( _newObject )
63         * 2 = MediaWiki\StubObject\StubGlobalUser::_unstub
64         * 3 = MediaWiki\StubObject\StubObject::_call
65         * 4 = MediaWiki\StubObject\StubObject::__call
66         * 5 = MediaWiki\StubObject\StubGlobalUser::<method of global called>
67         * 6 = Actual function using the global.
68         * (the same applies to _get/__get or _set/__set instead of _call/__call)
69         *
70         * Of course its theoretically possible to have other call
71         * sequences for this method, but that seems to be
72         * rather unlikely.
73         */
74        // Officially deprecated since 1.35
75        wfDeprecated( '$wgUser', '1.35', false, 6 );
76        return $this->realUser;
77    }
78
79    /**
80     * Reset the stub global user to a different "real" user object, while ensuring that
81     * any method calls on that object will still trigger deprecation notices.
82     *
83     * @param StubGlobalUser|User $user
84     */
85    public static function setUser( $user ) {
86        // This is intended to be interacting with the deprecated global
87        // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
88        global $wgUser;
89
90        self::$destructorDeprecationDisarmed = true;
91        // Supports MediaWiki\StubObject\StubGlobalUser parameter in case something fetched the existing value of
92        // $wgUser, set it to something else, and now is trying to restore it
93        $realUser = self::getRealUser( $user );
94        $wgUser = new self( $realUser );
95        self::$destructorDeprecationDisarmed = false;
96    }
97
98    /**
99     * Get the relevant "real" user object based on either a User object or a MediaWiki\StubObject\StubGlobalUser
100     * wrapper. Bypasses deprecation notices from converting a MediaWiki\StubObject\StubGlobalUser to an actual
101     * user, and does not change $wgUser.
102     *
103     * @param StubGlobalUser|User $globalUser
104     * @return User
105     */
106    public static function getRealUser( $globalUser ): User {
107        if ( $globalUser instanceof StubGlobalUser ) {
108            return $globalUser->realUser;
109        } elseif ( $globalUser instanceof User ) {
110            return $globalUser;
111        } else {
112            throw new InvalidArgumentException(
113                '$globalUser must be a User (or MediaWiki\StubObject\StubGlobalUser), got ' .
114                ( is_object( $globalUser ) ? get_class( $globalUser ) : gettype( $globalUser ) )
115            );
116        }
117    }
118
119    /**
120     * This function creates a new object of the real class and replace it in
121     * the global variable.
122     * This is public, for the convenience of external callers wishing to access
123     * properties, e.g. eval.php
124     *
125     * Overriding MediaWiki\StubObject\StubObject::_unstub because for some reason that thinks there is
126     * an unstub loop when trying to use the magic __set() logic, but there isn't
127     * any loop because _newObject() returns a specific instance of User rather
128     * than calling any methods that could then try to use $wgUser. The main difference
129     * between this and the parent method is that we don't try to check for
130     * recursion loops.
131     *
132     * @param string $name Name of the method called in this object.
133     * @param int $level Level to go in the stack trace to get the function
134     *   who called this function.
135     * @return User The unstubbed version
136     */
137    // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
138    public function _unstub( $name = '_unstub', $level = 2 ) {
139        if ( !$GLOBALS[$this->global] instanceof self ) {
140            return $GLOBALS[$this->global]; // already unstubbed.
141        }
142
143        $caller = wfGetCaller( $level );
144        wfDebug( "Unstubbing \${$this->global} on call of "
145            . "\${$this->global}::$name from $caller" );
146        $GLOBALS[$this->global] = $this->_newObject();
147        return $GLOBALS[$this->global];
148    }
149
150    public function __destruct() {
151        if ( !self::$destructorDeprecationDisarmed ) {
152            wfDeprecatedMsg( '$wgUser reassignment detected', '1.37', false, 3 );
153        }
154    }
155}
156
157/** @deprecated class alias since 1.40 */
158class_alias( StubGlobalUser::class, 'StubGlobalUser' );