Passed
Push — master ( 8ceacb...8c98e8 )
by Jean-Christophe
15:18
created

Twig::__construct()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5.1647

Importance

Changes 4
Bugs 0 Features 2
Metric Value
eloc 16
c 4
b 0
f 2
dl 0
loc 26
ccs 13
cts 16
cp 0.8125
rs 9.4222
cc 5
nc 8
nop 1
crap 5.1647
1
<?php
2
3
namespace Ubiquity\views\engine;
4
5
use Twig\Environment;
6
use Twig\TwigFunction;
7
use Twig\TwigTest;
8
use Twig\Loader\FilesystemLoader;
9
use Ubiquity\cache\CacheManager;
10
use Ubiquity\controllers\Router;
11
use Ubiquity\controllers\Startup;
12
use Ubiquity\core\Framework;
13
use Ubiquity\events\EventsManager;
14
use Ubiquity\events\ViewEvents;
15
use Ubiquity\exceptions\ThemesException;
16
use Ubiquity\translation\TranslatorManager;
17
use Ubiquity\utils\base\UFileSystem;
18
use Ubiquity\themes\ThemesManager;
19
use Ubiquity\assets\AssetsManager;
20
21
/**
22
 * Ubiquity Twig template engine.
23
 *
24
 * Ubiquity\views\engine$Twig
25
 * This class is part of Ubiquity
26
 *
27
 * @author jcheron <[email protected]>
28
 * @version 1.0.11
29
 *
30
 */
