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 array $extensions |
22
|
|
|
* @property string $engine |
23
|
|
|
*/ |
24
|
|
|
final class Template extends Base |
25
|
|
|
{ |
26
|
|
|
|
27
|
|
|
/** Known engines */ |
28
|
|
|
const ENGINE_TWIG = 'Slick\Template\Engine\Twig'; |
29
|
|
|
|
30
|
|
|
/** Known engine extensions */ |
31
|
|
|
const EXTENSION_TWIG_TEXT = 'Slick\Template\Extension\Text'; |
32
|
|
|
const EXTENSION_TWIG_I18N = 'Slick\Template\Extension\I18n'; |
33
|
|
|
|
34
|
|
|
/** @var string Engine interface */ |
35
|
|
|
private static $interface = 'Slick\Template\TemplateEngineInterface'; |
36
|
|
|
private static $extensionInterface = |
37
|
|
|
'Slick\Template\EngineExtensionInterface'; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @readwrite |
41
|
|
|
* @var string The engine to use |
42
|
|
|
*/ |
43
|
|
|
protected $engine = self::ENGINE_TWIG; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @readwrite |
47
|
|
|
* @var array Options for template initializing |
48
|
|
|
*/ |
49
|
|
|
protected $options = array(); |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @var string[] a list of available paths |
53
|
|
|
*/ |
54
|
|
|
protected static $paths = ['./']; |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @readwrite |
58
|
|
|
* @var array Array containing template extensions |
59
|
|
|
*/ |
60
|
|
|
protected $extensions = [ |
61
|
|
|
self::EXTENSION_TWIG_TEXT => null, |
62
|
|
|
self::EXTENSION_TWIG_I18N => null, |
63
|
|
|
]; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Prepends a searchable path to available paths list. |
67
|
|
|
* |
68
|
|
|
* @param string $path |
69
|
|
|
*/ |
70
|
2 |
View Code Duplication |
public static function addPath($path) |
|
|
|
|
71
|
|
|
{ |
72
|
2 |
|
$path = str_replace('//', '/', rtrim($path, '/')); |
73
|
2 |
|
if (is_dir($path) && !in_array($path, self::$paths)) { |
74
|
2 |
|
array_unshift(self::$paths, $path); |
75
|
2 |
|
} |
76
|
2 |
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Prepends a searchable path to available paths list. |
80
|
|
|
* |
81
|
|
|
* @param string $path |
82
|
|
|
*/ |
83
|
2 |
View Code Duplication |
public static function appendPath($path) |
|
|
|
|
84
|
|
|
{ |
85
|
2 |
|
$path = str_replace('//', '/', rtrim($path, '/')); |
86
|
2 |
|
if (is_dir($path) && !in_array($path, self::$paths)) { |
87
|
2 |
|
array_push(self::$paths, $path); |
88
|
2 |
|
} |
89
|
2 |
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Gets the list of defined paths |
93
|
|
|
* |
94
|
|
|
* @return \string[] |
95
|
|
|
*/ |
96
|
4 |
|
public static function getPaths() |
97
|
|
|
{ |
98
|
4 |
|
return self::$paths; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Initializes the engine |
103
|
|
|
* |
104
|
|
|
* @throws Exception\InvalidArgumentException |
105
|
|
|
* |
106
|
|
|
* @return TemplateEngineInterface |
107
|
|
|
*/ |
108
|
4 |
|
public function initialize() |
109
|
|
|
{ |
110
|
4 |
|
$this->checkClass(); |
111
|
|
|
/** @var TemplateEngineInterface $engine */ |
112
|
2 |
|
$engine = new $this->engine($this->options); |
113
|
2 |
|
$engine->setLocations(self::$paths); |
114
|
2 |
|
return $this->applyExtensions($engine); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Adds an extension to the template engine |
119
|
|
|
* |
120
|
|
|
* @param string|object $className The class name or an instance |
121
|
|
|
* of EngineExtensionInterface interface |
122
|
|
|
* |
123
|
|
|
* @return self|$this|Template |
124
|
|
|
*/ |
125
|
4 |
|
public function addExtension($className) |
126
|
|
|
{ |
127
|
4 |
|
$object = is_object($className) ? $className : null; |
128
|
4 |
|
$className = is_object($className) ? get_class($object) : $className; |
129
|
|
|
|
130
|
4 |
|
$this->checkClass($className, self::$extensionInterface); |
131
|
|
|
|
132
|
2 |
|
$this->extensions[$className] = $object; |
133
|
2 |
|
return $this; |
134
|
|
|
|
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Apply defined extensions to the provided template engine |
139
|
|
|
* |
140
|
|
|
* @param TemplateEngineInterface $engine |
141
|
|
|
* |
142
|
|
|
* @return TemplateEngineInterface |
143
|
|
|
*/ |
144
|
2 |
|
protected function applyExtensions(TemplateEngineInterface $engine) |
145
|
|
|
{ |
146
|
2 |
|
foreach ($this->extensions as $className => $extension) { |
147
|
2 |
|
$ext = $this->getExtension($className, $extension); |
148
|
2 |
|
if ($ext->appliesTo($engine)) { |
149
|
2 |
|
$ext->update($engine); |
150
|
2 |
|
} |
151
|
2 |
|
} |
152
|
2 |
|
return $engine; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* @param string $class |
157
|
|
|
* @param EngineExtensionInterface $extension |
158
|
|
|
* |
159
|
|
|
* @return EngineExtensionInterface |
160
|
|
|
*/ |
161
|
2 |
|
protected function getExtension($class, $extension) |
162
|
|
|
{ |
163
|
2 |
|
if (is_object($extension)) { |
164
|
2 |
|
return $extension; |
165
|
|
|
} |
166
|
|
|
|
167
|
2 |
|
$this->checkClass($class, self::$extensionInterface); |
168
|
2 |
|
return new $class(); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Check if type is a valid configuration driver |
173
|
|
|
* |
174
|
|
|
* @param null $name |
175
|
|
|
* @param null $interface |
176
|
|
|
*/ |
177
|
8 |
|
protected function checkClass($name = null, $interface = null) |
178
|
|
|
{ |
179
|
8 |
|
$name = null == $name ? $this->engine : $name; |
180
|
8 |
|
$interface = null == $interface ? self::$interface : $interface; |
181
|
|
|
|
182
|
8 |
|
if (!class_exists($name)) { |
183
|
2 |
|
throw new Exception\InvalidArgumentException( |
184
|
2 |
|
"The class '{$name}' was not found" |
185
|
2 |
|
); |
186
|
|
|
} |
187
|
|
|
|
188
|
6 |
|
$reflection = new ReflectionClass($name); |
189
|
6 |
|
if (!$reflection->implementsInterface($interface)) { |
190
|
2 |
|
throw new Exception\InvalidArgumentException( |
191
|
2 |
|
"Class '{$name}' does not implement {$interface}" |
192
|
2 |
|
); |
193
|
|
|
} |
194
|
4 |
|
} |
195
|
|
|
} |
196
|
|
|
|
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.