Passed
Push — 2.x ( 142284...bb2117 )
by Hari
01:27 queued 12s
created

TemplateRegistry::parseName()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 1
dl 0
loc 17
ccs 0
cts 0
cp 0
crap 12
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * This file is part of Aura for PHP.
5
 *
6
 * @license http://opensource.org/licenses/bsd-license.php BSD
7
 *
8
 */
9
namespace Aura\View;
10
11
/**
12
 *
13
 * A registry for templates.
14
 *
15
 * @package Aura.View
16
 *
17
 */
18
class TemplateRegistry
19
{
20
    /**
21
     *
22
     * The map of explicit template names and locations.
23
     *
24
     * @var array
25
     *
26
     */
27
    protected $map = array();
28
29
    /**
30
     *
31
     * The paths to search for implicit template names.
32
     *
33
     * @var array
34
     *
35
     */
36
    protected $paths = array();
37
38
    /**
39
     *
40
     * The namespaced paths to search for implicit template names.
41
     *
42
     * @var array
43
     *
44
     */
45
    protected $namespaces = array();
46
47
    /**
48
     *
49
     * Templates found in the search paths.
50
     *
51
     * @var array
52
     *
53
     */
54
    protected $found = array();
55
56
    /**
57
     *
58
     * File extension to use when searching the path list for templates.
59
     *
60
     * @var string
61
     *
62
     */
63
    protected $templateFileExtension = '.php';
64
65 16
    /**
66
     *
67
     * Constructor.
68
     *
69 16
     * @param array $map A map of explicit template names and locations.
70 1
     *
71 16
     * @param array $paths A map of filesystem paths to search for templates.
72 16
     *
73 16
     * @param array $namespaces A map of filesystem paths to search for namespaced templates.
74
     *
75
     */
76
    public function __construct(
77
        array $map = array(),
78
        array $paths = array(),
79
        array $namespaces = array()
80
    ) {
81
        foreach ($map as $name => $spec) {
82
            $this->set($name, $spec);
83
        }
84
        $this->setPaths($paths);
85
        $this->setNamespaces($namespaces);
86
    }
87
88
    /**
89
     *
90
     * Registers a template.
91 11
     *
92
     * If the template is a string, it is treated as a path to a PHP include
93 11
     * file, and gets wrapped inside a closure that includes that file.
94 2
     * Otherwise the template is treated as a callable.
95 2
     *
96 11
     * @param string $name Register the template under this name.
97 11
     *
98
     * @param string|callable $spec A string path to a PHP include file, or a
99
     * callable.
100
     *
101
     * @return null
102
     *
103
     */
104
    public function set($name, $spec)
105
    {
106
        if (is_string($spec)) {
107
            $spec = $this->enclose($spec);
108 1
        }
109
        $this->map[$name] = $spec;
110 1
    }
111
112
    /**
113
     *
114
     * Is a named template registered?
115
     *
116
     * @param string $name The template name.
117
     *
118
     * @return bool
119
     *
120
     */
121
    public function has($name)
122 8
    {
123
        return isset($this->map[$name]) || $this->find($name);
124 8
    }
125 7
126
    /**
127
     *
128 2
     * Is a namespace registered?
129 1
     *
130
     * @param string $name The namespace.
131
     *
132 2
     * @return bool
133
     *
134
     */
135
    public function hasNamespace($namespace)
136
    {
137
        return isset($this->namespaces[$namespace]);
138
    }
139
140
    /**
141
     *
142 3
     * Gets a template from the registry.
143
     *
144 3
     * @param string $name The template name.
145
     *
146
     * @return \Closure
147
     *
148
     */
149
    public function get($name)
150
    {
151
        if (isset($this->map[$name])) {
152
            return $this->map[$name];
153
        }
154
155
        if ($this->find($name)) {
156
            return $this->found[$name];
157
        }
158
159
        throw new Exception\TemplateNotFound($name);
160
    }
161
162 1
    /**
163
     *
164 1
     * Gets a copy of the current search paths.
165 1
     *
166 1
     * @return array
167
     *
168
     */
169
    public function getPaths()
170
    {
171
        return $this->paths;
172
    }
173
174
    /**
175
     *
176
     * Adds one path to the top of the search paths.
177
     *
178
     *     $registry->prependPath('/path/1');
179
     *     $registry->prependPath('/path/2');
180
     *     $registry->prependPath('/path/3');
181
     *     // $this->getPaths() reveals that the directory search
182
     *     // order will be '/path/3/', '/path/2/', '/path/1/'.
183 2
     *
184
     * @param string $path The directories to add to the paths.
185 2
     * @param string|null $namespace The directory namespace
186 2
     *
187 2
     * @return null
188
     *
189
     */
190
    public function prependPath($path, $namespace = null)
191
    {
192
        $this->found = [];
193
        $path = rtrim($path, DIRECTORY_SEPARATOR);
194
195
        if ($namespace !== null) {
196
            if (! $this->hasNamespace($namespace)) {
197
                $this->namespaces[$namespace] = [];
198
            }
199
            array_unshift($this->namespaces[$namespace], $path);
200
            return;
201
        }
202
        array_unshift($this->paths, $path);
203
    }
204
205
    /**
206 16
     *
207
     * Adds one path to the end of the search paths.
208 16
     *
209 16
     *     $registry->appendPath('/path/1');
210 16
     *     $registry->appendPath('/path/2');
211
     *     $registry->appendPath('/path/3');
212
     *     // $registry->getPaths() reveals that the directory search
213
     *     // order will be '/path/1/', '/path/2/', '/path/3/'.
214
     *
215
     * @param array|string $path The directories to add to the paths.
216
     * @param string|null $namespace The directory namespace
217
     *
218
     * @return null
219
     *
220
     */
221 1
    public function appendPath($path, $namespace = null)
222
    {
223 1
        $this->found = [];
224 1
        $path = rtrim($path, DIRECTORY_SEPARATOR);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type array; however, parameter $string of rtrim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

224
        $path = rtrim(/** @scrutinizer ignore-type */ $path, DIRECTORY_SEPARATOR);
Loading history...
225
226
        if ($namespace !== null) {
227
            if (! $this->hasNamespace($namespace)) {
228
                $this->namespaces[$namespace] = [];
229
            }
230
            $this->namespaces[$namespace][] = $path;
231
            return;
232
        }
233
234
        $this->paths[] = $path;
235 2
    }
236
237 2
    /**
238 1
     *
239
     * Sets the paths directly.
240
     *
241 2
     *      $registry->setPaths([
242 1
     *          '/path/1',
243 1
     *          '/path/2',
244 1
     *          '/path/3',
245 1
     *      ]);
246
     *      // $registry->getPaths() reveals that the search order will
247 2
     *      // be '/path/1', '/path/2', '/path/3'.
248
     *
249 2
     * @param array $paths The paths to set.
250
     *
251
     * @return null
252
     *
253
     */
254
    public function setPaths(array $paths)
255
    {
256
        $this->paths = $paths;
257
        $this->found = [];
258
    }
259
260
    /**
261 1
     * Set namespaces directly
262
     *
263 1
     * @param array $namespaces array of namesspaces
264
     *
265
     * @return void
266
     *
267
     * @access public
268
     */
269
    public function setNamespaces(array $namespaces)
270
    {
271
        $this->namespaces = $namespaces;
272
        $this->found = [];
273
    }
274
275
    /**
276
     *
277 2
     * Sets the extension to be used when searching for templates via find().
278 2
     *
279 2
     * @param string $templateFileExtension
280 2
     *
281
     * @return null
282
     *
283
     */
284
    public function setTemplateFileExtension($templateFileExtension)
285
    {
286
        $this->templateFileExtension = $templateFileExtension;
287
    }
288
289
    /**
290
     *
291
     * Finds a template in the search paths.
292
     *
293
     * @param string $name The template name.
294
     *
295
     * @return bool True if found, false if not.
296
     *
297
     */
298
    protected function find($name)
299
    {
300
        if (isset($this->found[$name])) {
301
            return true;
302
        }
303
304
        if ($this->isNamespaced($name)) {
305
            return $this->findNamespaced($name);
306
        }
307
308
        foreach ($this->paths as $path) {
309
            $file = $path . DIRECTORY_SEPARATOR . $name . $this->templateFileExtension;
310
            if ($this->isReadable($file)) {
311
                $this->found[$name] = $this->enclose($file);
312
                return true;
313
            }
314
        }
315
316
        return false;
317
    }
318
319
    /**
320
     * Parse namespaced template name
321
     *
322
     * @param string $name namespaced template name
323
     *
324
     * @return array
325
     * @throws InvalidArgumentException if invalid template name
326
     *
327
     * @access protected
328
     */
329
    protected function parseName($name)
330
    {
331
        $info  = explode('::', $name);
332
        $count = count($info);
333
334
        if ($count == 1) {
335
            return array('name' => $info[0]);
336
        }
337
338
        if ($count == 2) {
339
            return array(
340
                'namespace' => $info[0],
341
                'name'      => $info[1]
342
            );
343
        }
344
345
        throw new \InvalidArgumentException('Invalid name: ' . $name);
346
    }
347
348
    /**
349
     * Is template name namespaced?
350
     *
351
     * @param string $name name to check
352
     *
353
     * @return bool
354
     *
355
     * @access protected
356
     */
357
    protected function isNamespaced($name)
358
    {
359
        $info = $this->parseName($name);
360
        return isset($info['namespace']);;
361
    }
362
363
    /**
364
     * Fine a namespaced template
365
     *
366
     * @param string $name namespaced template name
367
     *
368
     * @return bool
369
     *
370
     * @access protected
371
     */
372
    protected function findNamespaced($name)
373
    {
374
        $info = $this->parseName($name);
375
        $namespace = $info['namespace'];
376
        $shortname = $info['name'];
377
378
        if (! $this->hasNamespace($namespace)) {
379
            return false;
380
        }
381
382
        $paths = $this->namespaces[$namespace];
383
384
        foreach ($paths as $path) {
385
            $file = $path . DIRECTORY_SEPARATOR . $shortname . $this->templateFileExtension;
386
            if ($this->isReadable($file)) {
387
                $this->found[$name] = $this->enclose($file);
388
                return true;
389
            }
390
        }
391
392
        return false;
393
    }
394
395
    /**
396
     *
397
     * Checks to see if a file is readable.
398
     *
399
     * @param string $file The file to find.
400
     *
401
     * @return bool
402
     *
403
     */
404
    protected function isReadable($file)
405
    {
406
        return is_readable($file);
407
    }
408
409
    /**
410
     *
411
     * Wraps a template file name in a Closure.
412
     *
413
     * @param string $__FILE__ The file name.
414
     *
415
     * @return \Closure
416
     *
417
     */
418
    protected function enclose($__FILE__)
419
    {
420
        return function (array $__VARS__ = array()) use ($__FILE__) {
421
            extract($__VARS__, EXTR_SKIP);
422
            require $__FILE__;
423
        };
424
    }
425
}
426