Files
fmgapp/framework/templating/DefaultImplementation.php

518 lines
13 KiB
PHP
Executable File

<?php declare(strict_types=1); namespace IR\Templating; if (!defined('IR_START')) exit('<pre>No direct script access allowed</pre>');
/**
* @framework Wevads Framework
* @version 1.0
* @author Amine Idrissi <contact@iresponse.tech>
* @date 2019
* @name DefaultImplementation.php
*/
# core
use IR\Core\Registry as Registry;
use IR\Core\Application as Application;
# utilities
use IR\Utils\Types\Strings as Strings;
# routing
use IR\Routing\Router as Router;
# http
use IR\Http\Request as Request;
/**
* @name DefaultImplementation
* @description DefaultImplementation class
*/
class DefaultImplementation extends Implementation
{
/**
* @name __construct
* @description the class constructor
* @access public
* @param string $options
* @return Extended
*/
public function __construct($options = [])
{
parent::__construct($options);
$this->_defaultPath = VIEWS_PATH;
$this->_map = [
"partial" => [
"opener" => "{partial",
"closer" => "}",
"handler" => "_partial"
],
"include" => [
"opener" => "{include",
"closer" => "}",
"handler" => "_include"
],
"yield" => [
"opener" => "{yield",
"closer" => "}",
"handler" => "_yield"
]
] + $this->_map;
$this->_map["statement"]["tags"] = [
"set" => [
"isolated" => false,
"arguments" => "{key}",
"handler" => "set"
],
"append" => [
"isolated" => false,
"arguments" => "{key}",
"handler" => "append"
],
"prepend" => [
"isolated" => false,
"arguments" => "{key}",
"handler" => "prepend"
]
] + $this->_map["statement"]["tags"];
}
/**
* @name set
* @description
* @access public
* @param string $key
* @param string $value
* @return
*/
public function set($key, $value)
{
if (Strings::getInstance()->indexOf($value, "\$_text") > -1)
{
$first = Strings::getInstance()->indexOf($value, "\"");
$last = Strings::getInstance()->indexOf($value, "\"");
$value = stripslashes(substr($value, $first + 1, ($last - $first) - 1));
}
if (is_array($key))
{
$key = $this->_getKey($key);
}
$this->_setValue($key, $value);
}
/**
* @name append
* @description
* @access public
* @param string $key
* @param string $value
* @return
*/
public function append($key, $value)
{
if (is_array($key))
{
$key = $this->_getKey($key);
}
$previous = $this->_getValue($key);
$this->set($key, $previous.$value);
}
/**
* @name prepend
* @description
* @access public
* @param string $key
* @param string $value
* @return
*/
public function prepend($key, $value)
{
if (is_array($key))
{
$key = $this->_getKey($key);
}
$previous = $this->_getValue($key);
$this->set($key, $value.$previous);
}
/**
* @name _yield
* @description
* @access protected
* @param array $tree
* @param string $content
* @return
*/
public function _yield($tree, $content)
{
$content = trim($content);
$key = trim($tree["raw"]);
$value = addslashes($this->_getValue($key));
return "\n\$_text[] = \"{$value}\";\n";
}
/**
* @name _getKey
* @description
* @access protected
* @param array $tree
* @return
*/
protected function _getKey($tree)
{
if (empty($tree["arguments"]["key"]))
{
return null;
}
return trim($tree["arguments"]["key"]);
}
/**
* @name _setValue
* @description
* @access protected
* @param array $key
* @param string $value
* @return
*/
protected function _setValue($key, $value)
{
if (!empty($key))
{
$default = $this->getDefaultKey();
$data = Registry::getInstance()->get($default,[]);
$data[$key] = $value;
Registry::getInstance()->set($default, $data);
}
}
/**
* @name _getValue
* @description
* @access protected
* @param array $key
* @return string
*/
protected function _getValue($key)
{
$data = Registry::getInstance()->get($this->getDefaultKey());
if (isset($data[$key]))
{
return $data[$key];
}
return "";
}
/**
* @name _include
* @description
* @access protected
* @param array $tree
* @param array $content
* @return string
*/
protected function _include($tree)
{
$file = trim($tree["raw"]);
if(Application::isValid())
{
if(Application::getCurrent()->router instanceof Router)
{
$file = str_replace('$__page',Application::getCurrent()->router->controller, $file);
}
}
$finalFilePath = $this->getDefaultPath() . DS . $file;
if(file_exists($finalFilePath))
{
$template = new Template([
"implementation" => new self()
]);
if(count(file($finalFilePath,FILE_IGNORE_NEW_LINES)))
{
$template->parse($finalFilePath);
$functionName = 'anon_' . Strings::getInstance()->random(8,true,false,true,false);
return "function $functionName(\$_data){" . $template->getCode() . "};\n\$_text[] = $functionName(\$_data);\n";
}
}
return '';
}
/**
* @name _partial
* @description
* @access protected
* @param array $tree
* @return string
*/
protected function _partial($tree)
{
$address = trim($tree["raw"], " /");
if (Strings::getInstance()->indexOf($address, "http") != 0)
{
$host = Request::getInstance()->retrieve('HTTP_HOST',Request::SERVER);
$address = "http://{$host}/{$address}";
}
$response = Request::getInstance()->curl(trim($address));
return "\n\$_text[] = \"{$response}\";\n";
}
/**
* @name _echo
* @description converts the string “{echo $hello}” to “$_text[] = $hello”, so that it is already optimized for our final evaluated function.
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _echo($tree, $content)
{
$raw = $this->_script($tree, $content);
return "\n\$_text[] = {$raw}\n";
}
/**
* @name _script
* @description converts the string “{:$foo + = 1}” to “$foo + = 1”, so that it is already optimized for our final evaluated function.
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _script($tree)
{
$raw = !empty($tree["raw"]) ? $tree["raw"] : "";
return "{$raw};";
}
/**
* @name _each
* @description returns the code to perform a foreach loop through an array
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _each($tree, $content)
{
$object = $tree["arguments"]["object"];
$element = $tree["arguments"]["element"];
return $this->_loop($tree,
"foreach ({$object} as {$element}_i => {$element}) {
{$content}
}"
);
}
/**
* @name _for
* @description produces the code to perform a for loop through an array
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _for($tree, $content)
{
$object = $tree["arguments"]["object"];
$element = $tree["arguments"]["element"];
return $this->_loop($tree,
"for ({$element}_i = 0; {$element}_i < count((array)({$object})); {$element}_i++) {
{$element} = {$object}[{$element}_i];
{$content}
}"
);
}
/**
* @name _if
* @description return code to perform an IF statement in the template
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _if($tree, $content)
{
$raw = $tree["raw"];
return "if({$raw}) {{$content}}";
}
/**
* @name _elseif
* @description return code to perform an ELSEIF statement in the template
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _elseif($tree, $content)
{
$raw = $tree["raw"];
return "elseif({$raw}) {{$content}}";
}
/**
* @name _else
* @description return code to perform an ELSE statement in the template
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _else($tree, $content)
{
return count($tree) ? "else {{$content}}" : "";
}
/**
* @name _macro
* @description creates the string representation of a function,based on the contents of a {macro...}...{/macro} tag set.
* @notice it is possible, using the {macro} tag, to define functions, which we then use within our templates.
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _macro($tree, $content)
{
$arguments = $tree["arguments"];
$name = $arguments["name"];
$args = $arguments["args"];
return "function {$name}({$args}) {
\$_text = [);
{$content}
return implode(\$_text);
}";
}
/**
* @name _literal
* @description quotes any content within it.
* @notice the template parser only stops directly quoting the content when it finds a {/literal} closing tag.
* @access protected
* @param string $tree
* @param string $content
* @return string
*/
protected function _literal($tree, $content)
{
$content = trim($content);
$source = addslashes($tree["source"]);
return "\n\$_text[] = \"{$source}\";\n";
}
/**
* @name _loop
* @description it augments the output of _for , _foreach with checks for the contents of the arrays used by those statements, as long as an {else} tag follows them.
* @access protected
* @param string $tree
* @param string $inner
* @return string
*/
protected function _loop($tree, $inner)
{
$number = $tree["number"];
$object = $tree["arguments"]["object"];
$children = $tree["parent"]["children"];
if (!empty($children[$number + 1]["tag"]) && $children[$number + 1]["tag"] == "else")
{
return "if (is_array({$object}) && count((array)({$object})) > 0) {{$inner}}";
}
return $inner;
}
/**
* @readwrite
* @access protected
* @var array
*/
protected $_map = [
"echo" => [
"opener" => "{echo",
"closer" => "}",
"handler" => "_echo"
],
"script" => [
"opener" => "{script",
"closer" => "}",
"handler" => "_script"
],
"statement" => [
"opener" => "{",
"closer" => "}",
"tags" => [
"foreach" => [
"isolated" => false,
"arguments" => "{element} in {object}",
"handler" => "_each"
],
"for" => [
"isolated" => false,
"arguments" => "{element} in {object}",
"handler" => "_for"
],
"if" => [
"isolated" => false,
"arguments" => null,
"handler" => "_if"
],
"elseif" => [
"isolated" => true,
"arguments" => null,
"handler" => "_elseif"
],
"else" => [
"isolated" => true,
"arguments" => null,
"handler" => "_else"
],
"macro" => [
"isolated" => false,
"arguments" => "{name}({args})",
"handler" => "_macro"
],
"literal" => [
"isolated" => false,
"arguments" => null,
"handler" => "_literal"
]
]
]
];
/**
* @readwrite
* @access protected
* @var string
*/
protected $_defaultPath;
/**
* @readwrite
* @access protected
* @var string
*/
protected $_defaultKey = "_data";
}