PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev2
Elementor Website Builder – more than just a page builder v3.28.0-dev2
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / vendor_prefixed / twig / src / ExtensionSet.php

ExtensionSet.php in Elementor Website Builder – more than just a page builder 3.28.0-dev2, at vendor_prefixed/twig/src/ExtensionSet.php

395 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace ElementorDeps\Twig;
12
13 use ElementorDeps\Twig\Error\RuntimeError;
14 use ElementorDeps\Twig\Extension\ExtensionInterface;
15 use ElementorDeps\Twig\Extension\GlobalsInterface;
16 use ElementorDeps\Twig\Extension\StagingExtension;
17 use ElementorDeps\Twig\Node\Expression\AbstractExpression;
18 use ElementorDeps\Twig\Node\Expression\Binary\AbstractBinary;
19 use ElementorDeps\Twig\Node\Expression\Unary\AbstractUnary;
20 use ElementorDeps\Twig\NodeVisitor\NodeVisitorInterface;
21 use ElementorDeps\Twig\TokenParser\TokenParserInterface;
22 /**
23 * @author Fabien Potencier <fabien@symfony.com>
24 *
25 * @internal
26 */
27 final class ExtensionSet
28 {
29 private $extensions;
30 private $initialized = \false;
31 private $runtimeInitialized = \false;
32 private $staging;
33 private $parsers;
34 private $visitors;
35 /** @var array<string, TwigFilter> */
36 private $filters;
37 /** @var array<string, TwigTest> */
38 private $tests;
39 /** @var array<string, TwigFunction> */
40 private $functions;
41 /** @var array<string, array{precedence: int, class: class-string<AbstractExpression>}> */
42 private $unaryOperators;
43 /** @var array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}> */
44 private $binaryOperators;
45 /** @var array<string, mixed> */
46 private $globals;
47 private $functionCallbacks = [];
48 private $filterCallbacks = [];
49 private $parserCallbacks = [];
50 private $lastModified = 0;
51 public function __construct()
52 {
53 $this->staging = new StagingExtension();
54 }
55 public function initRuntime()
56 {
57 $this->runtimeInitialized = \true;
58 }
59 public function hasExtension(string $class) : bool
60 {
61 return isset($this->extensions[\ltrim($class, '\\')]);
62 }
63 public function getExtension(string $class) : ExtensionInterface
64 {
65 $class = \ltrim($class, '\\');
66 if (!isset($this->extensions[$class])) {
67 throw new RuntimeError(\sprintf('The "%s" extension is not enabled.', $class));
68 }
69 return $this->extensions[$class];
70 }
71 /**
72 * @param ExtensionInterface[] $extensions
73 */
74 public function setExtensions(array $extensions) : void
75 {
76 foreach ($extensions as $extension) {
77 $this->addExtension($extension);
78 }
79 }
80 /**
81 * @return ExtensionInterface[]
82 */
83 public function getExtensions() : array
84 {
85 return $this->extensions;
86 }
87 public function getSignature() : string
88 {
89 return \json_encode(\array_keys($this->extensions));
90 }
91 public function isInitialized() : bool
92 {
93 return $this->initialized || $this->runtimeInitialized;
94 }
95 public function getLastModified() : int
96 {
97 if (0 !== $this->lastModified) {
98 return $this->lastModified;
99 }
100 foreach ($this->extensions as $extension) {
101 $r = new \ReflectionObject($extension);
102 if (\is_file($r->getFileName()) && ($extensionTime = \filemtime($r->getFileName())) > $this->lastModified) {
103 $this->lastModified = $extensionTime;
104 }
105 }
106 return $this->lastModified;
107 }
108 public function addExtension(ExtensionInterface $extension) : void
109 {
110 $class = \get_class($extension);
111 if ($this->initialized) {
112 throw new \LogicException(\sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class));
113 }
114 if (isset($this->extensions[$class])) {
115 throw new \LogicException(\sprintf('Unable to register extension "%s" as it is already registered.', $class));
116 }
117 $this->extensions[$class] = $extension;
118 }
119 public function addFunction(TwigFunction $function) : void
120 {
121 if ($this->initialized) {
122 throw new \LogicException(\sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName()));
123 }
124 $this->staging->addFunction($function);
125 }
126 /**
127 * @return TwigFunction[]
128 */
129 public function getFunctions() : array
130 {
131 if (!$this->initialized) {
132 $this->initExtensions();
133 }
134 return $this->functions;
135 }
136 public function getFunction(string $name) : ?TwigFunction
137 {
138 if (!$this->initialized) {
139 $this->initExtensions();
140 }
141 if (isset($this->functions[$name])) {
142 return $this->functions[$name];
143 }
144 foreach ($this->functions as $pattern => $function) {
145 $pattern = \str_replace('\\*', '(.*?)', \preg_quote($pattern, '#'), $count);
146 if ($count && \preg_match('#^' . $pattern . '$#', $name, $matches)) {
147 \array_shift($matches);
148 $function->setArguments($matches);
149 return $function;
150 }
151 }
152 foreach ($this->functionCallbacks as $callback) {
153 if (\false !== ($function = $callback($name))) {
154 return $function;
155 }
156 }
157 return null;
158 }
159 public function registerUndefinedFunctionCallback(callable $callable) : void
160 {
161 $this->functionCallbacks[] = $callable;
162 }
163 public function addFilter(TwigFilter $filter) : void
164 {
165 if ($this->initialized) {
166 throw new \LogicException(\sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName()));
167 }
168 $this->staging->addFilter($filter);
169 }
170 /**
171 * @return TwigFilter[]
172 */
173 public function getFilters() : array
174 {
175 if (!$this->initialized) {
176 $this->initExtensions();
177 }
178 return $this->filters;
179 }
180 public function getFilter(string $name) : ?TwigFilter
181 {
182 if (!$this->initialized) {
183 $this->initExtensions();
184 }
185 if (isset($this->filters[$name])) {
186 return $this->filters[$name];
187 }
188 foreach ($this->filters as $pattern => $filter) {
189 $pattern = \str_replace('\\*', '(.*?)', \preg_quote($pattern, '#'), $count);
190 if ($count && \preg_match('#^' . $pattern . '$#', $name, $matches)) {
191 \array_shift($matches);
192 $filter->setArguments($matches);
193 return $filter;
194 }
195 }
196 foreach ($this->filterCallbacks as $callback) {
197 if (\false !== ($filter = $callback($name))) {
198 return $filter;
199 }
200 }
201 return null;
202 }
203 public function registerUndefinedFilterCallback(callable $callable) : void
204 {
205 $this->filterCallbacks[] = $callable;
206 }
207 public function addNodeVisitor(NodeVisitorInterface $visitor) : void
208 {
209 if ($this->initialized) {
210 throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.');
211 }
212 $this->staging->addNodeVisitor($visitor);
213 }
214 /**
215 * @return NodeVisitorInterface[]
216 */
217 public function getNodeVisitors() : array
218 {
219 if (!$this->initialized) {
220 $this->initExtensions();
221 }
222 return $this->visitors;
223 }
224 public function addTokenParser(TokenParserInterface $parser) : void
225 {
226 if ($this->initialized) {
227 throw new \LogicException('Unable to add a token parser as extensions have already been initialized.');
228 }
229 $this->staging->addTokenParser($parser);
230 }
231 /**
232 * @return TokenParserInterface[]
233 */
234 public function getTokenParsers() : array
235 {
236 if (!$this->initialized) {
237 $this->initExtensions();
238 }
239 return $this->parsers;
240 }
241 public function getTokenParser(string $name) : ?TokenParserInterface
242 {
243 if (!$this->initialized) {
244 $this->initExtensions();
245 }
246 if (isset($this->parsers[$name])) {
247 return $this->parsers[$name];
248 }
249 foreach ($this->parserCallbacks as $callback) {
250 if (\false !== ($parser = $callback($name))) {
251 return $parser;
252 }
253 }
254 return null;
255 }
256 public function registerUndefinedTokenParserCallback(callable $callable) : void
257 {
258 $this->parserCallbacks[] = $callable;
259 }
260 /**
261 * @return array<string, mixed>
262 */
263 public function getGlobals() : array
264 {
265 if (null !== $this->globals) {
266 return $this->globals;
267 }
268 $globals = [];
269 foreach ($this->extensions as $extension) {
270 if (!$extension instanceof GlobalsInterface) {
271 continue;
272 }
273 $extGlobals = $extension->getGlobals();
274 if (!\is_array($extGlobals)) {
275 throw new \UnexpectedValueException(\sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension)));
276 }
277 $globals = \array_merge($globals, $extGlobals);
278 }
279 if ($this->initialized) {
280 $this->globals = $globals;
281 }
282 return $globals;
283 }
284 public function addTest(TwigTest $test) : void
285 {
286 if ($this->initialized) {
287 throw new \LogicException(\sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName()));
288 }
289 $this->staging->addTest($test);
290 }
291 /**
292 * @return TwigTest[]
293 */
294 public function getTests() : array
295 {
296 if (!$this->initialized) {
297 $this->initExtensions();
298 }
299 return $this->tests;
300 }
301 public function getTest(string $name) : ?TwigTest
302 {
303 if (!$this->initialized) {
304 $this->initExtensions();
305 }
306 if (isset($this->tests[$name])) {
307 return $this->tests[$name];
308 }
309 foreach ($this->tests as $pattern => $test) {
310 $pattern = \str_replace('\\*', '(.*?)', \preg_quote($pattern, '#'), $count);
311 if ($count) {
312 if (\preg_match('#^' . $pattern . '$#', $name, $matches)) {
313 \array_shift($matches);
314 $test->setArguments($matches);
315 return $test;
316 }
317 }
318 }
319 return null;
320 }
321 /**
322 * @return array<string, array{precedence: int, class: class-string<AbstractExpression>}>
323 */
324 public function getUnaryOperators() : array
325 {
326 if (!$this->initialized) {
327 $this->initExtensions();
328 }
329 return $this->unaryOperators;
330 }
331 /**
332 * @return array<string, array{precedence: int, class?: class-string<AbstractExpression>, associativity: ExpressionParser::OPERATOR_*}>
333 */
334 public function getBinaryOperators() : array
335 {
336 if (!$this->initialized) {
337 $this->initExtensions();
338 }
339 return $this->binaryOperators;
340 }
341 private function initExtensions() : void
342 {
343 $this->parsers = [];
344 $this->filters = [];
345 $this->functions = [];
346 $this->tests = [];
347 $this->visitors = [];
348 $this->unaryOperators = [];
349 $this->binaryOperators = [];
350 foreach ($this->extensions as $extension) {
351 $this->initExtension($extension);
352 }
353 $this->initExtension($this->staging);
354 // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
355 $this->initialized = \true;
356 }
357 private function initExtension(ExtensionInterface $extension) : void
358 {
359 // filters
360 foreach ($extension->getFilters() as $filter) {
361 $this->filters[$filter->getName()] = $filter;
362 }
363 // functions
364 foreach ($extension->getFunctions() as $function) {
365 $this->functions[$function->getName()] = $function;
366 }
367 // tests
368 foreach ($extension->getTests() as $test) {
369 $this->tests[$test->getName()] = $test;
370 }
371 // token parsers
372 foreach ($extension->getTokenParsers() as $parser) {
373 if (!$parser instanceof TokenParserInterface) {
374 throw new \LogicException('getTokenParsers() must return an array of \\Twig\\TokenParser\\TokenParserInterface.');
375 }
376 $this->parsers[$parser->getTag()] = $parser;
377 }
378 // node visitors
379 foreach ($extension->getNodeVisitors() as $visitor) {
380 $this->visitors[] = $visitor;
381 }
382 // operators
383 if ($operators = $extension->getOperators()) {
384 if (!\is_array($operators)) {
385 throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators) . (\is_resource($operators) ? '' : '#' . $operators)));
386 }
387 if (2 !== \count($operators)) {
388 throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators)));
389 }
390 $this->unaryOperators = \array_merge($this->unaryOperators, $operators[0]);
391 $this->binaryOperators = \array_merge($this->binaryOperators, $operators[1]);
392 }
393 }
394 }
395