Passed
Branch php-cs-fixer (b9836a)
by Fabio
15:02
created

TTheme::setBaseUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * TThemeManager class
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @copyright Copyright &copy; 2005-2016 The PRADO Group
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 * @package Prado\Web\UI
10
 */
11
12
namespace Prado\Web\UI;
13
14
use Prado\Exceptions\TIOException;
15
use Prado\Exceptions\TConfigurationException;
16
use Prado\Prado;
17
use Prado\TApplicationMode;
18
19
/**
20
 * TTheme class
21
 *
22
 * TTheme represents a particular theme. It is merely a collection of skins
23
 * that are applicable to the corresponding controls.
24
 *
25
 * Each theme is stored as a directory and files under that directory.
26
 * The theme name is the directory name. When TTheme is created, the files
27
 * whose name has the extension ".skin" are parsed and saved as controls skins.
28
 *
29
 * A skin is essentially a list of initial property values that are to be applied
30
 * to a control when the skin is applied.
31
 * Each type of control can have multiple skins identified by the SkinID.
32
 * If a skin does not have SkinID, it is the default skin that will be applied
33
 * to controls that do not specify particular SkinID.
34
 *
35
 * Whenever possible, TTheme will try to make use of available cache to save
36
 * the parsing time.
37
 *
38
 * To apply a theme to a particular control, call {@link applySkin}.
39
 *
40
 * @author Qiang Xue <[email protected]>
41
 * @package Prado\Web\UI
42
 * @since 3.0
43
 */
