Completed
Pull Request — 2.x (#83)
by jake
02:42
created

TemplateRegistry::findNamespaced()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 13
cts 13
cp 1
rs 8.9197
c 0
b 0
f 0
cc 4
eloc 13
nc 4
nop 1
crap 4
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
    /**
66
     *
67
     * Constructor.
68
     *
69
     * @param array $map A map of explicit template names and locations.
70
     *
71
     * @param array $paths A map of filesystem paths to search for templates.
72
     *
73
     * @param array $namespaces A map of filesystem paths to search for namespaced templates.
74
     *
75
     */
76 19
    public function __construct(
77
        array $map = array(),
78
        array $paths = array(),
79
        array $namespaces = array()
80
    ) {
81 19
        foreach ($map as $name => $spec) {
82 1
            $this->set($name, $spec);
83
        }
84 19
        $this->setPaths($paths);
85 19
        $this->setNamespaces($namespaces);
86 19
    }
87
88
    /**
89
     *
90
     * Registers a template.
91
     *
92
     * If the template is a string, it is treated as a path to a PHP include
93
     * file, and gets wrapped inside a closure that includes that file.
94
     * Otherwise the template is treated as a callable.
95
     *
96
     * @param string $name Register the template under this name.
97
     *
98
     * @param string|callable $spec A string path to a PHP include file, or a
99
     * callable.
100
     *
101
     * @return null
102
     *
103
     */
104 11
    public function set($name, $spec)
105
    {
106 11
        if (is_string($spec)) {
107 2
            $spec = $this->enclose($spec);
108
        }
109 11
        $this->map[$name] = $spec;
110 11
    }
111
112
    /**
113
     *
114
     * Is a named template registered?
115
     *
116
     * @param string $name The template name.
117
     *
118
     * @return bool
119
     *
120
     */
121 1
    public function has($name)
122
    {
123 1
        return isset($this->map[$name]) || $this->find($name);
124
    }
125
126
    /**
127
     *
128
     * Is a namespace registered?
129
     *
130
     * @param string $name The namespace.
0 ignored issues
show
Bug introduced by
There is no parameter named $name. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
131
     *
132
     * @return bool
133
     *
134
     */
135 2
    public function hasNamespace($namespace)
136
    {
137 2
        return isset($this->namespaces[$namespace]);
138
    }
139
140
    /**
141
     *
142
     * Gets a template from the registry.
143
     *
144
     * @param string $name The template name.
145
     *
146
     * @return \Closure
147
     *
148
     */
149 11
    public function get($name)
150
    {
151 11
        if (isset($this->map[$name])) {
152 7
            return $this->map[$name];
153
        }
154
155 5
        if ($this->find($name)) {
156 2
            return $this->found[$name];
157
        }
158
159 4
        throw new Exception\TemplateNotFound($name);
160
    }
161
162
    /**
163
     *
164
     * Gets a copy of the current search paths.
165
     *
166
     * @return array
167
     *
168
     */
169 3
    public function getPaths()
170
    {
171 3
        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
     *
184
     * @param string $path The directories to add to the paths.
185
     * @param string|null $namespace The directory namespace
186
     *
187
     * @return null
188
     *
189
     */
190 2
    public function prependPath($path, $namespace = null)
191
    {
192 2
        $this->found = [];
193 2
        $path = rtrim($path, DIRECTORY_SEPARATOR);
194
195 2
        if ($namespace !== null) {
196 1
            if (! $this->hasNamespace($namespace)) {
197 1
                $this->namespaces[$namespace] = [];
198
            }
199 1
            array_unshift($this->namespaces[$namespace], $path);
200 1
            return;
201
        }
202 1
        array_unshift($this->paths, $path);
203 1
    }
204
205
    /**
206
     *
207
     * Adds one path to the end of the search paths.
208
     *
209
     *     $registry->appendPath('/path/1');
210
     *     $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 3
    public function appendPath($path, $namespace = null)
222
    {
223 3
        $this->found = [];
224 3
        $path = rtrim($path, DIRECTORY_SEPARATOR);
225
226 3
        if ($namespace !== null) {
227 1
            if (! $this->hasNamespace($namespace)) {
228 1
                $this->namespaces[$namespace] = [];
229
            }
230 1
            $this->namespaces[$namespace][] = $path;
231 1
            return;
232
        }
233
234 3
        $this->paths[] = $path;
235 3
    }
236
237
    /**
238
     *
239
     * Sets the paths directly.
240
     *
241
     *      $registry->setPaths([
242
     *          '/path/1',
243
     *          '/path/2',
244
     *          '/path/3',
245
     *      ]);
246
     *      // $registry->getPaths() reveals that the search order will
247
     *      // be '/path/1', '/path/2', '/path/3'.
248
     *
249
     * @param array $paths The paths to set.
250
     *
251
     * @return null
252
     *
253
     */
254 19
    public function setPaths(array $paths)
255
    {
256 19
        $this->paths = $paths;
257 19
        $this->found = [];
258 19
    }
259
260
    /**
261
     * Set namespaces directly
262
     *
263
     * @param array $namespaces array of namesspaces
264
     *
265
     * @return void
266
     *
267
     * @access public
268
     */
269 19
    public function setNamespaces(array $namespaces)
270
    {
271 19
        $this->namespaces = $namespaces;
272 19
        $this->found = [];
273 19
    }
274
275
    /**
276
     *
277
     * Sets the extension to be used when searching for templates via find().
278
     *
279
     * @param string $templateFileExtension
280
     *
281
     * @return null
282
     *
283
     */
284 1
    public function setTemplateFileExtension($templateFileExtension)
285
    {
286 1
        $this->templateFileExtension = $templateFileExtension;
287 1
    }
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 5
    protected function find($name)
299
    {
300 5
        if (isset($this->found[$name])) {
301 1
            return true;
302
        }
303
304 5
        if ($this->isNamespaced($name)) {
305 2
            return $this->findNamespaced($name);
306
        }
307
308 2
        foreach ($this->paths as $path) {
309 1
            $file = $path . DIRECTORY_SEPARATOR . $name . $this->templateFileExtension;
310 1
            if ($this->isReadable($file)) {
311 1
                $this->found[$name] = $this->enclose($file);
312 1
                return true;
313
            }
314
        }
315
316 2
        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 5
    protected function parseName($name)
330
    {
331 5
        $info  = explode('::', $name);
332 5
        $count = count($info);
333
334 5
        if ($count == 1) {
335 2
            return array('name' => $info[0]);
336
        }
337
338 3
        if ($count == 2) {
339
            return array(
340 2
                'namespace' => $info[0],
341 2
                'name'      => $info[1]
342
            );
343
        }
344
345 1
        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 5
    protected function isNamespaced($name)
358
    {
359 5
        $info = $this->parseName($name);
360 4
        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 2
    protected function findNamespaced($name)
373
    {
374 2
        $info = $this->parseName($name);
375 2
        $namespace = $info['namespace'];
376 2
        $shortname = $info['name'];
377
378 2
        if (! $this->hasNamespace($namespace)) {
379 1
            return false;
380
        }
381
382 1
        $paths = $this->namespaces[$namespace];
383
384 1
        foreach ($paths as $path) {
385 1
            $file = $path . DIRECTORY_SEPARATOR . $shortname . $this->templateFileExtension;
386 1
            if ($this->isReadable($file)) {
387 1
                $this->found[$name] = $this->enclose($file);
388 1
                return true;
389
            }
390
        }
391
392 1
        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 2
    protected function isReadable($file)
405
    {
406 2
        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 2
        return function (array $__VARS__ = array()) use ($__FILE__) {
421 2
            extract($__VARS__, EXTR_SKIP);
422 2
            require $__FILE__;
423 2
        };
424
    }
425
}
426