Skip to content
Permalink
Browse files

Engine: templates are wrapped into classes

  • Loading branch information...
dg committed Jan 28, 2015
1 parent 95bfce5 commit cc72d91b6e66362ba4d527a7b4bbbea04b1bdc26
Showing with 105 additions and 50 deletions.
  1. +7 −1 src/Latte/Compiler.php
  2. +22 −21 src/Latte/Engine.php
  3. +1 −1 tests/Latte/CoreMacros.status.phpt
  4. +6 −6 tests/Latte/Engine.onCompile.phpt
  5. +2 −1 tests/Latte/expected/macros.defineblock.phtml
  6. +4 −1 tests/Latte/expected/macros.dynamicblock.phtml
  7. +3 −1 tests/Latte/expected/macros.filters.phtml
  8. +2 −1 tests/Latte/expected/macros.first-sep-last.phtml
  9. +4 −1 tests/Latte/expected/macros.general.html.phtml
  10. +4 −1 tests/Latte/expected/macros.general.xhtml.phtml
  11. +3 −1 tests/Latte/expected/macros.ical.phtml
  12. +3 −1 tests/Latte/expected/macros.include.inc1.phtml
  13. +3 −1 tests/Latte/expected/macros.include.inc2.phtml
  14. +3 −1 tests/Latte/expected/macros.include.inc3.phtml
  15. +4 −1 tests/Latte/expected/macros.include.phtml
  16. +2 −1 tests/Latte/expected/macros.includeblock.inc.phtml
  17. +2 −1 tests/Latte/expected/macros.includeblock.phtml
  18. +2 −1 tests/Latte/expected/macros.inheritance.child1.child.phtml
  19. +3 −1 tests/Latte/expected/macros.inheritance.child1.parent.phtml
  20. +4 −1 tests/Latte/expected/macros.inheritance.child2.phtml
  21. +2 −1 tests/Latte/expected/macros.inheritance.child5.phtml
  22. +2 −0 tests/Latte/expected/macros.recursive.phtml
  23. +5 −1 tests/Latte/expected/macros.syntax.phtml
  24. +3 −1 tests/Latte/expected/macros.unquoted.phtml
  25. +4 −1 tests/Latte/expected/macros.use.phtml
  26. +2 −1 tests/Latte/expected/macros.xml.phtml
  27. +1 −0 tests/Latte/macros.debugbreak.phpt
  28. +2 −0 tests/Latte/macros.php.phpt
@@ -92,7 +92,7 @@ public function addMacro($name, IMacro $macro)
* @param Token[]
* @return string
*/
public function compile(array $tokens)
public function compile(array $tokens, $className = NULL)
{
$this->templateId = substr(lcg_value(), 2, 10);
$this->tokens = $tokens;
@@ -129,6 +129,12 @@ public function compile(array $tokens)
}
$output = $this->expandTokens($output);
$output = "<?php\n"
. 'class ' . ($className ?: 'Template') . " extends Latte\\Template {\n"

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Jan 29, 2015

Contributor

Really? Just Template? Why not sth random?

This comment has been minimized.

Copy link
@dg

dg Jan 29, 2015

Author Member

It's hard to create instance of class with random name ;)

This comment has been minimized.

Copy link
@Majkl578

Majkl578 Jan 29, 2015

Contributor

