Skip to content

Commit a7e9196

Browse files
committed
initial commit
0 parents  commit a7e9196

File tree

4 files changed

+312
-0
lines changed

4 files changed

+312
-0
lines changed

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Dave Olsen, http://dmolsen.com
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

composer.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "PatternLab/TwigPatternEngine",
3+
"description": "Twig-based Pattern Engine for the PHP version of Pattern Lab",
4+
"keywords": ["twig", "pattern lab", "pattern engine"],
5+
"homepage": "http://patternlab.io",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Dave Olsen",
10+
"email": "[email protected]",
11+
"homepage": "http://dmolsen.com",
12+
"role": "Lead Developer"
13+
}
14+
],
15+
"autoload": {
16+
"psr-0": {
17+
"PatternLab\\TwigPatternEngine": "src/"
18+
}
19+
},
20+
"require": {
21+
"twig/twig": "v1.15.1"
22+
}
23+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*!
4+
* Twig Pattern Engine Rule Class
5+
*
6+
* Copyright (c) 2014 Dave Olsen, http://dmolsen.com
7+
* Licensed under the MIT license
8+
*
9+
* If the test matches "twig" it will return an instance of the Twig Pattern Engine
10+
*
11+
*/
12+
13+
namespace PatternLab\TwigPatternEngine;
14+
15+
use \PatternLab\Config;
16+
use \PatternLab\TwigPatternEngine\TwigLoader;
17+
use \PatternLab\PatternEngine\Rule;
18+
19+
class PatternEngineRule extends Rule {
20+
21+
public function __construct($options) {
22+
23+
parent::__construct($options);
24+
25+
$this->engineProp = "twig";
26+
27+
}
28+
29+
public function getInstance($options) {
30+
31+
$options = new TwigLoader(__DIR__."/../..".Config::$options["patternSourceDir"],array("patternPaths" => $options["patternPaths"]));
32+
33+
return new \Twig_Environment($options);
34+
35+
}
36+
37+
}
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
<?php
2+
3+
/*!
4+
* Pattern Engine Twig Loader Class
5+
*
6+
* Copyright (c) 2014 Dave Olsen, http://dmolsen.com
7+
* Licensed under the MIT license
8+
*
9+
* The Twig Pattern Loader has been modified from the FilesystemLoader
10+
* by Fabien Potencier <[email protected]>
11+
*
12+
*/
13+
14+
namespace PatternLab\TwigPatternEngine;
15+
16+
use \PatternLab\PatternEngine\Loader;
17+
18+
class TwigLoader implements \Twig_LoaderInterface, \Twig_ExistsLoaderInterface {
19+
20+
/** Identifier of the main namespace. */
21+
const MAIN_NAMESPACE = '__main__';
22+
23+
protected $paths = array();
24+
protected $cache = array();
25+
protected $patternPaths = array();
26+
protected $extension = '.twig';
27+
28+
/**
29+
* Constructor.
30+
*
31+
* @param string|array $paths A path or an array of paths where to look for templates
32+
*/
33+
public function __construct($paths = array(),$patternPaths = array()) {
34+
if ($paths) {
35+
$this->setPaths($paths);
36+
}
37+
$options['patternPaths'] = $patternPaths['patternPaths'];
38+
$this->patternLoader = new Loader($options);
39+
}
40+
41+
/**
42+
* Returns the paths to the templates.
43+
*
44+
* @param string $namespace A path namespace
45+
*
46+
* @return array The array of paths where to look for templates
47+
*/
48+
public function getPaths($namespace = self::MAIN_NAMESPACE) {
49+
return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array();
50+
}
51+
52+
/**
53+
* Returns the path namespaces.
54+
*
55+
* The main namespace is always defined.
56+
*
57+
* @return array The array of defined namespaces
58+
*/
59+
public function getNamespaces() {
60+
return array_keys($this->paths);
61+
}
62+
63+
/**
64+
* Sets the paths where templates are stored.
65+
*
66+
* @param string|array $paths A path or an array of paths where to look for templates
67+
* @param string $namespace A path namespace
68+
*/
69+
public function setPaths($paths, $namespace = self::MAIN_NAMESPACE) {
70+
if (!is_array($paths)) {
71+
$paths = array($paths);
72+
}
73+
74+
$this->paths[$namespace] = array();
75+
foreach ($paths as $path) {
76+
$this->addPath($path, $namespace);
77+
}
78+
}
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 Twig_Error_Loader
87+
*/
88+
public function addPath($path, $namespace = self::MAIN_NAMESPACE) {
89+
// invalidate the cache
90+
$this->cache = array();
91+
92+
if (!is_dir($path)) {
93+
throw new \Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
94+
}
95+
96+
$this->paths[$namespace][] = rtrim($path, '/\\');
97+
}
98+
99+
/**
100+
* Prepends a path where templates are stored.
101+
*
102+
* @param string $path A path where to look for templates
103+
* @param string $namespace A path name
104+
*
105+
* @throws Twig_Error_Loader
106+
*/
107+
public function prependPath($path, $namespace = self::MAIN_NAMESPACE) {
108+
// invalidate the cache
109+
$this->cache = array();
110+
111+
if (!is_dir($path)) {
112+
throw new \Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path));
113+
}
114+
115+
$path = rtrim($path, '/\\');
116+
117+
if (!isset($this->paths[$namespace])) {
118+
$this->paths[$namespace][] = $path;
119+
} else {
120+
array_unshift($this->paths[$namespace], $path);
121+
}
122+
123+
}
124+
125+
/**
126+
* {@inheritdoc}
127+
*/
128+
public function getSource($name) {
129+
return file_get_contents($this->findTemplate($name));
130+
}
131+
132+
/**
133+
* {@inheritdoc}
134+
*/
135+
public function getCacheKey($name) {
136+
return $this->findTemplate($name);
137+
}
138+
139+
/**
140+
* {@inheritdoc}
141+
*/
142+
public function exists($name) {
143+
144+
$name = $this->normalizeName($name);
145+
146+
if (isset($this->cache[$name])) {
147+
return true;
148+
}
149+
150+
try {
151+
$this->findTemplate($name);
152+
153+
return true;
154+
} catch (\Twig_Error_Loader $exception) {
155+
return false;
156+
}
157+
}
158+
159+
/**
160+
* {@inheritdoc}
161+
*/
162+
public function isFresh($name, $time) {
163+
return filemtime($this->findTemplate($name)) <= $time;
164+
}
165+
166+
protected function findTemplate($name) {
167+
168+
list($partialName,$styleModifier,$parameters) = $this->patternLoader->getPartialInfo($name);
169+
170+
$name = $this->patternLoader->getFileName($partialName,$this->extension);
171+
172+
$name = $this->normalizeName($name);
173+
174+
if (isset($this->cache[$name])) {
175+
return $this->cache[$name];
176+
}
177+
178+
$this->validateName($name);
179+
180+
$namespace = self::MAIN_NAMESPACE;
181+
$shortname = $name;
182+
if (isset($name[0]) && '@' == $name[0]) {
183+
if (false === $pos = strpos($name, '/')) {
184+
throw new \Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name));
185+
}
186+
187+
$namespace = substr($name, 1, $pos - 1);
188+
$shortname = substr($name, $pos + 1);
189+
}
190+
191+
if (!isset($this->paths[$namespace])) {
192+
throw new \Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
193+
}
194+
195+
foreach ($this->paths[$namespace] as $path) {
196+
if (is_file($path.'/'.$shortname)) {
197+
return $this->cache[$name] = $path.'/'.$shortname;
198+
}
199+
}
200+
201+
202+
throw new \Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $partialName, implode(', ', $this->paths[$namespace])));
203+
}
204+
205+
protected function normalizeName($name) {
206+
return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));
207+
}
208+
209+
protected function validateName($name) {
210+
211+
if (false !== strpos($name, "\0")) {
212+
throw new \Twig_Error_Loader('A template name cannot contain NUL bytes.');
213+
}
214+
215+
$name = ltrim($name, '/');
216+
$parts = explode('/', $name);
217+
$level = 0;
218+
foreach ($parts as $part) {
219+
if ('..' === $part) {
220+
--$level;
221+
} elseif ('.' !== $part) {
222+
++$level;
223+
}
224+
225+
if ($level < 0) {
226+
throw new \Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name));
227+
}
228+
}
229+
230+
}
231+
232+
}

0 commit comments

Comments
 (0)