FilesystemLoader   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 3
dl 0
loc 238
ccs 89
cts 89
cp 1
rs 9.28
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getPaths() 0 4 2
A getNamespaces() 0 4 1
A setPaths() 0 11 3
A addPath() 0 11 2
A prependPath() 0 17 3
A getSource() 0 4 1
A getCacheKey() 0 4 1
A exists() 0 14 3
A parseName() 0 15 4
A normalizeName() 0 4 1
A findTemplate() 0 17 4
A searchTemplate() 0 17 6
A validateTemplate() 0 14 3
A locateTemplate() 0 19 4
1
<?php
2
/**
3
 * @author @jenschude <[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 25
    public function __construct(FileLocatorInterface $locator, TemplateNameParserInterface $parser)
32
    {
33 25
        $this->locator = $locator;
34 25
        $this->parser = $parser;
35 25
        $this->setPaths([]);
36 25
    }
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 25
    public function setPaths($paths, $namespace = self::MAIN_NAMESPACE)
69
    {
70 25
        if (!is_array($paths)) {
71 1
            $paths = [$paths];
72
        }
73
74 25
        $this->paths[$namespace] = [];
75 25
        foreach ($paths as $path) {
76 4
            $this->addPath($path, $namespace);
77
        }
78 25
    }
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 20
    public function addPath($path, $namespace = self::MAIN_NAMESPACE)
89
    {
90
        // invalidate the cache
91 20
        $this->cache = $this->errorCache = [];
92
93 20
        if (!is_dir($path)) {
94 2
            throw new LoaderException(sprintf('The "%s" directory does not exist.', $path));
95
        }
96
97 18
        $this->paths[$namespace][] = rtrim($path, '/\\');
98 18
    }
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
        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 7
    public function getSource($name)
130
    {
131 7
        return file_get_contents($this->findTemplate($name));
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137 4
    public function getCacheKey($name)
138
    {
139 4
        return $this->findTemplate($name);
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145 7
    public function exists($template)
146
    {
147 7
        $name = $this->normalizeName($template);
148
149 7
        if (isset($this->cache[$name])) {
150 1
            return true;
151
        }
152
153
        try {
154 7
            return false !== $this->findTemplate($name, false);
155 1
        } catch (LoaderException $exception) {
156 1
            return false;
157
        }
158
    }
159
160 14
    protected function parseName($name, $default = self::MAIN_NAMESPACE)
161
    {
162 14
        if (isset($name[0]) && '@' == $name[0]) {
163 6
            if (false === $pos = strpos($name, '/')) {
164 2
                throw new LoaderException(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
165
            }
166
167 4
            $namespace = substr($name, 1, $pos - 1);
168 4
            $shortname = substr($name, $pos + 1);
169
170 4
            return array($namespace, $shortname);
171
        }
172
173 10
        return array($default, $name);
174
    }
175
176 14
    protected function normalizeName($name)
177
    {
178 14
        return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
179
    }
180
181 14
    protected function findTemplate($template, $throw = true)
182
    {
183 14
        $normalizedName = $this->normalizeName($template);
184
185 14
        if (isset($this->cache[$normalizedName])) {
186 3
            return $this->cache[$normalizedName];
187
        }
188
189 14
        list($namespace, $shortName) = $this->parseName($normalizedName);
190
191 12
        if (!$this->validateTemplate($normalizedName, $namespace)) {
192 3
            if ($throw) { throw new LoaderException($this->errorCache[$normalizedName]); }
193 2
            return false;
194
        }
195
196 10
        return $this->searchTemplate($template, $normalizedName, $shortName, $namespace, $throw);
197
    }
198
199 10
    private function searchTemplate($template, $name, $shortName, $namespace, $throw) {
200 10
        foreach ($this->paths[$namespace] as $path) {
201 7
            if (is_file($path.'/'.$shortName)) {
202 3
                if (false !== $realpath = realpath($path.'/'.$shortName)) {
203 3
                    return $this->cache[$name] = $realpath;
204
                }
205
206 5
                return $this->cache[$name] = $path.'/'.$shortName;
207
            }
208
        }
209
210 9
        if (!$template = $this->locateTemplate($template, $name, $namespace)) {
211 5
            if ($throw) { throw new LoaderException($this->errorCache[$name]); }
212 2
            return false;
213
        }
214 4
        return $template;
215
    }
216
217 12
    private function validateTemplate($name, $namespace)
218
    {
219 12
        if (isset($this->errorCache[$name])) {
220 1
            return false;
221
        }
222
223 12
        if (!isset($this->paths[$namespace])) {
224 2
            $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace);
225
226 2
            return false;
227
        }
228
229 10
        return true;
230
    }
231
232 9
    private function locateTemplate($template, $name, $namespace)
233
    {
234
        try {
235 9
            $template = $this->parser->parse($template);
236 9
            $realpath = $this->locator->locate($template);
237 7
            if (false !== $realpath && null !== $realpath) {
238 7
                return $this->cache[$name] = $realpath;
239
            }
240 2
        } catch (\Exception $e) {
241
            // catch locator not found exceptions
242
        }
243
244 5
        $this->errorCache[$name] = sprintf(
245 5
            'Unable to find template "%s" (looked into: %s).',
246 5
            $name,
247 5
            implode(', ', $this->paths[$namespace])
248
        );
249 5
        return false;
250
    }
251
}
252