So, if I understand it correctly (haven't followed related discussion), you will have a generic Template class in global scope? That'd sound like a bad idea.

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Jan 29, 2015

Contributor

@Majkl578 It has been fixed cdf25b7

. "function render() {\n"
. 'foreach ($this->params as $__k => $__v) $$__k = $__v; unset($__k, $__v);'

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Jan 29, 2015

Contributor

btw: do use consider $this safe to rely upon? Or should you always use $template? ~~~Using $this would allow @internal methods in Template to be private.~~~ Obviously you can make them private even when using $template.

This comment has been minimized.

Copy link
@JanTvrdik

JanTvrdik Jan 29, 2015

Contributor

ping, did you miss this comments?

. '?>' . $output . "<?php\n}}";
return $output;
}
@@ -77,18 +77,20 @@ class Engine extends Object
'upper' => 'Latte\Runtime\Filters::upper',
);
/** @var string */
private $baseTemplateClass = 'Latte\Template';
/**
* Renders template to output.
* @return void
*/
public function render($name, array $params = array())
{
$template = new $this->baseTemplateClass($params, $this->filters, $this, $name);
$this->loadCacheFile($name, $template->getParameters());
$class = $this->getTemplateClass($name);
if (!class_exists($class, FALSE)) {
$this->loadCacheFile($name);
}
$template = new $class($params, $this->filters, $this, $name);
$template->render();
}
@@ -125,7 +127,7 @@ public function compile($name)
$tokens = $this->getParser()->setContentType($this->contentType)
->parse($source);
$code = $this->getCompiler()->setContentType($this->contentType)
->compile($tokens);
->compile($tokens, $this->getTemplateClass($name));
if (!preg_match('#\n|\?#', $name)) {
$code = "<?php\n// source: $name\n?>" . $code;
@@ -143,19 +145,15 @@ public function compile($name)
/**
* @return void
*/
private function loadCacheFile($name, $params)
private function loadCacheFile($name)
{
if (!$this->tempDirectory) {
return call_user_func(function() {
foreach (func_get_arg(1) as $__k => $__v) {
$$__k = $__v;
}
unset($__k, $__v);
eval('?>' . func_get_arg(0));
}, $this->compile($name), $params);
eval('?>' . $this->compile($name));
return;
}
$file = $this->getCacheFile($name);
$handle = fopen($file, 'c+');
if (!$handle) {
throw new \RuntimeException("Unable to open or create file '$file'.");
@@ -176,13 +174,7 @@ private function loadCacheFile($name, $params)
flock($handle, LOCK_SH); // holds the lock
}
call_user_func(function() {
foreach (func_get_arg(1) as $__k => $__v) {
$$__k = $__v;
}
unset($__k, $__v);
include func_get_arg(0);
}, $file, $params);
include $file;
}
@@ -207,6 +199,15 @@ public function getCacheFile($name)
}
/**
* @return string
*/
public function getTemplateClass($name)
{

This comment has been minimized.

Copy link
@milo

milo Feb 20, 2015

Member

The $tempDirectory may be relative and class name different for same template. E.g.

string(41) "D:\Web\temp\nsbub\app/../temp/cache/latte"
string(43) "D:\Web\temp\nsbub\tests/../temp/cache/latte"

This comment has been minimized.

Copy link
@milo

milo Feb 20, 2015

Member

As a consequence, loadCacheFile() loads existing file, but following new $class fails, because the class name is now different.

This comment has been minimized.

Copy link
@dg

dg Feb 20, 2015

Author Member

I think it's fine.

This comment has been minimized.

Copy link
@milo

This comment has been minimized.

Copy link
@dg

dg Feb 20, 2015

Author Member

Aha!

return 'Template' . md5("$this->tempDirectory\00$name");
}
/**
* Registers run-time filter.
* @param string|NULL
@@ -18,7 +18,7 @@ Assert::match('%A%
<?php header((isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : "HTTP/1.1") . " " . 200, TRUE, 200) ?>
<?php if (!headers_sent()) header((isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : "HTTP/1.1") . " " . 300, TRUE, 300) ;
', $latte->compile('
%A%', $latte->compile('
{status 200}
{status 300?}
@@ -22,8 +22,8 @@ test(function () {
Notes::add('adding macros 2');
};
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::same(array(
'adding macros 1',
@@ -46,8 +46,8 @@ test(function () {
$latte->setLoader(new Latte\Loaders\StringLoader);
$latte->onCompile = new ArrayIterator($callbacks);
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::same(array(
'adding macros 3',
@@ -86,8 +86,8 @@ test(function () {
$latte->setLoader(new Latte\Loaders\StringLoader);
$latte->onCompile = new Event($callbacks);
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%a%;', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::match('%A%$var%A%', $latte->compile('{$var}'));
Assert::same(array(
'adding macros 5',
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -34,3 +34,4 @@ if ($_l->extends) { ob_start();}
<?php if ($_l->extends) { ob_end_clean(); return $template->renderChildTemplate($_l->extends, get_defined_vars()); } ?>

<?php call_user_func(reset($_b->blocks['test']), $_b, array('var' => 20) + get_defined_vars()) ;
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -62,3 +62,6 @@ if (!function_exists($_b->blocks["word$name"]['%[a-z0-9]+%'] = '_%[a-z0-9]+%_wor
// block "word$name"
//
if (!function_exists($_b->blocks["word$name"]['%[a-z0-9]+%'] = '_%[a-z0-9]+%__word_name_')) { function _%[a-z0-9]+%__word_name_($_b, $_args) { foreach ($_args as $__k => $__v) $$__k = $__v ;}} call_user_func(reset($_b->blocks["word$name"]), $_b, get_defined_vars()) ?>

<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -84,3 +84,5 @@ Nested blocks: <?php ob_start() ?> Outer <?php ob_start() ?> Inner Block <?php
Block <?php echo $template->truncate(ob_get_clean(), 20) ?>

</p>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -36,3 +36,4 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
<span>, </span><?php } ?>
<?php if ($iterator->isLast()) { ?><span>)</span>
<?php } $iterations++; } array_pop($_l->its); $iterator = end($_l->its) ;
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -307,3 +307,6 @@ Hello<?php } $iterations++; } $iterations = 0; foreach (array(1) as $foo) { if (
<?php } array_pop($_l->switch) ?>
<?php echo $template->nl2br("\n") ?>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'xhtml')
;
@@ -307,3 +307,6 @@ Hello<?php } $iterations++; } $iterations = 0; foreach (array(1) as $foo) { if (
<?php } array_pop($_l->switch) ?>
<?php echo $template->nl2br("\n") ?>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'ical')
;
@@ -25,3 +25,5 @@ DESCRIPTION:
CLASS:PUBLIC
END:VEVENT
END:VCALENDAR
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -17,3 +17,5 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
<textarea>
pre
</textarea>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -10,3 +10,5 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
?>
<p>Included file #2 (<?php echo Latte\Runtime\Filters::escapeHtml($localvar, ENT_NOQUOTES) ?>
, <?php echo Latte\Runtime\Filters::escapeHtml($hello, ENT_NOQUOTES) ?>)</p>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -10,3 +10,5 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
?>
<p>Included file #3 (<?php echo Latte\Runtime\Filters::escapeHtml($localvar, ENT_NOQUOTES) ?>
, <?php echo Latte\Runtime\Filters::escapeHtml($hello, ENT_NOQUOTES) ?>)</p>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -10,3 +10,6 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
?>

<?php ob_start(); $_b->templates['%[a-z0-9]+%']->renderChildTemplate('subdir/include1.latte' . '', array('localvar' => 10) + $template->getParameters()); echo $template->indent(ob_get_clean()) ?>

<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -27,3 +27,4 @@ if ($_l->extends) { ob_start();}
// main template
//
if ($_l->extends) { ob_end_clean(); return $template->renderChildTemplate($_l->extends, get_defined_vars()); }
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -13,3 +13,4 @@ list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')


<?php Latte\Macros\BlockMacros::callBlock($_b, 'test', $template->getParameters()) ;
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -46,3 +46,4 @@ call_user_func(reset($_b->blocks['title']), $_b, get_defined_vars()) ?>


<?php call_user_func(reset($_b->blocks['content']), $_b, get_defined_vars()) ;
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -55,3 +55,5 @@ call_user_func(reset($_b->blocks['title']), $_b, get_defined_vars()) ?></title>
</div>
</body>
</html>
<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -53,3 +53,6 @@ call_user_func(reset($_b->blocks['content']), $_b, get_defined_vars()) ?>


<?php call_user_func(reset($_b->blocks['sidebar']), $_b, get_defined_vars()) ?>

<?php
%A%
@@ -1,6 +1,6 @@
<?php
// source: %a%
%A%
// prolog Latte\Macros\CoreMacros
list($_b, $_g, $_l) = $template->initialize('%[a-z0-9]+%', 'html')
;
@@ -29,3 +29,4 @@ if ($_l->extends) { ob_start();}

<?php if ($_l->extends) { ob_end_clean(); return $template->renderChildTemplate($_l->extends, get_defined_vars()); }
call_user_func(reset($_b->blocks['content']), $_b, get_defined_vars()) ;
%A%
@@ -10,3 +10,5 @@
<li><?php echo Latte\Runtime\Filters::escapeHtml($template->upper(function() { return; }), ENT_NOQUOTES) ?></li>
<li><?php echo Latte\Runtime\Filters::escapeHtml($template->upper(function() { return; }, $item->{10}), ENT_NOQUOTES) ?></li>
</ul>
<?php
%A%
Oops, something went wrong.

2 comments on commit cc72d91

@JanTvrdik

This comment has been minimized.

Copy link
Contributor

JanTvrdik replied Jan 29, 2015

👍 Do you plan to turn blocks into methods? And $_l and $_g into properties?

@dg

This comment has been minimized.

Copy link
Member Author

dg replied Jan 29, 2015

I do. At this moment (commit), the intention is to speed up rendering for 2.3

Please sign in to comment.
You can’t perform that action at this time.