diff --git a/README.textile b/README.textile index ccd74bdb..46528336 100644 --- a/README.textile +++ b/README.textile @@ -41,7 +41,7 @@ Example snippet: h2. Howto use Liquid -Code to render: +Code to render with original php-liquid:
$liquid->parse(file_get_contents('templates/products.tpl'))->render($products);
@@ -61,3 +61,24 @@ h2. Fork Notes
This fork is based on php-liquid by Mateo Murphy. The original library is still hosted at: ("http://code.google.com/p/php-liquid/":http://code.google.com/p/php-liquid/)
+Variables couldn't be used inside an 'include' or an 'extends' tag.
+
+Which means the below code didn't work:
+
+
+{% include foo %}
+{% include {{ foo }} %}
+
+
+With this modification it will work (where a string not inside a " or ' is considered as a variable):
+
+
+{% include merchant/'head' %}
+{% extends "root"/foo/bar/'index' %}
+
+
+Code to render with modified php-liquid (backward compatible, which means the original example does still work but variables can't be used in include and extends tags):
+
+
+$liquid->parse(file_get_contents('templates/products.tpl'), $products)->render();
+
diff --git a/lib/LiquidContext.class.php b/lib/LiquidContext.class.php
index 6ba00265..264ad92c 100644
--- a/lib/LiquidContext.class.php
+++ b/lib/LiquidContext.class.php
@@ -68,6 +68,17 @@ public function addFilters($filter)
}
+ /**
+ * Add registers to the context
+ *
+ * @param array $registers
+ */
+ public function addRegisters($registers = array())
+ {
+ $this->registers = $registers;
+ }
+
+
/**
* Invoke the filter that matches given name
*
diff --git a/lib/LiquidTemplate.class.php b/lib/LiquidTemplate.class.php
index ee0eb970..3cf5b06d 100644
--- a/lib/LiquidTemplate.class.php
+++ b/lib/LiquidTemplate.class.php
@@ -39,6 +39,11 @@ class LiquidTemplate
private static $_cache;
+ /**
+ * @var LiquidContext The context for keeping and resolving variables
+ */
+ private static $_context;
+
/**
* Constructor
@@ -131,6 +136,17 @@ public static function getTags()
}
+ /**
+ *
+ *
+ * @return array
+ */
+ public static function getContext()
+ {
+ return self::$_context;
+ }
+
+
/**
* Register the filter
*
@@ -158,11 +174,14 @@ public static function tokenize($source)
* Parses the given source string
*
* @param string $source
+ * @param array $assigns An array of values for the template
*/
- public function parse($source)
+ public function parse($source, array $assigns = array())
{
$cache = self::$_cache;
+ self::$_context = new LiquidContext($assigns, null);
+
if (isset($cache))
{
if (($this->_root = $cache->read(md5($source))) != false && $this->_root->checkIncludes() != true)
@@ -192,7 +211,13 @@ public function parse($source)
*/
public function render(array $assigns = array(), $filters = null, $registers = null)
{
- $context = new LiquidContext($assigns, $registers);
+ $context = self::$_context;
+ if (!empty($assigns) && is_array($assigns)) {
+ $context->merge($assigns);
+ }
+ if (!is_null($registers) && is_array($registers)) {
+ $context->addRegisters($registers);
+ }
if (!is_null($filters))
{
@@ -211,6 +236,7 @@ public function render(array $assigns = array(), $filters = null, $registers = n
$context->addFilters($filter);
}
+ self::$_context = $context;
return $this->_root->render($context);
}
}
diff --git a/lib/Tag/LiquidTagExtends.class.php b/lib/Tag/LiquidTagExtends.class.php
index fff9a923..827915a8 100644
--- a/lib/Tag/LiquidTagExtends.class.php
+++ b/lib/Tag/LiquidTagExtends.class.php
@@ -38,50 +38,72 @@ class LiquidTagExtends extends LiquidTag
*/
public function __construct($markup, &$tokens, &$fileSystem)
{
- $regex = new LiquidRegexp('/("[^"]+"|\'[^\']+\')?/');
+ $regex = new LiquidRegexp('/([^\s]+)?/');
if ($regex->match($markup))
{
- $this->_templateName = substr($regex->matches[1], 1, strlen($regex->matches[1]) - 2);
+ $regexTemplateName = new LiquidRegexp('/"[^"]+"|\'[^\']+\'|[^"\'\/]+/');
+ if ($regexTemplateName->match_all($regex->matches[1])) {
+ $regexQuote = new LiquidRegexp('/"[^"]+"|\'[^\']+\'/');
+ $context = LiquidTemplate::getContext();
+ $templName = "";
+ foreach ($regexTemplateName->matches[0] as $templPart) {
+ $templPartName = '';
+ if ($regexQuote->match($templPart)) {
+ $templPartName = trim($templPart,"\"''");
+ } else {
+ $templPartName = $context->get($templPart);
+ }
+ if (!empty($templPartName)) {
+ if (!empty($templName)) $templName .= "/";
+ $templName .= $templPartName;
+ }
+ }
+ $this->_templateName = $templName;
+ }
+
+ if (empty($this->_templateName)) {
+ throw new LiquidException("Error in tag 'extends' - Valid syntax: include [template]|'[template]' (with|for) [object|collection]");
+ }
}
else
{
- throw new LiquidException("Error in tag 'extends' - Valid syntax: extends '[template name]'");
+ throw new LiquidException("Error in tag 'extends' - Valid syntax: extends [template]|'[template name]'");
}
parent::__construct($markup, $tokens, $fileSystem);
}
- private function _findBlocks($tokens)
- {
- $blockstartRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*block (\w+)\s*(.*)?' . LIQUID_TAG_END . '$/');
- $blockendRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*endblock\s*?' . LIQUID_TAG_END . '$/');
-
- $b = array();
- $name = null;
-
- foreach($tokens as $token)
- {
- if($blockstartRegexp->match($token))
- {
- $name = $blockstartRegexp->matches[1];
- $b[$name] = array();
- }
- else if($blockendRegexp->match($token))
- {
- $name = null;
- }
- else
- {
- if(isset($name))
- {
- array_push($b[$name], $token);
- }
- }
- }
-
- return $b;
+ private function _findBlocks($tokens)
+ {
+ $blockstartRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*block (\w+)\s*(.*)?' . LIQUID_TAG_END . '$/');
+ $blockendRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*endblock\s*?' . LIQUID_TAG_END . '$/');
+
+ $b = array();
+ $name = null;
+
+ foreach($tokens as $token)
+ {
+ if($blockstartRegexp->match($token))
+ {
+ $name = $blockstartRegexp->matches[1];
+ $b[$name] = array();
+ }
+ else if($blockendRegexp->match($token))
+ {
+ $name = null;
+ }
+ else
+ {
+ if(isset($name))
+ {
+ array_push($b[$name], $token);
+ }
+ }
+ }
+
+ return $b;
}
@@ -120,10 +142,10 @@ public function parse(&$tokens)
$childtokens = $this->_findBlocks($tokens);
$blockstartRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*block (\w+)\s*(.*)?' . LIQUID_TAG_END . '$/');
- $blockendRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*endblock\s*?' . LIQUID_TAG_END . '$/');
-
- $b = array();
- $name = null;
+ $blockendRegexp = new LiquidRegexp('/^' . LIQUID_TAG_START . '\s*endblock\s*?' . LIQUID_TAG_END . '$/');
+
+ $b = array();
+ $name = null;
$rest = array();
$aufzeichnen = false;
@@ -131,7 +153,7 @@ public function parse(&$tokens)
for($i = 0; $i < count($maintokens); $i++)
{
if($blockstartRegexp->match($maintokens[$i]))
- {
+ {
$name = $blockstartRegexp->matches[1];
if(isset($childtokens[$name]))
@@ -141,16 +163,16 @@ public function parse(&$tokens)
foreach($childtokens[$name] as $item)
array_push($rest, $item);
}
-
- }
+
+ }
if(!$aufzeichnen)
- array_push($rest, $maintokens[$i]);
+ array_push($rest, $maintokens[$i]);
- if($blockendRegexp->match($maintokens[$i]) && $aufzeichnen === true)
- {
+ if($blockendRegexp->match($maintokens[$i]) && $aufzeichnen === true)
+ {
$aufzeichnen = false;
array_push($rest, $maintokens[$i]);
- }
+ }
}
}
diff --git a/lib/Tag/LiquidTagInclude.class.php b/lib/Tag/LiquidTagInclude.class.php
index b2760808..e5a72133 100644
--- a/lib/Tag/LiquidTagInclude.class.php
+++ b/lib/Tag/LiquidTagInclude.class.php
@@ -45,8 +45,8 @@ class LiquidTagInclude extends LiquidTag
*/
private $_document;
- /**
- * @var string The Source Hash
+ /**
+ * @var string The Source Hash
*/
protected $_hash;
@@ -61,12 +61,33 @@ class LiquidTagInclude extends LiquidTag
*/
public function __construct($markup, &$tokens, &$fileSystem)
{
- $regex = new LiquidRegexp('/("[^"]+"|\'[^\']+\')(\s+(with|for)\s+(' . LIQUID_QUOTED_FRAGMENT . '+))?/');
+ $regex = new LiquidRegexp('/([^\s]+)(\s+(with|for)\s+(' . LIQUID_QUOTED_FRAGMENT . '+))?/');
if ($regex->match($markup))
{
+ $regexTemplateName = new LiquidRegexp('/"[^"]+"|\'[^\']+\'|[^"\'\/]+/');
+ if ($regexTemplateName->match_all($regex->matches[1])) {
+ $regexQuote = new LiquidRegexp('/"[^"]+"|\'[^\']+\'/');
+ $context = LiquidTemplate::getContext();
+ $templName = "";
+ foreach ($regexTemplateName->matches[0] as $templPart) {
+ $templPartName = '';
+ if ($regexQuote->match($templPart)) {
+ $templPartName = trim($templPart,"\"''");
+ } else {
+ $templPartName = $context->get($templPart);
+ }
+ if (!empty($templPartName)) {
+ if (!empty($templName)) $templName .= "/";
+ $templName .= $templPartName;
+ }
+ }
+ $this->_templateName = $templName;
+ }
- $this->_templateName = substr($regex->matches[1], 1, strlen($regex->matches[1]) - 2);
+ if (empty($this->_templateName)) {
+ throw new LiquidException("Error in tag 'include' - Valid syntax: include [template]|'[template]' (with|for) [object|collection]");
+ }
if (isset($regex->matches[1]))
{
@@ -78,7 +99,7 @@ public function __construct($markup, &$tokens, &$fileSystem)
}
else
{
- throw new LiquidException("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]");
+ throw new LiquidException("Error in tag 'include' - Valid syntax: include [template]|'[template]' (with|for) [object|collection]");
}
parent::__construct($markup, $tokens, $fileSystem);
diff --git a/test/liquid/StandardTagTest.php b/test/liquid/StandardTagTest.php
index a28d3442..08824bf5 100644
--- a/test/liquid/StandardTagTest.php
+++ b/test/liquid/StandardTagTest.php
@@ -20,8 +20,23 @@ function readTemplateFile($templatePath)
{
if ($templatePath == 'inner') {
return "Inner: {{ inner }}{{ other }}";
-
- }
+ }
+
+ if ($templatePath == 'inner2') {
+ return "Inner: {{ inner }}{{ other }}";
+ }
+
+ if ($templatePath == 'prob/foo/bar/prob/inner2') {
+ return "Inner in prob/foo/bar/prob/: {{ inner }}{{ other }}";
+ }
+
+ if ($templatePath == 'outer') {
+ return "Outer: {% block title %}outer-title{% endblock %}";
+ }
+
+ if ($templatePath == 'prob/foo/bar/prob/outer') {
+ return "Outer in prob/foo/bar/prob: {% block title %}outer-title{% endblock %}";
+ }
}
}
@@ -344,4 +359,44 @@ function test_include_tag_no_with()
$this->assertEqual("Outer-Inner: orig-Outer-Inner: orig23", $output);
}
+ function test_include_tag_with_variable()
+ {
+ $template = new LiquidTemplate();
+ $template->setFileSystem(new LiquidTestFileSystem());
+
+ $template->parse("Outer-{% include inner2 %}-Outer with variable-{% include inner2 other:'23' %}", array("inner2"=>"inner2", "inner"=>"orig", "var" => array(1,2,3)));
+ $output = $template->render();
+ $this->assertEqual("Outer-Inner: orig-Outer with variable-Inner: orig23", $output);
+
+ $template->parse("Outer-{% include 'prob'/foo/bar/\"prob\"/inner2 %}-Outer with variable-{% include 'prob'/foo/bar/\"prob\"/inner2 other:'23' %}", array("inner2"=>"inner2", "foo"=>"foo", "bar"=>"bar", "inner"=>"orig", "var" => array(1,2,3)));
+ $output = $template->render();
+ $this->assertEqual("Outer-Inner in prob/foo/bar/prob/: orig-Outer with variable-Inner in prob/foo/bar/prob/: orig23", $output);
+ }
+
+ function test_extends_tag()
+ {
+ $template = new LiquidTemplate();
+ $template->setFileSystem(new LiquidTestFileSystem());
+
+ $template->parse("{% extends 'outer' %} {% block title %}inner-title{% endblock %}");
+
+ $output = $template->render();
+
+ $this->assertEqual("Outer: inner-title", $output);
+ }
+
+ function test_extends_tag_with_variable()
+ {
+ $template = new LiquidTemplate();
+ $template->setFileSystem(new LiquidTestFileSystem());
+
+ $template->parse("{% extends outer %} {% block title %}inner-title with variable{% endblock %}", array("outer"=>"outer"));
+ $output = $template->render();
+ $this->assertEqual("Outer: inner-title with variable", $output);
+
+ $template->parse("{% extends 'prob'/foo/bar/\"prob\"/outer %} {% block title %}inner-title with variable{% endblock %}", array("outer"=>"outer", "foo"=>"foo", "bar"=>"bar"));
+ $output = $template->render();
+ $this->assertEqual("Outer in prob/foo/bar/prob: inner-title with variable", $output);
+ }
+
}
\ No newline at end of file