1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of slick/template package |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
namespace Slick\Template; |
11
|
|
|
|
12
|
|
|
use Slick\Common\Base; |
13
|
|
|
use ReflectionClass; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Template factory class |
17
|
|
|
* |
18
|
|
|
* @package Slick\Template |
19
|
|
|
* @author Filipe Silva <[email protected]> |
20
|
|
|
* |
21
|
|
|
* @property string $engine |
22
|
|
|
*/ |
23
|
|
|
final class Template extends Base |
24
|
|
|
{ |
25
|
|
|
|
26
|
|
|
/** Known engines */ |
27
|
|
|
const ENGINE_TWIG = 'Slick\Template\Engine\Twig'; |
28
|
|
|
|
29
|
|
|
/** Known engine extensions */ |
30
|
|
|
const EXTENSION_TWIG_TEXT = 'Slick\Template\Extension\Text'; |
31
|
|
|
const EXTENSION_TWIG_I18N = 'Slick\Template\Extension\I18n'; |
32
|
|
|
|
33
|
|
|
/** @var string Engine interface */ |
34
|
|
|
private static $interface = 'Slick\Template\TemplateEngineInterface'; |
35
|
|
|
private static $extensionInterface = |
36
|
|
|
'Slick\Template\EngineExtensionInterface'; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @readwrite |
40
|
|
|
* @var string The engine to use |
41
|
|
|
*/ |
42
|
|
|
protected $engine = self::ENGINE_TWIG; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @readwrite |
46
|
|
|
* @var array Options for template initializing |
47
|
|
|
*/ |
48
|
|
|
protected $options = array(); |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var string[] a list of available paths |
52
|
|
|
*/ |
53
|
|
|
protected static $paths = ['./']; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var array Default options for template initializing |
57
|
|
|
*/ |
58
|
|
|
protected static $defaultOptions = []; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var array Array containing template extensions |
62
|
|
|
*/ |
63
|
|
|
private static $extensions = [ |
64
|
|
|
self::EXTENSION_TWIG_TEXT => null, |
65
|
|
|
self::EXTENSION_TWIG_I18N => null, |
66
|
|
|
]; |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Prepends a searchable path to available paths list. |
70
|
|
|
* |
71
|
|
|
* @param string $path |
72
|
|
|
*/ |
73
|
2 |
View Code Duplication |
public static function addPath($path) |
|
|
|
|
74
|
|
|
{ |
75
|
2 |
|
$path = str_replace('//', '/', rtrim($path, '/')); |
76
|
2 |
|
if (is_dir($path) && !in_array($path, self::$paths)) { |
77
|
2 |
|
array_unshift(self::$paths, $path); |
78
|
1 |
|
} |
79
|
2 |
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Prepends a searchable path to available paths list. |
83
|
|
|
* |
84
|
|
|
* @param string $path |
85
|
|
|
*/ |
86
|
2 |
View Code Duplication |
public static function appendPath($path) |
|
|
|
|
87
|
|
|
{ |
88
|
2 |
|
$path = str_replace('//', '/', rtrim($path, '/')); |
89
|
2 |
|
if (is_dir($path) && !in_array($path, self::$paths)) { |
90
|
2 |
|
array_push(self::$paths, $path); |
91
|
1 |
|
} |
92
|
2 |
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Gets the list of defined paths |
96
|
|
|
* |
97
|
|
|
* @return \string[] |
98
|
|
|
*/ |
99
|
4 |
|
public static function getPaths() |
100
|
|
|
{ |
101
|
4 |
|
return self::$paths; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Initializes the engine |
106
|
|
|
* |
107
|
|
|
* @throws Exception\InvalidArgumentException |
108
|
|
|
* |
109
|
|
|
* @return TemplateEngineInterface |
110
|
|
|
*/ |
111
|
4 |
|
public function initialize() |
112
|
|
|
{ |
113
|
4 |
|
$this->checkClass(); |
114
|
2 |
|
$options = array_merge(static::$defaultOptions, $this->options); |
115
|
|
|
/** @var TemplateEngineInterface $engine */ |
116
|
2 |
|
$engine = new $this->engine($options); |
117
|
2 |
|
$engine->setLocations(self::$paths); |
118
|
2 |
|
return $this->applyExtensions($engine); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Adds an extension to the template engine |
123
|
|
|
* |
124
|
|
|
* @param string|object $className The class name or an instance |
125
|
|
|
* of EngineExtensionInterface interface |
126
|
|
|
* |
127
|
|
|
* @return self|$this|Template |
128
|
|
|
*/ |
129
|
6 |
|
public function addExtension($className) |
130
|
|
|
{ |
131
|
6 |
|
$object = is_object($className) ? $className : null; |
132
|
6 |
|
$className = is_object($className) ? get_class($object) : $className; |
133
|
|
|
|
134
|
6 |
|
$this->checkClass($className, self::$extensionInterface); |
135
|
|
|
|
136
|
4 |
|
self::$extensions[$className] = $object; |
137
|
4 |
|
return $this; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* Registers the provided class name as an extension |
142
|
|
|
* |
143
|
|
|
* @param string|object $extension The class name or an instance |
144
|
|
|
* of EngineExtensionInterface interface |
145
|
|
|
* |
146
|
|
|
* @return Template |
147
|
|
|
*/ |
148
|
2 |
|
public static function register($extension) |
149
|
|
|
{ |
150
|
2 |
|
$template = new Template; |
151
|
2 |
|
return $template->addExtension($extension); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Apply defined extensions to the provided template engine |
156
|
|
|
* |
157
|
|
|
* @param TemplateEngineInterface $engine |
158
|
|
|
* |
159
|
|
|
* @return TemplateEngineInterface |
160
|
|
|
*/ |
161
|
2 |
|
protected function applyExtensions(TemplateEngineInterface $engine) |
162
|
|
|
{ |
163
|
2 |
|
foreach (static::$extensions as $className => $extension) { |
|
|
|
|
164
|
2 |
|
$ext = $this->getExtension($className, $extension); |
165
|
2 |
|
if ($ext->appliesTo($engine)) { |
166
|
2 |
|
$ext->update($engine); |
167
|
1 |
|
} |
168
|
1 |
|
} |
169
|
2 |
|
return $engine; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* @param string $class |
174
|
|
|
* @param EngineExtensionInterface $extension |
175
|
|
|
* |
176
|
|
|
* @return EngineExtensionInterface |
177
|
|
|
*/ |
178
|
2 |
|
protected function getExtension($class, $extension) |
179
|
|
|
{ |
180
|
2 |
|
if (is_object($extension)) { |
181
|
2 |
|
return $extension; |
182
|
|
|
} |
183
|
|
|
|
184
|
2 |
|
$this->checkClass($class, self::$extensionInterface); |
185
|
2 |
|
return new $class(); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Check if type is a valid configuration driver |
190
|
|
|
* |
191
|
|
|
* @param null $name |
192
|
|
|
* @param null $interface |
193
|
|
|
*/ |
194
|
10 |
|
protected function checkClass($name = null, $interface = null) |
195
|
|
|
{ |
196
|
10 |
|
$name = null == $name ? $this->engine : $name; |
197
|
10 |
|
$interface = null == $interface ? self::$interface : $interface; |
198
|
|
|
|
199
|
10 |
|
if (!class_exists($name)) { |
200
|
2 |
|
throw new Exception\InvalidArgumentException( |
201
|
2 |
|
"The class '{$name}' was not found" |
202
|
1 |
|
); |
203
|
|
|
} |
204
|
|
|
|
205
|
8 |
|
$reflection = new ReflectionClass($name); |
206
|
8 |
|
if (!$reflection->implementsInterface($interface)) { |
207
|
2 |
|
throw new Exception\InvalidArgumentException( |
208
|
2 |
|
"Class '{$name}' does not implement {$interface}" |
209
|
1 |
|
); |
210
|
|
|
} |
211
|
6 |
|
} |
212
|
|
|
|
213
|
|
|
/** |
214
|
|
|
* Get current configured extensions |
215
|
|
|
* |
216
|
|
|
* @return array |
217
|
|
|
*/ |
218
|
4 |
|
public function getExtensions() |
219
|
|
|
{ |
220
|
4 |
|
return self::$extensions; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Set or reset the list of extensions |
225
|
|
|
* |
226
|
|
|
* @param array $extensions |
227
|
|
|
* |
228
|
|
|
* @return Template |
229
|
|
|
*/ |
230
|
2 |
|
public function setExtensions(array $extensions) |
231
|
|
|
{ |
232
|
2 |
|
self::$extensions = $extensions; |
233
|
2 |
|
return $this; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* Set default options |
238
|
|
|
* |
239
|
|
|
* If an array is given on $option parameter it should be assigned |
240
|
|
|
* to the static $defaultOptions property. |
241
|
|
|
* |
242
|
|
|
* For other values only the key provided in $option parameter should |
243
|
|
|
* be overridden. |
244
|
|
|
* |
245
|
|
|
* @param array|string|int $option |
246
|
|
|
* |
247
|
|
|
* @param mixed $value |
248
|
|
|
*/ |
249
|
4 |
|
public static function setDefaultOptions($option, $value = null) |
250
|
|
|
{ |
251
|
4 |
|
if (is_array($option) && null == $value) { |
252
|
4 |
|
static::$defaultOptions = $option; |
253
|
2 |
|
} |
254
|
|
|
|
255
|
4 |
|
if (is_scalar($option)) { |
256
|
2 |
|
static::$defaultOptions[$option] = $value; |
257
|
1 |
|
} |
258
|
4 |
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Get current default options |
262
|
|
|
* |
263
|
|
|
* @return array |
264
|
|
|
*/ |
265
|
4 |
|
public static function getDefaultOptions() |
266
|
|
|
{ |
267
|
4 |
|
return static::$defaultOptions; |
268
|
|
|
} |
269
|
|
|
} |
270
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.