1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @author @jayS-de <[email protected]> |
4
|
|
|
*/ |
5
|
|
|
|
6
|
|
|
|
7
|
|
|
namespace JaySDe\HandlebarsBundle\Loader; |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
use JaySDe\HandlebarsBundle\Error\LoaderException; |
11
|
|
|
use Symfony\Component\Config\FileLocatorInterface; |
12
|
|
|
use Symfony\Component\Templating\TemplateNameParserInterface; |
13
|
|
|
|
14
|
|
|
class FilesystemLoader |
15
|
|
|
{ |
16
|
|
|
/** Identifier of the main namespace. */ |
17
|
|
|
const MAIN_NAMESPACE = '__main__'; |
18
|
|
|
|
19
|
|
|
protected $locator; |
20
|
|
|
protected $parser; |
21
|
|
|
|
22
|
|
|
protected $paths = []; |
23
|
|
|
protected $cache = []; |
24
|
|
|
protected $errorCache = []; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* FilesystemLoader constructor. |
28
|
|
|
* @param FileLocatorInterface $locator |
29
|
|
|
* @param TemplateNameParserInterface $parser |
30
|
|
|
*/ |
31
|
23 |
|
public function __construct(FileLocatorInterface $locator, TemplateNameParserInterface $parser) |
32
|
|
|
{ |
33
|
23 |
|
$this->locator = $locator; |
34
|
23 |
|
$this->parser = $parser; |
35
|
23 |
|
$this->setPaths([]); |
36
|
23 |
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Returns the paths to the templates. |
40
|
|
|
* |
41
|
|
|
* @param string $namespace A path namespace |
42
|
|
|
* |
43
|
|
|
* @return array The array of paths where to look for templates |
44
|
|
|
*/ |
45
|
7 |
|
public function getPaths($namespace = self::MAIN_NAMESPACE) |
46
|
|
|
{ |
47
|
7 |
|
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : []; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Returns the path namespaces. |
52
|
|
|
* |
53
|
|
|
* The main namespace is always defined. |
54
|
|
|
* |
55
|
|
|
* @return array The array of defined namespaces |
56
|
|
|
*/ |
57
|
1 |
|
public function getNamespaces() |
58
|
|
|
{ |
59
|
1 |
|
return array_keys($this->paths); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Sets the paths where templates are stored. |
64
|
|
|
* |
65
|
|
|
* @param string|array $paths A path or an array of paths where to look for templates |
66
|
|
|
* @param string $namespace A path namespace |
67
|
|
|
*/ |
68
|
23 |
|
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE) |
69
|
|
|
{ |
70
|
23 |
|
if (!is_array($paths)) { |
71
|
1 |
|
$paths = [$paths]; |
72
|
|
|
} |
73
|
|
|
|
74
|
23 |
|
$this->paths[$namespace] = []; |
75
|
23 |
|
foreach ($paths as $path) { |
76
|
4 |
|
$this->addPath($path, $namespace); |
77
|
|
|
} |
78
|
23 |
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Adds a path where templates are stored. |
82
|
|
|
* |
83
|
|
|
* @param string $path A path where to look for templates |
84
|
|
|
* @param string $namespace A path name |
85
|
|
|
* |
86
|
|
|
* @throws LoaderException |
87
|
|
|
*/ |
88
|
18 |
|
public function addPath($path, $namespace = self::MAIN_NAMESPACE) |
89
|
|
|
{ |
90
|
|
|
// invalidate the cache |
91
|
18 |
|
$this->cache = $this->errorCache = []; |
92
|
|
|
|
93
|
18 |
|
if (!is_dir($path)) { |
94
|
2 |
|
throw new LoaderException(sprintf('The "%s" directory does not exist.', $path)); |
95
|
|
|
} |
96
|
|
|
|
97
|
16 |
|
$this->paths[$namespace][] = rtrim($path, '/\\'); |
98
|
16 |
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Prepends a path where templates are stored. |
102
|
|
|
* |
103
|
|
|
* @param string $path A path where to look for templates |
104
|
|
|
* @param string $namespace A path name |
105
|
|
|
* |
106
|
|
|
* @throws LoaderException |
107
|
|
|
*/ |
108
|
3 |
|
public function prependPath($path, $namespace = self::MAIN_NAMESPACE) |
109
|
|
|
{ |
110
|
|
|
// invalidate the cache |
111
|
3 |
|
$this->cache = $this->errorCache = []; |
112
|
|
|
|
113
|
3 |
|
if (!is_dir($path)) { |
114
|
1 |
|
throw new LoaderException(sprintf('The "%s" directory does not exist.', $path)); |
115
|
|
|
} |
116
|
|
|
|
117
|
2 |
|
$path = rtrim($path, '/\\'); |
118
|
|
|
|
119
|
2 |
View Code Duplication |
if (!isset($this->paths[$namespace])) { |
|
|
|
|
120
|
1 |
|
$this->paths[$namespace][] = $path; |
121
|
|
|
} else { |
122
|
1 |
|
array_unshift($this->paths[$namespace], $path); |
123
|
|
|
} |
124
|
2 |
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* {@inheritdoc} |
128
|
|
|
*/ |
129
|
5 |
|
public function getSource($name) |
130
|
|
|
{ |
131
|
5 |
|
return file_get_contents($this->findTemplate($name)); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* {@inheritdoc} |
136
|
|
|
*/ |
137
|
2 |
|
public function getCacheKey($name) |
138
|
|
|
{ |
139
|
2 |
|
return $this->findTemplate($name); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* {@inheritdoc} |
144
|
|
|
*/ |
145
|
6 |
|
public function exists($template) |
146
|
|
|
{ |
147
|
6 |
|
$name = $this->normalizeName($template); |
148
|
|
|
|
149
|
6 |
|
if (isset($this->cache[$name])) { |
150
|
1 |
|
return true; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
try { |
154
|
6 |
|
return false !== $this->findTemplate($name, false); |
155
|
1 |
|
} catch (LoaderException $exception) { |
156
|
1 |
|
return false; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
|
160
|
12 |
|
protected function parseName($name, $default = self::MAIN_NAMESPACE) |
161
|
|
|
{ |
162
|
12 |
|
if (isset($name[0]) && '@' == $name[0]) { |
163
|
5 |
|
if (false === $pos = strpos($name, '/')) { |
164
|
2 |
|
throw new LoaderException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); |
165
|
|
|
} |
166
|
|
|
|
167
|
3 |
|
$namespace = substr($name, 1, $pos - 1); |
168
|
3 |
|
$shortname = substr($name, $pos + 1); |
169
|
|
|
|
170
|
3 |
|
return array($namespace, $shortname); |
171
|
|
|
} |
172
|
|
|
|
173
|
8 |
|
return array($default, $name); |
174
|
|
|
} |
175
|
|
|
|
176
|
12 |
|
protected function normalizeName($name) |
177
|
|
|
{ |
178
|
12 |
|
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); |
179
|
|
|
} |
180
|
|
|
|
181
|
12 |
|
protected function findTemplate($template, $throw = true) |
182
|
|
|
{ |
183
|
12 |
|
$name = $this->normalizeName($template); |
184
|
|
|
|
185
|
12 |
|
if (isset($this->cache[$name])) { |
186
|
1 |
|
return $this->cache[$name]; |
187
|
|
|
} |
188
|
|
|
|
189
|
12 |
|
list($namespace, $shortname) = $this->parseName($name); |
190
|
|
|
|
191
|
|
|
try { |
192
|
10 |
|
$this->validateTemplate($name, $namespace); |
193
|
3 |
|
} catch (LoaderException $e) { |
194
|
3 |
|
if ($throw) { |
195
|
2 |
|
throw $e; |
196
|
|
|
} |
197
|
2 |
|
return false; |
198
|
|
|
} |
199
|
|
|
|
200
|
8 |
|
foreach ($this->paths[$namespace] as $path) { |
201
|
5 |
|
if (is_file($path.'/'.$shortname)) { |
202
|
1 |
|
if (false !== $realpath = realpath($path.'/'.$shortname)) { |
203
|
1 |
|
return $this->cache[$name] = $realpath; |
204
|
|
|
} |
205
|
|
|
|
206
|
4 |
|
return $this->cache[$name] = $path.'/'.$shortname; |
207
|
|
|
} |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
try { |
211
|
8 |
|
return $this->locateTemplate($template, $name, $namespace); |
212
|
4 |
|
} catch (LoaderException $e) { |
213
|
4 |
|
if ($throw) { |
214
|
3 |
|
throw $e; |
215
|
|
|
} |
216
|
1 |
|
return false; |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
10 |
|
private function validateTemplate($name, $namespace) |
221
|
|
|
{ |
222
|
10 |
|
if (isset($this->errorCache[$name])) { |
223
|
1 |
|
throw new LoaderException($this->errorCache[$name]); |
224
|
|
|
} |
225
|
|
|
|
226
|
10 |
View Code Duplication |
if (!isset($this->paths[$namespace])) { |
|
|
|
|
227
|
2 |
|
$this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace); |
228
|
|
|
|
229
|
2 |
|
throw new LoaderException($this->errorCache[$name]); |
230
|
|
|
} |
231
|
|
|
|
232
|
8 |
|
return true; |
233
|
|
|
} |
234
|
|
|
|
235
|
8 |
|
private function locateTemplate($template, $name, $namespace) |
236
|
|
|
{ |
237
|
|
|
try { |
238
|
8 |
|
$template = $this->parser->parse($template); |
239
|
8 |
|
$realpath = $this->locator->locate($template); |
240
|
7 |
|
if (false !== $realpath && null !== $realpath) { |
241
|
7 |
|
return $this->cache[$name] = $realpath; |
242
|
|
|
} |
243
|
1 |
|
} catch (\Exception $e) { |
244
|
|
|
// catch locator not found exceptions |
245
|
|
|
} |
246
|
|
|
|
247
|
4 |
|
$this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])); |
248
|
|
|
|
249
|
4 |
|
throw new LoaderException($this->errorCache[$name]); |
250
|
|
|
} |
251
|
|
|
} |
252
|
|
|
|
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.