mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Big update
This commit is contained in:
@ -234,7 +234,7 @@ class Aspect {
|
|||||||
*/
|
*/
|
||||||
public static function factory($source, $compile_dir = '/tmp', $options = 0) {
|
public static function factory($source, $compile_dir = '/tmp', $options = 0) {
|
||||||
if(is_string($source)) {
|
if(is_string($source)) {
|
||||||
$provider = new \Aspect\Provider\FS($source);
|
$provider = new \Aspect\FSProvider($source);
|
||||||
} elseif($source instanceof Aspect\ProviderInterface) {
|
} elseif($source instanceof Aspect\ProviderInterface) {
|
||||||
$provider = $source;
|
$provider = $source;
|
||||||
} else {
|
} else {
|
||||||
@ -464,7 +464,7 @@ class Aspect {
|
|||||||
*/
|
*/
|
||||||
public function setOptions($options) {
|
public function setOptions($options) {
|
||||||
if(is_array($options)) {
|
if(is_array($options)) {
|
||||||
$options = Aspect\Misc::makeMask($options, self::$_option_list);
|
$options = self::_makeMask($options, self::$_option_list);
|
||||||
}
|
}
|
||||||
$this->_storage = array();
|
$this->_storage = array();
|
||||||
$this->_options = $options;
|
$this->_options = $options;
|
||||||
@ -652,4 +652,28 @@ class Aspect {
|
|||||||
return Template::factory($this)->source($name, $code);
|
return Template::factory($this)->source($name, $code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create bit-mask from associative array use fully associative array possible keys with bit values
|
||||||
|
* @static
|
||||||
|
* @param array $values custom assoc array, ["a" => true, "b" => false]
|
||||||
|
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
|
||||||
|
* @param int $mask the initial value of the mask
|
||||||
|
* @return int result, ( $mask | a ) & ~b
|
||||||
|
* @throws \RuntimeException if key from custom assoc doesn't exists into possible values
|
||||||
|
*/
|
||||||
|
private static function _makeMask(array $values, array $options, $mask = 0) {
|
||||||
|
foreach($values as $value) {
|
||||||
|
if(isset($options[$value])) {
|
||||||
|
if($options[$value]) {
|
||||||
|
$mask |= $options[$value];
|
||||||
|
} else {
|
||||||
|
$mask &= ~$options[$value];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException("Undefined parameter $value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $mask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,4 +661,53 @@ class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import macros from templates
|
||||||
|
*
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Template $tpl
|
||||||
|
* @return string
|
||||||
|
* @throws ImproperUseException
|
||||||
|
*/
|
||||||
|
public static function tagImport(Tokenizer $tokens, Template $tpl) {
|
||||||
|
$tpl->parseFirstArg($tokens, $name);
|
||||||
|
if(!$name) {
|
||||||
|
throw new ImproperUseException("Invalid usage tag {import}");
|
||||||
|
}
|
||||||
|
$donor = $tpl->getStorage()->getRawTemplate()->load($name, true);
|
||||||
|
if(!empty($donor->_macros)) {
|
||||||
|
$tpl->_macros = array_merge($tpl->_macros, $donor->_macros);
|
||||||
|
$tpl->addDepend($donor);
|
||||||
|
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare or invoke macros
|
||||||
|
*
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
* @param Scope $scope
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function macrosOpen(Tokenizer $tokens, Scope $scope) {
|
||||||
|
$tokens->get('.');
|
||||||
|
$name = $tokens->get(Tokenizer::MACRO_STRING);
|
||||||
|
if($tokens->is('(')) {
|
||||||
|
$tokens->skip();
|
||||||
|
|
||||||
|
return '';
|
||||||
|
} elseif(isset($scope->tpl->_macros[$name])) {
|
||||||
|
$p = $scope->tpl->parseParams($tokens);
|
||||||
|
$scope->closed = true;
|
||||||
|
return '$_tpl = $tpl; $tpl = '.self::_toArray($p).' + '.$scope->tpl->_macros[$name]["defaults"].'; '.$scope->tpl->_macros[$name]["body"].'; $tpl = $_tpl; unset($_tpl);';
|
||||||
|
} else {
|
||||||
|
throw new ImproperUseException("Unknown tag or macros {{$name}}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function macrosClose(Tokenizer $tokens, Scope $scope) {
|
||||||
|
$scope->tpl->_macros[ $scope["name"] ] = $scope->getContent();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
129
src/Aspect/FSProvider.php
Normal file
129
src/Aspect/FSProvider.php
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aspect;
|
||||||
|
|
||||||
|
use Aspect\ProviderInterface;
|
||||||
|
/**
|
||||||
|
* Templates provider
|
||||||
|
* @author Ivan Shalganov
|
||||||
|
*/
|
||||||
|
class FSProvider implements ProviderInterface {
|
||||||
|
private $_path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean directory from files
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public static function clean($path) {
|
||||||
|
if(is_file($path)) {
|
||||||
|
unlink($path);
|
||||||
|
} elseif(is_dir($path)) {
|
||||||
|
$iterator = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path,
|
||||||
|
\FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS),
|
||||||
|
\RecursiveIteratorIterator::CHILD_FIRST));
|
||||||
|
foreach($iterator as $file) {
|
||||||
|
/* @var \splFileInfo $file*/
|
||||||
|
if($file->isFile()) {
|
||||||
|
if(strpos($file->getBasename(), ",") !== 0) {
|
||||||
|
unlink($file->getRealPath());
|
||||||
|
}
|
||||||
|
} elseif($file->isDir()) {
|
||||||
|
rmdir($file->getRealPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive remove directory
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
*/
|
||||||
|
public static function rm($path) {
|
||||||
|
self::clean($path);
|
||||||
|
if(is_dir($path)) {
|
||||||
|
rmdir($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function put($path, $content) {
|
||||||
|
file_put_contents($path, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct($template_dir) {
|
||||||
|
if($_dir = realpath($template_dir)) {
|
||||||
|
$this->_path = $_dir;
|
||||||
|
} else {
|
||||||
|
throw new \LogicException("Template directory {$template_dir} doesn't exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string $tpl
|
||||||
|
* @param int $time
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSource($tpl, &$time) {
|
||||||
|
$tpl = $this->_getTemplatePath($tpl);
|
||||||
|
clearstatcache(null, $tpl);
|
||||||
|
$time = filemtime($tpl);
|
||||||
|
return file_get_contents($tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastModified($tpl) {
|
||||||
|
clearstatcache(null, $tpl = $this->_getTemplatePath($tpl));
|
||||||
|
return filemtime($tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get template path
|
||||||
|
* @param $tpl
|
||||||
|
* @return string
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
protected function _getTemplatePath($tpl) {
|
||||||
|
if(($path = realpath($this->_path."/".$tpl)) && strpos($path, $this->_path) === 0) {
|
||||||
|
return $path;
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException("Template $tpl not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $tpl
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isTemplateExists($tpl) {
|
||||||
|
return file_exists($this->_path."/".$tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLastModifiedBatch($tpls) {
|
||||||
|
$tpls = array_flip($tpls);
|
||||||
|
foreach($tpls as $tpl => &$time) {
|
||||||
|
$time = $this->getLastModified($tpl);
|
||||||
|
}
|
||||||
|
return $tpls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify templates by change time
|
||||||
|
*
|
||||||
|
* @param array $templates [template_name => modified, ...] By conversation you may trust the template's name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function verify(array $templates) {
|
||||||
|
foreach($templates as $template => $mtime) {
|
||||||
|
clearstatcache(null, $template = $this->_path.'/'.$template);
|
||||||
|
if(@filemtime($template) !== $mtime) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Aspect;
|
|
||||||
|
|
||||||
class Func {
|
|
||||||
public static function mailto($params) {
|
|
||||||
if(empty($params["address"])) {
|
|
||||||
trigger_error(E_USER_WARNING, "Modifier mailto: paramenter 'address' required");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(empty($params["text"])) {
|
|
||||||
$params["text"] = $params["address"];
|
|
||||||
}
|
|
||||||
|
|
||||||
return '<a href="mailto:'.$params["address"].'">'.$params["text"].'</a>';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Aspect;
|
|
||||||
|
|
||||||
|
|
||||||
class Misc {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create bit-mask from associative array use fully associative array possible keys with bit values
|
|
||||||
* @static
|
|
||||||
* @param array $values custom assoc array, ["a" => true, "b" => false]
|
|
||||||
* @param array $options possible values, ["a" => 0b001, "b" => 0b010, "c" => 0b100]
|
|
||||||
* @param int $mask the initial value of the mask
|
|
||||||
* @return int result, ( $mask | a ) & ~b
|
|
||||||
* @throws \RuntimeException if key from custom assoc doesn't exists into possible values
|
|
||||||
*/
|
|
||||||
public static function makeMask(array $values, array $options, $mask = 0) {
|
|
||||||
foreach($values as $value) {
|
|
||||||
if(isset($options[$value])) {
|
|
||||||
if($options[$value]) {
|
|
||||||
$mask |= $options[$value];
|
|
||||||
} else {
|
|
||||||
$mask &= ~$options[$value];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException("Undefined parameter $value");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clean directory from files
|
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
*/
|
|
||||||
public static function clean($path) {
|
|
||||||
if(is_file($path)) {
|
|
||||||
unlink($path);
|
|
||||||
} elseif(is_dir($path)) {
|
|
||||||
$iterator = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path,
|
|
||||||
\FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS),
|
|
||||||
\RecursiveIteratorIterator::CHILD_FIRST));
|
|
||||||
foreach($iterator as $file) {
|
|
||||||
/* @var \splFileInfo $file*/
|
|
||||||
if($file->isFile()) {
|
|
||||||
if(strpos($file->getBasename(), ",") !== 0) {
|
|
||||||
unlink($file->getRealPath());
|
|
||||||
}
|
|
||||||
} elseif($file->isDir()) {
|
|
||||||
rmdir($file->getRealPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive remove directory
|
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
*/
|
|
||||||
public static function rm($path) {
|
|
||||||
self::clean($path);
|
|
||||||
if(is_dir($path)) {
|
|
||||||
rmdir($path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function put($path, $content) {
|
|
||||||
file_put_contents($path, $content);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +1,43 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Aspect.
|
||||||
|
*
|
||||||
|
* (c) 2013 Ivan Shalganov
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
namespace Aspect;
|
namespace Aspect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of modifiers
|
||||||
|
*
|
||||||
|
* @package aspect
|
||||||
|
* @author Ivan Shalganov <owner@bzick.net>
|
||||||
|
*/
|
||||||
class Modifier {
|
class Modifier {
|
||||||
|
|
||||||
public static function dateFormat($date, $format = "%b %e, %Y") {
|
/**
|
||||||
|
* Date format
|
||||||
|
*
|
||||||
|
* @param string|int $date
|
||||||
|
* @param string $format
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function dateFormat($date, $format = "%b %e, %Y") {
|
||||||
if(is_string($date) && !is_numeric($date)) {
|
if(is_string($date) && !is_numeric($date)) {
|
||||||
$date = strtotime($date);
|
$date = strtotime($date);
|
||||||
if(!$date) $date = time();
|
if(!$date) $date = time();
|
||||||
}
|
}
|
||||||
//dump($format, $date);
|
|
||||||
return strftime($format, $date);
|
return strftime($format, $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function date($date, $format = "Y m d") {
|
/**
|
||||||
|
* @param string $date
|
||||||
|
* @param string $format
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function date($date, $format = "Y m d") {
|
||||||
if(is_string($date) && !is_numeric($date)) {
|
if(is_string($date) && !is_numeric($date)) {
|
||||||
$date = strtotime($date);
|
$date = strtotime($date);
|
||||||
if(!$date) $date = time();
|
if(!$date) $date = time();
|
||||||
@ -21,6 +45,13 @@ class Modifier {
|
|||||||
return date($format, $date);
|
return date($format, $date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape string
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param string $type
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public static function escape($text, $type = 'html') {
|
public static function escape($text, $type = 'html') {
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case "url":
|
case "url":
|
||||||
@ -32,7 +63,14 @@ class Modifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function unescape($text, $type = 'html') {
|
/**
|
||||||
|
* Unescape escaped string
|
||||||
|
*
|
||||||
|
* @param string $text
|
||||||
|
* @param string $type
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function unescape($text, $type = 'html') {
|
||||||
switch($type) {
|
switch($type) {
|
||||||
case "url":
|
case "url":
|
||||||
return urldecode($text);
|
return urldecode($text);
|
||||||
@ -43,10 +81,14 @@ class Modifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function defaultValue(&$value, $default = null) {
|
/**
|
||||||
return ($value === null) ? $default : $value;
|
* @param string $string
|
||||||
}
|
* @param int $length
|
||||||
|
* @param string $etc
|
||||||
|
* @param bool $break_words
|
||||||
|
* @param bool $middle
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public static function truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false) {
|
public static function truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false) {
|
||||||
$length -= min($length, strlen($etc));
|
$length -= min($length, strlen($etc));
|
||||||
if (!$break_words && !$middle) {
|
if (!$break_words && !$middle) {
|
||||||
@ -73,4 +115,18 @@ class Modifier {
|
|||||||
return preg_replace('#[ \t]{2,}#', ' ', $str);
|
return preg_replace('#[ \t]{2,}#', ' ', $str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $item
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function length($item) {
|
||||||
|
if(is_scalar($item)) {
|
||||||
|
return strlen($item);
|
||||||
|
} elseif (is_array($item)) {
|
||||||
|
return count($item);
|
||||||
|
} else {
|
||||||
|
return count((array)$item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace Aspect\Provider;
|
|
||||||
|
|
||||||
use Aspect\ProviderInterface;
|
|
||||||
/**
|
|
||||||
* Templates provider
|
|
||||||
* @author Ivan Shalganov
|
|
||||||
*/
|
|
||||||
class FS implements ProviderInterface {
|
|
||||||
private $_path;
|
|
||||||
|
|
||||||
public function __construct($template_dir) {
|
|
||||||
if($_dir = realpath($template_dir)) {
|
|
||||||
$this->_path = $_dir;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException("Template directory {$template_dir} doesn't exists");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param string $tpl
|
|
||||||
* @param int $time
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getSource($tpl, &$time) {
|
|
||||||
$tpl = $this->_getTemplatePath($tpl);
|
|
||||||
clearstatcache(null, $tpl);
|
|
||||||
$time = filemtime($tpl);
|
|
||||||
return file_get_contents($tpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastModified($tpl) {
|
|
||||||
clearstatcache(null, $tpl = $this->_getTemplatePath($tpl));
|
|
||||||
return filemtime($tpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getList() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get template path
|
|
||||||
* @param $tpl
|
|
||||||
* @return string
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
protected function _getTemplatePath($tpl) {
|
|
||||||
if(($path = realpath($this->_path."/".$tpl)) && strpos($path, $this->_path) === 0) {
|
|
||||||
return $path;
|
|
||||||
} else {
|
|
||||||
throw new \RuntimeException("Template $tpl not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $tpl
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTemplateExists($tpl) {
|
|
||||||
return file_exists($this->_path."/".$tpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLastModifiedBatch($tpls) {
|
|
||||||
$tpls = array_flip($tpls);
|
|
||||||
foreach($tpls as $tpl => &$time) {
|
|
||||||
$time = $this->getLastModified($tpl);
|
|
||||||
}
|
|
||||||
return $tpls;
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,7 +20,13 @@ interface ProviderInterface {
|
|||||||
*/
|
*/
|
||||||
public function getLastModified($tpl);
|
public function getLastModified($tpl);
|
||||||
|
|
||||||
public function getLastModifiedBatch($tpls);
|
/**
|
||||||
|
* Verify templates by change time
|
||||||
|
*
|
||||||
|
* @param array $templates [template_name => modified, ...] By conversation you may trust the template's name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function verify(array $templates);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Aspect.
|
||||||
|
*
|
||||||
|
* (c) 2013 Ivan Shalganov
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
namespace Aspect;
|
namespace Aspect;
|
||||||
|
|
||||||
use Aspect;
|
use Aspect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aspect template compiler
|
* Template compiler
|
||||||
|
*
|
||||||
|
* @package aspect
|
||||||
|
* @author Ivan Shalganov <owner@bzick.net>
|
||||||
*/
|
*/
|
||||||
class Template extends Render {
|
class Template extends Render {
|
||||||
|
|
||||||
@ -303,7 +313,7 @@ class Template extends Render {
|
|||||||
$this->_ignore = true;
|
$this->_ignore = true;
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
$code = '';
|
$code = '';
|
||||||
} else {
|
} else {
|
||||||
$code = $this->_parseAct($tokens);
|
$code = $this->_parseAct($tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,6 +336,7 @@ class Template extends Render {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close tag handler
|
* Close tag handler
|
||||||
|
*
|
||||||
* @param Tokenizer $tokens
|
* @param Tokenizer $tokens
|
||||||
* @return mixed
|
* @return mixed
|
||||||
* @throws TokenizeException
|
* @throws TokenizeException
|
||||||
@ -358,14 +369,14 @@ class Template extends Render {
|
|||||||
if($tokens->is(Tokenizer::MACRO_STRING)) {
|
if($tokens->is(Tokenizer::MACRO_STRING)) {
|
||||||
$action = $tokens->current();
|
$action = $tokens->current();
|
||||||
} else {
|
} else {
|
||||||
return 'echo '.$this->parseExp($tokens).';';
|
return 'echo '.$this->parseExp($tokens).';'; // may be math and boolean expression
|
||||||
}
|
}
|
||||||
|
|
||||||
if($tokens->isNext("(")) {
|
if($tokens->isNext("(", T_NAMESPACE, T_DOUBLE_COLON)) { // just invoke function or static method
|
||||||
return "echo ".$this->parseExp($tokens).";";
|
return "echo ".$this->parseExp($tokens).";";
|
||||||
}
|
}
|
||||||
|
|
||||||
if($act = $this->_aspect->getFunction($action)) {
|
if($act = $this->_aspect->getFunction($action)) { // call some function
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
switch($act["type"]) {
|
switch($act["type"]) {
|
||||||
case Aspect::BLOCK_COMPILER:
|
case Aspect::BLOCK_COMPILER:
|
||||||
@ -386,19 +397,32 @@ class Template extends Render {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for($j = $i = count($this->_stack)-1; $i>=0; $i--) {
|
for($j = $i = count($this->_stack)-1; $i>=0; $i--) { // call function's internal tag
|
||||||
if($this->_stack[$i]->hasTag($action, $j - $i)) {
|
if($this->_stack[$i]->hasTag($action, $j - $i)) {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
return $this->_stack[$i]->tag($action, $tokens);
|
return $this->_stack[$i]->tag($action, $tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($tags = $this->_aspect->getTagOwners($action)) {
|
if($tags = $this->_aspect->getTagOwners($action)) { // unknown template tag
|
||||||
throw new TokenizeException("Unexpected tag '$action' (this tag can be used with '".implode("', '", $tags)."')");
|
throw new TokenizeException("Unexpected tag '$action' (this tag can be used with '".implode("', '", $tags)."')");
|
||||||
} else {
|
} else {
|
||||||
throw new TokenizeException("Unexpected tag $action");
|
throw new TokenizeException("Unexpected tag $action");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Tokenizer $tokens
|
||||||
|
*/
|
||||||
|
private function _parseMacros(Tokenizer $tokens) {
|
||||||
|
$tokens->get('.');
|
||||||
|
$name = $tokens->get(Tokenizer::MACRO_STRING);
|
||||||
|
if($tokens->is('(')) {
|
||||||
|
$tokens->skip();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse expressions. The mix of math operations, boolean operations, scalars, arrays and variables.
|
* Parse expressions. The mix of math operations, boolean operations, scalars, arrays and variables.
|
||||||
*
|
*
|
||||||
@ -610,9 +634,9 @@ class Template extends Render {
|
|||||||
}
|
}
|
||||||
$expr2 = $this->parseExp($tokens, true);
|
$expr2 = $this->parseExp($tokens, true);
|
||||||
if($empty) {
|
if($empty) {
|
||||||
return '(empty('.$_var.') ? '.$expr2.' : '.$expr1;
|
return '(empty('.$_var.') ? '.$expr2.' : '.$expr1.')';
|
||||||
} else {
|
} else {
|
||||||
return '(isset('.$_var.') ? '.$expr1.' : '.$expr2;
|
return '(isset('.$_var.') ? '.$expr1.' : '.$expr2.')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif($t === "!") {
|
} elseif($t === "!") {
|
||||||
@ -676,11 +700,42 @@ class Template extends Render {
|
|||||||
$_str .= $tokens->current();
|
$_str .= $tokens->current();
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
} elseif($t === T_VARIABLE) {
|
} elseif($t === T_VARIABLE) {
|
||||||
$_str .= '".$tpl["'.substr($tokens->current(), 1).'"]."';
|
if(strlen($_str) > 1) {
|
||||||
|
$_str .= '".';
|
||||||
|
} else {
|
||||||
|
$_str = "";
|
||||||
|
}
|
||||||
|
$_str .= '$tpl["'.substr($tokens->current(), 1).'"]';
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
|
if($tokens->is($stop)) {
|
||||||
|
$tokens->skip();
|
||||||
|
return $_str;
|
||||||
|
} else {
|
||||||
|
$_str .= '."';
|
||||||
|
}
|
||||||
} elseif($t === T_CURLY_OPEN) {
|
} elseif($t === T_CURLY_OPEN) {
|
||||||
|
if(strlen($_str) > 1) {
|
||||||
|
$_str .= '".';
|
||||||
|
} else {
|
||||||
|
$_str = "";
|
||||||
|
}
|
||||||
$tokens->getNext(T_VARIABLE);
|
$tokens->getNext(T_VARIABLE);
|
||||||
$_str .= '".('.$this->parseExp($tokens).')."';
|
$_str .= '('.$this->parseExp($tokens).')';
|
||||||
|
/*if(!$tokens->valid()) {
|
||||||
|
$more = $this->_getMoreSubstr($stop);
|
||||||
|
//var_dump($more); exit;
|
||||||
|
$tokens->append("}".$more, $p);
|
||||||
|
var_dump("Curly", $more, $tokens->getSnippetAsString());
|
||||||
|
exit;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//$tokens->skip('}');
|
||||||
|
if($tokens->is($stop)) {
|
||||||
|
$tokens->next();
|
||||||
|
return $_str;
|
||||||
|
} else {
|
||||||
|
$_str .= '."';
|
||||||
|
}
|
||||||
} elseif($t === "}") {
|
} elseif($t === "}") {
|
||||||
$tokens->next();
|
$tokens->next();
|
||||||
} elseif($t === $stop) {
|
} elseif($t === $stop) {
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Aspect.
|
||||||
|
*
|
||||||
|
* (c) 2013 Ivan Shalganov
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
namespace Aspect;
|
namespace Aspect;
|
||||||
|
|
||||||
defined('T_INSTEADOF') || define('T_INSTEADOF', 341);
|
defined('T_INSTEADOF') || define('T_INSTEADOF', 341);
|
||||||
@ -16,6 +24,9 @@ defined('T_TRAIT_C') || define('T_TRAIT_C', 365);
|
|||||||
* @property array $prev the previous token
|
* @property array $prev the previous token
|
||||||
* @property array $curr the current token
|
* @property array $curr the current token
|
||||||
* @property array $next the next token
|
* @property array $next the next token
|
||||||
|
*
|
||||||
|
* @package aspect
|
||||||
|
* @author Ivan Shalganov <owner@bzick.net>
|
||||||
*/
|
*/
|
||||||
class Tokenizer {
|
class Tokenizer {
|
||||||
const TOKEN = 0;
|
const TOKEN = 0;
|
||||||
@ -363,6 +374,10 @@ class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function count() {
|
||||||
|
return $this->_max;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the key of the current element
|
* Return the key of the current element
|
||||||
* @return mixed scalar on success, or null on failure.
|
* @return mixed scalar on success, or null on failure.
|
||||||
@ -522,8 +537,9 @@ class Tokenizer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse code and append tokens. This method move pointer to offset.
|
* Parse code and append tokens. This method move pointer to offset.
|
||||||
|
*
|
||||||
* @param string $code
|
* @param string $code
|
||||||
* @param int $offset
|
* @param int $offset if not -1 replace tokens from position $offset
|
||||||
* @return Tokenizer
|
* @return Tokenizer
|
||||||
*/
|
*/
|
||||||
public function append($code, $offset = -1) {
|
public function append($code, $offset = -1) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Aspect;
|
namespace Aspect;
|
||||||
use Aspect;
|
use Aspect, Aspect\FSProvider as FS;
|
||||||
|
|
||||||
class TestCase extends \PHPUnit_Framework_TestCase {
|
class TestCase extends \PHPUnit_Framework_TestCase {
|
||||||
/**
|
/**
|
||||||
@ -12,7 +12,7 @@ class TestCase extends \PHPUnit_Framework_TestCase {
|
|||||||
if(!file_exists(ASPECT_RESOURCES.'/compile')) {
|
if(!file_exists(ASPECT_RESOURCES.'/compile')) {
|
||||||
mkdir(ASPECT_RESOURCES.'/compile', 0777, true);
|
mkdir(ASPECT_RESOURCES.'/compile', 0777, true);
|
||||||
} else {
|
} else {
|
||||||
Misc::clean(ASPECT_RESOURCES.'/compile/');
|
FS::clean(ASPECT_RESOURCES.'/compile/');
|
||||||
}
|
}
|
||||||
$this->aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
|
$this->aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ class TestCase extends \PHPUnit_Framework_TestCase {
|
|||||||
if(!file_exists(ASPECT_RESOURCES.'/template')) {
|
if(!file_exists(ASPECT_RESOURCES.'/template')) {
|
||||||
mkdir(ASPECT_RESOURCES.'/template', 0777, true);
|
mkdir(ASPECT_RESOURCES.'/template', 0777, true);
|
||||||
} else {
|
} else {
|
||||||
Misc::clean(ASPECT_RESOURCES.'/template/');
|
FS::clean(ASPECT_RESOURCES.'/template/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class ExtendsTemplateTest extends TestCase {
|
|||||||
* @param $vars
|
* @param $vars
|
||||||
* @param $result
|
* @param $result
|
||||||
*/
|
*/
|
||||||
public function testDynamicExtends($name, $code, $vars, $result) {
|
public function _testDynamicExtends($name, $code, $vars, $result) {
|
||||||
static $i = 0;
|
static $i = 0;
|
||||||
$vars["iteration"] = $i++;
|
$vars["iteration"] = $i++;
|
||||||
$this->execTpl($name, $code, $vars, $result);
|
$this->execTpl($name, $code, $vars, $result);
|
||||||
@ -60,7 +60,7 @@ class ExtendsTemplateTest extends TestCase {
|
|||||||
/**
|
/**
|
||||||
* @group extends
|
* @group extends
|
||||||
*/
|
*/
|
||||||
public function _testChildLevel1() {
|
public function testChildLevel1() {
|
||||||
//echo($this->aspect->fetch("child1.tpl", array("a" => "a char"))); exit;
|
//echo($this->aspect->fetch("child1.tpl", array("a" => "a char"))); exit;
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Aspect\Provider;
|
namespace Aspect;
|
||||||
use Aspect;
|
use Aspect;
|
||||||
|
|
||||||
class FSTest extends \Aspect\TestCase {
|
class FSProviderTest extends \Aspect\TestCase {
|
||||||
/**
|
/**
|
||||||
* @var Provider
|
* @var FSProvider
|
||||||
*/
|
*/
|
||||||
public $provider;
|
public $provider;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ class FSTest extends \Aspect\TestCase {
|
|||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->tpl("template1.tpl", 'Template 1 {$a}');
|
$this->tpl("template1.tpl", 'Template 1 {$a}');
|
||||||
$this->tpl("template2.tpl", 'Template 2 {$a}');
|
$this->tpl("template2.tpl", 'Template 2 {$a}');
|
||||||
$this->provider = new FS(ASPECT_RESOURCES.'/template');
|
$this->provider = new FSProvider(ASPECT_RESOURCES.'/template');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIsTemplateExists() {
|
public function testIsTemplateExists() {
|
@ -15,6 +15,10 @@ class TemplateTest extends TestCase {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*public function testSandbox() {
|
||||||
|
var_dump($this->aspect->compileCode('{"$s:{$b+1}f d {$d}"}')->_body);
|
||||||
|
exit;
|
||||||
|
}*/
|
||||||
|
|
||||||
public static function providerVars() {
|
public static function providerVars() {
|
||||||
$a = array("a" => "World");
|
$a = array("a" => "World");
|
||||||
@ -69,6 +73,42 @@ class TemplateTest extends TestCase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function providerScalars() {
|
||||||
|
return array(
|
||||||
|
array('77', 77),
|
||||||
|
array('-33', -33),
|
||||||
|
array('0.2', 0.2),
|
||||||
|
array('-0.3', -0.3),
|
||||||
|
array('1e6', 1e6),
|
||||||
|
array('-2e6', -2e6),
|
||||||
|
array('"str"', 'str'),
|
||||||
|
array('"str\nand\nmany\nlines"', "str\nand\nmany\nlines"),
|
||||||
|
array('"str and \'substr\'"', "str and 'substr'"),
|
||||||
|
array('"str and \"substr\""', 'str and "substr"'),
|
||||||
|
array("'str'", 'str'),
|
||||||
|
array("'str\\nin\\none\\nline'", 'str\nin\none\nline'),
|
||||||
|
array("'str and \"substr\"'", 'str and "substr"'),
|
||||||
|
array("'str and \'substr\''", "str and 'substr'"),
|
||||||
|
array('"$one"', '1'),
|
||||||
|
array('"$one $two"', '1 2'),
|
||||||
|
array('"$one and $two"', '1 and 2'),
|
||||||
|
array('"a $one and $two b"', 'a 1 and 2 b'),
|
||||||
|
array('"{$one}"', '1'),
|
||||||
|
array('"a {$one} b"', 'a 1 b'),
|
||||||
|
array('"{$one + 2}"', '3'),
|
||||||
|
array('"{$one * $two + 1}"', '3'),
|
||||||
|
array('"{$one} and {$two}"', '1 and 2'),
|
||||||
|
array('"$one and {$two}"', '1 and 2'),
|
||||||
|
array('"{$one} and $two"', '1 and 2'),
|
||||||
|
array('"a {$one} and {$two} b"', 'a 1 and 2 b'),
|
||||||
|
array('"{$one+1} and {$two-1}"', '2 and 1'),
|
||||||
|
array('"a {$one+1} and {$two-1} b"', 'a 2 and 1 b'),
|
||||||
|
array('"a {$one|dots} and {$two|dots} b"', 'a 1... and 2... b'),
|
||||||
|
array('"a {$one|dots} and $two b"', 'a 1... and 2 b'),
|
||||||
|
array('"a $one and {$two|dots} b"', 'a 1 and 2... b'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static function providerVarsInvalid() {
|
public static function providerVarsInvalid() {
|
||||||
return array(
|
return array(
|
||||||
array('hello, {$a.}!', 'Aspect\CompileException', "Unexpected end of expression"),
|
array('hello, {$a.}!', 'Aspect\CompileException', "Unexpected end of expression"),
|
||||||
|
Reference in New Issue
Block a user