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
22use MediaWiki\MediaWikiServices;
23
24/**
25 * A mutable version of ResourceLoaderContext.
26 *
27 * Allows changing specific properties of a context object,
28 * without changing the main one. Inspired by MediaWiki's DerivativeContext.
29 *
30 * @ingroup ResourceLoader
31 * @since 1.24
32 */
33class DerivativeResourceLoaderContext extends ResourceLoaderContext {
34	private const INHERIT_VALUE = -1;
35
36	/**
37	 * @var ResourceLoaderContext
38	 */
39	private $context;
40
41	/** @var int|array */
42	protected $modules = self::INHERIT_VALUE;
43	protected $language = self::INHERIT_VALUE;
44	protected $direction = self::INHERIT_VALUE;
45	protected $skin = self::INHERIT_VALUE;
46	protected $user = self::INHERIT_VALUE;
47	protected $userObj = self::INHERIT_VALUE;
48	protected $debug = self::INHERIT_VALUE;
49	protected $only = self::INHERIT_VALUE;
50	protected $version = self::INHERIT_VALUE;
51	protected $raw = self::INHERIT_VALUE;
52	protected $contentOverrideCallback = self::INHERIT_VALUE;
53
54	public function __construct( ResourceLoaderContext $context ) {
55		$this->context = $context;
56	}
57
58	public function getModules() : array {
59		if ( $this->modules === self::INHERIT_VALUE ) {
60			return $this->context->getModules();
61		}
62
63		return $this->modules;
64	}
65
66	/**
67	 * @param string[] $modules
68	 */
69	public function setModules( array $modules ) {
70		$this->modules = $modules;
71	}
72
73	public function getLanguage() : string {
74		if ( $this->language === self::INHERIT_VALUE ) {
75			return $this->context->getLanguage();
76		}
77		return $this->language;
78	}
79
80	public function setLanguage( string $language ) {
81		$this->language = $language;
82		// Invalidate direction since it is based on language
83		$this->direction = null;
84		$this->hash = null;
85	}
86
87	public function getDirection() : string {
88		if ( $this->direction === self::INHERIT_VALUE ) {
89			return $this->context->getDirection();
90		}
91		if ( $this->direction === null ) {
92			$this->direction = MediaWikiServices::getInstance()->getLanguageFactory()
93				->getLanguage( $this->getLanguage() )->getDir();
94		}
95		return $this->direction;
96	}
97
98	public function setDirection( string $direction ) {
99		$this->direction = $direction;
100		$this->hash = null;
101	}
102
103	public function getSkin() : string {
104		if ( $this->skin === self::INHERIT_VALUE ) {
105			return $this->context->getSkin();
106		}
107		return $this->skin;
108	}
109
110	public function setSkin( string $skin ) {
111		$this->skin = $skin;
112		$this->hash = null;
113	}
114
115	public function getUser() : ?string {
116		if ( $this->user === self::INHERIT_VALUE ) {
117			return $this->context->getUser();
118		}
119		return $this->user;
120	}
121
122	public function getUserObj() : User {
123		if ( $this->userObj === self::INHERIT_VALUE ) {
124			return $this->context->getUserObj();
125		}
126		if ( $this->userObj === null ) {
127			$username = $this->getUser();
128			if ( $username ) {
129				$this->userObj = User::newFromName( $username ) ?: new User;
130			} else {
131				$this->userObj = new User;
132			}
133		}
134		return $this->userObj;
135	}
136
137	/**
138	 * @param string|null $user
139	 */
140	public function setUser( ?string $user ) {
141		$this->user = $user;
142		$this->hash = null;
143		// Clear getUserObj cache
144		$this->userObj = null;
145	}
146
147	public function getDebug() : bool {
148		if ( $this->debug === self::INHERIT_VALUE ) {
149			return $this->context->getDebug();
150		}
151		return $this->debug;
152	}
153
154	public function setDebug( bool $debug ) {
155		$this->debug = $debug;
156		$this->hash = null;
157	}
158
159	public function getOnly() : ?string {
160		if ( $this->only === self::INHERIT_VALUE ) {
161			return $this->context->getOnly();
162		}
163		return $this->only;
164	}
165
166	/**
167	 * @param string|null $only
168	 */
169	public function setOnly( ?string $only ) {
170		$this->only = $only;
171		$this->hash = null;
172	}
173
174	public function getVersion() : ?string {
175		if ( $this->version === self::INHERIT_VALUE ) {
176			return $this->context->getVersion();
177		}
178		return $this->version;
179	}
180
181	/**
182	 * @param string|null $version
183	 */
184	public function setVersion( ?string $version ) {
185		$this->version = $version;
186		$this->hash = null;
187	}
188
189	public function getRaw() : bool {
190		if ( $this->raw === self::INHERIT_VALUE ) {
191			return $this->context->getRaw();
192		}
193		return $this->raw;
194	}
195
196	public function setRaw( bool $raw ) {
197		$this->raw = $raw;
198	}
199
200	public function getRequest() : WebRequest {
201		return $this->context->getRequest();
202	}
203
204	public function getResourceLoader() : ResourceLoader {
205		return $this->context->getResourceLoader();
206	}
207
208	public function getContentOverrideCallback() {
209		if ( $this->contentOverrideCallback === self::INHERIT_VALUE ) {
210			return $this->context->getContentOverrideCallback();
211		}
212		return $this->contentOverrideCallback;
213	}
214
215	/**
216	 * @see self::getContentOverrideCallback
217	 * @since 1.32
218	 * @param callable|null|int $callback As per self::getContentOverrideCallback,
219	 *  or self::INHERIT_VALUE
220	 */
221	public function setContentOverrideCallback( $callback ) {
222		$this->contentOverrideCallback = $callback;
223	}
224
225}
226