44
class TTheme extends \Prado\TApplicationComponent implements ITheme
45
{
46
	/**
47
	 * prefix for cache variable name used to store parsed themes
48
	 */
49
	const THEME_CACHE_PREFIX = 'prado:theme:';
50
	/**
51
	 * Extension name of skin files
52
	 */
53
	const SKIN_FILE_EXT = '.skin';
54
	/**
55
	 * @var string theme path
56
	 */
57
	private $_themePath;
58
	/**
59
	 * @var string theme url
60
	 */
61
	private $_themeUrl;
62
	/**
63
	 * @var array list of skins for the theme
64
	 */
65
	private $_skins;
66
	/**
67
	 * @var string theme name
68
	 */
69
	private $_name = '';
70
	/**
71
	 * @var array list of css files
72
	 */
73
	private $_cssFiles = [];
74
	/**
75
	 * @var array list of js files
76
	 */
77
	private $_jsFiles = [];
78
79
	/**
80
	 * Constructor.
81
	 * @param string theme path
0 ignored issues
show
Bug introduced by
The type Prado\Web\UI\theme was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
82
	 * @param string theme URL
83
	 * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
84
	 */
85
	public function __construct($themePath, $themeUrl)
86
	{
87
		$this->_themeUrl = $themeUrl;
88
		$this->_themePath = realpath($themePath);
89
		$this->_name = basename($themePath);
90
		$cacheValid = false;
91
		// TODO: the following needs to be cleaned up (Qiang)
92
		if(($cache = $this->getApplication()->getCache()) !== null)
93
		{
94
			$array = $cache->get(self::THEME_CACHE_PREFIX . $themePath);
95
			if(is_array($array))
96
			{
97
				list($skins, $cssFiles, $jsFiles, $timestamp) = $array;
98
				if($this->getApplication()->getMode() !== TApplicationMode::Performance)
0 ignored issues
show
introduced by
The condition $this->getApplication()-...cationMode::Performance can never be false.
Loading history...
99
				{
100
					if(($dir = opendir($themePath)) === false)
101
						throw new TIOException('theme_path_inexistent', $themePath);
102
					$cacheValid = true;
103
					while(($file = readdir($dir)) !== false)
104
					{
105
						if($file === '.' || $file === '..')
106
							continue;
107
						elseif(basename($file, '.css') !== $file)
108
							$this->_cssFiles[] = $themeUrl . '/' . $file;
109
						elseif(basename($file, '.js') !== $file)
110
							$this->_jsFiles[] = $themeUrl . '/' . $file;
111
						elseif(basename($file, self::SKIN_FILE_EXT) !== $file && filemtime($themePath . DIRECTORY_SEPARATOR . $file) > $timestamp)
112
						{
113
							$cacheValid = false;
114
							break;
115
						}
116
					}
117
					closedir($dir);
118
					if($cacheValid)
119
						$this->_skins = $skins;
120
				}
121
				else
122
				{
123
					$cacheValid = true;
124
					$this->_cssFiles = $cssFiles;
125
					$this->_jsFiles = $jsFiles;
126
					$this->_skins = $skins;
127
				}
128
			}
129
		}
130
		if(!$cacheValid)
131
		{
132
			$this->_cssFiles = [];
133
			$this->_jsFiles = [];
134
			$this->_skins = [];
135
			if(($dir = opendir($themePath)) === false)
136
				throw new TIOException('theme_path_inexistent', $themePath);
137
			while(($file = readdir($dir)) !== false)
138
			{
139
				if($file === '.' || $file === '..')
140
					continue;
141
				elseif(basename($file, '.css') !== $file)
142
					$this->_cssFiles[] = $themeUrl . '/' . $file;
143
				elseif(basename($file, '.js') !== $file)
144
					$this->_jsFiles[] = $themeUrl . '/' . $file;
145
				elseif(basename($file, self::SKIN_FILE_EXT) !== $file)
146
				{
147
					$template = new TTemplate(file_get_contents($themePath . '/' . $file), $themePath, $themePath . '/' . $file);
148
					foreach($template->getItems() as $skin)
149
					{
150
						if(!isset($skin[2]))  // a text string, ignored
151
							continue;
152
						elseif($skin[0] !== -1)
153
							throw new TConfigurationException('theme_control_nested', $skin[1], dirname($themePath));
154
						$type = $skin[1];
155
						$id = isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
156
						unset($skin[2]['skinid']);
157
						if(isset($this->_skins[$type][$id]))
158
							throw new TConfigurationException('theme_skinid_duplicated', $type, $id, dirname($themePath));
159
						/*
160
						foreach($skin[2] as $name=>$value)
161
						{
162
							if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER))
163
								throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
164
						}
165
						*/
166
						$this->_skins[$type][$id] = $skin[2];
167
					}
168
				}
169
			}
170
			closedir($dir);
171
			sort($this->_cssFiles);
172
			sort($this->_jsFiles);
173
			if($cache !== null)
174
				$cache->set(self::THEME_CACHE_PREFIX . $themePath, [$this->_skins,$this->_cssFiles,$this->_jsFiles,time()]);
175
		}
176
	}
177
178
	/**
179
	 * @return string theme name
180
	 */
181
	public function getName()
182
	{
183
		return $this->_name;
184
	}
185
186
	/**
187
	 * @param string theme name
188
	 */
189
	protected function setName($value)
190
	{
191
		$this->_name = $value;
192
	}
193
194
	/**
195
	 * @return string the URL to the theme folder (without ending slash)
196
	 */
197
	public function getBaseUrl()
198
	{
199
		return $this->_themeUrl;
200
	}
201
202
	/**
203
	 * @param string the URL to the theme folder
0 ignored issues
show
Bug introduced by
The type Prado\Web\UI\the was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
204
	 */
205
	protected function setBaseUrl($value)
206
	{
207
		$this->_themeUrl = rtrim($value, '/');
208
	}
209
210
	/**
211
	 * @return string the file path to the theme folder
212
	 */
213
	public function getBasePath()
214
	{
215
		return $this->_themePath;
216
	}
217
218
	/**
219
	 * @param string tthe file path to the theme folder
220
	 */
221
	protected function setBasePath($value)
222
	{
223
		$this->_themePath = $value;
224
	}
225
226
	/**
227
	 * @return array list of skins for the theme
228
	 */
229
	public function getSkins()
230
	{
231
		return $this->_skins;
232
	}
233
234
	/**
235
	 * @param array list of skins for the theme
0 ignored issues
show
Bug introduced by
The type Prado\Web\UI\list was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
236
	 */
237
	protected function setSkins($value)
238
	{
239
		$this->_skins = $value;
240
	}
241
242
	/**
243
	 * Applies the theme to a particular control.
244
	 * The control's class name and SkinID value will be used to
245
	 * identify which skin to be applied. If the control's SkinID is empty,
246
	 * the default skin will be applied.
247
	 * @param TControl the control to be applied with a skin
248
	 * @return boolean if a skin is successfully applied
249
	 * @throws TConfigurationException if any error happened during the skin application
250
	 */
251
	public function applySkin($control)
252
	{
253
		$type = get_class($control);
254
		if(($id = $control->getSkinID()) === '')
255
			$id = 0;
256
		if(isset($this->_skins[$type][$id]))
257
		{
258
			foreach($this->_skins[$type][$id] as $name => $value)
259
			{
260
				Prado::trace("Applying skin $name to $type", 'Prado\Web\UI\TThemeManager');
261
				if(is_array($value))
262
				{
263
					switch($value[0])
264
					{
265
						case TTemplate::CONFIG_EXPRESSION:
266
							$value = $this->evaluateExpression($value[1]);
267
							break;
268
						case TTemplate::CONFIG_ASSET:
269
							$value = $this->_themeUrl . '/' . ltrim($value[1], '/');
270
							break;
271
						case TTemplate::CONFIG_DATABIND:
272
							$control->bindProperty($name, $value[1]);
273
							break;
274
						case TTemplate::CONFIG_PARAMETER:
275
							$control->setSubProperty($name, $this->getApplication()->getParameters()->itemAt($value[1]));
276
							break;
277
						case TTemplate::CONFIG_TEMPLATE:
278
							$control->setSubProperty($name, $value[1]);
279
							break;
280
						case TTemplate::CONFIG_LOCALIZATION:
281
							$control->setSubProperty($name, Prado::localize($value[1]));
282
							break;
283
						default:
284
							throw new TConfigurationException('theme_tag_unexpected', $name, $value[0]);
285
							break;
286
					}
287
				}
288
				if(!is_array($value))
289
				{
290
					if(strpos($name, '.') === false)	// is simple property or custom attribute
291
					{
292
						if($control->hasProperty($name))
293
						{
294
							if($control->canSetProperty($name))
295
							{
296
								$setter = 'set' . $name;
297
								$control->$setter($value);
298
							}
299
							else
300
								throw new TConfigurationException('theme_property_readonly', $type, $name);
301
						}
302
						else
303
							throw new TConfigurationException('theme_property_undefined', $type, $name);
304
					}
305
					else	// complex property
306
						$control->setSubProperty($name, $value);
307
				}
308
			}
309
			return true;
310
		}
311
		else
312
			return false;
313
	}
314
315
	/**
316
	 * @return array list of CSS files (URL) in the theme
317
	 */
318
	public function getStyleSheetFiles()
319
	{
320
		return $this->_cssFiles;
321
	}
322
323
	/**
324
	 * @param array list of CSS files (URL) in the theme
325
	 */
326
	protected function setStyleSheetFiles($value)
327
	{
328
		$this->_cssFiles = $value;
329
	}
330
331
	/**
332
	 * @return array list of Javascript files (URL) in the theme
333
	 */
334
	public function getJavaScriptFiles()
335
	{
336
		return $this->_jsFiles;
337
	}
338
339
	/**
340
	 * @param array list of Javascript files (URL) in the theme
341
	 */
342
	protected function setJavaScriptFiles($value)
343
	{
344
		$this->_jsFiles = $value;
345
	}
346
}