31
class Twig extends TemplateEngine {
32
	private $twig;
33
	private $loader;
34
	
35 64
	public function __construct($options = []) {
36 64
		$loader = new FilesystemLoader (\ROOT . \DS . 'views' . \DS);
37 64
		$loader->addPath(Startup::getFrameworkDir().\DS .'..'.\DS .'core'.\DS.'views', 'framework');
38 64
		$this->loader = $loader;
39
		
40 64
		if (($options ['cache'] ?? false) === true) {
41
			$options ['cache'] = CacheManager::getCacheSubDirectory('views');
42
		}
43
		
44 64
		$this->twig = new Environment ($loader, $options);
45
		
46 64
		if (isset($options['extensions'])) {
47
			foreach ($options['extensions'] as $ext) {
48
				$this->twig->addExtension(new $ext());
49
			}
50
		}
51
		
52 64
		if (isset ($options ['activeTheme'])) {
53 63
			ThemesManager::setActiveThemeFromTwig($options ['activeTheme']);
54 63
			$this->setTheme($options ['activeTheme'], ThemesManager::THEMES_FOLDER);
55 63
			unset ($options ['activeTheme']);
56
		} else {
57 2
			$this->loader->setPaths([\ROOT . \DS . 'views'], 'activeTheme');
58
		}
59
		
60 64
		$this->addHelpers();
61 64
	}
62
	
63 64
	protected function addHelpers() {
64 64
		$this->addFunction('path', function ($name, $params = [], $absolute = false) {
65 2
			return Router::path($name, $params, $absolute);
66 64
		});
67
			
68 64
		$this->addFunction('url', function ($name, $params = []) {
69
			return Router::url($name, $params);
70 64
		});
71
				
72 64
		if (\class_exists('\\Ubiquity\\security\\csrf\\UCsrfHttp')) {
73
			$this->addFunction('csrfMeta', function ($name) {
74
				return \Ubiquity\security\csrf\UCsrfHttp::getTokenMeta($name);
75
			}, true);
76
				$this->addFunction('csrf', function ($name) {
77
					return \Ubiquity\security\csrf\UCsrfHttp::getTokenField($name);
78
				}, true);
79
		}
80
		
81 64
		if (\class_exists('\\Ubiquity\security\\acl\\AclManager')) {
82
			$this->addFunction('isAllowedRoute', function ($role, $routeName) {
83
				return \Ubiquity\security\acl\AclManager::isAllowedRoute($role, $routeName);
84
			}, true);
85
		}
86
		
87 64
		$this->addFunction('css', function ($resource, $parameters = [], $absolute = false) {
88 9
			if ($this->hasThemeResource($resource)) {
89 9
				return AssetsManager::css_($resource, $parameters, $absolute);
90
			}
91
			return AssetsManager::css($resource, $parameters, $absolute);
92 64
		}, true);
93
			
94 64
		$this->addFunction('js', function ($resource, $parameters = [], $absolute = false) {
95 1
			if ($this->hasThemeResource($resource)) {
96 1
				return AssetsManager::js_($resource, $parameters, $absolute);
97
			}
98
			return AssetsManager::js($resource, $parameters, $absolute);
99 64
		}, true);
100
			
101 64
		$t = new TwigFunction ('t', function ($context, $id, array $parameters = array(), $domain = null, $locale = null) {
102 1
			$trans = TranslatorManager::trans($id, $parameters, $domain, $locale);
103 1
			return $this->twig->createTemplate($trans)->render($context);
104 64
		}, ['needs_context' => true]);
105
			
106 64
		$tc = new TwigFunction ('tc', function ($context, $id, array $choice, array $parameters = array(), $domain = null, $locale = null) {
107 1
			$trans = TranslatorManager::transChoice($id, $choice, $parameters, $domain, $locale);
108 1
			return $this->twig->createTemplate($trans)->render($context);
109 64
		}, ['needs_context' => true]);
110 64
		$this->twig->addFunction($t);
111 64
		$this->twig->addFunction($tc);
112
		
113 64
		$test = new TwigTest ('instanceOf', function ($var, $class) {
114
			return $var instanceof $class;
115 64
		});
116 64
		$this->twig->addTest($test);
117 64
		$this->twig->addGlobal('app', new Framework ());
118 64
	}
119
	
120 9
	protected function hasThemeResource(&$resource) {
121 9
		$resource = \str_replace('@activeTheme/', '', $resource, $count);
122 9
		return $count > 0;
123
	}
124
	
125 64
	protected function addFunction($name, $callback, $safe = false) {
126 64
		$options = ($safe) ? ['is_safe' => ['html']] : [];
127 64
		$this->twig->addFunction(new TwigFunction ($name, $callback, $options));
128 64
	}
129
	
130
	/*
131
	 * (non-PHPdoc)
132
	 * @see TemplateEngine::render()
133
	 */
134 30
	public function render($viewName, $pData, $asString) {
135 30
		$pData ['config'] = Startup::getConfig();
136 30
		EventsManager::trigger(ViewEvents::BEFORE_RENDER, $viewName, $pData);
137 30
		$render = $this->twig->render($viewName, $pData);
138 30
		EventsManager::trigger(ViewEvents::AFTER_RENDER, $render, $viewName, $pData);
139 30
		if ($asString) {
140 5
			return $render;
141
		} else {
142 30
			echo $render;
143
		}
144 30
	}
145
	
146
	/**
147
	 *
148
	 * {@inheritdoc}
149
	 * @see \Ubiquity\views\engine\TemplateEngine::getBlockNames()
150
	 */
151
	public function getBlockNames($templateName) {
152
		try {
153
			$result = $this->twig->load($templateName)->getBlockNames();
154
		} catch (\Error $e) {
155
			$result = [];
156
		}
157
		return $result;
158
	}
159
	
160
	/**
161
	 *
162
	 * {@inheritdoc}
163
	 * @see \Ubiquity\views\engine\TemplateEngine::getCode()
164
	 */
165 2
	public function getCode($templateName) {
166 2
		return UFileSystem::load($this->twig->load($templateName)->getSourceContext()->getPath());
167
	}
168
	
169
	/**
170
	 * Adds a new path in a namespace
171
	 *
172
	 * @param string $path The path to add
173
	 * @param string $namespace The namespace to use
174
	 */
175 16
	public function addPath(string $path, string $namespace) {
176 16
		$this->loader->addPath($path, $namespace);
177 16
	}
178
179
	/**
180
	 * Sets a path in a namespace
181
	 *
182
	 * @param array $paths The paths to add
183
	 * @param string $namespace The namespace to use
184
	 */
185
	public function setPaths(array $paths, string $namespace) {
186
		$this->loader->setPaths($paths, $namespace);
187
	}
188
	
189
	/**
190
	 * Defines the activeTheme.
191
	 * **activeTheme** namespace is @activeTheme
192
	 *
193
	 * @param string $theme
194
	 * @param string $themeFolder
195
	 * @throws ThemesException
196
	 */
197 63
	public function setTheme($theme, $themeFolder = ThemesManager::THEMES_FOLDER) {
198 63
		$path = \ROOT . \DS . 'views' . \DS . $themeFolder . \DS . $theme;
199 63
		if ($theme == '') {
200
			$path = \ROOT . \DS . 'views';
201
		}
202 63
		if (\file_exists($path)) {
203 63
			$this->loader->setPaths([$path], 'activeTheme');
204
		} else {
205
			throw new ThemesException (sprintf('The path `%s` does not exists!', $path));
206
		}
207 63
	}
208
	
209
	/**
210
	 * Checks if we have the source code of a template, given its name.
211
	 *
212
	 * @param string $name
213
	 * @return boolean
214
	 */
215 1
	public function exists($name) {
216 1
		return $this->twig->getLoader()->exists($name);
217
	}
218
}
219