Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
73.17% |
30 / 41 |
CRAP | |
87.93% |
153 / 174 |
| SyntaxAwareTrait | |
0.00% |
0 / 1 |
|
73.17% |
30 / 41 |
60.32 | |
87.93% |
153 / 174 |
| getFunctionConstraint | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| setFunctions | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| functions | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| getFunctions | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| hasFunction | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| extractFunctions | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| getDirectiveConstraint | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 1 |
|||
| setDirectives | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| directives | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| getDirectives | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| hasDirective | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| extractDirectives | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| setConstants | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| constants | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| getConstants | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| extractConstants | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| setVariables | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| variables | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| getVariables | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| extractVariables | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| setBasePath | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| basePath | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| getBasePath | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| setContentDefault | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| contentDefault | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| getContentDefault | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| setContentBorderMarker | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| contentBorderMarker | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
| getContentBorderMarker | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| compile | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
| preProcess | |
100.00% |
1 / 1 |
4 | |
100.00% |
22 / 22 |
|||
| postProcess | |
100.00% |
1 / 1 |
3 | |
100.00% |
18 / 18 |
|||
| preProcessValueResolver | |
100.00% |
1 / 1 |
1 | |
100.00% |
10 / 10 |
|||
| postProcessValueResolver | |
100.00% |
1 / 1 |
1 | |
100.00% |
10 / 10 |
|||
| execute | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| resolve | |
100.00% |
1 / 1 |
1 | |
100.00% |
11 / 11 |
|||
| resolvePlaceholder | |
100.00% |
1 / 1 |
3 | |
100.00% |
8 / 8 |
|||
| __php | |
100.00% |
1 / 1 |
2 | |
100.00% |
7 / 7 |
|||
| __include | |
0.00% |
0 / 1 |
4.91 | |
61.54% |
8 / 13 |
|||
| __require | |
100.00% |
1 / 1 |
2 | |
100.00% |
9 / 9 |
|||
| readResource | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| <?php | |
| namespace Doozer\Syntax; | |
| /** | |
| * Doozer - Syntax - SyntaxAwareTrait. | |
| * | |
| * SyntaxAwareTrait.php - Syntax trait enriching classes with parser, interpreter and compiler for expression support. | |
| * | |
| * PHP versions 5.6 | |
| * | |
| * LICENSE: | |
| * | |
| * The MIT License (MIT) | |
| * | |
| * Copyright (c) 2005 - 2016, Benjamin Carl - All rights reserved. | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy of this software | |
| * and associated documentation files (the "Software"), to deal in the Software without restriction, | |
| * including without limitation the rights to use, copy, modify, merge, publish, distribute, | |
| * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is | |
| * furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in all copies or | |
| * substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT | |
| * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| * | |
| * Please feel free to contact us via e-mail: opensource@clickalicious.de | |
| * | |
| * @category Doozer-Framework | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * @copyright 2005 - 2016 Benjamin Carl | |
| * @license https://opensource.org/licenses/MIT The MIT License | |
| * | |
| * @version Git: $Id: ce3c910d2b2430dfec0a5bbc2ef27afdb92ccaa2 $ | |
| * | |
| * @link https://github.com/Doozer-Framework/Syntax | |
| */ | |
| use Doozer\Syntax\Exception\CompilerException; | |
| use Doozer\Syntax\Exception\ExecutionFailedException; | |
| use Doozer\Syntax\Exception\FileNotFoundException; | |
| use Doozer\Syntax\Exception\IncludeFailedException; | |
| use Doozer\Syntax\Exception\PostProcessorException; | |
| use Doozer\Syntax\Exception\PreProcessorException; | |
| use Doozer\Syntax\Exception\RequireFailedException; | |
| use Doozer\Syntax\Exception\ResolvePlaceholderException; | |
| use Doozer\Syntax\Exception\SyntaxException; | |
| /** | |
| * SyntaxAwareTrait | |
| * Syntax trait enriching classes with parser, interpreter and compiler for expression support. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| trait SyntaxAwareTrait | |
| { | |
| /** | |
| * The directives of Doozer syntax. | |
| * The bool value controls fail-on-error status (true|false). | |
| * Directives are executed before variables or constants are being resolved. | |
| * | |
| * If set to (bool)"true" then parser will fail with exception, | |
| * otherwise (bool)"false" will continue on error. | |
| * | |
| * @var array | |
| */ | |
| protected $directives = [ | |
| 'include' => false, // Include Directive: {{include($filename)}} | |
| 'require' => true, // Require Directive: {{require($filename)}} | |
| ]; | |
| /** | |
| * The functions of Doozer syntax. | |
| * The bool value controls fail-on-error status (true|false). | |
| * Functions are executed after variables or constants are being resolved. | |
| * So variables and or constants can be used as arguments. | |
| * | |
| * If set to (bool)"true" then parser will fail with exception, | |
| * otherwise (bool)"false" will continue on error. | |
| * | |
| * @var array | |
| */ | |
| protected $functions = [ | |
| 'php' => true, // PHP Function: {{php(function(){...})}} | |
| ]; | |
| /** | |
| * Key => value collection of constants for compiling. | |
| * | |
| * @var array | |
| */ | |
| protected $constants = []; | |
| /** | |
| * Key => value collection of variables for compiling. | |
| * | |
| * @var array | |
| */ | |
| protected $variables = []; | |
| /** | |
| * Base path for included or required files. | |
| * | |
| * @var string | |
| */ | |
| protected $basePath = ''; | |
| /** | |
| * Default content returned on failed include. | |
| * | |
| * @var string | |
| */ | |
| protected $contentDefault = ''; | |
| /** | |
| * Content border marker. | |
| * | |
| * @example If we use this trait in JSON context we would set this marker to " (double qoute). | |
| * So JSON keeps valid and on compile we use the border marker when replacing content "{{...}}" | |
| * | |
| * @var string | |
| */ | |
| protected $contentBorderMarker = ''; | |
| /** | |
| * Returns the constraint for a passed function. | |
| * | |
| * @param string $identifier Identifier of constraint to return. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return mixed | |
| */ | |
| protected function getFunctionConstraint($identifier) | |
| { | |
| return $this->functions[$identifier]; | |
| } | |
| /** | |
| * Setter for functions. | |
| * | |
| * @param array $functions Functions to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setFunctions(array $functions = []) | |
| { | |
| $this->functions = $functions; | |
| } | |
| /** | |
| * Fluent: Setter for functions. | |
| * | |
| * @param array $functions Functions to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function functions(array $functions = []) | |
| { | |
| $this->setFunctions($functions); | |
| return $this; | |
| } | |
| /** | |
| * Getter for functions. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array|null Collection of functions if set, otherwise NULL | |
| */ | |
| protected function getFunctions() | |
| { | |
| return $this->functions; | |
| } | |
| /** | |
| * Validates a passed function against defined ones. | |
| * | |
| * @param string $function Function to validate | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return bool TRUE if function is valid, otherwise FALSE | |
| */ | |
| protected function hasFunction($function) | |
| { | |
| return isset($this->getFunctions()[$function]); | |
| } | |
| /** | |
| * Returns the extracted functions of a passed string. | |
| * | |
| * @param string $buffer Buffer to extract functions from | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array Of found functions or empty one if no matches | |
| */ | |
| protected function extractFunctions($buffer) | |
| { | |
| $pattern = '/\{{2}(php)\({1}([A-Za-z0-9_\-\.\{\}\\\'\(\)\s\;\/$=<>]+)\){1}\}{2}/u'; | |
| preg_match_all($pattern, $buffer, $result); | |
| return $result; | |
| } | |
| /** | |
| * Returns the constraint for a passed directive. | |
| * | |
| * @param string $identifier Identifier of constraint to return. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return mixed | |
| */ | |
| protected function getDirectiveConstraint($identifier) | |
| { | |
| return $this->directives[$identifier]; | |
| } | |
| /** | |
| * Setter for directives. | |
| * | |
| * @param array $directives Directives to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setDirectives(array $directives = []) | |
| { | |
| $this->directives = $directives; | |
| } | |
| /** | |
| * Fluent: Setter for directives. | |
| * | |
| * @param array $directives Directives to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function directives(array $directives = []) | |
| { | |
| $this->setDirectives($directives); | |
| return $this; | |
| } | |
| /** | |
| * Getter for directives. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array|null Collection of directives if set, otherwise NULL | |
| */ | |
| protected function getDirectives() | |
| { | |
| return $this->directives; | |
| } | |
| /** | |
| * Validates a passed directive against defined ones. | |
| * | |
| * @param string $directive Directive to validate | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return bool TRUE if directive is valid, otherwise FALSE | |
| */ | |
| protected function hasDirective($directive) | |
| { | |
| return isset($this->getDirectives()[$directive]); | |
| } | |
| /** | |
| * Returns the extracted directives of a passed string. | |
| * | |
| * @param string $buffer Buffer to extract directives from | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array Of found directives or empty one if no matches | |
| */ | |
| protected function extractDirectives($buffer) | |
| { | |
| $pattern = '/\{{2}([a-z]+)\({1}([A-Za-z0-9_\-\.\/]+)\){1}\}{2}/u'; | |
| preg_match_all($pattern, $buffer, $result); | |
| return $result; | |
| } | |
| /** | |
| * Setter for constants. | |
| * | |
| * @param array $constants Variables to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setConstants(array $constants = []) | |
| { | |
| $this->constants = $constants; | |
| } | |
| /** | |
| * Fluent: Setter for constants. | |
| * | |
| * @param array $constants Variables to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function constants(array $constants = []) | |
| { | |
| $this->setConstants($constants); | |
| return $this; | |
| } | |
| /** | |
| * Getter for constants. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array|null Collection of constants if set, otherwise NULL | |
| */ | |
| protected function getConstants() | |
| { | |
| return $this->constants; | |
| } | |
| /** | |
| * Returns the extracted constants of a passed string. | |
| * | |
| * @param string $buffer Buffer to parse | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array Of found constants or empty one if no matches | |
| */ | |
| protected function extractConstants($buffer) | |
| { | |
| $pattern = '/\{{2}([A-Z0-9_]{1,255})\}{2}/'; | |
| preg_match_all($pattern, $buffer, $result); | |
| return array_unique($result[1]); | |
| } | |
| /** | |
| * Setter for variables. | |
| * | |
| * @param array $variables Variables to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setVariables(array $variables = []) | |
| { | |
| $this->variables = $variables; | |
| } | |
| /** | |
| * Fluent: Setter for variables. | |
| * | |
| * @param array $variables Variables to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function variables(array $variables = []) | |
| { | |
| $this->setVariables($variables); | |
| return $this; | |
| } | |
| /** | |
| * Getter for variables. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array|null Collection of variables if set, otherwise NULL | |
| */ | |
| protected function getVariables() | |
| { | |
| return $this->variables; | |
| } | |
| /** | |
| * Returns the extracted variables of a passed string. | |
| * | |
| * @param string $buffer Buffer to parse | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return array Of found constants or empty one if no matches | |
| */ | |
| protected function extractVariables($buffer) | |
| { | |
| $pattern = '/\{{2}([a-z0-9\._]{1,255})\}{2}/'; | |
| preg_match_all($pattern, $buffer, $result); | |
| return array_unique($result[1]); | |
| } | |
| /** | |
| * Setter for basePath. | |
| * | |
| * @param string $basePath BasePath to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setBasePath($basePath) | |
| { | |
| $this->basePath = $basePath; | |
| } | |
| /** | |
| * Fluent: Setter for basePath. | |
| * | |
| * @param string $basePath BasePath to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function basePath($basePath) | |
| { | |
| $this->setBasePath($basePath); | |
| return $this; | |
| } | |
| /** | |
| * Getter for basePath. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string The basePath | |
| */ | |
| protected function getBasePath() | |
| { | |
| return $this->basePath; | |
| } | |
| /** | |
| * Setter for contentDefault. | |
| * | |
| * @param string $contentDefault DefaultContent to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setContentDefault($contentDefault) | |
| { | |
| $this->contentDefault = $contentDefault; | |
| } | |
| /** | |
| * Fluent: Setter for contentDefault. | |
| * | |
| * @param string $contentDefault DefaultContent to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function contentDefault($contentDefault) | |
| { | |
| $this->setContentDefault($contentDefault); | |
| return $this; | |
| } | |
| /** | |
| * Getter for contentDefault. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string The contentDefault | |
| */ | |
| protected function getContentDefault() | |
| { | |
| return $this->contentDefault; | |
| } | |
| /** | |
| * Setter for contentBorderMarker. | |
| * | |
| * @param string $contentBorderMarker DefaultContent to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| */ | |
| protected function setContentBorderMarker($contentBorderMarker) | |
| { | |
| $this->contentBorderMarker = $contentBorderMarker; | |
| } | |
| /** | |
| * Fluent: Setter for contentBorderMarker. | |
| * | |
| * @param string $contentBorderMarker DefaultContent to set. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return $this Instance for chaining | |
| */ | |
| protected function contentBorderMarker($contentBorderMarker) | |
| { | |
| $this->setContentBorderMarker($contentBorderMarker); | |
| return $this; | |
| } | |
| /** | |
| * Getter for contentBorderMarker. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string The contentBorderMarker | |
| */ | |
| protected function getContentBorderMarker() | |
| { | |
| return $this->contentBorderMarker; | |
| } | |
| /** | |
| * Combines the whole stack of calls required to compile any kind of Doozer syntax. | |
| * | |
| * @param string $sourceCode Source code to compile | |
| * | |
| * @return string Compiled source code. | |
| * | |
| * @throws CompilerException | |
| */ | |
| protected function compile($sourceCode) | |
| { | |
| try { | |
| $sourceCode = $this->preProcess($sourceCode); | |
| $sourceCode = $this->resolve($sourceCode); | |
| $sourceCode = $this->postProcess($sourceCode); | |
| } catch (\Exception $exception) { | |
| throw new CompilerException( | |
| $exception->getMessage(), | |
| null, | |
| $exception | |
| ); | |
| } | |
| return $sourceCode; | |
| } | |
| /** | |
| * Pre-processes source and returns interpolated content for compiler. | |
| * | |
| * @link http://www.cprogramming.com/reference/preprocessor/ | |
| * | |
| * @param string $sourceCode Source to process | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Processed result | |
| * | |
| * @throws SyntaxException | |
| * @throws PreProcessorException | |
| */ | |
| protected function preProcess($sourceCode) | |
| { | |
| $directives = $this->extractDirectives($sourceCode); | |
| $countDirectives = count($directives[0]); | |
| for ($i = 0; $i < $countDirectives; ++$i) { | |
| $syntax = $directives[0][$i]; | |
| $directive = $directives[1][$i]; | |
| $argument = $directives[2][$i]; | |
| if (true !== $this->hasDirective($directive)) { | |
| throw new SyntaxException( | |
| sprintf('Syntax error. Directive "%s" is invalid and could not be processed.', $directive) | |
| ); | |
| } | |
| try { | |
| $sourceCode = $this->preProcessValueResolver( | |
| $sourceCode, | |
| $directives[0][$i], | |
| $this->execute($directive, $argument) | |
| ); | |
| } catch (\Exception $exception) { | |
| throw new PreProcessorException( | |
| sprintf('Error processing directive "%s".', $syntax), | |
| null, | |
| $exception | |
| ); | |
| } | |
| } | |
| return $sourceCode; | |
| } | |
| /** | |
| * Post processing of source code. | |
| * This part of compiler is responsible for executing function calls which can | |
| * rely on previously resolved variables or constants. | |
| * | |
| * @param string $sourceCode Source code being post processed. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Post processed source code. | |
| * | |
| * @throws SyntaxException | |
| * @throws PostProcessorException | |
| */ | |
| protected function postProcess($sourceCode) | |
| { | |
| $functions = $this->extractFunctions($sourceCode); | |
| $countFunctions = count($functions[0]); | |
| for ($i = 0; $i < $countFunctions; ++$i) { | |
| $syntax = $functions[0][$i]; | |
| $function = $functions[1][$i]; | |
| $argument = $functions[2][$i]; | |
| try { | |
| $sourceCode = $this->postProcessValueResolver( | |
| $sourceCode, | |
| $functions[0][$i], | |
| $this->execute($function, $argument) | |
| ); | |
| } catch (\Exception $exception) { | |
| throw new PostProcessorException( | |
| sprintf('Error processing function "%s".', $syntax), | |
| null, | |
| $exception | |
| ); | |
| } | |
| } | |
| return $sourceCode; | |
| } | |
| protected function preProcessValueResolver($sourceCode, $placeholder, $value) | |
| { | |
| // Construct marker for replace | |
| $marker = sprintf( | |
| '%s%s%s', | |
| $this->getContentBorderMarker(), | |
| $placeholder, | |
| $this->getContentBorderMarker() | |
| ); | |
| return str_replace( | |
| $marker, | |
| $value, | |
| $sourceCode | |
| ); | |
| } | |
| protected function postProcessValueResolver($sourceCode, $placeholder, $value) | |
| { | |
| // Construct marker for replace | |
| $marker = sprintf( | |
| '%s%s%s', | |
| $this->getContentBorderMarker(), | |
| $placeholder, | |
| $this->getContentBorderMarker() | |
| ); | |
| return str_replace( | |
| $marker, | |
| $value, | |
| $sourceCode | |
| ); | |
| /* | |
| // JSON thingy ?! | |
| if (true === is_string($result)) { | |
| $marker = '%s'; | |
| } else { | |
| $marker = '"%s"'; | |
| $result = json_encode($result); | |
| } | |
| */ | |
| } | |
| /** | |
| * Executes a directive like "require" or "include". | |
| * | |
| * @param string $directive Directive to execute. | |
| * @param string $argument Arguments to pass to execution. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return mixed Result of execution | |
| * | |
| * @throws RequireFailedException | |
| * @throws IncludeFailedException | |
| * @throws ExecutionFailedException | |
| */ | |
| protected function execute($directive, $argument) | |
| { | |
| return $this->{'__'.$directive}($argument); | |
| } | |
| /** | |
| * Compiles (replacing {{VARIABLES & CONSTANTS}}) a preprocessed buffer to final result. | |
| * | |
| * @param string $buffer Buffer to compile | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Compiled buffer | |
| * | |
| * @throws ResolvePlaceholderException | |
| */ | |
| protected function resolve($buffer) | |
| { | |
| // Replace constants | |
| $buffer = $this->resolvePlaceholder( | |
| $buffer, | |
| $this->extractConstants($buffer), | |
| $this->getConstants() | |
| ); | |
| // Replace variables | |
| $buffer = $this->resolvePlaceholder( | |
| $buffer, | |
| $this->extractVariables($buffer), | |
| $this->getVariables() | |
| ); | |
| return $buffer; | |
| } | |
| /** | |
| * Generic placeholder replacer for variables & constants. | |
| * | |
| * @param string $buffer Buffer to resolve placeholder in. | |
| * @param array $placeholders Collection of placeholders to be replaced. | |
| * @param array $replacements Collection of key => value pairs used for resolving. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Buffer with replaced content. | |
| * | |
| * @throws ResolvePlaceholderException | |
| */ | |
| protected function resolvePlaceholder($buffer, array $placeholders, array $replacements) | |
| { | |
| foreach ($placeholders as $placeholder) { | |
| if (false === isset($replacements[$placeholder])) { | |
| throw new ResolvePlaceholderException( | |
| sprintf('Placeholder "%s" can not be resolved. Value not found!', $placeholder) | |
| ); | |
| } | |
| $buffer = str_replace('{{'.$placeholder.'}}', $replacements[$placeholder], $buffer); | |
| } | |
| return $buffer; | |
| } | |
| /** | |
| * Implementation of __php. | |
| * | |
| * @param string $code Code to be executed. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Result of operation | |
| * | |
| * @throws ExecutionFailedException | |
| */ | |
| protected function __php($code) | |
| { | |
| // Inject return to receive closure via eval() | |
| $code = 'return '.$code; | |
| $code = @eval($code); | |
| if (false === $code) { | |
| throw new ExecutionFailedException( | |
| sprintf('Executing PHP code "%s" failed.', $code) | |
| ); | |
| } | |
| // Execute closure and receive result (must be string or \stdClass) | |
| return $code(); | |
| } | |
| /** | |
| * Includes a resource. | |
| * | |
| * @param mixed $identifier Identifier for resource to include. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return mixed Result of inclusion. | |
| * | |
| * @throws IncludeFailedException On any exceptional behavior. | |
| */ | |
| protected function __include($identifier) | |
| { | |
| $resource = realpath($this->getBasePath().$identifier); | |
| $content = $this->getContentDefault(); | |
| if (false !== $resource) { | |
| try { | |
| $sourceCode = $this->readResource($resource); | |
| $content = $this->compile($sourceCode); | |
| } catch (FileNotFoundException $exception) { | |
| // Intentionally left empty. | |
| } catch (\Exception $exception) { | |
| throw new IncludeFailedException( | |
| sprintf('Error processing include "%s".', $resource), | |
| null, | |
| $exception | |
| ); | |
| } | |
| } | |
| return $content; | |
| } | |
| /** | |
| * Requires a resource and return its content. | |
| * | |
| * @param mixed $identifier Identifier for require. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return mixed Result of inclusion. | |
| * | |
| * @throws RequireFailedException On any exceptional behavior. | |
| */ | |
| protected function __require($identifier) | |
| { | |
| $resource = realpath($this->getBasePath().$identifier); | |
| try { | |
| $sourceCode = $this->readResource($resource); | |
| $content = $this->compile($sourceCode); | |
| } catch (\Exception $exception) { | |
| throw new RequireFailedException( | |
| sprintf('Error requiring resource "%s".', $identifier), | |
| null, | |
| $exception | |
| ); | |
| } | |
| return $content; | |
| } | |
| /** | |
| * Reads given resource from filesystem and returns content as string. | |
| * | |
| * @param string $resource Resource to read int string. | |
| * | |
| * @author Benjamin Carl <opensource@clickalicious.de> | |
| * | |
| * @return string Content of resource | |
| * | |
| * @throws FileNotFoundException If a file could not be found | |
| */ | |
| protected function readResource($resource) | |
| { | |
| if (true !== file_exists($resource)) { | |
| throw new FileNotFoundException( | |
| sprintf('File "%s" can not be found.', $resource) | |
| ); | |
| } | |
| return file_get_contents($resource); | |
| } | |
| } |