1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Theme Manager for Yii2 |
4
|
|
|
* |
5
|
|
|
* @link https://github.com/hiqdev/yii2-thememanager |
6
|
|
|
* @package yii2-thememanager |
7
|
|
|
* @license BSD-3-Clause |
8
|
|
|
* @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/) |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace hiqdev\thememanager; |
12
|
|
|
|
13
|
|
|
use ReflectionClass; |
14
|
|
|
use Yii; |
15
|
|
|
use yii\helpers\ArrayHelper; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Theme class. |
19
|
|
|
*/ |
20
|
|
|
class Theme extends \yii\base\Theme implements \hiqdev\yii2\collection\ItemWithNameInterface |
21
|
|
|
{ |
22
|
|
|
use GetManagerTrait; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @var string theme name |
26
|
|
|
*/ |
27
|
|
|
public $name; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var string theme label |
31
|
|
|
*/ |
32
|
|
|
public $label; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var array assets to be registered for this theme |
36
|
|
|
*/ |
37
|
|
|
public $assets = []; |
38
|
|
|
|
39
|
|
|
private $_view; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Returns the view object that can be used to render views or view files. |
43
|
|
|
* The [[render()]] and [[renderFile()]] methods will use |
44
|
|
|
* this view object to implement the actual view rendering. |
45
|
|
|
* If not set, it will default to the "view" application component. |
46
|
|
|
* |
47
|
|
|
* @return \yii\web\View the view object that can be used to render views or view files |
48
|
|
|
*/ |
49
|
|
|
public function getView() |
50
|
|
|
{ |
51
|
|
|
if ($this->_view === null) { |
52
|
|
|
$this->_view = $this->getManager()->getView(); |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
return $this->_view; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Sets the view object to be used. |
60
|
|
|
* |
61
|
|
|
* @param View $view the view object that can be used to render views or view files |
62
|
|
|
*/ |
63
|
|
|
public function setView($view) |
64
|
|
|
{ |
65
|
|
|
$this->_view = $view; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
public $pathMap = []; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* Getter for pathMap. |
72
|
|
|
*/ |
73
|
|
|
public function init() |
74
|
|
|
{ |
75
|
|
|
parent::init(); |
76
|
|
|
if (!is_array($this->pathMap)) { |
77
|
|
|
$this->pathMap = []; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
$this->pathMap = $this->compilePathMap(ArrayHelper::merge([ |
81
|
|
|
'$themedViewPaths' => $this->buildThemedViewPaths(), |
82
|
|
|
'$themedWidgetPaths' => '$themedViewPaths/widgets', |
83
|
|
|
Yii::$app->viewPath => '$themedViewPaths', |
84
|
|
|
__DIR__ . '/widgets/views' => '$themedWidgetPaths', |
85
|
|
|
], $this->getManager()->pathMap, $this->pathMap)); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
public function compilePathMap($map) |
89
|
|
|
{ |
90
|
|
|
$map = $this->substituteVars($map); |
91
|
|
|
|
92
|
|
|
$themeSubpath = '/src/themes/' . $this->name; |
93
|
|
|
|
94
|
|
|
$res = []; |
95
|
|
|
foreach ($map as $from => &$tos) { |
96
|
|
|
$tos = array_reverse(array_unique(array_values($tos))); |
97
|
|
|
$new = []; |
98
|
|
|
foreach ($tos as $to) { |
99
|
|
|
$to = Yii::getAlias($to); |
100
|
|
|
$alt = preg_replace('#(.*)/src/views(.*)$#', '${1}'.$themeSubpath.'${2}', $to); |
101
|
|
|
if ($alt) { |
102
|
|
|
$new[] = $alt; |
103
|
|
|
} |
104
|
|
|
$new[] = $to; |
105
|
|
|
} |
106
|
|
|
#$res[Yii::getAlias($from)] = $new; |
|
|
|
|
107
|
|
|
$res[Yii::getAlias($from)] = array_values(array_filter($new, 'file_exists')); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
return array_filter($res); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
public function substituteVars($vars) |
114
|
|
|
{ |
115
|
|
|
$proceed = true; |
116
|
|
|
while ($proceed) { |
117
|
|
|
$proceed = false; |
118
|
|
|
foreach ($vars as $key => $exp) { |
119
|
|
|
if ($this->isVar($exp)) { |
120
|
|
|
$value = $this->calcExp($exp, $vars); |
121
|
|
|
if (isset($value)) { |
122
|
|
|
$vars[$key] = $value; |
123
|
|
|
$proceed = true; |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
foreach (array_keys($vars) as $key) { |
130
|
|
|
if ($this->isVar($key)) { |
131
|
|
|
unset($vars[$key]); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
return $vars; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
public function isVar($name) |
139
|
|
|
{ |
140
|
|
|
return is_string($name) && (strncmp($name, '$', 1) === 0); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
public function calcExp($exp, $vars) |
144
|
|
|
{ |
145
|
|
|
$pos = strpos($exp, '/'); |
146
|
|
|
if ($pos === false) { |
147
|
|
|
return $vars[$exp]; |
148
|
|
|
} |
149
|
|
|
list($name, $suffix) = explode('/', $exp, 2); |
150
|
|
|
|
151
|
|
|
return array_map(function ($a) use ($suffix) { |
152
|
|
|
return "$a/$suffix"; |
153
|
|
|
}, $vars[$name]); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
public function buildThemedViewPaths() |
157
|
|
|
{ |
158
|
|
|
return array_map(function ($a) { |
159
|
|
|
return "$a/views"; |
160
|
|
|
}, $this->findParentPaths()); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function findParentPaths() |
164
|
|
|
{ |
165
|
|
|
$dirs = []; |
166
|
|
|
$ref = $this->getReflection(); |
167
|
|
|
for ($depth = 0; $depth < 10; ++$depth) { |
168
|
|
|
$dirs[] = dirname($ref->getFileName()); |
169
|
|
|
$ref = $ref->getParentClass(); |
170
|
|
|
if (__CLASS__ === $ref->name) { |
171
|
|
|
break; |
172
|
|
|
} |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
return $dirs; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
protected $_reflection; |
179
|
|
|
|
180
|
|
|
public function getReflection() |
181
|
|
|
{ |
182
|
|
|
if (!$this->_reflection) { |
183
|
|
|
$this->_reflection = new ReflectionClass($this); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
return $this->_reflection; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
private $_settings; |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* @param string $settings theme settings model class name or config |
193
|
|
|
*/ |
194
|
|
|
public function setSettings($settings) |
195
|
|
|
{ |
196
|
|
|
$this->_settings = $settings; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
public function getSettings() |
200
|
|
|
{ |
201
|
|
|
if (!is_object($this->_settings)) { |
202
|
|
|
if (!$this->_settings) { |
203
|
|
|
$this->_settings = static::findSettingsClass(get_called_class()); |
204
|
|
|
} |
205
|
|
|
$data = $this->getManager()->getThemeSettings(); |
206
|
|
|
$this->_settings = Yii::createObject($this->_settings); |
207
|
|
|
$this->_settings->load($data); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
return $this->_settings; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
public static function calcSettingsClass($class) |
214
|
|
|
{ |
215
|
|
|
return substr($class, 0, strrpos($class, '\\')) . '\\models\\Settings'; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
public static function findSettingsClass($class) |
219
|
|
|
{ |
220
|
|
|
$res = static::calcSettingsClass($class); |
221
|
|
|
|
222
|
|
|
return class_exists($res) ? $res : static::findSettingsClass(get_parent_class($class)); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
public function getDetailedTheme() |
226
|
|
|
{ |
227
|
|
|
$localDetailedTheme = str_replace('\Theme', '\DetailedTheme', get_called_class()); |
228
|
|
|
$class = class_exists($localDetailedTheme) ? $localDetailedTheme : DetailedTheme::class; |
229
|
|
|
|
230
|
|
|
return new $class($this); |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.