Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.87% covered (warning)
89.87%
71 / 79
85.19% covered (warning)
85.19%
23 / 27
CRAP
0.00% covered (danger)
0.00%
0 / 1
DerivativeContext
89.87% covered (warning)
89.87%
71 / 79
85.19% covered (warning)
85.19%
23 / 27
47.10
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModules
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setModules
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLanguage
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setLanguage
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getDirection
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 setDirection
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSkin
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setSkin
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUser
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getUserIdentity
70.00% covered (warning)
70.00%
7 / 10
0.00% covered (danger)
0.00%
0 / 1
4.43
 getUserObj
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
4.02
 setUser
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getDebug
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setDebug
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getOnly
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setOnly
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getVersion
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setVersion
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getRaw
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setRaw
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isSourceMap
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 setIsSourceMap
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRequest
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getResourceLoader
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getContentOverrideCallback
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 setContentOverrideCallback
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
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 * @author Kunal Mehta
20 */
21
22namespace MediaWiki\ResourceLoader;
23
24use MediaWiki\MediaWikiServices;
25use MediaWiki\Request\WebRequest;
26use MediaWiki\User\User;
27use MediaWiki\User\UserIdentity;
28use MediaWiki\User\UserRigorOptions;
29
30/**
31 * A mutable version of Context.
32 *
33 * Allows changing specific properties of a context object,
34 * without changing the main one. Inspired by MediaWiki's DerivativeContext.
35 *
36 * @ingroup ResourceLoader
37 * @since 1.24
38 */
39class DerivativeContext extends Context {
40    private const INHERIT_VALUE = -1;
41
42    /**
43     * @var Context
44     */
45    private $context;
46
47    /** @var int|string[] */
48    protected $modules = self::INHERIT_VALUE;
49    /** @var int|string */
50    protected $language = self::INHERIT_VALUE;
51    /** @var int|string|null */
52    protected $direction = self::INHERIT_VALUE;
53    /** @var int|string */
54    protected $skin = self::INHERIT_VALUE;
55    /** @var int|string|null */
56    protected $user = self::INHERIT_VALUE;
57    /** @var int|UserIdentity|null|false */
58    protected $userIdentity = self::INHERIT_VALUE;
59    /** @var int|User|null */
60    protected $userObj = self::INHERIT_VALUE;
61    /** @var int */
62    protected $debug = self::INHERIT_VALUE;
63    /** @var int|string|null */
64    protected $only = self::INHERIT_VALUE;
65    /** @var int|string|null */
66    protected $version = self::INHERIT_VALUE;
67    /** @var int|bool */
68    protected $raw = self::INHERIT_VALUE;
69    /** @var int|bool */
70    protected $sourcemap = self::INHERIT_VALUE;
71    /** @var int|callable|null */
72    protected $contentOverrideCallback = self::INHERIT_VALUE;
73
74    public function __construct( Context $context ) {
75        $this->context = $context;
76    }
77
78    public function getModules(): array {
79        if ( $this->modules === self::INHERIT_VALUE ) {
80            return $this->context->getModules();
81        }
82
83        return $this->modules;
84    }
85
86    /**
87     * @param string[] $modules
88     */
89    public function setModules( array $modules ) {
90        $this->modules = $modules;
91    }
92
93    public function getLanguage(): string {
94        if ( $this->language === self::INHERIT_VALUE ) {
95            return $this->context->getLanguage();
96        }
97        return $this->language;
98    }
99
100    public function setLanguage( string $language ) {
101        $this->language = $language;
102        // Invalidate direction since it is based on language
103        $this->direction = null;
104        $this->hash = null;
105    }
106
107    public function getDirection(): string {
108        if ( $this->direction === self::INHERIT_VALUE ) {
109            return $this->context->getDirection();
110        }
111        if ( $this->direction === null ) {
112            $this->direction = MediaWikiServices::getInstance()->getLanguageFactory()
113                ->getLanguage( $this->getLanguage() )->getDir();
114        }
115        return $this->direction;
116    }
117
118    public function setDirection( string $direction ) {
119        $this->direction = $direction;
120        $this->hash = null;
121    }
122
123    public function getSkin(): string {
124        if ( $this->skin === self::INHERIT_VALUE ) {
125            return $this->context->getSkin();
126        }
127        return $this->skin;
128    }
129
130    public function setSkin( string $skin ) {
131        $this->skin = $skin;
132        $this->hash = null;
133    }
134
135    public function getUser(): ?string {
136        if ( $this->user === self::INHERIT_VALUE ) {
137            return $this->context->getUser();
138        }
139        return $this->user;
140    }
141
142    public function getUserIdentity(): ?UserIdentity {
143        if ( $this->userIdentity === self::INHERIT_VALUE ) {
144            return $this->context->getUserIdentity();
145        }
146        if ( $this->userIdentity === false ) {
147            $username = $this->getUser();
148            if ( $username === null ) {
149                // Anonymous user
150                $this->userIdentity = null;
151            } else {
152                // Use provided username if valid
153                $this->userIdentity = MediaWikiServices::getInstance()
154                    ->getUserFactory()
155                    ->newFromName( $username, UserRigorOptions::RIGOR_VALID );
156            }
157        }
158        return $this->userIdentity;
159    }
160
161    public function getUserObj(): User {
162        if ( $this->userObj === self::INHERIT_VALUE ) {
163            return $this->context->getUserObj();
164        }
165        if ( $this->userObj === null ) {
166            $username = $this->getUser();
167            $userFactory = MediaWikiServices::getInstance()->getUserFactory();
168            if ( $username ) {
169                $this->userObj = $userFactory->newFromName( $username, UserRigorOptions::RIGOR_VALID );
170            }
171            $this->userObj ??= $userFactory->newAnonymous();
172        }
173        return $this->userObj;
174    }
175
176    /**
177     * @param string|null $user
178     */
179    public function setUser( ?string $user ) {
180        $this->user = $user;
181        $this->hash = null;
182        // Clear getUserObj cache
183        $this->userObj = null;
184        $this->userIdentity = false;
185    }
186
187    public function getDebug(): int {
188        if ( $this->debug === self::INHERIT_VALUE ) {
189            return $this->context->getDebug();
190        }
191        return $this->debug;
192    }
193
194    public function setDebug( int $debug ) {
195        $this->debug = $debug;
196        $this->hash = null;
197    }
198
199    public function getOnly(): ?string {
200        if ( $this->only === self::INHERIT_VALUE ) {
201            return $this->context->getOnly();
202        }
203        return $this->only;
204    }
205
206    /**
207     * @param string|null $only
208     */
209    public function setOnly( ?string $only ) {
210        $this->only = $only;
211        $this->hash = null;
212    }
213
214    public function getVersion(): ?string {
215        if ( $this->version === self::INHERIT_VALUE ) {
216            return $this->context->getVersion();
217        }
218        return $this->version;
219    }
220
221    /**
222     * @param string|null $version
223     */
224    public function setVersion( ?string $version ) {
225        $this->version = $version;
226        $this->hash = null;
227    }
228
229    public function getRaw(): bool {
230        if ( $this->raw === self::INHERIT_VALUE ) {
231            return $this->context->getRaw();
232        }
233        return $this->raw;
234    }
235
236    public function setRaw( bool $raw ) {
237        $this->raw = $raw;
238    }
239
240    public function isSourceMap(): bool {
241        if ( $this->sourcemap === self::INHERIT_VALUE ) {
242            return $this->context->isSourceMap();
243        }
244        return $this->sourcemap;
245    }
246
247    public function setIsSourceMap( bool $sourcemap ) {
248        $this->sourcemap = $sourcemap;
249    }
250
251    public function getRequest(): WebRequest {
252        return $this->context->getRequest();
253    }
254
255    public function getResourceLoader(): ResourceLoader {
256        return $this->context->getResourceLoader();
257    }
258
259    public function getContentOverrideCallback() {
260        if ( $this->contentOverrideCallback === self::INHERIT_VALUE ) {
261            return $this->context->getContentOverrideCallback();
262        }
263        return $this->contentOverrideCallback;
264    }
265
266    /**
267     * @see self::getContentOverrideCallback
268     * @since 1.32
269     * @param callable|null|int $callback As per self::getContentOverrideCallback,
270     *  or self::INHERIT_VALUE
271     */
272    public function setContentOverrideCallback( $callback ) {
273        $this->contentOverrideCallback = $callback;
274    }
275
276}