mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Optimize extends
This commit is contained in:
parent
f42d0cff5d
commit
a515c8e969
@ -11,7 +11,7 @@ Cytro - awesome template engine for PHP
|
||||
* [Secure](./docs/settings.md)
|
||||
* [Simple](./ideology.md)
|
||||
* [Flexible](./docs/main.md#extends)
|
||||
* [Lightweight](./docs/benchmark.md#satistic)
|
||||
* [Lightweight](./docs/benchmark.md#stats)
|
||||
* [Powerful](./docs/main.md)
|
||||
* Easy to use:
|
||||
|
||||
|
@ -5,6 +5,8 @@ To start benchmark run script `benchmark/run.php`.
|
||||
|
||||
### Smarty3 vs Twig vs Cytro
|
||||
|
||||
PHP 5.4.11
|
||||
|
||||
Print varaibles
|
||||
|
||||
smarty3: !compiled and !loaded 8.7919 sec, 21.1 MiB
|
||||
@ -15,9 +17,9 @@ To start benchmark run script `benchmark/run.php`.
|
||||
twig: compiled and !loaded 0.0337 sec, 16.1 MiB
|
||||
twig: compiled and loaded 0.0027 sec, 16.1 MiB
|
||||
|
||||
cytro: !compiled and !loaded 1.0142 sec, 8.8 MiB
|
||||
cytro: compiled and !loaded 0.0167 sec, 6.1 MiB
|
||||
cytro: compiled and loaded 0.0024 sec, 6.1 MiB
|
||||
cytro: !compiled and !loaded 1.0142 sec, 8.8 MiB
|
||||
cytro: compiled and !loaded 0.0167 sec, 6.1 MiB
|
||||
cytro: compiled and loaded 0.0024 sec, 6.1 MiB
|
||||
|
||||
Iterates array
|
||||
|
||||
@ -29,9 +31,9 @@ To start benchmark run script `benchmark/run.php`.
|
||||
twig: compiled and !loaded 0.0605 sec, 2.9 MiB
|
||||
twig: compiled and loaded 0.0550 sec, 2.9 MiB
|
||||
|
||||
cytro: !compiled and !loaded 0.0093 sec, 3.0 MiB
|
||||
cytro: compiled and !loaded 0.0033 sec, 2.4 MiB
|
||||
cytro: compiled and loaded 0.0027 sec, 2.4 MiB
|
||||
cytro: !compiled and !loaded 0.0093 sec, 3.0 MiB
|
||||
cytro: compiled and !loaded 0.0033 sec, 2.4 MiB
|
||||
cytro: compiled and loaded 0.0027 sec, 2.4 MiB
|
||||
|
||||
templates inheritance
|
||||
|
||||
@ -43,10 +45,18 @@ To start benchmark run script `benchmark/run.php`.
|
||||
twig: compiled and !loaded 0.0255 sec, 6.3 MiB
|
||||
twig: compiled and loaded 0.0038 sec, 6.3 MiB
|
||||
|
||||
cytro: !compiled and !loaded 0.1222 sec, 3.9 MiB
|
||||
cytro: compiled and !loaded 0.0004 sec, 2.4 MiB
|
||||
cytro: compiled and loaded 0.0000 sec, 2.4 MiB
|
||||
cytro: !compiled and !loaded 0.1222 sec, 3.9 MiB
|
||||
cytro: compiled and !loaded 0.0004 sec, 2.4 MiB
|
||||
cytro: compiled and loaded 0.0000 sec, 2.4 MiB
|
||||
|
||||
* **!compiled and !loaded** - template engine object created but parsers not initialized and templates not compiled
|
||||
* **compiled and !loaded** - template engine object created, template compiled but not loaded
|
||||
* **compiled and loaded** - template engine object created, template compiled and loaded
|
||||
* **compiled and loaded** - template engine object created, template compiled and loaded
|
||||
|
||||
### Stats
|
||||
|
||||
| Template Engine | Files | Classes | Lines |
|
||||
| --------------- | ------:| --------:| ------:|
|
||||
| Smarty3 (3.1.13)| 320 | 190 | 55095 |
|
||||
| Twig (1.13.0) | 162 | 131 | 13908 |
|
||||
| Cytro (1.0.1) | 9 | 16 | 3899 |
|
49
docs/ext/inheritance.md
Normal file
49
docs/ext/inheritance.md
Normal file
@ -0,0 +1,49 @@
|
||||
Inheritance algorithm
|
||||
=====================
|
||||
|
||||
Variant #1. Sunny.
|
||||
|
||||
| level.2.tpl | b1 | add new block | `$tpl->block['b1'] = $content;`
|
||||
| level.2.tpl | b1 | rewrite block | `$tpl->block['b1'] = $content;`
|
||||
| level.1.tpl | b1 | skip because block exists | `if(!isset($tpl->block['b1'])) $tpl->block['b1'] = $content;`
|
||||
| use.tpl | b1 | skip because block exists | `if(!isset($tpl->block['b1'])) $tpl->block['b1'] = $content;`
|
||||
| use.tpl | b2 | add new block | `$tpl->block['b2'] = $content;`
|
||||
| level.1.tpl | b2 | rewrite block | `$tpl->block['b2'] = $content;`
|
||||
| parent.tpl | b1 | get block from stack
|
||||
| parent.tpl | b2 | get block from stack
|
||||
| parent.tpl | b3 | get own block
|
||||
------Result--------
|
||||
| level.2.tpl | b1 |
|
||||
| level.1.tpl | b2 |
|
||||
|
||||
Variant #2. Сloudy.
|
||||
|
||||
| level.2.tpl | b1 | add new block
|
||||
| level.1.tpl | b1 | skip because block exists
|
||||
| use.tpl | b1 | skip because block exists
|
||||
| use.tpl | b2 | add new block
|
||||
| level.1.tpl | b2 | rewrite block
|
||||
| $parent | b1 | dynamic extend
|
||||
------Result--------
|
||||
| level.2.tpl | b1 |
|
||||
| level.1.tpl | b2 |
|
||||
|
||||
Variant #3. Rain.
|
||||
|
||||
Variant #4. Tornado.
|
||||
|
||||
|
||||
|
||||
Error Info (x2) :
|
||||
Exception: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '839621621,839622021)' at line 1
|
||||
Query: SELECT `image_id`, `filename` FROM `s3_image_version` WHERE `format_id`=1 AND `image_id` IN (,839621621,839622021)
|
||||
#0 /www/oml.ru/s3/lib/class.db.php(480): Db::parseError('SELECT `image_i...')
|
||||
#1 /www/oml.ru/s3/forms/class.shop2.product.form.php(225): Db::query('SELECT `image_i...')
|
||||
#2 /www/oml.ru/s3/lib/class.form.php(2390): Shop2ProductForm->fillControls()
|
||||
#3 /www/oml.ru/s3/lib/class.form.php(1444): Form->execute()
|
||||
#4 /www/oml.ru/public/my/s3/data/shop2_product/edit.cphp(44): Form->display(Object(Smarty), 'form.ajax.tpl')
|
||||
#5 {main}
|
||||
|
||||
Place: /www/oml.ru/s3/lib/class.db.php:607
|
||||
Time: 2013-06-05 03:54:51
|
||||
Url: http://agyumama.ru/my/s3/data/shop2_product/edit.cphp?shop_id=196421&ver_id=636664&access=u%3B270377&popup=1&product_id=89445221&rnd=9296&xhr=1
|
@ -10,6 +10,8 @@ Documentation
|
||||
* [Callbacks and filters](./callbacks.md)
|
||||
* [Operators](./operators.md)
|
||||
|
||||
***
|
||||
|
||||
### Modifiers
|
||||
|
||||
[Usage](./syntax.md#modifiers)
|
||||
@ -28,6 +30,8 @@ Documentation
|
||||
`strtotime`, `gettype`, `is_double`, `ip2long`, `long2ip`, `strip_tags`, `nl2br`
|
||||
* or [add](./ext/mods.md) your own
|
||||
|
||||
***
|
||||
|
||||
### Tags
|
||||
|
||||
[Usage](./syntax.md#tags)
|
||||
@ -46,6 +50,8 @@ Documentation
|
||||
* [autotrim](./tags/autotrim.md)
|
||||
* or [add](./ext/tags.md) your own
|
||||
|
||||
***
|
||||
|
||||
### Extends
|
||||
|
||||
* [Add tags](./ext/tags.md)
|
||||
|
@ -54,6 +54,8 @@ Tag {extends} [RU]
|
||||
|
||||
### {parent}
|
||||
|
||||
Planned. Not supported yet.
|
||||
|
||||
```smarty
|
||||
{block 'block1'}
|
||||
content ...
|
||||
|
@ -388,53 +388,66 @@ class Compiler {
|
||||
$tpl->_compatible = true;
|
||||
}
|
||||
if($name) { // static extends
|
||||
dump("$tpl: static extend $name");
|
||||
$tpl->_extends = $tpl->getStorage()->getRawTemplate()->load($name, false);
|
||||
// $tpl->_compatible = &$tpl->_extends->_compatible;
|
||||
if(!isset($tpl->_compatible)) {
|
||||
$tpl->_compatible = &$tpl->_extends->_compatible;;
|
||||
$tpl->_compatible = &$tpl->_extends->_compatible;
|
||||
}
|
||||
$tpl->addDepend($tpl->_extends);
|
||||
return "";
|
||||
} else { // dynamic extends
|
||||
if(!isset($tpl->_compatible)) {
|
||||
$tpl->_compatible = false;
|
||||
if(!isset($tpl->_compatible)) {
|
||||
$tpl->_compatible = true;
|
||||
}
|
||||
$tpl->_extends = $tpl_name;
|
||||
dump("$tpl: dynamic extend $tpl_name");
|
||||
$tpl->_extends = $tpl_name;
|
||||
return '$parent = $tpl->getStorage()->getTemplate('.$tpl_name.', \Cytro\Template::EXTENDED);';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post compile action for {extends ...} tag
|
||||
* @param $body
|
||||
* @param string $body
|
||||
* @param Template $tpl
|
||||
*/
|
||||
public static function extendBody(&$body, $tpl) {
|
||||
$t = $tpl;
|
||||
$t = $tpl;
|
||||
// var_dump("$tpl: ".$tpl->getBody());
|
||||
while(isset($t->_extends)) {
|
||||
$t = $t->_extends;
|
||||
if(is_object($t)) {
|
||||
$t->_extended = true;
|
||||
$tpl->addDepend($t);
|
||||
$t->_compatible = &$tpl->_compatible;
|
||||
$t->blocks = &$tpl->blocks;
|
||||
$t->compile();
|
||||
if(!isset($t->_extends)) { // last item => parent
|
||||
if(empty($tpl->_compatible)) {
|
||||
$body = $t->getBody();
|
||||
} else {
|
||||
$body = '<?php ob_start(); ?>'.$body.'<?php ob_end_clean(); ?>'.$t->getBody();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
$body .= $t->getBody();
|
||||
}
|
||||
} else {
|
||||
$body = '<?php ob_start(); ?>'.$body.'<?php ob_end_clean(); $parent->b = &$tpl->b; $parent->display((array)$tpl); unset($tpl->b, $parent->b); ?>';
|
||||
return;
|
||||
}
|
||||
}
|
||||
if($tpl->uses) {
|
||||
dump("$tpl: append use blocks: ".var_export($tpl->uses, 1));
|
||||
$tpl->blocks += $tpl->uses;
|
||||
}
|
||||
while(isset($t->_extends)) {
|
||||
$t = $t->_extends;
|
||||
if(is_object($t)) {
|
||||
/* @var \Cytro\Template $t */
|
||||
$t->_extended = true;
|
||||
$tpl->addDepend($t);
|
||||
$t->_compatible = &$tpl->_compatible;
|
||||
$t->blocks = &$tpl->blocks;
|
||||
dump("$tpl: before compile $t have blocks: ".var_export($tpl->blocks, 1));
|
||||
$t->compile();
|
||||
if($t->uses) {
|
||||
dump("$tpl: after compile $t have use blocks: ".var_export($tpl->uses, 1));
|
||||
$tpl->blocks += $t->uses;
|
||||
}
|
||||
dump("$tpl: after compile $t have blocks: ".var_export($tpl->blocks, 1));
|
||||
if(!isset($t->_extends)) { // last item => parent
|
||||
if(empty($tpl->_compatible)) {
|
||||
$body = $t->getBody();
|
||||
} else {
|
||||
$body = '<?php ob_start(); ?>'.$body.'<?php ob_end_clean(); ?>'.$t->getBody();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
$body .= $t->getBody();
|
||||
}
|
||||
} else {
|
||||
$body = '<?php ob_start(); ?>'.$body.'<?php ob_end_clean(); $parent->b = &$tpl->b; $parent->display((array)$tpl); unset($tpl->b, $parent->b); ?>';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,18 +458,35 @@ class Compiler {
|
||||
* @return string
|
||||
*/
|
||||
public static function tagUse(Tokenizer $tokens, Template $tpl) {
|
||||
$tpl->parsePlainArg($tokens, $name);
|
||||
$cname = $tpl->parsePlainArg($tokens, $name);
|
||||
if($name) {
|
||||
dump("$tpl: static use $name");
|
||||
$donor = $tpl->getStorage()->getRawTemplate()->load($name, false);
|
||||
$donor->_extended = true;
|
||||
$tpl->_compatible = &$donor->_compatible;
|
||||
$donor->compile();
|
||||
if(empty($tpl->_compatible)) {
|
||||
$tpl->blocks += $donor->blocks;
|
||||
}
|
||||
return '?>'.$donor->getBody().'<?php ';
|
||||
$donor->_extends = $tpl;
|
||||
$donor->_compatible = &$tpl->_compatible;
|
||||
//$donor->blocks = &$tpl->blocks;
|
||||
dump("$tpl: before compile donor $donor have blocks: ".var_export($tpl->blocks, 1));
|
||||
$donor->compile();
|
||||
dump("$tpl: before use block from $donor: ".var_export($donor->blocks, 1));
|
||||
$blocks = $donor->blocks;
|
||||
foreach($blocks as $name => $code) {
|
||||
if(isset($tpl->blocks[$name])) {
|
||||
$tpl->blocks[$name] = $code;
|
||||
unset($blocks[$name]);
|
||||
}
|
||||
}
|
||||
dump("$tpl: after use block from $donor: ".var_export($tpl->blocks, 1));
|
||||
dump("$tpl: save tail from $donor: ".var_export($blocks, 1));
|
||||
$tpl->uses = $blocks + $tpl->uses;
|
||||
$tpl->addDepend($donor);
|
||||
return '?>'.$donor->getBody().'<?php ';
|
||||
} else {
|
||||
throw new ImproperUseException('template name must be given explicitly');
|
||||
$tpl->_compatible = true;
|
||||
return '$donor = $tpl->getStorage()->getTemplate('.$cname.', \Cytro\Template::EXTENDED);'.PHP_EOL.
|
||||
'$donor->fetch((array)$tpl);'.PHP_EOL.
|
||||
'$tpl->b += (array)$donor->b';
|
||||
// throw new ImproperUseException('template name must be given explicitly');
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,9 +498,9 @@ class Compiler {
|
||||
* @throws ImproperUseException
|
||||
*/
|
||||
public static function tagBlockOpen(Tokenizer $tokens, Scope $scope) {
|
||||
$p = $scope->tpl->parsePlainArg($tokens, $name);
|
||||
$scope["name"] = $name;
|
||||
$scope["cname"] = $p;
|
||||
$scope["cname"] = $scope->tpl->parsePlainArg($tokens, $name);
|
||||
$scope["name"] = $name;
|
||||
dump("{$scope->tpl}: open block ".$scope["name"]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,58 +510,60 @@ class Compiler {
|
||||
* @return string
|
||||
*/
|
||||
public static function tagBlockClose($tokens, Scope $scope) {
|
||||
$tpl = $scope->tpl;
|
||||
if(isset($tpl->_extends)) { // is child
|
||||
if($scope["name"]) { // is scalar name
|
||||
if($tpl->_compatible) { // is compatible mode
|
||||
$scope->replaceContent(
|
||||
'<?php /* 1) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(empty($tpl->b['.$scope["cname"].'])) { '.
|
||||
'$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php };".
|
||||
"} ?>".PHP_EOL
|
||||
);
|
||||
} elseif(!isset($tpl->blocks[ $scope["name"] ])) { // is block not registered
|
||||
$tpl->blocks[ $scope["name"] ] = $scope->getContent();
|
||||
$scope->replaceContent(
|
||||
'<?php /* 2) Block '.$tpl.': '.$scope["cname"].' '.$tpl->_compatible.' */'.PHP_EOL.' $tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php }; ?>".PHP_EOL
|
||||
);
|
||||
}
|
||||
} else { // dynamic name
|
||||
$tpl->_compatible = true; // enable compatible mode
|
||||
$scope->replaceContent(
|
||||
'<?php /* 3) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(empty($tpl->b['.$scope["cname"].'])) { '.
|
||||
'$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php };".
|
||||
"} ?>".PHP_EOL
|
||||
);
|
||||
}
|
||||
} else { // is parent
|
||||
if(isset($tpl->blocks[ $scope["name"] ])) { // has block
|
||||
if($tpl->_compatible) { // compatible mode enabled
|
||||
$scope->replaceContent(
|
||||
'<?php /* 4) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(isset($tpl->b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL.
|
||||
$tpl->blocks[ $scope["name"] ].
|
||||
'<?php } ?>'.PHP_EOL
|
||||
);
|
||||
|
||||
} else {
|
||||
$scope->replaceContent($tpl->blocks[ $scope["name"] ]);
|
||||
}
|
||||
$tpl = $scope->tpl;
|
||||
if(isset($tpl->_extends)) { // is child
|
||||
if($scope["name"]) { // is scalar name
|
||||
if($tpl->_compatible) { // is compatible mode
|
||||
$scope->replaceContent(
|
||||
'<?php /* 1) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(empty($tpl->b['.$scope["cname"].'])) { '.
|
||||
'$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php };".
|
||||
"} ?>".PHP_EOL
|
||||
);
|
||||
} elseif(!isset($tpl->blocks[ $scope["name"] ])) { // is block not registered
|
||||
$tpl->blocks[ $scope["name"] ] = $scope->getContent();
|
||||
$scope->replaceContent(
|
||||
'<?php /* 2) Block '.$tpl.': '.$scope["cname"].' '.$tpl->_compatible.' */'.PHP_EOL.' $tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php }; ?>".PHP_EOL
|
||||
);
|
||||
}
|
||||
} else { // dynamic name
|
||||
$tpl->_compatible = true; // enable compatible mode
|
||||
$scope->replaceContent(
|
||||
'<?php /* 3) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(empty($tpl->b['.$scope["cname"].'])) { '.
|
||||
'$tpl->b['.$scope["cname"].'] = function($tpl) { ?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
"<?php };".
|
||||
"} ?>".PHP_EOL
|
||||
);
|
||||
}
|
||||
} else { // is parent
|
||||
if(isset($tpl->blocks[ $scope["name"] ])) { // has block
|
||||
if($tpl->_compatible) { // compatible mode enabled
|
||||
$scope->replaceContent(
|
||||
'<?php /* 4) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(isset($tpl->b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL.
|
||||
$tpl->blocks[ $scope["name"] ].
|
||||
'<?php } ?>'.PHP_EOL
|
||||
);
|
||||
|
||||
} else {
|
||||
$scope->replaceContent($tpl->blocks[ $scope["name"] ]);
|
||||
}
|
||||
// } elseif(isset($tpl->_extended) || !empty($tpl->_compatible)) {
|
||||
} elseif(isset($tpl->_extended) && $tpl->_compatible || empty($tpl->_extended)) {
|
||||
} elseif(isset($tpl->_extended) && $tpl->_compatible || empty($tpl->_extended)) {
|
||||
// var_dump("$tpl: exxx");
|
||||
$scope->replaceContent(
|
||||
'<?php /* 5) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(isset($tpl->b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
'<?php } ?>'.PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
$scope->replaceContent(
|
||||
'<?php /* 5) Block '.$tpl.': '.$scope["cname"].' */'.PHP_EOL.' if(isset($tpl->b['.$scope["cname"].'])) { echo $tpl->b['.$scope["cname"].']->__invoke($tpl); } else {?>'.PHP_EOL.
|
||||
$scope->getContent().
|
||||
'<?php } ?>'.PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
|
||||
}
|
||||
|
||||
public static function tagParent($tokens, Scope $scope) {
|
||||
|
@ -51,6 +51,15 @@ class Template extends Render {
|
||||
* @var array of blocks
|
||||
*/
|
||||
public $blocks = array();
|
||||
|
||||
public $uses = array();
|
||||
|
||||
public $parents = array();
|
||||
|
||||
public $_extends;
|
||||
public $_extended = false;
|
||||
public $_compatible;
|
||||
|
||||
/**
|
||||
* Call stack
|
||||
* @var Scope[]
|
||||
@ -1070,4 +1079,5 @@ class Template extends Render {
|
||||
|
||||
class CompileException extends \ErrorException {}
|
||||
class SecurityException extends CompileException {}
|
||||
class ImproperUseException extends \LogicException {}
|
||||
class ImproperUseException extends \LogicException {}
|
||||
class ReparseTagException extends \Exception {}
|
@ -101,7 +101,7 @@ class Tokenizer {
|
||||
\T_NEW => 1, \T_PRINT => 1, \T_PRIVATE => 1, \T_PUBLIC => 1, \T_PROTECTED => 1, \T_REQUIRE => 1,
|
||||
\T_REQUIRE_ONCE => 1,\T_RETURN => 1, \T_RETURN => 1, \T_STRING => 1, \T_SWITCH => 1, \T_THROW => 1,
|
||||
\T_TRAIT => 1, \T_TRAIT_C => 1, \T_TRY => 1, \T_UNSET => 1, \T_UNSET => 1, \T_VAR => 1,
|
||||
\T_WHILE => 1, \T_YIELD => 1
|
||||
\T_WHILE => 1, \T_YIELD => 1, \T_USE => 1
|
||||
),
|
||||
self::MACRO_INCDEC => array(
|
||||
\T_INC => 1, \T_DEC => 1
|
||||
|
@ -14,4 +14,11 @@ function drop() {
|
||||
$e = new Exception();
|
||||
echo "-------\nDump trace: \n".$e->getTraceAsString()."\n";
|
||||
exit();
|
||||
}
|
||||
|
||||
function dump() {
|
||||
foreach(func_get_args() as $arg) {
|
||||
fwrite(STDERR, "DUMP: ".call_user_func("print_r", $arg, true)."\n");
|
||||
|
||||
}
|
||||
}
|
@ -1,11 +1,25 @@
|
||||
<?php
|
||||
namespace Cytro;
|
||||
use Cytro, Cytro\TestCase;
|
||||
use Symfony\Component\Process\Exception\LogicException;
|
||||
|
||||
class ExtendsTemplateTest extends TestCase {
|
||||
|
||||
public static function templates(array $vars) {
|
||||
public function _testSandbox() {
|
||||
$this->cytro = Cytro::factory(CYTRO_RESOURCES.'/provider', CYTRO_RESOURCES.'/compile');
|
||||
try {
|
||||
print_r($this->cytro->getTemplate('use/child.tpl')->getBody());
|
||||
} catch (\Exception $e) {
|
||||
echo "$e";
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Templates skeletons
|
||||
* @param array $vars
|
||||
* @return array
|
||||
*/
|
||||
public static function templates(array $vars) {
|
||||
return array(
|
||||
array(
|
||||
"name" => "level.0.tpl",
|
||||
@ -22,6 +36,7 @@ class ExtendsTemplateTest extends TestCase {
|
||||
array(
|
||||
"name" => "level.1.tpl",
|
||||
"level" => 1,
|
||||
"use" => false,
|
||||
"blocks" => array(
|
||||
"b1" => "from level 1"
|
||||
),
|
||||
@ -33,6 +48,7 @@ class ExtendsTemplateTest extends TestCase {
|
||||
array(
|
||||
"name" => "level.2.tpl",
|
||||
"level" => 2,
|
||||
"use" => false,
|
||||
"blocks" => array(
|
||||
"b2" => "from level 2",
|
||||
"b4" => "unused block"
|
||||
@ -45,6 +61,7 @@ class ExtendsTemplateTest extends TestCase {
|
||||
array(
|
||||
"name" => "level.3.tpl",
|
||||
"level" => 3,
|
||||
"use" => false,
|
||||
"blocks" => array(
|
||||
"b1" => "from level 3",
|
||||
"b2" => "also from level 3"
|
||||
@ -57,10 +74,19 @@ class ExtendsTemplateTest extends TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
public static function generate($block_mask, $extend_mask, array $vars) {
|
||||
/**
|
||||
* Generate templates by skeletons
|
||||
*
|
||||
* @param $block_mask
|
||||
* @param $extend_mask
|
||||
* @param array $skels
|
||||
* @return array
|
||||
*/
|
||||
public static function generate($block_mask, $extend_mask, $skels) {
|
||||
$t = array();
|
||||
foreach(self::templates($vars) as $level => $tpl) {
|
||||
foreach($skels as $level => $tpl) {
|
||||
$src = 'level#'.$level.' ';
|
||||
|
||||
foreach($tpl["blocks"] as $bname => &$bcode) {
|
||||
$src .= sprintf($block_mask, $bname, $bname.': '.$bcode)." level#$level ";
|
||||
}
|
||||
@ -75,10 +101,8 @@ class ExtendsTemplateTest extends TestCase {
|
||||
}
|
||||
return $t;
|
||||
}
|
||||
/**
|
||||
* @group static-extend
|
||||
*/
|
||||
public function testTemplateExtends() {
|
||||
|
||||
public function _testTemplateExtends() {
|
||||
$vars = array(
|
||||
"b1" => "b1",
|
||||
"b2" => "b2",
|
||||
@ -87,14 +111,15 @@ class ExtendsTemplateTest extends TestCase {
|
||||
"level" => "level",
|
||||
"default" => 5
|
||||
);
|
||||
$tpls = self::generate('{block "%s"}%s{/block}', '{extends "level.%d.tpl"}', $vars);
|
||||
$tpls = self::generate('{block "%s"}%s{/block}', '{extends "level.%d.tpl"}', self::templates($vars));
|
||||
foreach($tpls as $name => $tpl) {
|
||||
$this->tpl($name, $tpl["src"]);
|
||||
$this->assertSame($this->cytro->fetch($name, $vars), $tpl["dst"]);
|
||||
}
|
||||
return;
|
||||
$vars["default"]++;
|
||||
$this->cytro->flush();
|
||||
$tpls = self::generate('{block "{$%s}"}%s{/block}', '{extends "level.%d.tpl"}', $vars);
|
||||
$tpls = self::generate('{block "{$%s}"}%s{/block}', '{extends "level.%d.tpl"}', self::templates($vars));
|
||||
arsort($tpls);
|
||||
foreach($tpls as $name => $tpl) {
|
||||
$this->tpl("d.".$name, $tpl["src"]);
|
||||
@ -102,12 +127,24 @@ class ExtendsTemplateTest extends TestCase {
|
||||
}
|
||||
$vars["default"]++;
|
||||
$this->cytro->flush();
|
||||
$tpls = self::generate('{block "%s"}%s{/block}', '{extends "$level.%d.tpl"}', $vars);
|
||||
$tpls = self::generate('{block "%s"}%s{/block}', '{extends "$level.%d.tpl"}', self::templates($vars));
|
||||
arsort($tpls);
|
||||
foreach($tpls as $name => $tpl) {
|
||||
$this->tpl("x.".$name, $tpl["src"]);
|
||||
$this->assertSame($this->cytro->fetch("x.".$name, $vars), $tpl["dst"]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group use
|
||||
*/
|
||||
public function testUse() {
|
||||
$this->cytro = Cytro::factory(CYTRO_RESOURCES.'/provider', CYTRO_RESOURCES.'/compile');
|
||||
$this->assertSame("<html>\n block 1 blocks \n block 2 child \n</html>", $this->cytro->fetch('use/child.tpl'));
|
||||
}
|
||||
|
||||
public function _testParent() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
2
tests/resources/provider/use/blocks.tpl
Normal file
2
tests/resources/provider/use/blocks.tpl
Normal file
@ -0,0 +1,2 @@
|
||||
{block 'b1'} block 1 blocks {/block}
|
||||
{block 'b2'} block 2 blocks {/block}
|
3
tests/resources/provider/use/child.tpl
Normal file
3
tests/resources/provider/use/child.tpl
Normal file
@ -0,0 +1,3 @@
|
||||
{extends 'use/parent.tpl'}
|
||||
{use 'use/blocks.tpl'}
|
||||
{block 'b2'} block 2 child {/block}
|
4
tests/resources/provider/use/parent.tpl
Normal file
4
tests/resources/provider/use/parent.tpl
Normal file
@ -0,0 +1,4 @@
|
||||
<html>
|
||||
{block 'b1'} block 1 parent {/block}
|
||||
{block 'b2'} block 2 parent {/block}
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user