From 31239170cdbd69e4e1ae5465c3f5b32611ed9313 Mon Sep 17 00:00:00 2001 From: Alexander Guz Date: Wed, 8 Feb 2017 16:32:45 +0100 Subject: [PATCH 001/296] Require phpunit: ~4.8 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 67b2b241..3a99081a 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "php": ">= 5.3" }, "require-dev": { - "phpunit/phpunit": "*" + "phpunit/phpunit": "~4.8" }, "autoload": { "psr-4": { From 5ba17442c021629940d09d9afe2d61c3d781361a Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 23 May 2017 01:36:04 +1000 Subject: [PATCH 002/296] Fix minor typos and inconsistencies --- src/Liquid/AbstractBlock.php | 2 +- src/Liquid/Context.php | 2 +- src/Liquid/StandardFilters.php | 2 +- src/Liquid/Tag/TagBlock.php | 2 +- src/Liquid/Tag/TagCapture.php | 2 +- src/Liquid/Tag/TagCase.php | 2 +- src/Liquid/Tag/TagIfchanged.php | 4 +--- src/Liquid/Tag/TagRaw.php | 2 +- src/Liquid/Tag/TagUnless.php | 2 +- tests/Liquid/OutputTest.php | 8 ++++---- tests/Liquid/StandardFiltersTest.php | 4 ++-- 11 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index e8d16dcf..0f2d5d66 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -143,7 +143,7 @@ protected function unknownTag($tag, $params, array $tokens) { case 'end': throw new LiquidException("'end' is not a valid delimiter for " . $this->blockName() . " tags. Use " . $this->blockDelimiter()); default: - throw new LiquidException("Unkown tag $tag"); + throw new LiquidException("Unknown tag $tag"); } } diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 9a1ca3e9..1707df48 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -54,7 +54,7 @@ public function __construct(array $assigns = array(), array $registers = array() $this->assigns = array($assigns); $this->registers = $registers; $this->filterbank = new Filterbank($this); - // first empty array serves as source for ovverides, e.g. as in TagDecrement + // first empty array serves as source for overrides, e.g. as in TagDecrement $this->environments = array(array(), $_SERVER); } diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index de7bce98..48d96505 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -428,7 +428,7 @@ public static function slice($input, $offset, $length = null) { } return $input; - } + } /** diff --git a/src/Liquid/Tag/TagBlock.php b/src/Liquid/Tag/TagBlock.php index ee29b90a..982e468d 100644 --- a/src/Liquid/Tag/TagBlock.php +++ b/src/Liquid/Tag/TagBlock.php @@ -36,7 +36,7 @@ class TagBlock extends AbstractBlock * Constructor * * @param string $markup - * @param Array $tokens + * @param array $tokens * @param FileSystem $fileSystem * * @throws \Liquid\LiquidException diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index c6d356c4..8d8c7536 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -37,7 +37,7 @@ class TagCapture extends AbstractBlock * Constructor * * @param string $markup - * @param Array $tokens + * @param array $tokens * @param FileSystem $fileSystem * * @throws \Liquid\LiquidException diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 9f131a2b..092dac99 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -112,7 +112,7 @@ public function unknownTag($tag, $params, array $tokens) { break; case 'else': - // push the last nodelist onto the stack and prepare to recieve the else nodes + // push the last nodelist onto the stack and prepare to receive the else nodes $this->pushNodelist(); $this->right = null; $this->elseNodelist = &$this->nodelist; diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index 0ad50b47..235f9aaa 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -13,9 +13,7 @@ use Liquid\AbstractBlock; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; -use Liquid\Regexp; /** * Quickly create a table from a collection @@ -33,7 +31,7 @@ class TagIfchanged extends AbstractBlock * Constructor * * @param string $markup - * @param Array $tokens + * @param array $tokens * @param FileSystem $fileSystem * * @throws \Liquid\LiquidException diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index d5acf00c..5186acca 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -43,7 +43,7 @@ public function parse(array &$tokens) { $token = array_shift($tokens); if ($tagRegexp->match($token)) { - // If we found the proper block delimitor just end parsing here and let the outer block proceed + // If we found the proper block delimiter just end parsing here and let the outer block proceed if ($tagRegexp->matches[1] == $this->blockDelimiter()) { return; } diff --git a/src/Liquid/Tag/TagUnless.php b/src/Liquid/Tag/TagUnless.php index f0cc6f56..c2c9db47 100644 --- a/src/Liquid/Tag/TagUnless.php +++ b/src/Liquid/Tag/TagUnless.php @@ -27,7 +27,7 @@ class TagUnless extends TagIf{ /** - * Replace first finded key in $subject to value + * Replace first found key in $subject to value * * @param array $replacer (key => value array) * @param string $subject diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index b31c518d..7b1038e2 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -69,16 +69,16 @@ public function testVariableTrasversing() { public function testVariablePiping() { $text = " {{ car.gm | make_funny }} "; - $expectd = " LOL "; + $expected = " LOL "; - $this->assertTemplateResult($expectd, $text, $this->assigns); + $this->assertTemplateResult($expected, $text, $this->assigns); } public function testVariablePipingWithInput() { $text = " {{ car.gm | cite_funny }} "; - $expectd = " LOL: bad "; + $expected = " LOL: bad "; - $this->assertTemplateResult($expectd, $text, $this->assigns); + $this->assertTemplateResult($expected, $text, $this->assigns); } public function testVariablePipingWithArgs() { diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 7257c751..bd9d8316 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -261,7 +261,7 @@ public function testPrepend() { } public function testSlice() { - // Slize up to the end + // Slice up to the end $data = array( array( array(), @@ -289,7 +289,7 @@ public function testSlice() { $this->assertEquals($item[1], StandardFilters::slice($item[0], 2)); } - // Slize a few elements + // Slice a few elements $data = array( array( array(), From 9b562e05da92a0936b19966d701041d4f564c6b5 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 23 May 2017 01:52:04 +1000 Subject: [PATCH 003/296] Support Traversable loops and filters --- src/Liquid/Context.php | 4 +- src/Liquid/StandardFilters.php | 78 +++++++++++++---- src/Liquid/Tag/TagFor.php | 4 + src/Liquid/Tag/TagPaginate.php | 3 + src/Liquid/Tag/TagTablerow.php | 4 + tests/Liquid/StandardFiltersTest.php | 121 +++++++++++++++++++++++++-- 6 files changed, 189 insertions(+), 25 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 1707df48..ebf7efc0 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -308,7 +308,7 @@ private function variable($key) { } // finally, resolve objects to values - if (is_object($object)) { + if (is_object($object) && !($object instanceof \Traversable)) { if (method_exists($object, '__toString')) { $object = (string) $object; } elseif (method_exists($object, 'toLiquid')) { @@ -317,7 +317,7 @@ private function variable($key) { } // if everything else fails, throw up - if (is_object($object)) { + if (is_object($object) && !($object instanceof \Traversable)) { $class = get_class($object); throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` method"); } diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 48d96505..242b3010 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -152,11 +152,15 @@ public static function escape_once($input) { /** * Returns the first element of an array * - * @param array $input + * @param array|\Iterator $input * * @return mixed */ public static function first($input) { + if ($input instanceof \Iterator) { + $input->rewind(); + return $input->current(); + } return is_array($input) ? reset($input) : $input; } @@ -174,12 +178,22 @@ public static function floor($input) { /** * Joins elements of an array with a given character between them * - * @param array $input + * @param array|\Traversable $input * @param string $glue * * @return string */ public static function join($input, $glue = ' ') { + if ($input instanceof \Traversable) { + $str = ''; + foreach ($input as $elem) { + if ($str) { + $str .= $glue; + } + $str .= $elem; + } + return $str; + } return is_array($input) ? implode($glue, $input) : $input; } @@ -187,11 +201,18 @@ public static function join($input, $glue = ' ') { /** * Returns the last element of an array * - * @param array $input + * @param array|\Traversable $input * * @return mixed */ public static function last($input) { + if ($input instanceof \Traversable) { + $last = null; + foreach ($input as $elem){ + $last = $elem; + } + return $last; + } return is_array($input) ? end($input) : $input; } @@ -209,20 +230,26 @@ public static function lstrip($input) { /** * Map/collect on a given property * - * @param array $input + * @param array|\Traversable $input * @param string $property * * @return string */ - public static function map(array $input, $property) { - return array_reduce($input, function($result, $elem) use ($property) { + public static function map($input, $property) { + if ($input instanceof \Traversable) { + $input = iterator_to_array($input); + } + if (!is_array($input)) { + return $input; + } + return array_map(function ($elem) use ($property) { if (is_callable($elem)) { - return $result . $elem(); + return $elem(); } elseif (is_array($elem) && array_key_exists($property, $elem)) { - return $result . $elem[$property]; + return $elem[$property]; } - return $result . ''; - }, ''); + return null; + }, $input); } @@ -357,11 +384,14 @@ public static function replace_first($input, $string, $replacement = '') { /** * Reverse the elements of an array * - * @param array $input + * @param array|\Traversable $input * * @return array */ - public static function reverse(array $input) { + public static function reverse($input) { + if ($input instanceof \Traversable) { + $input = iterator_to_array($input); + } return array_reverse($input); } @@ -397,6 +427,9 @@ public static function rstrip($input) { * @return int */ public static function size($input) { + if ($input instanceof \Iterator) { + return iterator_count($input); + } if (is_string($input) || is_numeric($input)) { return strlen($input); } elseif (is_array($input)) { @@ -412,13 +445,16 @@ public static function size($input) { /** - * @param array|string $input + * @param array|\Iterator|string $input * @param int $offset * @param int $length * - * @return array|string + * @return array|\Iterator|string */ public static function slice($input, $offset, $length = null) { + if ($input instanceof \Iterator) { + $input = iterator_to_array($input); + } if (is_array($input)) { $input = array_slice($input, $offset, $length); } elseif (is_string($input)) { @@ -434,12 +470,15 @@ public static function slice($input, $offset, $length = null) { /** * Sort the elements of an array * - * @param array $input + * @param array|\Traversable $input * @param string $property use this property of an array element * * @return array */ - public static function sort(array $input, $property = null) { + public static function sort($input, $property = null) { + if ($input instanceof \Traversable) { + $input = iterator_to_array($input); + } if ($property === null) { asort($input); } else { @@ -566,11 +605,14 @@ public static function truncatewords($input, $words = 3, $ending = '...') { /** * Remove duplicate elements from an array * - * @param array $input + * @param array|\Traversable $input * * @return array */ - public static function uniq(array $input) { + public static function uniq($input) { + if ($input instanceof \Traversable) { + $input = iterator_to_array($input); + } return array_unique($input); } diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index 7096d301..c0f50112 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -110,6 +110,10 @@ public function render(Context $context) { case 'collection': $collection = $context->get($this->collectionName); + + if ($collection instanceof \Traversable) { + $collection = iterator_to_array($collection); + } if (is_null($collection) || !is_array($collection) || count($collection) == 0) { return ''; diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 1ab81884..29b3c287 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -109,6 +109,9 @@ public function render(Context $context) { $this->currentPage = ( is_numeric($context->get('page')) ) ? $context->get('page') : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); + if ($this->collection instanceof \Traversable) { + $this->collection = iterator_to_array($this->collection); + } $this->collectionSize = count($this->collection); $this->totalPages = ceil($this->collectionSize / $this->numberItems); $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 8f6ba435..efc29e08 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -78,6 +78,10 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu public function render(Context $context) { $collection = $context->get($this->collectionName); + if ($collection instanceof \Traversable) { + $collection = iterator_to_array($collection); + } + if (!is_array($collection)) { die('not array, ' . var_export($collection, true)); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index bd9d8316..99022c3f 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -63,6 +63,7 @@ public function testSize() { 4 => 1000, 3 => 100, 2 => array('one', 'two'), + 1 => new \ArrayIterator(array('one')), SizeClass::SIZE => new SizeClass(), ); @@ -267,6 +268,10 @@ public function testSlice() { array(), array(), ), + array( + new \ArrayIterator(array()), + array(), + ), array( '', '', @@ -275,6 +280,10 @@ public function testSlice() { array(1,2,3,4,5), array(3,4,5), ), + array( + new \ArrayIterator(array(1,2,3,4,5)), + array(3,4,5), + ), array( '12345', '345' @@ -286,15 +295,27 @@ public function testSlice() { ); foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::slice($item[0], 2)); + $actual = StandardFilters::slice($item[0], 2); + if ($actual instanceof \Traversable) { + $actual = iterator_to_array($actual); + } + $this->assertEquals($item[1], $actual); } // Slice a few elements $data = array( + array( + null, + null, + ), array( array(), array(), ), + array( + new \ArrayIterator(array()), + array(), + ), array( '', '', @@ -303,6 +324,10 @@ public function testSlice() { array(1,2,3,4,5), array(3,4), ), + array( + new \ArrayIterator(array(1,2,3,4,5)), + array(3,4), + ), array( '12345', '34' @@ -314,7 +339,11 @@ public function testSlice() { ); foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::slice($item[0], 2, 2)); + $actual = StandardFilters::slice($item[0], 2, 2); + if ($actual instanceof \Traversable) { + $actual = iterator_to_array($actual); + } + $this->assertEquals($item[1], $actual); } } @@ -377,6 +406,10 @@ public function testJoin() { array(), '', ), + array( + new \ArrayIterator(array()), + '' + ), array( '', '', @@ -385,6 +418,10 @@ public function testJoin() { array(1,2,3,4,5), '1 2 3 4 5' ), + array( + new \ArrayIterator(array(1,2,3,4,5)), + '1 2 3 4 5' + ), array( 100, 100 @@ -397,6 +434,7 @@ public function testJoin() { // Custom glue $this->assertEquals('1-2-3', StandardFilters::join(array(1, 2, 3), '-')); + $this->assertEquals('1-2-3', StandardFilters::join(new \ArrayIterator(array(1, 2, 3)), '-')); } public function testSort() { @@ -405,10 +443,18 @@ public function testSort() { array(), array(), ), + array( + new \ArrayIterator(array()), + array(), + ), array( array(1, 5, 3, 4, 2), array(1, 2, 3, 4, 5), ), + array( + new \ArrayIterator(array(1, 5, 3, 4, 2)), + array(1, 2, 3, 4, 5), + ), ); foreach ($data as $item) { @@ -428,6 +474,7 @@ public function testSort() { ); $this->assertEquals($expected, StandardFilters::sort($original, 'b'), '', 0, 10, true); + $this->assertEquals($expected, StandardFilters::sort(new \ArrayIterator($original), 'b'), '', 0, 10, true); } /* @@ -463,10 +510,18 @@ public function testUnique() { array(), array(), ), + array( + new \ArrayIterator(array()), + array(), + ), array( array(1, 1, 5, 3, 4, 2, 5, 2), array(1, 5, 3, 4, 2), ), + array( + new \ArrayIterator(array(1, 1, 5, 3, 4, 2, 5, 2)), + array(1, 5, 3, 4, 2), + ), ); foreach ($data as $item) { @@ -480,10 +535,18 @@ public function testReverse() { array(), array(), ), + array( + new \ArrayIterator(array()), + array(), + ), array( array(1, 1, 5, 3, 4, 2, 5, 2), array(2, 5, 2, 4, 3, 5, 1, 1), ), + array( + new \ArrayIterator(array(1, 1, 5, 3, 4, 2, 5, 2)), + array(2, 5, 2, 4, 3, 5, 1, 1), + ), ); foreach ($data as $item) { @@ -495,7 +558,11 @@ public function testMap() { $data = array( array( array(), - '', + array(), + ), + array( + new \ArrayIterator(array()), + array(), ), array( array( @@ -511,12 +578,32 @@ function() { 'no_attr' => 'another value ' ), ), - 'from function value ', + array('from function ', 'value ', null), + ), + array( + new \ArrayIterator(array( + function() { + return 'from function '; + }, + array( + 'b' => 10, + 'attr' => 'value ', + ), + array( + 'a' => 20, + 'no_attr' => 'another value ' + ), + )), + array('from function ', 'value ', null), ), ); foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::map($item[0], 'attr')); + $actual = StandardFilters::map($item[0], 'attr'); + if ($actual instanceof \Traversable) { + $actual = iterator_to_array($actual); + } + $this->assertEquals($item[1], $actual); } } @@ -526,14 +613,26 @@ public function testFirst() { array(), false, ), + array( + new \ArrayIterator(array()), + false, + ), array( array('two', 'one', 'three'), 'two', ), + array( + new \ArrayIterator(array('two', 'one', 'three')), + 'two', + ), array( array(100, 400, 200), 100, ), + array( + new \ArrayIterator(array(100, 400, 200)), + 100, + ), ); foreach ($data as $item) { @@ -547,14 +646,26 @@ public function testLast() { array(), false, ), + array( + new \ArrayIterator(array()), + false, + ), array( array('two', 'one', 'three'), 'three', ), + array( + new \ArrayIterator(array('two', 'one', 'three')), + 'three', + ), array( array(100, 400, 200), 200, ), + array( + new \ArrayIterator(array(100, 400, 200)), + 200, + ), ); foreach ($data as $item) { From 72e24dd28a495a4f13d28750a6ab751d3f9dc5a5 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 23 May 2017 01:57:19 +1000 Subject: [PATCH 004/296] More flexible variable name regex --- src/Liquid/Liquid.php | 13 +++++++++++-- src/Liquid/Tag/TagDecrement.php | 2 +- src/Liquid/Tag/TagFor.php | 4 ++-- src/Liquid/Tag/TagIncrement.php | 2 +- src/Liquid/Tag/TagPaginate.php | 2 +- src/Liquid/Tag/TagTablerow.php | 2 +- tests/Liquid/Tag/TagDecrementTest.php | 4 ++++ tests/Liquid/Tag/TagForTest.php | 12 ++++++++++++ tests/Liquid/TestCase.php | 2 +- 9 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index c668886a..5fdc65d9 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -64,8 +64,8 @@ class Liquid // Variable end. 'VARIABLE_END' => '}}', - // The characters allowed in a variable. - 'ALLOWED_VARIABLE_CHARS' => '[a-zA-Z_.-]', + // Variable name. + 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z_0-9.-]*', 'QUOTED_STRING' => '"[^"]*"|\'[^\']*\'', 'QUOTED_STRING_FILTER_ARGUMENT' => '"[^":]*"|\'[^\':]*\'', @@ -82,6 +82,10 @@ class Liquid * @return string */ public static function get($key) { + // backward compatibility + if ($key === 'ALLOWED_VARIABLE_CHARS') { + return substr(self::$config['VARIABLE_NAME'], 0, -1); + } if (array_key_exists($key, self::$config)) { return self::$config[$key]; } else { @@ -108,6 +112,11 @@ public static function get($key) { * @param string $value */ public static function set($key, $value) { + // backward compatibility + if ($key === 'ALLOWED_VARIABLE_CHARS') { + $key = 'VARIABLE_NAME'; + $value .= '+'; + } self::$config[$key] = $value; } diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index 23cad030..4c481c4e 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -46,7 +46,7 @@ class TagDecrement extends AbstractTag * @throws \Liquid\LiquidException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - $syntax = new Regexp("/(" . Liquid::get('ALLOWED_VARIABLE_CHARS') . "+)/"); + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { $this->toDecrement = $syntax->matches[0]; diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index 7096d301..55a53063 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -67,7 +67,7 @@ class TagFor extends AbstractBlock public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); - $syntaxRegexp = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('ALLOWED_VARIABLE_CHARS') . '+)/'); + $syntaxRegexp = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntaxRegexp->match($markup)) { @@ -78,7 +78,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu } else { - $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\s*..\s*(\d|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\)/'); + $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d+|' . Liquid::get('VARIABLE_NAME') . ')\s*\.\.\s*(\d+|' . Liquid::get('VARIABLE_NAME') . ')\)/'); if ($syntaxRegexp->match($markup)) { $this->type = 'digit'; $this->variableName = $syntaxRegexp->matches[1]; diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index e60ff0f6..2c105b60 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -46,7 +46,7 @@ class TagIncrement extends AbstractTag * @throws \Liquid\LiquidException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - $syntax = new Regexp("/(" . Liquid::get('ALLOWED_VARIABLE_CHARS') . "+)/"); + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { $this->toIncrement = $syntax->matches[0]; diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 1ab81884..a363593c 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -84,7 +84,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu parent::__construct($markup, $tokens, $fileSystem); - $syntax = new Regexp('/(' . Liquid::get('ALLOWED_VARIABLE_CHARS') . '+)\s+by\s+(\w+)/'); + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')\s+by\s+(\w+)/'); if ($syntax->match($markup)) { $this->collectionName = $syntax->matches[1]; diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 8f6ba435..e74fdcfc 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -56,7 +56,7 @@ class TagTablerow extends AbstractBlock public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); - $syntax = new Regexp("/(\w+)\s+in\s+(" . Liquid::get('ALLOWED_VARIABLE_CHARS') . "+)/"); + $syntax = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { $this->variableName = $syntax->matches[1]; diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index c270cf5d..a5902b7a 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -36,4 +36,8 @@ public function testDecrementVariable() { public function testDecrementNestedVariable() { $this->assertTemplateResult(42, '{% for var in vars %}{% decrement var %}{{ var }}{% endfor %}', array('vars' => array(43))); } + + public function testVariableNameContainingNumber() { + $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', array('var123' => 43)); + } } diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 5da06e70..ebc23960 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -72,6 +72,18 @@ public function testForHelpers() { $this->assertTemplateResult(' 0 0 1 ', '{%for item in array%} {{forloop.last}} {%endfor%}', $assigns); } + public function testForHelpersWithOffsetAndLimit() { + $assigns = array('array' => array(0, 1, 2, 3, 4)); + + $this->assertTemplateResult(' 1/3 2/3 3/3 ', '{%for item in array offset:1 limit:3%} {{forloop.index}}/{{forloop.length}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 1 2 3 ', '{%for item in array offset:1 limit:3%} {{forloop.index}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 0 1 2 ', '{%for item in array offset:1 limit:3%} {{forloop.index0}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 2 1 0 ', '{%for item in array offset:1 limit:3%} {{forloop.rindex0}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 3 2 1 ', '{%for item in array offset:1 limit:3%} {{forloop.rindex}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 1 0 0 ', '{%for item in array offset:1 limit:3%} {{forloop.first}} {%endfor%}', $assigns); + $this->assertTemplateResult(' 0 0 1 ', '{%for item in array offset:1 limit:3%} {{forloop.last}} {%endfor%}', $assigns); + } + public function testForAndIf() { $assigns = array('array' => array(1, 2, 3)); $this->assertTemplateResult(' yay ', '{%for item in array%} {% if forloop.first %}yay{% endif %} {%endfor%}', $assigns); diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 682f251e..1fbbeb4c 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -37,7 +37,7 @@ protected function setUp() { 'TAG_END' => '%}', 'VARIABLE_START' => '{{', 'VARIABLE_END' => '}}', - 'ALLOWED_VARIABLE_CHARS' => '[a-zA-Z_.-]', + 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z0-9_.-]*', 'QUOTED_STRING' => '"[^":]*"|\'[^\':]*\'', ); From e269b40e0b13a6e514c7c499c06e0dde506c5634 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 23 May 2017 13:42:25 +1000 Subject: [PATCH 005/296] Normalize whitespace --- examples/block.php | 2 +- src/Liquid/Filterbank.php | 2 +- src/Liquid/StandardFilters.php | 21 ++- src/Liquid/Tag/TagFor.php | 74 ++++---- src/Liquid/Tag/TagIfchanged.php | 4 +- src/Liquid/Tag/TagPaginate.php | 260 +++++++++++++------------- src/Liquid/Tag/TagUnless.php | 6 +- tests/Liquid/DropTest.php | 2 +- tests/Liquid/Tag/NoTransformTest.php | 2 +- tests/Liquid/Tag/TagDecrementTest.php | 4 +- 10 files changed, 190 insertions(+), 187 deletions(-) diff --git a/examples/block.php b/examples/block.php index 3fe9d884..30893e3b 100644 --- a/examples/block.php +++ b/examples/block.php @@ -36,5 +36,5 @@ 'copyright' => '© Copyright 2014 Guz Alexander - All rights reserved.' ) ); - + echo $liquid->render($assigns); diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index f3943201..b04211f6 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -54,7 +54,7 @@ public function __construct(Context $context) { * Adds a filter to the bank * * @param mixed $filter Can either be an object, the name of a class (in which case the - * filters will be called statically) or the name of a function. + * filters will be called statically) or the name of a function. * * @throws LiquidException * @return bool diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 48d96505..9c7a6908 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -100,7 +100,7 @@ public static function _default($input, $default_value) { public static function divided_by($input, $operand) { return (int)$input / (int)$operand; } - + /** * Convert an input to lowercase @@ -125,6 +125,7 @@ public static function raw($input) { return $input; } + /** * Escape a string * @@ -386,8 +387,8 @@ public static function round($input, $n = 0) { */ public static function rstrip($input) { return rtrim($input); - } - + } + /** * Return the size of an array or of an string @@ -539,7 +540,7 @@ public static function truncate($input, $characters = 100, $ending = '...') { return $input; } - + /** * Truncate string down to x words @@ -573,7 +574,8 @@ public static function truncatewords($input, $words = 3, $ending = '...') { public static function uniq(array $input) { return array_unique($input); } - + + /** * Convert an input to uppercase * @@ -585,6 +587,7 @@ public static function upcase($input) { return is_string($input) ? strtoupper($input) : $input; } + /** * URL encodes a string * @@ -607,9 +610,9 @@ public static function url_encode($input) { * */ public function __call($name, $arguments) { - if ($name === 'default') { - return $this->_default($arguments[0], $arguments[1]); - } - } + if ($name === 'default') { + return $this->_default($arguments[0], $arguments[1]); + } + } } diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index 55a53063..73dfedfc 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -26,11 +26,11 @@ * {%for item in array%} {{item}} {%endfor%} * * With an array of 1, 2, 3, 4, will return 1 2 3 4 - * - * or * - * {%for i in (1..10)%} {{i}} {%endfor%} - * {%for i in (1..variable)%} {{i}} {%endfor%} + * or + * + * {%for i in (1..10)%} {{i}} {%endfor%} + * {%for i in (1..variable)%} {{i}} {%endfor%} * */ class TagFor extends AbstractBlock @@ -49,7 +49,7 @@ class TagFor extends AbstractBlock * @var string The name of the loop, which is a compound of the collection and variable names */ private $name; - + /** * @var string The type of the loop (collection or digit) */ @@ -70,14 +70,14 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $syntaxRegexp = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntaxRegexp->match($markup)) { - + $this->variableName = $syntaxRegexp->matches[1]; $this->collectionName = $syntaxRegexp->matches[2]; $this->name = $syntaxRegexp->matches[1] . '-' . $syntaxRegexp->matches[2]; $this->extractAttributes($markup); - + } else { - + $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d+|' . Liquid::get('VARIABLE_NAME') . ')\s*\.\.\s*(\d+|' . Liquid::get('VARIABLE_NAME') . ')\)/'); if ($syntaxRegexp->match($markup)) { $this->type = 'digit'; @@ -86,7 +86,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->collectionName = $syntaxRegexp->matches[3]; $this->name = $syntaxRegexp->matches[1].'-digit'; $this->extractAttributes($markup); - } else { + } else { throw new LiquidException("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]"); } } @@ -100,46 +100,46 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * @return null|string */ public function render(Context $context) { - + if (!isset($context->registers['for'])) { $context->registers['for'] = array(); } - + switch ($this->type){ - + case 'collection': $collection = $context->get($this->collectionName); - + if (is_null($collection) || !is_array($collection) || count($collection) == 0) { return ''; } - + $range = array(0, count($collection)); - + if (isset($this->attributes['limit']) || isset($this->attributes['offset'])) { $offset = 0; - + if (isset($this->attributes['offset'])) { $offset = ($this->attributes['offset'] == 'continue') ? $context->registers['for'][$this->name] : $context->get($this->attributes['offset']); } - + $limit = (isset($this->attributes['limit'])) ? $context->get($this->attributes['limit']) : null; $rangeEnd = $limit ? $limit : count($collection) - $offset; $range = array($offset, $rangeEnd); - + $context->registers['for'][$this->name] = $rangeEnd + $offset; } - + $result = ''; $segment = array_slice($collection, $range[0], $range[1]); if (!count($segment)) { return null; } - + $context->push(); $length = count($segment); - + $index = 0; foreach ($segment as $key => $item) { $value = is_numeric($key) ? $item : array($key, $item); @@ -154,53 +154,53 @@ public function render(Context $context) { 'first' => (int)($index == 0), 'last' => (int)($index == $length - 1) )); - + $result .= $this->renderAll($this->nodelist, $context); - + $index++; } - + break; - + case 'digit': - + $start = $this->start; if (!is_integer($this->start)) { $start = $context->get($this->start); } - + $end = $this->collectionName; if (!is_integer($this->collectionName)) { $end = $context->get($this->collectionName); } - + $range = array($start, $end); - + $context->push(); $result = ''; $index = 0; $length = $range[1] - $range[0]; for ($i=$range[0]; $i<=$range[1]; $i++) { - + $context->set($this->variableName, $i); $context->set('forloop', array( 'name' => $this->name, - 'length' => $length, - 'index' => $index + 1, - 'index0' => $index, + 'length' => $length, + 'index' => $index + 1, + 'index0' => $index, 'rindex' => $length - $index, 'rindex0' => $length - $index - 1, 'first' => (int)($index == 0), 'last' => (int)($index == $length - 1) )); - + $result .= $this->renderAll($this->nodelist, $context); - + $index++; } - + break; - + } $context->pop(); diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index 235f9aaa..aea8bf2a 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -54,8 +54,8 @@ public function render(Context $context) { return ''; } else { $this->lastValue = $output; - return $this->lastValue; + return $this->lastValue; } - + } } diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index a363593c..143124ff 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -19,151 +19,151 @@ use Liquid\Regexp; /** - * The paginate tag works in conjunction with the for tag to split content into numerous pages. + * The paginate tag works in conjunction with the for tag to split content into numerous pages. * * Example: * - * {% paginate collection.products by 5 %} - * {% for product in collection.products %} - * - * {% endfor %} - * {% endpaginate %} + * {% paginate collection.products by 5 %} + * {% for product in collection.products %} + * + * {% endfor %} + * {% endpaginate %} * */ class TagPaginate extends AbstractBlock { /** - * @var array The collection to paginate - */ - private $collectionName; - - /** - * @var array The collection object - */ - private $collection; - - /** - * - * @var int The size of the collection - */ - private $collectionSize; + * @var string The collection to paginate + */ + private $collectionName; /** - * @var int The number of items to paginate by - */ - private $numberItems; - - /** - * @var int The current page - */ - private $currentPage; - - /** - * @var int The current offset (no of pages times no of items) - */ - private $currentOffset; - - /** - * @var int Total pages - */ - private $totalPages; - - - /** - * Constructor - * - * @param string $markup - * @param array $tokens + * @var array The collection object + */ + private $collection; + + /** + * + * @var int The size of the collection + */ + private $collectionSize; + + /** + * @var int The number of items to paginate by + */ + private $numberItems; + + /** + * @var int The current page + */ + private $currentPage; + + /** + * @var int The current offset (no of pages times no of items) + */ + private $currentOffset; + + /** + * @var int Total pages + */ + private $totalPages; + + + /** + * Constructor + * + * @param string $markup + * @param array $tokens * @param FileSystem $fileSystem - * + * * @throws \Liquid\LiquidException - * - */ + * + */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - - parent::__construct($markup, $tokens, $fileSystem); - - $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')\s+by\s+(\w+)/'); - - if ($syntax->match($markup)) { - $this->collectionName = $syntax->matches[1]; - $this->numberItems = $syntax->matches[2]; - $this->extractAttributes($markup); - } else { - throw new LiquidException("Syntax Error - Valid syntax: paginate [collection] by [items]"); - } - - } - - /** - * Renders the tag - * - * @param Context $context - * - * @return string - * - */ - public function render(Context $context) { - - $this->currentPage = ( is_numeric($context->get('page')) ) ? $context->get('page') : 1; - $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; - $this->collection = $context->get($this->collectionName); - $this->collectionSize = count($this->collection); - $this->totalPages = ceil($this->collectionSize / $this->numberItems); - $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); - - // Sets the collection if it's a key of another collection (ie search.results, collection.products, blog.articles) - $segments = explode('.', $this->collectionName); - if (count($segments) == 2) { - $context->set($segments[0], array($segments[1] => $paginatedCollection)); - } else { - $context->set($this->collectionName, $paginatedCollection); - } - - $paginate = array( - 'page_size' => $this->numberItems, - 'current_page' => $this->currentPage, - 'current_offset' => $this->currentOffset, - 'pages' => $this->totalPages, - 'items' => $this->collectionSize - ); - - if ( $this->currentPage != 1 ) { - $paginate['previous']['title'] = 'Previous'; - $paginate['previous']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage - 1); - - } - - if ( $this->currentPage != $this->totalPages ) { - $paginate['next']['title'] = 'Next'; - $paginate['next']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage + 1); - } - - $context->set('paginate', $paginate); - - return parent::render($context); - - } - - /** - * Returns the current page URL - * - * @param Context $context - * - * @return string - * - */ - public function currentUrl($context) { - - $uri = explode('?', $context->get('REQUEST_URI')); - - $url = 'http'; + + parent::__construct($markup, $tokens, $fileSystem); + + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')\s+by\s+(\w+)/'); + + if ($syntax->match($markup)) { + $this->collectionName = $syntax->matches[1]; + $this->numberItems = $syntax->matches[2]; + $this->extractAttributes($markup); + } else { + throw new LiquidException("Syntax Error - Valid syntax: paginate [collection] by [items]"); + } + + } + + /** + * Renders the tag + * + * @param Context $context + * + * @return string + * + */ + public function render(Context $context) { + + $this->currentPage = ( is_numeric($context->get('page')) ) ? $context->get('page') : 1; + $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; + $this->collection = $context->get($this->collectionName); + $this->collectionSize = count($this->collection); + $this->totalPages = ceil($this->collectionSize / $this->numberItems); + $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); + + // Sets the collection if it's a key of another collection (ie search.results, collection.products, blog.articles) + $segments = explode('.', $this->collectionName); + if (count($segments) == 2) { + $context->set($segments[0], array($segments[1] => $paginatedCollection)); + } else { + $context->set($this->collectionName, $paginatedCollection); + } + + $paginate = array( + 'page_size' => $this->numberItems, + 'current_page' => $this->currentPage, + 'current_offset' => $this->currentOffset, + 'pages' => $this->totalPages, + 'items' => $this->collectionSize + ); + + if ( $this->currentPage != 1 ) { + $paginate['previous']['title'] = 'Previous'; + $paginate['previous']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage - 1); + + } + + if ( $this->currentPage != $this->totalPages ) { + $paginate['next']['title'] = 'Next'; + $paginate['next']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage + 1); + } + + $context->set('paginate', $paginate); + + return parent::render($context); + + } + + /** + * Returns the current page URL + * + * @param Context $context + * + * @return string + * + */ + public function currentUrl($context) { + + $uri = explode('?', $context->get('REQUEST_URI')); + + $url = 'http'; if ($context->get('HTTPS') == 'on') $url .= 's'; $url .= '://' . $context->get('HTTP_HOST') . reset($uri); - + return $url; - - } - + + } + } diff --git a/src/Liquid/Tag/TagUnless.php b/src/Liquid/Tag/TagUnless.php index c2c9db47..25694c76 100644 --- a/src/Liquid/Tag/TagUnless.php +++ b/src/Liquid/Tag/TagUnless.php @@ -52,7 +52,7 @@ protected function strReplaceOne($replacer, $subject) { * a != 1 or b != 2 */ protected function revertOperators() { - + // replace $replacerOperators = array( '==' => '!=', @@ -62,12 +62,12 @@ protected function revertOperators() { '<' => '>=', '!=' => '==' ); - + $replacerLogicalOperators = array( 'or' => 'and', 'and' => 'or' ); - + if (count($this->blocks) > 0) { if (count($this->blocks[0]) > 1) { $condition = $this->blocks[0][1]; diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index ce11b464..61fd9377 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -24,7 +24,7 @@ public function get_array() { return array('text1', 'text2'); } - public function text() { + public function text() { return 'text1'; } } diff --git a/tests/Liquid/Tag/NoTransformTest.php b/tests/Liquid/Tag/NoTransformTest.php index 65474b4a..29da3130 100644 --- a/tests/Liquid/Tag/NoTransformTest.php +++ b/tests/Liquid/Tag/NoTransformTest.php @@ -25,7 +25,7 @@ public function testNoTransform() { $this->assertTemplateResult('', ''); $text = "this shouldnt see any transformation either but has multiple lines - as you can clearly see here ..."; + as you can clearly see here ..."; $this->assertTemplateResult($text, $text); } diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index a5902b7a..28d1c1af 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -38,6 +38,6 @@ public function testDecrementNestedVariable() { } public function testVariableNameContainingNumber() { - $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', array('var123' => 43)); - } + $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', array('var123' => 43)); + } } From 5cdca94bfb6ca144e4ab2bdec0e33d6e8f4fba45 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 1 Jun 2017 18:09:12 +0900 Subject: [PATCH 006/296] Fix date filter for format with comma --- src/Liquid/Liquid.php | 2 +- tests/Liquid/StandardFiltersTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index c668886a..b4b0d797 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -68,7 +68,7 @@ class Liquid 'ALLOWED_VARIABLE_CHARS' => '[a-zA-Z_.-]', 'QUOTED_STRING' => '"[^"]*"|\'[^\']*\'', - 'QUOTED_STRING_FILTER_ARGUMENT' => '"[^":]*"|\'[^\':]*\'', + 'QUOTED_STRING_FILTER_ARGUMENT' => '"[^"]*"|\'[^\']*\'', // Automatically escape any variables unless told otherwise by a "raw" filter 'ESCAPE_BY_DEFAULT' => false, diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 7257c751..ae11a5c9 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -849,4 +849,14 @@ public function testSecondFilterOverwritesFirst() { $this->context->addFilters(new CanadianMoneyFilter(), 'money'); $this->assertEquals(' 1000$ CAD ', $var->render($this->context)); } + + public function testDate() { + $var = new Variable('var | date, "%Y"'); + $this->context->set('var', '2017-07-01 21:00:00'); + $this->assertEquals('2017', $var->render($this->context)); + + $var = new Variable("var | date: '%d/%m/%Y %l:%M %p'"); + $this->context->set('var', '2017-07-01 21:00:00'); + $this->assertEquals('01/07/2017 9:00 PM', $var->render($this->context)); + } } From ac3a24594a0a1be8f9a3dcc7d12a1ae23794f567 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 23 May 2017 11:07:41 +0900 Subject: [PATCH 007/296] Context: capture value returned from `get` method for objects having `field_exists` method --- src/Liquid/Context.php | 2 +- tests/Liquid/ContextTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index ebf7efc0..538a9ffa 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -292,7 +292,7 @@ private function variable($key) { return null; } - call_user_func(array($object, Liquid::get('GET_PROPERTY_METHOD')), $nextPartName); + $object = call_user_func(array($object, Liquid::get('GET_PROPERTY_METHOD')), $nextPartName); } else { // if it's just a regular object, attempt to access a property if (property_exists($object, $nextPartName)) { diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 9923a76a..f0b7ab67 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -37,6 +37,19 @@ public function __toString() { } } +class GetSetObject +{ + public function field_exists($name) { + return $name == 'answer'; + } + + public function get($prop) { + if ($prop == 'answer') { + return 42; + } + } +} + class HiFilter { public function hi($value) { @@ -116,6 +129,12 @@ public function testVariableIsObjectWithNoToLiquid() { $this->assertEquals("forty two", $this->context->get('test')); } + public function testGetSetObject() { + $this->context->set('object', new GetSetObject()); + $this->assertEquals(42, $this->context->get('object.answer')); + $this->assertNull($this->context->get('object.invalid')); + } + /** * @expectedException \Liquid\LiquidException */ From 4cdc12e28e185bf22b76e901c21ed0aa15bf2aae Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 23 May 2017 11:14:54 +0900 Subject: [PATCH 008/296] Context: call `toLiquid` on every embedded object, not just the first one; plain values have null-valued properties --- src/Liquid/Context.php | 105 +++++++++++++++++++++-------------- tests/Liquid/ContextTest.php | 24 ++++++++ 2 files changed, 86 insertions(+), 43 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 538a9ffa..700415ab 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -247,20 +247,25 @@ private function variable($key) { $object = $this->fetch(array_shift($parts)); - if (is_object($object)) { + while (count($parts) > 0) { + // since we still have a part to consider + // and since we can't dig deeper into plain values + // it can be thought as if it has a property with a null value + if (!is_object($object) && !is_array($object)) { + return null; + } + + // first try to cast an object to an array or value if (method_exists($object, 'toLiquid')) { $object = $object->toLiquid(); - } else if (method_exists($object, 'toArray')) { + } elseif (method_exists($object, 'toArray')) { $object = $object->toArray(); } - // we'll cover regular objects later - } - if ($object === null) { - return null; - } + if (is_null($object)) { + return null; + } - while (count($parts) > 0) { if ($object instanceof Drop) { $object->setContext($this); } @@ -273,53 +278,67 @@ private function variable($key) { return count($object); } - if (array_key_exists($nextPartName, $object)) { - $object = $object[$nextPartName]; - } else { + // no key - no value + if (!array_key_exists($nextPartName, $object)) { + return null; + } + + $object = $object[$nextPartName]; + continue; + } + + if (!is_object($object)) { + // we got plain value, yet asked to resolve a part + // think plain values have a null part with any name + return null; + } + + if ($object instanceof Drop) { + // if the object is a drop, make sure it supports the given method + if (!$object->hasKey($nextPartName)) { return null; } - } elseif (is_object($object)) { - if ($object instanceof Drop) { - // if the object is a drop, make sure it supports the given method - if (!$object->hasKey($nextPartName)) { - return null; - } - - $object = $object->invokeDrop($nextPartName); - } elseif (method_exists($object, Liquid::get('HAS_PROPERTY_METHOD'))) { - if (!call_user_func(array($object, Liquid::get('HAS_PROPERTY_METHOD')), $nextPartName)) { - return null; - } - - $object = call_user_func(array($object, Liquid::get('GET_PROPERTY_METHOD')), $nextPartName); - } else { - // if it's just a regular object, attempt to access a property - if (property_exists($object, $nextPartName)) { - $object = $object->$nextPartName; - } elseif (method_exists($object, $nextPartName)) { - // then try a method - $object = call_user_func(array($object, $nextPartName)); - } else { - return null; - } + $object = $object->invokeDrop($nextPartName); + continue; + } + + // if it has `get` or `field_exists` methods + if (method_exists($object, Liquid::get('HAS_PROPERTY_METHOD'))) { + if (!call_user_func(array($object, Liquid::get('HAS_PROPERTY_METHOD')), $nextPartName)) { + return null; } + + $object = call_user_func(array($object, Liquid::get('GET_PROPERTY_METHOD')), $nextPartName); + continue; } - } - // finally, resolve objects to values - if (is_object($object) && !($object instanceof \Traversable)) { - if (method_exists($object, '__toString')) { - $object = (string) $object; - } elseif (method_exists($object, 'toLiquid')) { - $object = $object->toLiquid(); + // if it's just a regular object, attempt to access a property + if (property_exists($object, $nextPartName)) { + $object = $object->$nextPartName; + continue; + } + + // then try a method + if (method_exists($object, $nextPartName)) { + $object = call_user_func(array($object, $nextPartName)); + continue; } + + // we'll try casting this object in the next iteration + } + + // finally, resolve an object to a string or a plain value + if (method_exists($object, '__toString')) { + $object = (string) $object; + } elseif (method_exists($object, 'toLiquid')) { + $object = $object->toLiquid(); } // if everything else fails, throw up if (is_object($object) && !($object instanceof \Traversable)) { $class = get_class($object); - throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` method"); + throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` methods"); } return $object; diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index f0b7ab67..bff4f914 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -37,6 +37,21 @@ public function __toString() { } } +class NestedObject +{ + public $property; + public $value = -1; + + public function toLiquid() { + // we intentionally made the value different so + // that we could see where it is coming from + return array( + 'property' => $this->property, + 'value' => 42, + ); + } +} + class GetSetObject { public function field_exists($name) { @@ -129,6 +144,15 @@ public function testVariableIsObjectWithNoToLiquid() { $this->assertEquals("forty two", $this->context->get('test')); } + public function testNestedObject() { + $object = new NestedObject(); + $object->property = new NestedObject(); + $this->context->set('object', $object); + $this->assertEquals(42, $this->context->get('object.value')); + $this->assertEquals(42, $this->context->get('object.property.value')); + $this->assertNull($this->context->get('object.property.value.invalid')); + } + public function testGetSetObject() { $this->context->set('object', new GetSetObject()); $this->assertEquals(42, $this->context->get('object.answer')); From c8e9674132f991b9b5cb57baecc9dc93a9dfe324 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 1 Jun 2017 16:12:39 +0900 Subject: [PATCH 009/296] Context: first try accessing a public method, then resort to a property Reason to this is that property_exists ignores all accessibility. Before this change, even if we had a public method with the same name, we would cause a fatal error trying to access a private property. Now this will only happen if there's no public method. > Fatal error: Uncaught Error: Cannot access private property Fixes #38 --- src/Liquid/Context.php | 12 ++++++------ tests/Liquid/ContextTest.php | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 700415ab..d2bfd676 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -313,15 +313,15 @@ private function variable($key) { continue; } - // if it's just a regular object, attempt to access a property - if (property_exists($object, $nextPartName)) { - $object = $object->$nextPartName; + // if it's just a regular object, attempt to access a public method + if (is_callable(array($object, $nextPartName))) { + $object = call_user_func(array($object, $nextPartName)); continue; } - // then try a method - if (method_exists($object, $nextPartName)) { - $object = call_user_func(array($object, $nextPartName)); + // then try a property (independent of accessibility) + if (property_exists($object, $nextPartName)) { + $object = $object->$nextPartName; continue; } diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index bff4f914..db1a9535 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -28,6 +28,12 @@ public function amount() { class NoToLiquid { public $answer = 42; + private $name = null; + + public function name() { + return 'example'; + } + public function count() { return 1; } @@ -142,6 +148,7 @@ public function testVariableIsObjectWithNoToLiquid() { $this->assertEquals(42, $this->context->get('test.answer')); $this->assertEquals(1, $this->context->get('test.count')); $this->assertEquals("forty two", $this->context->get('test')); + $this->assertEquals("example", $this->context->get('test.name')); } public function testNestedObject() { From dc17a86c749685153e531357bbf5f3ec700f4d18 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 17 Jul 2017 15:25:17 +0900 Subject: [PATCH 010/296] Context: verify that Traversable objects can actually be used --- src/Liquid/Context.php | 7 ++++++- tests/Liquid/Tag/TagForTest.php | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index d2bfd676..034e66c0 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -328,6 +328,11 @@ private function variable($key) { // we'll try casting this object in the next iteration } + // Traversable objects are taken care of inside filters + if ($object instanceof \Traversable) { + return $object; + } + // finally, resolve an object to a string or a plain value if (method_exists($object, '__toString')) { $object = (string) $object; @@ -336,7 +341,7 @@ private function variable($key) { } // if everything else fails, throw up - if (is_object($object) && !($object instanceof \Traversable)) { + if (is_object($object)) { $class = get_class($object); throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` methods"); } diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 5da06e70..28bb7d0c 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -26,6 +26,7 @@ public function testForInvalidSyntax() { public function testFor() { $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' boo boo boo boo ', '{%for item in array%} boo {%endfor%}', array('array' => new \ArrayIterator(array(1, 2, 3, 4)))); $this->assertTemplateResult('yoyo', '{%for item in array%}yo{%endfor%}', array('array' => array(1, 2))); $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1))); $this->assertTemplateResult('', '{%for item in array%}{%endfor%}', array('array' => array(1, 2))); From 61d47e74b4ddaaa1605950e8d2f2480aa394835f Mon Sep 17 00:00:00 2001 From: Alexander Guz Date: Mon, 17 Jul 2017 10:03:27 +0200 Subject: [PATCH 011/296] Changelog for 1.3.0 --- CHANGELOG | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c3ecef9f..771f7971 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +* 1.3.0 (2017-07-17) + + * Support Traversable loops and filters + * Fix date filter for format with colon + * Various minor improvements and bugs fixes + * 1.2.1 (2016-12-12) * Remove content injection from $_GET. From face88f951fe8cfb6956cbd731d101d974da56ce Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 11:46:33 +0900 Subject: [PATCH 012/296] Allow looping over extended ranges Fixes #36 --- src/Liquid/Tag/TagFor.php | 2 +- tests/Liquid/Tag/TagForTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index c0f50112..e520c34a 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -78,7 +78,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu } else { - $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\s*..\s*(\d|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\)/'); + $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d+|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\s*..\s*(\d+|'.Liquid::get('ALLOWED_VARIABLE_CHARS').'+)\)/'); if ($syntaxRegexp->match($markup)) { $this->type = 'digit'; $this->variableName = $syntaxRegexp->matches[1]; diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 28bb7d0c..df97b4d5 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -83,6 +83,7 @@ public function testForAndIf() { public function testLimiting() { $assigns = array('array' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); $this->assertTemplateResult('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', $assigns); + $this->assertTemplateResult('1234567890', '{%for i in array limit:20 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('3456', '{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('3456', '{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}', $assigns); @@ -181,4 +182,13 @@ public function testPauseResumeBIGOffset() { XPCTD; $this->assertTemplateResult($expected, $markup, $assigns); } + + public function testForWithRanges() { + $this->assertTemplateResult('123456789', '{%for i in (1..9)%}{{i}}{%endfor%}'); + $this->assertTemplateResult(' 9 10 11', '{%for i in (9..11)%} {{i}}{%endfor%}'); + $this->assertTemplateResult('9991000', '{%for i in (999..1000)%}{{i}}{%endfor%}'); + + $assigns = array('variable' => 100); + $this->assertTemplateResult('9596979899100', '{%for i in (95..variable)%}{{i}}{%endfor%}', $assigns); + } } From c9f7c0be7dd84c4a444cc04b03a87fc8861f3ef7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 12:19:44 +0900 Subject: [PATCH 013/296] Math filters should not cast to int Shopify's liquid does just so. Fixes #27 --- src/Liquid/StandardFilters.php | 42 ++++++++++++++-------------- tests/Liquid/StandardFiltersTest.php | 24 +++++++++++----- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 242b3010..8c6ab797 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -92,13 +92,13 @@ public static function _default($input, $default_value) { /** * division * - * @param int $input - * @param int $operand + * @param float $input + * @param float $operand * - * @return int + * @return float */ public static function divided_by($input, $operand) { - return (int)$input / (int)$operand; + return (float)$input / (float)$operand; } @@ -256,27 +256,27 @@ public static function map($input, $property) { /** * subtraction * - * @param int $input - * @param int $operand + * @param float $input + * @param float $operand * - * @return int + * @return float */ public static function minus($input, $operand) { - return (int)$input - (int)$operand; + return (float)$input - (float)$operand; } /** * modulo * - * @param int $input - * @param int $operand + * @param float $input + * @param float $operand * * @return int */ public static function modulo($input, $operand) { - return (int)$input % (int)$operand; - } + return (float)$input % (float)$operand; + } /** @@ -296,14 +296,14 @@ public static function newline_to_br($input) { /** * addition * - * @param int $input - * @param int $operand + * @param float $input + * @param float $operand * - * @return int + * @return float */ public static function plus($input, $operand) { - return (int)$input + (int)$operand; - } + return (float)$input + (float)$operand; + } /** @@ -550,13 +550,13 @@ public static function strip_newlines($input) { /** * multiplication * - * @param int $input - * @param int $operand + * @param float $input + * @param float $operand * - * @return int + * @return float */ public static function times($input, $operand) { - return (int)$input * (int)$operand; + return (float)$input * (float)$operand; } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 01958a5b..225e6cfc 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -768,12 +768,12 @@ public function testPlus() { array( 1.5, 2.7, - 3, + 4.2, ), ); foreach ($data as $item) { - $this->assertSame($item[2], StandardFilters::plus($item[0], $item[1])); + $this->assertEquals($item[2], StandardFilters::plus($item[0], $item[1]), '', 0.00001); } } @@ -792,12 +792,12 @@ public function testMinus() { array( 1.5, 2.7, - -1, + -1.2, ), ); foreach ($data as $item) { - $this->assertSame($item[2], StandardFilters::minus($item[0], $item[1])); + $this->assertEquals($item[2], StandardFilters::minus($item[0], $item[1]), '', 0.00001); } } @@ -816,12 +816,12 @@ public function testTimes() { array( 1.5, 2.7, - 2, + 4.05, ), ); foreach ($data as $item) { - $this->assertSame($item[2], StandardFilters::times($item[0], $item[1])); + $this->assertEquals($item[2], StandardFilters::times($item[0], $item[1]), '', 0.00001); } } @@ -842,10 +842,15 @@ public function testDivideBy() { 200, 0, ), + array( + 10, + 0.5, + 20, + ), ); foreach ($data as $item) { - $this->assertSame($item[2], StandardFilters::divided_by($item[0], $item[1])); + $this->assertEquals($item[2], StandardFilters::divided_by($item[0], $item[1]), '', 0.00001); } } @@ -866,6 +871,11 @@ public function testModulo() { 3, 2, ), + array( + 8.9, + 3.5, + 2, + ), ); foreach ($data as $item) { From 31f967782c7b2417596570a288e77483e5abbde9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 12:27:46 +0900 Subject: [PATCH 014/296] StandardFilters::modulo should return the floating point remainder just as Shopify's liquid does --- src/Liquid/StandardFilters.php | 4 ++-- tests/Liquid/StandardFiltersTest.php | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 8c6ab797..dbf9d95d 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -272,10 +272,10 @@ public static function minus($input, $operand) { * @param float $input * @param float $operand * - * @return int + * @return float */ public static function modulo($input, $operand) { - return (float)$input % (float)$operand; + return fmod((float)$input, (float)$operand); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 225e6cfc..dfebc100 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -874,12 +874,17 @@ public function testModulo() { array( 8.9, 3.5, - 2, + 1.9, + ), + array( + 183.357, + 12, + 3.357, ), ); foreach ($data as $item) { - $this->assertSame($item[2], StandardFilters::modulo($item[0], $item[1])); + $this->assertEquals($item[2], StandardFilters::modulo($item[0], $item[1]), '', 0.00001); } } From f719507d62637bdb5918ed62b9ce5291fd4108a7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 12:47:50 +0900 Subject: [PATCH 015/296] phpunit shall use autoloader from composer --- composer.json | 5 +++++ phpunit.xml | 9 +++++---- tests/bootstrap.php | 14 -------------- 3 files changed, 10 insertions(+), 18 deletions(-) delete mode 100644 tests/bootstrap.php diff --git a/composer.json b/composer.json index 3a99081a..cf003fc6 100644 --- a/composer.json +++ b/composer.json @@ -28,5 +28,10 @@ "psr-4": { "Liquid\\": "src/Liquid" } + }, + "autoload-dev": { + "psr-4": { + "Liquid\\": "tests/Liquid" + } } } diff --git a/phpunit.xml b/phpunit.xml index dffe2f14..13bf6659 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,13 +1,14 @@ - + - - tests/Liquid/ + + tests/ + - src/Liquid/ + src/ diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index abb3ec3d..00000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,14 +0,0 @@ -addPsr4('Liquid\\', __DIR__ . '/../src/Liquid'); -$loader->addPsr4('Liquid\\', __DIR__ . '/Liquid'); From d6cf3bdddecdd7e66ac3323bac173311569efa3a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 12:52:49 +0900 Subject: [PATCH 016/296] allow to override local configuration for phpunit --- phpunit.xml => phpunit.xml.dist | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename phpunit.xml => phpunit.xml.dist (100%) diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 100% rename from phpunit.xml rename to phpunit.xml.dist From fa6dfca7309fffd7db628eda27f43819e8724c98 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 12:53:44 +0900 Subject: [PATCH 017/296] phpunit shall generate coverage report --- phpunit.xml.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 13bf6659..320c95be 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,4 +11,9 @@ src/ + + + + + From d36284220fc0ed3f56fbd4c86f77b4aea9e88312 Mon Sep 17 00:00:00 2001 From: Mattias Ekendahl Date: Wed, 19 Jul 2017 11:08:49 +0200 Subject: [PATCH 018/296] Fixed syntax error for example in read me Missing ) at end of render call. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa2dc07b..0ee6a3c9 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ The main class is `Liquid::Template` class. There are two separate stages of wor $template = new Template(); $template->parse("Hello, {{ name }}!"); - echo $template->render(array('name' => 'Alex'); + echo $template->render(array('name' => 'Alex')); // Will echo // Hello, Alex! From fa1433ff60a0a88e60c3183b24e97ea9b1da0f1d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 18:14:08 +0900 Subject: [PATCH 019/296] .travis.yml: cache composer files, and use a faster container-based Travis virtual environment (without sudo) --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e71091d..bc8a10fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +sudo: false + language: php php: - 5.3 @@ -7,7 +9,9 @@ php: - 7.0 - 7.1 -before_script: - - composer install +cache: + directories: + - $HOME/.composer/cache -script: ./vendor/bin/phpunit +install: + - composer install --prefer-dist From e697e7a3fe7db0c2eaa6c2b6c61342b5c938b5e5 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 18:16:10 +0900 Subject: [PATCH 020/296] .travis.yml: submit coverage report to coveralls --- .travis.yml | 3 +++ composer.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bc8a10fd..7ea33dc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,3 +15,6 @@ cache: install: - composer install --prefer-dist + +after_success: + - travis_retry php vendor/bin/coveralls diff --git a/composer.json b/composer.json index cf003fc6..dc008fca 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "php": ">= 5.3" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "~4.8", + "satooshi/php-coveralls": "^1.0" }, "autoload": { "psr-4": { From 1475df0b4990a8fa0dab375d613043ee32dc03c1 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 18:18:07 +0900 Subject: [PATCH 021/296] Relax version requirements for PHPUnit - any version of PHPUnit under 6th should work for us - version 4.8 won't work under PHP 7.0+ --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index dc008fca..e9260ec0 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "php": ">= 5.3" }, "require-dev": { - "phpunit/phpunit": "~4.8", + "phpunit/phpunit": "<6", "satooshi/php-coveralls": "^1.0" }, "autoload": { From 82c7ccf3dd45e96efcbe6c2a1494d7fcef709dc8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 19 Jul 2017 18:19:40 +0900 Subject: [PATCH 022/296] README.md: coveralls badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa2dc07b..e2dd87bb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Liquid template engine for PHP [![Build Status](https://travis-ci.org/kalimatas/php-liquid.svg?branch=master)](https://travis-ci.org/kalimatas/php-liquid) +# Liquid template engine for PHP [![Build Status](https://travis-ci.org/kalimatas/php-liquid.svg?branch=master)](https://travis-ci.org/kalimatas/php-liquid) [![Coverage Status](https://coveralls.io/repos/github/kalimatas/php-liquid/badge.svg?branch=master)](https://coveralls.io/github/kalimatas/php-liquid?branch=master) Liquid is a PHP port of the [Liquid template engine for Ruby](https://github.com/Shopify/liquid), which was written by Tobias Lutke. Although there are many other templating engines for PHP, including Smarty (from which Liquid was partially inspired), Liquid had some advantages that made porting worthwhile: From 2ed200004c15b675dc4cf3ec34f64de81bcfff25 Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Tue, 23 May 2017 01:45:49 +1000 Subject: [PATCH 023/296] Support loop break and continue Fixes #13 --- src/Liquid/AbstractBlock.php | 7 +++++ src/Liquid/Tag/TagBreak.php | 41 ++++++++++++++++++++++++++ src/Liquid/Tag/TagContinue.php | 41 ++++++++++++++++++++++++++ src/Liquid/Tag/TagFor.php | 16 ++++++++++ src/Liquid/Tag/TagTablerow.php | 20 +++++++++++-- tests/Liquid/Tag/TagBreakTest.php | 44 ++++++++++++++++++++++++++++ tests/Liquid/Tag/TagContinueTest.php | 44 ++++++++++++++++++++++++++++ 7 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 src/Liquid/Tag/TagBreak.php create mode 100644 src/Liquid/Tag/TagContinue.php create mode 100644 tests/Liquid/Tag/TagBreakTest.php create mode 100644 tests/Liquid/Tag/TagContinueTest.php diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 0f2d5d66..5d3e6372 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -115,6 +115,13 @@ protected function renderAll(array $list, Context $context) { foreach ($list as $token) { $result .= (is_object($token) && method_exists($token, 'render')) ? $token->render($context) : $token; + + if (isset($context->registers['break'])) { + break; + } + if (isset($context->registers['continue'])) { + break; + } } return $result; diff --git a/src/Liquid/Tag/TagBreak.php b/src/Liquid/Tag/TagBreak.php new file mode 100644 index 00000000..15c9e3af --- /dev/null +++ b/src/Liquid/Tag/TagBreak.php @@ -0,0 +1,41 @@ +registers['break'] = true; + } +} \ No newline at end of file diff --git a/src/Liquid/Tag/TagContinue.php b/src/Liquid/Tag/TagContinue.php new file mode 100644 index 00000000..a5edb301 --- /dev/null +++ b/src/Liquid/Tag/TagContinue.php @@ -0,0 +1,41 @@ +registers['continue'] = true; + } +} \ No newline at end of file diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index e520c34a..6f2302ff 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -162,6 +162,14 @@ public function render(Context $context) { $result .= $this->renderAll($this->nodelist, $context); $index++; + + if (isset($context->registers['break'])) { + unset($context->registers['break']); + break; + } + if (isset($context->registers['continue'])) { + unset($context->registers['continue']); + } } break; @@ -201,6 +209,14 @@ public function render(Context $context) { $result .= $this->renderAll($this->nodelist, $context); $index++; + + if (isset($context->registers['break'])) { + unset($context->registers['break']); + break; + } + if (isset($context->registers['continue'])) { + unset($context->registers['continue']); + } } break; diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index efc29e08..f483a2af 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -97,7 +97,7 @@ public function render(Context $context) { $length = count($collection); - $cols = $context->get($this->attributes['cols']); + $cols = isset($this->attributes['cols']) ? $context->get($this->attributes['cols']) : PHP_INT_MAX; $row = 1; $col = 0; @@ -118,11 +118,25 @@ public function render(Context $context) { 'last' => (int)($index == $length - 1) )); - $result .= "" . $this->renderAll($this->nodelist, $context) . ""; + $text = $this->renderAll($this->nodelist, $context); + $break = isset($context->registers['break']); + $continue = isset($context->registers['continue']); + + if ((!$break && !$continue) || strlen(trim($text)) > 0) { + $result .= "$text"; + } if ($col == $cols && !($index == $length - 1)) { $col = 0; - $result .= "\n"; + $result .= "\n\n"; + } + + if ($break) { + unset($context->registers['break']); + break; + } + if ($continue) { + unset($context->registers['continue']); } } diff --git a/tests/Liquid/Tag/TagBreakTest.php b/tests/Liquid/Tag/TagBreakTest.php new file mode 100644 index 00000000..cdcaca1a --- /dev/null +++ b/tests/Liquid/Tag/TagBreakTest.php @@ -0,0 +1,44 @@ +assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); + } + + public function testRange() { + $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%break%} yo {%endfor%}'); + $this->assertTemplateResult(' yo ', '{%for item in (3..6)%} yo {%break%} {%endfor%}'); + $this->assertTemplateResult(' 3 4 ', '{%for item in (3..6)%} {%if item == 5%} {%break%} {%endif%} {{ item }} {%endfor%}'); + } + + public function testTablerow() { + $this->assertTemplateResult( + "\n\n", + '{%tablerow item in array%} {%break%} yo {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult( + "\n yo \n", + '{%tablerow item in array%} yo {%break%} {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult( + "\n 1 2 \n", + '{%tablerow item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + } +} diff --git a/tests/Liquid/Tag/TagContinueTest.php b/tests/Liquid/Tag/TagContinueTest.php new file mode 100644 index 00000000..383cfad6 --- /dev/null +++ b/tests/Liquid/Tag/TagContinueTest.php @@ -0,0 +1,44 @@ +assertTemplateResult(' ', '{%for item in array%} {%continue%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%continue%} {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' 1 2 4 ', '{%for item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); + } + + public function testRange() { + $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%continue%} yo {%endfor%}'); + $this->assertTemplateResult(' yo yo yo yo ', '{%for item in (3..6)%} yo {%continue%} {%endfor%}'); + $this->assertTemplateResult(' 3 4 6 ', '{%for item in (3..6)%} {%if item == 5%} {%continue%} {%endif%} {{ item }} {%endfor%}'); + } + + public function testTablerow() { + $this->assertTemplateResult( + "\n\n", + '{%tablerow item in array%} {%continue%} yo {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult( + "\n yo yo yo yo \n", + '{%tablerow item in array%} yo {%continue%} {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult( + "\n 1 2 4 \n", + '{%tablerow item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endtablerow%}', + array('array' => array(1, 2, 3, 4))); + } +} \ No newline at end of file From 7f2e419525cb64de0ccdebfaa534a042c560332f Mon Sep 17 00:00:00 2001 From: Tobias Salzmann Date: Mon, 13 Jun 2016 14:25:33 +0200 Subject: [PATCH 024/296] Allow negative numbers {% assign i = -100 %} or {% assign i = -10.0 %} was not possible --- src/Liquid/Context.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 034e66c0..9383fdd2 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -188,11 +188,11 @@ private function resolve($key) { return $matches[1]; } - if (preg_match('/^(\d+)$/', $key, $matches)) { + if (preg_match('/^(-?\d+)$/', $key, $matches)) { return $matches[1]; } - if (preg_match('/^(\d[\d\.]+)$/', $key, $matches)) { + if (preg_match('/^(-?\d[\d\.]+)$/', $key, $matches)) { return $matches[1]; } From 5765870ca1d400128d523629d132b37e74b465a4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 10:15:12 +0900 Subject: [PATCH 025/296] Test simple assignments with positive and negative numbers --- tests/Liquid/Tag/TagAssignTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index 705d056d..b1c173c7 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -65,4 +65,15 @@ public function testAssignWithFilters() { $template->parse('{% assign test = var1 | join : "." %}{{ test }}'); $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'a.b.c'); } + + /** + * Tests a simple assignment with numbers + */ + public function testNumbersAssign() { + $this->assertTemplateResult('42', '{% assign i = 42 %}{{ i }}'); + $this->assertTemplateResult('3.14', '{% assign i = 3.14 %}{{ i }}'); + $this->assertTemplateResult('-100', '{% assign i = -100 %}{{ i }}'); + $this->assertTemplateResult('-10', '{% assign i = -10.0 %}{{ i }}'); + $this->assertTemplateResult('-10.5', '{% assign i = -10.5 %}{{ i }}'); + } } From 4f2aee3175d1831816678e22334ec0ca760959a4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 10:59:00 +0900 Subject: [PATCH 026/296] TagRaw can only accept arrays, no need to check that --- src/Liquid/Tag/TagRaw.php | 6 +----- tests/Liquid/Tag/TagRawTest.php | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index 5186acca..9bd7f04f 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -35,17 +35,13 @@ public function parse(array &$tokens) { $this->nodelist = array(); - if (!is_array($tokens)) { - return; - } - while (count($tokens)) { $token = array_shift($tokens); if ($tagRegexp->match($token)) { // If we found the proper block delimiter just end parsing here and let the outer block proceed if ($tagRegexp->matches[1] == $this->blockDelimiter()) { - return; + break; } } diff --git a/tests/Liquid/Tag/TagRawTest.php b/tests/Liquid/Tag/TagRawTest.php index fbcdc933..33a501e9 100644 --- a/tests/Liquid/Tag/TagRawTest.php +++ b/tests/Liquid/Tag/TagRawTest.php @@ -20,5 +20,7 @@ public function testRaw() { '{{ y | plus: x }}{{{hello}}} is equal to 11.', '{% raw %}{{ y | plus: x }}{{{hello}}}{% endraw %} is equal to 11.', array('x' => 5, 'y' => 6) ); + + $this->assertTemplateResult('', '{% raw %}{% endraw %}'); } } From 327ff3ff6c1ed4fd84d21d189cd48426ac8aede7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:01:06 +0900 Subject: [PATCH 027/296] TagForTest with an empty array --- tests/Liquid/Tag/TagForTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 695bd3f4..15e2123d 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -25,6 +25,7 @@ public function testForInvalidSyntax() { } public function testFor() { + $this->assertTemplateResult('', '{%for item in array%} yo {%endfor%}', array('array' => array())); $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' boo boo boo boo ', '{%for item in array%} boo {%endfor%}', array('array' => new \ArrayIterator(array(1, 2, 3, 4)))); $this->assertTemplateResult('yoyo', '{%for item in array%}yo{%endfor%}', array('array' => array(1, 2))); From e7f2fc4ceccf40541bf572f4d3a0f442eae151e6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:19:58 +0900 Subject: [PATCH 028/296] Test for TagTablerow --- src/Liquid/Tag/TagTablerow.php | 4 +- tests/Liquid/Tag/TagTablerowTest.php | 58 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/Liquid/Tag/TagTablerowTest.php diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 64e03fcf..ca71fbe4 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -64,7 +64,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->extractAttributes($markup); } else { - throw new LiquidException("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3"); + throw new LiquidException("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols:3"); } } @@ -83,7 +83,7 @@ public function render(Context $context) { } if (!is_array($collection)) { - die('not array, ' . var_export($collection, true)); + throw new LiquidException("Not an array"); } // discard keys diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php new file mode 100644 index 00000000..08e4d80c --- /dev/null +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -0,0 +1,58 @@ +assertTemplateResult( + ''."\n".' yo yo yo yo '."\n", + '{% tablerow item in array %} yo {% endtablerow %}', + array('array' => array(1, 2, 3, 4))); + + $this->assertTemplateResult( + ' + item 1 + + item 2 +', + '{% tablerow item in array cols:1 %} item {{ item }} {% endtablerow %}', + array('array' => array(1, 2))); + + $this->assertTemplateResult( + ''."\n".' 2 3 '."\n", + '{% tablerow item in array limit:2 offset:1 %} {{ item }} {% endtablerow %}', + array('array' => array(1, 2, 3, 4))); + + $this->assertTemplateResult( + ''."\n".' yo yo '."\n", + '{%tablerow item in array%} yo {%endtablerow%}', + array('array' => new \ArrayIterator(array(1, 2)))); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testInvalidSyntax() { + $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testNotArray() { + $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); + } + +} \ No newline at end of file From 2cb6f0439e16fe68fb2de6e6c76475ddaae929b4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:23:32 +0900 Subject: [PATCH 029/296] Test TagUnless with a variable --- tests/Liquid/Tag/TagUnlessTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Liquid/Tag/TagUnlessTest.php b/tests/Liquid/Tag/TagUnlessTest.php index ff4d4364..7a57e561 100644 --- a/tests/Liquid/Tag/TagUnlessTest.php +++ b/tests/Liquid/Tag/TagUnlessTest.php @@ -26,4 +26,10 @@ public function testTrueNotEqlTrue() { $expected = " true "; $this->assertTemplateResult($expected, $text); } + + public function testWithVariable() { + $text = " {% unless variable %} true {% else %} false {% endunless %} "; + $expected = " false "; + $this->assertTemplateResult($expected, $text, array('variable' => true)); + } } \ No newline at end of file From 3d56d7a734945186a503f6e9781ff6ea57216207 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:27:02 +0900 Subject: [PATCH 030/296] Test a generic syntax error for TagIf --- tests/Liquid/Tag/TagIfTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 74cc5c61..81f1a2bd 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -198,6 +198,13 @@ public function testSyntaxErrorNotClosed() { $this->assertTemplateResult('', '{% if jerry == 1 %}'); } + /** + * @expectedException \Liquid\LiquidException + */ + public function testSyntaxErrorEnd() { + $this->assertTemplateResult('', '{% if jerry == 1 %}{% end %}'); + } + /** * @expectedException \Liquid\LiquidException */ From 544e361d54497242a3b6ebff24ad7e8b314aa02e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:32:37 +0900 Subject: [PATCH 031/296] Test for errors in TagCase --- tests/Liquid/Tag/TagCaseTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index d37db006..f4c835f5 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -39,4 +39,25 @@ public function testCaseWithElse() { $assigns = array('condition' => 6); $this->assertTemplateResult(' else ', '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', $assigns); } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testSyntaxErrorCase() { + $this->assertTemplateResult('', '{% case %}{% when 5 %}{% endcase %}'); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testSyntaxErrorWhen() { + $this->assertTemplateResult('', '{% case condition %}{% when %}{% endcase %}'); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testSyntaxErrorEnd() { + $this->assertTemplateResult('', '{% case condition %}{% end %}'); + } } From 5a9a96275ed0d9dacabaceb09725036af29c0a46 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:43:45 +0900 Subject: [PATCH 032/296] Test next page for TagPaginate --- tests/Liquid/Tag/TagPaginateTest.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index a473a665..0e5b68ac 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -15,17 +15,29 @@ class TagPaginateTest extends TestCase { - public function testWorks() { $text = "{% paginate products by 3 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; $expected = " 1 2 3 "; $this->assertTemplateResult($expected, $text, array('products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); } - + public function testVariables() { - $text = " {% paginate products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {% endpaginate %}"; + $text = " {% paginate search.products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {% endpaginate %}"; $expected = " 3 1 0 2 5 "; - $this->assertTemplateResult($expected, $text, array('products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + $this->assertTemplateResult($expected, $text, array('search' => array('products' => new \ArrayIterator(array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))))); + } + + public function testNextPage() + { + $text = "{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; + $expected = " 2 "; + $this->assertTemplateResult($expected, $text, array('page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testSyntaxErrorCase() { + $this->assertTemplateResult('', '{% paginate products %}{% endpaginate %}'); } - } From 4b77b6b1ccd31e50597a183c26703c8f9bbd6c3a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:56:32 +0900 Subject: [PATCH 033/296] Test that TagCase can take objects as usual --- tests/Liquid/Tag/TagCaseTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index f4c835f5..22023dbd 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -13,6 +13,13 @@ use Liquid\TestCase; +class Stringable +{ + public function __toString() { + return "100"; + } +} + class TagCaseTest extends TestCase { public function testCase() { @@ -60,4 +67,15 @@ public function testSyntaxErrorWhen() { public function testSyntaxErrorEnd() { $this->assertTemplateResult('', '{% case condition %}{% end %}'); } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testObject() { + $this->assertTemplateResult('', '{% case variable %}{% when 5 %}{% endcase %}', array('variable' => (object) array())); + } + + public function testStringable() { + $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new Stringable())); + } } From 252984c65acdec43065c54f9c4c0a9fd199494ce Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 11:59:35 +0900 Subject: [PATCH 034/296] Test TagIf for reverse order of arguments --- tests/Liquid/Tag/TagIfTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 81f1a2bd..fe9dec0f 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -108,6 +108,10 @@ public function testIsCollectionEmpty() { $text = " {% if array == empty %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('array' => array())); + + $text = " {% if empty == array %} true {% else %} false {% endif %} "; + $expected = " true "; + $this->assertTemplateResult($expected, $text, array('array' => array())); } public function testIsNotCollectionEmpty() { From d91bac359f8d1379bf6c6e3532e89b53f28a3eb0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 12:00:55 +0900 Subject: [PATCH 035/296] TagIfTest for incomparable arguments --- tests/Liquid/Tag/TagIfTest.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index fe9dec0f..c7a2b294 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -215,4 +215,11 @@ public function testSyntaxErrorEnd() { public function testInvalidOperator() { $this->assertTemplateResult('', '{% if foo === y %}true{% else %}false{% endif %}', array('foo' => true, 'y' => true)); } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testIncomparable() { + $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', array('foo' => (object) array())); + } } From 64957218b13ae30b0d8fa4707ef716b46ca13979 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 13:47:55 +0900 Subject: [PATCH 036/296] README.md: composer require not create-project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abdfe338..0a528f11 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Liquid was written to meet three templating library requirements: good performan You can install this lib via [composer](https://getcomposer.org/): - composer create-project liquid/liquid + composer require liquid/liquid ## Example template From a173d5ff7db4a47fe31f17c1d9e6d6d079d1733f Mon Sep 17 00:00:00 2001 From: schmoove Date: Thu, 1 Jun 2017 15:48:45 -0700 Subject: [PATCH 037/296] Return empty value if date($input) is empty As per original Ruby filter: https://github.com/Shopify/liquid/blob/master/lib/liquid/standardfilters.rb --- tests/Liquid/StandardFiltersTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index dfebc100..d58090e6 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -984,5 +984,9 @@ public function testDate() { $var = new Variable("var | date: '%d/%m/%Y %l:%M %p'"); $this->context->set('var', '2017-07-01 21:00:00'); $this->assertEquals('01/07/2017 9:00 PM', $var->render($this->context)); + + $var = new Variable('var | date, ""'); + $this->context->set('var', '2017-07-01 21:00:00'); + $this->assertEquals('', $var->render($this->context)); } } From 6d340fb241c992568b09d845df405b09d7cb1d71 Mon Sep 17 00:00:00 2001 From: schmoove Date: Thu, 1 Jun 2017 15:55:54 -0700 Subject: [PATCH 038/296] Added url_decode() as per original Liquid lib https://github.com/Shopify/liquid/blob/master/lib/liquid/standardfilters.rb --- src/Liquid/StandardFilters.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 934ef52f..c5b2d3a9 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -640,8 +640,18 @@ public static function upcase($input) { public static function url_encode($input) { return urlencode($input); } - - + + /** + * Decodes a URL-encoded string + * + * @param string $input + * + * @return string + */ + public static function url_decode($input) { + return urldecode($input); + } + /** * Use overloading to get around reserved php words - in this case 'default' * From 9a3ccd8622d12c483adeec92825998caa00fe1f9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 31 Aug 2017 17:05:15 +0900 Subject: [PATCH 039/296] Tests for url_encode and url_decode --- tests/Liquid/StandardFiltersTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index d58090e6..44cd8b12 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -105,6 +105,29 @@ public function testCapitalize() { } } + public function testUrlEncode() { + $data = array( + 'nothing' => 'nothing', + '%#&^' => '%25%23%26%5E', + ); + + foreach ($data as $element => $expected) { + $this->assertEquals($expected, StandardFilters::url_encode($element)); + } + } + + + public function testUrlDecode() { + $data = array( + '%25%23%26%5E' => '%#&^', + ); + + foreach ($data as $element => $expected) { + $this->assertEquals($expected, StandardFilters::url_decode($element)); + } + } + + public function testRaw() { $data = array( From 236dec618c23329d5e097a70b6b42f25aaf7a5ae Mon Sep 17 00:00:00 2001 From: schmoove Date: Sun, 4 Jun 2017 20:00:00 -0700 Subject: [PATCH 040/296] Added test for floats --- tests/Liquid/StandardFiltersTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 44cd8b12..7b68547d 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -817,6 +817,11 @@ public function testMinus() { 2.7, -1.2, ), + array( + 3.1, + 3.1, + 0 + ) ); foreach ($data as $item) { @@ -841,6 +846,11 @@ public function testTimes() { 2.7, 4.05, ), + array( + 7.5, + 0, + 0 + ) ); foreach ($data as $item) { @@ -970,6 +980,10 @@ public function testFloor() { 0.42, 0, ), + array( + 2.5, + 2, + ) ); foreach ($data as $item) { From 5cb70e112cc4864e4ecda9ed91db169fde3a2c60 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jul 2017 13:47:55 +0900 Subject: [PATCH 041/296] README.md: composer require not create-project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abdfe338..0a528f11 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Liquid was written to meet three templating library requirements: good performan You can install this lib via [composer](https://getcomposer.org/): - composer create-project liquid/liquid + composer require liquid/liquid ## Example template From f0d40a78d03857827df0ee773b0cf0807069993f Mon Sep 17 00:00:00 2001 From: schmoove Date: Wed, 30 Aug 2017 09:40:57 -0700 Subject: [PATCH 042/296] Match output of original Ruby method The original Ruby method only replaces `\n` characters: ``` def newline_to_br(input) input.to_s.gsub(/\n/, "
\n".freeze) end ``` Replacing both \n and \r can lead to double-carriage returns in some cases. We should aim to match the original behavior of the Ruby implementation as closely as possible. --- src/Liquid/StandardFilters.php | 10 ++++------ tests/Liquid/EscapeByDefaultTest.php | 2 +- tests/Liquid/StandardFiltersTest.php | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 934ef52f..d0fec938 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -287,12 +287,10 @@ public static function modulo($input, $operand) { * * @return string */ - public static function newline_to_br($input) { - return is_string($input) ? str_replace(array( - "\n", "\r" - ), '
', $input) : $input; - } - + public static function newline_to_br($input) { + return is_string($input) ? str_replace("\n", "
\n", $input) : $input; + } + /** * addition diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index 2d02e968..ffdd7e31 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -72,7 +72,7 @@ public function testRawInAutoMode() { public function testNlToBr() { Liquid::set('ESCAPE_BY_DEFAULT', true); $text = "{{ xss | newline_to_br }}"; - $expected = self::XSS."
".self::XSS; + $expected = self::XSS."
\n".self::XSS; $this->assertTemplateResult($expected, $text, array('xss' => self::XSS."\n".self::XSS)); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index dfebc100..442b5b36 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -155,7 +155,7 @@ public function testStripNewLines() { public function testNewLineToBr() { $data = array( - "one Word\r\n not\r\n" => "one Word

not

", + "one Word\n not\n" => "one Word
\n not
\n", 'test' => 'test', 3 => 3, ); From f3982cfef441999cc943c1a0350bb78fbd67791d Mon Sep 17 00:00:00 2001 From: schmoove Date: Fri, 1 Sep 2017 10:39:01 -0700 Subject: [PATCH 043/296] Support variable indicies --- src/Liquid/Context.php | 11 ++++++++--- tests/Liquid/VariableResolutionTest.php | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 9383fdd2..ded4fefb 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -238,10 +238,15 @@ private function fetch($key) { * @return mixed */ private function variable($key) { - // Support [0] style array indicies + // Support numeric and variable array indicies if (preg_match("|\[[0-9]+\]|", $key)) { - $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); - } + $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); + } else if (preg_match("|\[[0-9a-z._]+\]|", $key, $matches)) { + $index = $this->get(str_replace(array("[","]"),"", $matches[0])); + if ( strlen($index) ) { + $key = preg_replace("|\[([0-9a-z._]+)\]|", ".$index", $key); + } + } $parts = explode(Liquid::get('VARIABLE_ATTRIBUTE_SEPARATOR'), $key); diff --git a/tests/Liquid/VariableResolutionTest.php b/tests/Liquid/VariableResolutionTest.php index 2dc15b1b..13448ec9 100644 --- a/tests/Liquid/VariableResolutionTest.php +++ b/tests/Liquid/VariableResolutionTest.php @@ -40,4 +40,11 @@ public function testArrayScoping() { $template->parse('{{ test.test }}'); $this->assertEquals('worked', $template->render(array('test' => array('test' => 'worked')))); } + + public function testVariableArrayIndices() { + $template = new Template(); + + $template->parse("{% assign days = 'Mon,Tue,Wed,Thu,Fri,Sat,Sun' | split: ',' %}{% for i in (0..6) %}{{ days[i] }} {% endfor %}"); + $this->assertEquals('Mon Tue Wed Thu Fri Sat Sun ', $template->render()); + } } From 1ee15248f9f2e8487a2aaeb781543bb6e634fba7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 2 Sep 2017 11:33:36 +0900 Subject: [PATCH 044/296] No PHP 5.3 at Travis on Trusty See travis-ci/travis-ci#2963 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e71091d..7e63e5da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php php: - - 5.3 - 5.4 - 5.5 - 5.6 From fdbe54d4d57fe40267d74acc26ce92fc3ca88c78 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 16:56:26 +0900 Subject: [PATCH 045/296] LocalFileSystemTest should extend TestCase, not Testcase; now it can be tested separately --- tests/Liquid/LocalFileSystemTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 834c1c58..a5ecca66 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -11,7 +11,7 @@ namespace Liquid; -class LocalFileSystemTest extends Testcase +class LocalFileSystemTest extends TestCase { /** * @expectedException \Liquid\LiquidException From 285a31ee832e3e01904d868f0dd709f6649f27fb Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 17:50:34 +0900 Subject: [PATCH 046/296] LocalFileSystemTest: initialize filesystem root in one place --- tests/Liquid/LocalFileSystemTest.php | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index a5ecca66..34bd4884 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -13,6 +13,14 @@ class LocalFileSystemTest extends TestCase { + protected $root; + + protected function setUp() { + $this->root = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; + // reset to defaults + Liquid::set('INCLUDE_ALLOW_EXT', false); + } + /** * @expectedException \Liquid\LiquidException */ @@ -58,31 +66,27 @@ public function testIllegalTemplatePathNoFileExists() { } public function testValidPathWithDefaultExtension() { - $root = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; $templateName = 'mypartial'; - $fileSystem = new LocalFileSystem($root); - $this->assertEquals($root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); + $fileSystem = new LocalFileSystem($this->root); + $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } public function testValidPathWithCustomExtension() { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); - $root = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; $templateName = 'mypartial'; - $fileSystem = new LocalFileSystem($root); - $this->assertEquals($root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); + $fileSystem = new LocalFileSystem($this->root); + $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } public function testReadTemplateFile() { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); - $root = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; - - $fileSystem = new LocalFileSystem($root); + $fileSystem = new LocalFileSystem($this->root); $this->assertEquals('test content', trim($fileSystem->readTemplateFile('mypartial'))); } } From 79731f038cb0540a61deb0e3ae9a6e08db75836b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 18:19:32 +0900 Subject: [PATCH 047/296] LocalFileSystem: refactored fullPath method, additional tests for 100% coverage --- src/Liquid/LocalFileSystem.php | 46 +++++++++++++++++----------- tests/Liquid/LocalFileSystemTest.php | 31 ++++++++++++++++++- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/Liquid/LocalFileSystem.php b/src/Liquid/LocalFileSystem.php index c30904f5..7a8c583f 100644 --- a/src/Liquid/LocalFileSystem.php +++ b/src/Liquid/LocalFileSystem.php @@ -32,6 +32,15 @@ class LocalFileSystem implements FileSystem * @param string $root The root path for templates */ public function __construct($root) { + // since root path can only be set from constructor, we check it once right here + if (!empty($root)) { + $realRoot = realpath($root); + if ($realRoot === false) { + throw new LiquidException("Root path could not be found: '$root'"); + } + $root = $realRoot; + } + $this->root = $root; } @@ -40,15 +49,10 @@ public function __construct($root) { * * @param string $templatePath * - * @throws LiquidException * @return string template content */ public function readTemplateFile($templatePath) { - if (!($fullPath = $this->fullPath($templatePath))) { - throw new LiquidException("No such template '$templatePath'"); - } - - return file_get_contents($fullPath); + return file_get_contents($this->fullPath($templatePath)); } /** @@ -60,6 +64,10 @@ public function readTemplateFile($templatePath) { * @return string */ public function fullPath($templatePath) { + if (empty($templatePath)) { + throw new LiquidException("Empty template name"); + } + $nameRegex = Liquid::get('INCLUDE_ALLOW_EXT') ? new Regexp('/^[^.\/][a-zA-Z0-9_\.\/]+$/') : new Regexp('/^[^.\/][a-zA-Z0-9_\/]+$/'); @@ -68,22 +76,24 @@ public function fullPath($templatePath) { throw new LiquidException("Illegal template name '$templatePath'"); } - if (strpos($templatePath, '/') !== false) { - $fullPath = Liquid::get('INCLUDE_ALLOW_EXT') - ? $this->root . dirname($templatePath) . '/' . basename($templatePath) - : $this->root . dirname($templatePath) . '/' . Liquid::get('INCLUDE_PREFIX') . basename($templatePath) . '.' . Liquid::get('INCLUDE_SUFFIX'); - } else { - $fullPath = Liquid::get('INCLUDE_ALLOW_EXT') - ? $this->root . $templatePath - : $this->root . Liquid::get('INCLUDE_PREFIX') . $templatePath . '.' . Liquid::get('INCLUDE_SUFFIX'); + $templateDir = dirname($templatePath); + $templateFile = basename($templatePath); + + if (!Liquid::get('INCLUDE_ALLOW_EXT')) { + $templateFile = Liquid::get('INCLUDE_PREFIX') . $templateFile . '.' . Liquid::get('INCLUDE_SUFFIX'); } - $rootRegex = new Regexp('/' . preg_quote(realpath($this->root), '/') . '/'); + $fullPath = join(DIRECTORY_SEPARATOR, array($this->root, $templateDir, $templateFile)); + + $realFullPath = realpath($fullPath); + if ($realFullPath === false) { + throw new LiquidException("File not found: $fullPath"); + } - if (!$rootRegex->match(realpath($fullPath))) { - throw new LiquidException("Illegal template path '" . realpath($fullPath) . "'"); + if (strpos($realFullPath, $this->root) !== 0) { + throw new LiquidException("Illegal template full path: {$realFullPath} not under {$this->root}"); } - return $fullPath; + return $realFullPath; } } diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 34bd4884..de6a66cd 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -16,7 +16,7 @@ class LocalFileSystemTest extends TestCase protected $root; protected function setUp() { - $this->root = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; + $this->root = __DIR__ . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; // reset to defaults Liquid::set('INCLUDE_ALLOW_EXT', false); } @@ -29,6 +29,14 @@ public function testIllegalTemplateNameEmpty() { $fileSystem->fullPath(''); } + /** + * @expectedException \Liquid\LiquidException + */ + public function testIllegalRootPath() { + $fileSystem = new LocalFileSystem('invalid/not/found'); + $fileSystem->fullPath(''); + } + /** * @expectedException \Liquid\LiquidException */ @@ -65,6 +73,19 @@ public function testIllegalTemplatePathNoFileExists() { $fileSystem->fullPath('no_such_file_exists'); } + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage not under + */ + public function testIllegalTemplatePathNotUnderTemplateRoot() { + Liquid::set('INCLUDE_ALLOW_EXT', true); + $fileSystem = new LocalFileSystem(dirname($this->root)); + // find any fail under deeper under the root, so all other checks would pass + $filesUnderCurrentDir = array_map('basename', glob(dirname(__DIR__).'/../*')); + // path relative to root; we can't start it with a dot since it isn't allowed anyway + $fileSystem->fullPath(self::TEMPLATES_DIR."/../../../{$filesUnderCurrentDir[0]}"); + } + public function testValidPathWithDefaultExtension() { $templateName = 'mypartial'; @@ -82,6 +103,14 @@ public function testValidPathWithCustomExtension() { $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } + /** + * @expectedException \Liquid\LiquidException + */ + public function testReadIllegalTemplatePathNoFileExists() { + $fileSystem = new LocalFileSystem(dirname(__DIR__)); + $fileSystem->readTemplateFile('no_such_file_exists'); + } + public function testReadTemplateFile() { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); From c468c0d392191fedeb88fb53a4e673713d75b899 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 18:20:23 +0900 Subject: [PATCH 048/296] TagIncludeTest: test include tag with an actual file --- tests/Liquid/Tag/TagIncludeTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 79ce7bd1..53c0c8ac 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -14,6 +14,7 @@ use Liquid\TestCase; use Liquid\Template; use Liquid\FileSystem; +use Liquid\Liquid; /** * Helper FileSytem @@ -89,4 +90,14 @@ public function testIncludeTagNoWith() { $this->assertEquals("Outer-Inner: orig-Outer-Inner: orig23", $output); } + + public function testIncludeTemplateFile() { + Liquid::set('INCLUDE_PREFIX', ''); + Liquid::set('INCLUDE_SUFFIX', 'tpl'); + + $template = new Template(dirname(__DIR__).DIRECTORY_SEPARATOR.self::TEMPLATES_DIR); + $template->parse("{% include 'mypartial' %}"); + // template include inserts a new line + $this->assertEquals("test content\n", $template->render()); + } } From e7a08e29879f321cd1b9d9903aae4a78ab998438 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 18:37:01 +0900 Subject: [PATCH 049/296] TagExtendsTest: very basic test for extends --- tests/Liquid/Tag/LiquidTestFileSystem.php | 37 +++++++++++++++++++++++ tests/Liquid/Tag/TagExtendsTest.php | 27 +++++++++++++++++ tests/Liquid/Tag/TagIncludeTest.php | 20 ------------ 3 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 tests/Liquid/Tag/LiquidTestFileSystem.php create mode 100644 tests/Liquid/Tag/TagExtendsTest.php diff --git a/tests/Liquid/Tag/LiquidTestFileSystem.php b/tests/Liquid/Tag/LiquidTestFileSystem.php new file mode 100644 index 00000000..4c598162 --- /dev/null +++ b/tests/Liquid/Tag/LiquidTestFileSystem.php @@ -0,0 +1,37 @@ +setFileSystem(new LiquidTestFileSystem()); + $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); + $output = $template->render(array("hello" => "Hello!")); + $this->assertEquals("Hello!", $output); + } +} diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 53c0c8ac..f88f081d 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -13,28 +13,8 @@ use Liquid\TestCase; use Liquid\Template; -use Liquid\FileSystem; use Liquid\Liquid; -/** - * Helper FileSytem - */ -class LiquidTestFileSystem implements FileSystem -{ - /** - * @param string $templatePath - * - * @return string - */ - public function readTemplateFile($templatePath) { - if ($templatePath == 'inner') { - return "Inner: {{ inner }}{{ other }}"; - } - - return ''; - } -} - class TagIncludeTest extends TestCase { /** From 84dc2bc4c4db841957b2636a5d4e5e99c00539ee Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 18:59:38 +0900 Subject: [PATCH 050/296] TagExtendsTest - more tests --- src/Liquid/Tag/TagExtends.php | 2 +- tests/Liquid/Tag/LiquidTestFileSystem.php | 6 ++- tests/Liquid/Tag/TagExtendsTest.php | 54 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index aea841ee..a616313b 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -56,7 +56,7 @@ class TagExtends extends AbstractTag public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { $regex = new Regexp('/("[^"]+"|\'[^\']+\')?/'); - if ($regex->match($markup)) { + if ($regex->match($markup) && isset($regex->matches[1])) { $this->templateName = substr($regex->matches[1], 1, strlen($regex->matches[1]) - 2); } else { throw new LiquidException("Error in tag 'extends' - Valid syntax: extends '[template name]'"); diff --git a/tests/Liquid/Tag/LiquidTestFileSystem.php b/tests/Liquid/Tag/LiquidTestFileSystem.php index 4c598162..6e28d8db 100644 --- a/tests/Liquid/Tag/LiquidTestFileSystem.php +++ b/tests/Liquid/Tag/LiquidTestFileSystem.php @@ -29,7 +29,11 @@ public function readTemplateFile($templatePath) { } if ($templatePath == 'base') { - return "{% block content %}{% endblock %}"; + return "{% block content %}{% endblock %}{% block footer %}{% endblock %}"; + } + + if ($templatePath == 'sub-base') { + return "{% extends 'base' %}{% block content %}{% endblock %}{% block footer %} Boo! {% endblock %}"; } return ''; diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 61167903..5a8c1289 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -14,6 +14,9 @@ use Liquid\TestCase; use Liquid\Template; +/** + * @see TagExtends + */ class TagExtendsTest extends TestCase { public function testBasicExtends() @@ -24,4 +27,55 @@ public function testBasicExtends() $output = $template->render(array("hello" => "Hello!")); $this->assertEquals("Hello!", $output); } + + public function testDefaultContentExtends() + { + $template = new Template(); + $template->setFileSystem(new LiquidTestFileSystem()); + $template->parse("{% block content %}{{ hello }}{% endblock %}\n{% extends 'sub-base' %}"); + $output = $template->render(array("hello" => "Hello!")); + $this->assertEquals("Hello!\n Boo! ", $output); + } + + + public function testDeepExtends() + { + $template = new Template(); + $template->setFileSystem(new LiquidTestFileSystem()); + $template->parse('{% extends "sub-base" %}{% block content %}{{ hello }}{% endblock %}{% block footer %} I am a footer.{% endblock %}'); + $output = $template->render(array("hello" => "Hello!")); + $this->assertEquals("Hello! I am a footer.", $output); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testInvalidSyntaxNoTemplateName() { + $template = new Template(); + $template->parse("{% extends %}"); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testInvalidSyntaxNotQuotedTemplateName() { + $template = new Template(); + $template->parse("{% extends base %}"); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testInvalidSyntaxEmptyTemplateName() { + $template = new Template(); + $template->parse("{% extends '' %}"); + } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testInvalidSyntaxInvalidKeyword() { + $template = new Template(); + $template->parse("{% extends 'base' nothing-should-be-here %}"); + } } From 68f75d5cd4ae880a92318da19614ec8b12004d22 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 21 Sep 2017 18:59:57 +0900 Subject: [PATCH 051/296] TagExtends: not everyone can read German unfortunately --- src/Liquid/Tag/TagExtends.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index a616313b..574350dc 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -129,14 +129,14 @@ public function parse(array &$tokens) { $name = null; $rest = array(); - $aufzeichnen = false; + $keep = false; for ($i = 0; $i < count($maintokens); $i++) { if ($blockstartRegexp->match($maintokens[$i])) { $name = $blockstartRegexp->matches[1]; if (isset($childtokens[$name])) { - $aufzeichnen = true; + $keep = true; array_push($rest, $maintokens[$i]); foreach ($childtokens[$name] as $item) { array_push($rest, $item); @@ -144,12 +144,12 @@ public function parse(array &$tokens) { } } - if (!$aufzeichnen) { + if (!$keep) { array_push($rest, $maintokens[$i]); } - if ($blockendRegexp->match($maintokens[$i]) && $aufzeichnen === true) { - $aufzeichnen = false; + if ($blockendRegexp->match($maintokens[$i]) && $keep === true) { + $keep = false; array_push($rest, $maintokens[$i]); } } From 265b6ef21966984ad56c3bf74af85cb408ccb7d9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 09:28:48 +0900 Subject: [PATCH 052/296] LiquidTest: test ALLOWED_VARIABLE_CHARS existing for backward compatibility --- tests/Liquid/LiquidTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Liquid/LiquidTest.php b/tests/Liquid/LiquidTest.php index 21641f37..c8ee9ce9 100644 --- a/tests/Liquid/LiquidTest.php +++ b/tests/Liquid/LiquidTest.php @@ -24,6 +24,12 @@ public function testSetProperty() { $this->assertSame($value, Liquid::get($key)); } + public function testGetSetAllowedChars() { + Liquid::set('ALLOWED_VARIABLE_CHARS', 'abc'); + $this->assertSame('abc', Liquid::get('ALLOWED_VARIABLE_CHARS')); + $this->assertSame('abc+', Liquid::get('VARIABLE_NAME')); + } + public function testArrayFlattenEmptyArray() { $this->assertSame(array(), Liquid::arrayFlatten(array())); } From 09f038d1c21162189b19422287b055b75ebfb5ed Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 10:02:02 +0900 Subject: [PATCH 053/296] RegexpTest: extra tests for quote and with simple matching --- src/Liquid/Regexp.php | 2 +- tests/Liquid/RegexpTest.php | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index 45b79b23..82103e41 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -39,7 +39,7 @@ class Regexp * @return Regexp */ public function __construct($pattern) { - $this->pattern = (substr($pattern, '0', 1) != '/') + $this->pattern = (substr($pattern, 0, 1) != '/') ? '/' . $this->quote($pattern) . '/' : $pattern; } diff --git a/tests/Liquid/RegexpTest.php b/tests/Liquid/RegexpTest.php index fc1d0296..e462972a 100644 --- a/tests/Liquid/RegexpTest.php +++ b/tests/Liquid/RegexpTest.php @@ -11,7 +11,7 @@ namespace Liquid; -class LiquidRegexpTest extends TestCase +class RegexpTest extends TestCase { /** @var Regexp */ protected $regexp; @@ -45,4 +45,16 @@ public function testQuotedWords2() { public function testQuotedWordsInTheMiddle() { $this->assertEquals(array('arg1', 'arg2', '"arg 3"', 'arg4'), $this->regexp->scan('arg1 arg2 "arg 3" arg4 ')); } + + public function testPregQuote() { + $this->assertEquals('', $this->regexp->quote('')); + $this->assertEquals('abc', $this->regexp->quote('abc')); + $this->assertEquals('\/\(\{\}\)\/', $this->regexp->quote('/({})/')); + } + + public function testNoDelimiter() { + $regexp = new Regexp('(example)'); + $this->assertEquals(array('(example)'), $regexp->scan('(example)')); + $this->assertEquals(array(), $regexp->scan('nothing')); + } } From 13595eb6504fc498cf5709cb46a013b4a5763794 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 14:31:16 +0900 Subject: [PATCH 054/296] ApcTest: test case for APC cache --- tests/Liquid/Cache/ApcTest.php | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/Liquid/Cache/ApcTest.php diff --git a/tests/Liquid/Cache/ApcTest.php b/tests/Liquid/Cache/ApcTest.php new file mode 100644 index 00000000..09ff6da2 --- /dev/null +++ b/tests/Liquid/Cache/ApcTest.php @@ -0,0 +1,51 @@ +markTestSkipped("Alternative PHP Cache (APC) not available"); + } + + if (!ini_get('apc.enable_cli')) { + $this->markTestSkipped("APC not enabled with cli. Run with: php -d apc.enable_cli=1"); + } + + $this->cache = new Apc(); + } + + public function testNotExists() { + $this->assertFalse($this->cache->exists('no_such_key')); + } + + public function testReadNotExisting() { + $this->assertFalse($this->cache->read('no_such_key')); + } + + public function testSetGetFlush() { + $this->assertTrue($this->cache->write('test', 'example'), "Failed to set value."); + $this->assertSame('example', $this->cache->read('test')); + $this->assertTrue($this->cache->flush()); + $this->assertFalse($this->cache->read('test')); + } +} + From e00fe989e3b7ab3e14ee3b7469b2906bd4c4a9d2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 14:33:26 +0900 Subject: [PATCH 055/296] Apc: cast result from apc_fetch as bool --- src/Liquid/Cache/Apc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index eb6e6642..b564faca 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -47,7 +47,7 @@ public function read($key, $unserialize = true) { */ public function exists($key) { apc_fetch($this->prefix . $key, $success); - return $success; + return (bool) $success; } /** From 88ca6c185e3853e122ad87f105470ca9ad8477c8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 14:34:38 +0900 Subject: [PATCH 056/296] Cache/Apc: APC cache can be provided by a different extension (e.g. apcu), so we better check function name --- src/Liquid/Cache/Apc.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index b564faca..52abee88 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -31,8 +31,8 @@ class Apc extends Cache public function __construct(array $options = array()) { parent::__construct($options); - if (!extension_loaded('apc')) - throw new LiquidException('LiquidCacheApc requires PHP apc extension to be loaded.'); + if (!function_exists('apc_fetch')) + throw new LiquidException(get_class($this).' requires PHP apc extension or similar to be loaded.'); } /** From 6fdbe6af8e00fd4b33cda5427e911ac509aa6ad2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 15:20:47 +0900 Subject: [PATCH 057/296] Cache/Apc excluded from coverage report There's no easy way to get APC running at Travis, and if there is - it'll make builds quite a bit longer to run. --- src/Liquid/Cache/Apc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index 52abee88..538a1c3f 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -16,6 +16,8 @@ /** * Implements cache stored in Apc. + * + * @codeCoverageIgnore */ class Apc extends Cache { From dbb9f5dcd185cb5454970940fb4a3035c8c19ce3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 15:30:25 +0900 Subject: [PATCH 058/296] There's no point throwing an exception in Cache/File because file_put_contents will trigger an error all the same --- src/Liquid/Cache/File.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Liquid/Cache/File.php b/src/Liquid/Cache/File.php index 34fe72d3..0cea260d 100644 --- a/src/Liquid/Cache/File.php +++ b/src/Liquid/Cache/File.php @@ -69,12 +69,10 @@ public function exists($key) { * {@inheritdoc} */ public function write($key, $value, $serialize = true) { - if (file_put_contents($this->path . $this->prefix . $key, $serialize ? serialize($value) : $value) !== false) { - $this->gc(); - return true; - } + $bytes = file_put_contents($this->path . $this->prefix . $key, $serialize ? serialize($value) : $value); + $this->gc(); - throw new LiquidException('Can not write cache file'); + return $bytes !== false; } /** From 800a2de0ce7b4f78f3c426a4612be70d465b9a98 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 15:43:27 +0900 Subject: [PATCH 059/296] FileTest: set default and expected arguments for the test case --- tests/Liquid/Cache/FileTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index 4b8a3a64..dbe8b497 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -23,7 +23,11 @@ protected function setUp() { parent::setUp(); $this->cacheDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache_dir'; - $this->cache = new File(array('cache_dir' => $this->cacheDir)); + $this->cache = new File(array( + 'cache_dir' => $this->cacheDir, + 'cache_expire' => 3600, + 'cache_prefix' => 'liquid_', + )); } protected function tearDown() { From 857dd55530f3264da58f4409714c1b893271d716 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 16:34:14 +0900 Subject: [PATCH 060/296] TagIfTest: unexpected else --- tests/Liquid/Tag/TagIfTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index c7a2b294..f268540c 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -222,4 +222,22 @@ public function testInvalidOperator() { public function testIncomparable() { $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', array('foo' => (object) array())); } + + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage does not expect else tag + */ + public function testSyntaxErrorElse() { + $this->assertTemplateResult('', '{% if foo == 1 %}{% endif %}{% else %}'); + } + + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage Unknown tag + */ + public function testSyntaxErrorUnknown() { + $this->assertTemplateResult('', '{% unknown-tag %}'); + } + + } From cb0914e2fc63c568edd3078381c6fa4c5a2b513b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 16:43:36 +0900 Subject: [PATCH 061/296] Made StandardFilters::size exhaustive --- src/Liquid/StandardFilters.php | 17 ++++++++++++----- tests/Liquid/StandardFiltersTest.php | 8 ++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 51f1ea30..902d4047 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -429,17 +429,24 @@ public static function size($input) { if ($input instanceof \Iterator) { return iterator_count($input); } - if (is_string($input) || is_numeric($input)) { - return strlen($input); - } elseif (is_array($input)) { + + if (is_array($input)) { return count($input); - } elseif (is_object($input)) { + } + + if (is_object($input)) { if (method_exists($input, 'size')) { return $input->size(); } + + if (!method_exists($input, '__toString')) { + $class = get_class($input); + throw new LiquidException("Size of $class cannot be estimated: it has no method 'size' nor can be converted to a string"); + } } - return $input; + // only plain values and stringable objects left at this point + return strlen($input); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 909be20d..840cc258 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -72,6 +72,14 @@ public function testSize() { } } + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage cannot be estimated + */ + public function testSizeObject() { + StandardFilters::size((object) array()); + } + public function testDowncase() { $data = array( 'UpperCaseMiXed' => 'uppercasemixed', From 1c07bb04bf18d43d9ee3027c2719bc9692417d7a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 16:47:08 +0900 Subject: [PATCH 062/296] StandardFilters::sort should keep order for "same" values of sorted arrays --- tests/Liquid/StandardFiltersTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 840cc258..ccb69bb5 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -496,10 +496,12 @@ public function testSort() { $original = array( array('a' => 20, 'b' => 10), array('a' => 45, 'b' => 5), + array('a' => 40, 'b' => 5), array('a' => 30, 'b' => 48), ); $expected = array( array('a' => 45, 'b' => 5), + array('a' => 40, 'b' => 5), array('a' => 20, 'b' => 10), array('a' => 30, 'b' => 48), ); From c238cc8e0a776bd8474697075560227e70a02f71 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 17:01:51 +0900 Subject: [PATCH 063/296] Proper workaround for 'default' filter; it should work now --- src/Liquid/Filterbank.php | 5 +++++ src/Liquid/StandardFilters.php | 16 ---------------- tests/Liquid/StandardFiltersTest.php | 2 ++ 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index b04211f6..6a1498cb 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -102,6 +102,11 @@ public function addFilter($filter) { * @return string */ public function invoke($name, $value, array $args = array()) { + // workaround for a single standard filter being a reserved keyword - we can't use overloading for static calls + if ($name == 'default') { + $name = '_default'; + } + array_unshift($args, $value); // Consult the mapping diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 902d4047..df9722a8 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -656,20 +656,4 @@ public static function url_encode($input) { public static function url_decode($input) { return urldecode($input); } - - /** - * Use overloading to get around reserved php words - in this case 'default' - * - * @param string $name - * @param array $arguments - * - * @return string - * - */ - public function __call($name, $arguments) { - if ($name === 'default') { - return $this->_default($arguments[0], $arguments[1]); - } - } - } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index ccb69bb5..e19251c6 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -535,6 +535,8 @@ public function testSortKey() { public function testDefault() { $this->assertEquals('hello', StandardFilters::_default('', 'hello')); $this->assertEquals('world', StandardFilters::_default('world', 'hello')); + // check that our workaround for 'default' works as it should + $this->assertTemplateResult('something', '{{ nothing | default: "something" }}'); } public function testUnique() { From 5b806264908e04f6f8c67b6042aea94b8b928a9f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 17:07:58 +0900 Subject: [PATCH 064/296] StandardFilters::capitalize - test for edge case --- tests/Liquid/StandardFiltersTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index e19251c6..cf933754 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -105,6 +105,7 @@ public function testUpcase() { public function testCapitalize() { $data = array( 'one Word not' => 'One Word Not', + '1test' => '1Test', '' => '', ); From c51b4b1d0a651715998731641db42b07935839e8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 17:10:41 +0900 Subject: [PATCH 065/296] Test StandardFilters::date with 'r' format --- tests/Liquid/StandardFiltersTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index cf933754..fd634df4 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -1038,5 +1038,9 @@ public function testDate() { $var = new Variable('var | date, ""'); $this->context->set('var', '2017-07-01 21:00:00'); $this->assertEquals('', $var->render($this->context)); + + $var = new Variable('var | date, "r"'); + $this->context->set('var', 1000000000); + $this->assertEquals(date('r', 1000000000), $var->render($this->context)); } } From c40bebf4ca2419d22935ecde3debcf9c1bfad782 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 17:12:30 +0900 Subject: [PATCH 066/296] Test that StandardFilters::map returns the same value for non-arrays --- tests/Liquid/StandardFiltersTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index fd634df4..0588e40f 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -632,6 +632,10 @@ function() { )), array('from function ', 'value ', null), ), + array( + 0, + 0 + ) ); foreach ($data as $item) { From 4163b14005954e79526b7037db9e603103205e4d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 17:42:29 +0900 Subject: [PATCH 067/296] Liquid/Cache/Local - cache with data stored in an embedded variable with no handling of expiration dates for simplicity --- src/Liquid/Cache/Local.php | 56 ++++++++++++++++++++++++++++++++ tests/Liquid/Cache/LocalTest.php | 42 ++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/Liquid/Cache/Local.php create mode 100644 tests/Liquid/Cache/LocalTest.php diff --git a/src/Liquid/Cache/Local.php b/src/Liquid/Cache/Local.php new file mode 100644 index 00000000..ee7d88a5 --- /dev/null +++ b/src/Liquid/Cache/Local.php @@ -0,0 +1,56 @@ +cache[$key])) { + return $this->cache[$key]; + } + + return false; + } + + /** + * {@inheritdoc} + */ + public function exists($key) { + return isset($this->cache[$key]); + } + + /** + * {@inheritdoc} + */ + public function write($key, $value, $serialize = true) { + $this->cache[$key] = $value; + return true; + } + + /** + * {@inheritdoc} + */ + public function flush($expiredOnly = false) { + $this->cache = array(); + return true; + } +} \ No newline at end of file diff --git a/tests/Liquid/Cache/LocalTest.php b/tests/Liquid/Cache/LocalTest.php new file mode 100644 index 00000000..e75a6890 --- /dev/null +++ b/tests/Liquid/Cache/LocalTest.php @@ -0,0 +1,42 @@ +cache = new Local(); + } + + public function testNotExists() { + $this->assertFalse($this->cache->exists('no_such_key')); + } + + public function testReadNotExisting() { + $this->assertFalse($this->cache->read('no_such_key')); + } + + public function testSetGetFlush() { + $this->assertTrue($this->cache->write('test', 'example')); + $this->assertSame('example', $this->cache->read('test')); + $this->assertTrue($this->cache->flush()); + $this->assertFalse($this->cache->read('test')); + } +} \ No newline at end of file From 65bd0911220135b799662234eba63f254af7e759 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:32:25 +0900 Subject: [PATCH 068/296] Template: it should be possible to remove cache --- src/Liquid/Template.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 82ec0d3b..058b30ee 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -83,9 +83,15 @@ public function setCache($cache) { } else { throw new LiquidException('Invalid cache options!'); } - } else if ($cache instanceof Cache) { + } + + if ($cache instanceof Cache) { self::$cache = $cache; } + + if (is_null($cache)) { + self::$cache = null; + } } /** From 48fdc129afe120a07e1761343d46382e26d94c2d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:33:48 +0900 Subject: [PATCH 069/296] examples: no need to declare a namespace for autoloading here --- examples/block.php | 3 +-- examples/index.php | 3 +-- examples/simple.php | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/block.php b/examples/block.php index 30893e3b..de93b635 100644 --- a/examples/block.php +++ b/examples/block.php @@ -9,8 +9,7 @@ * @package Liquid */ -$loader = require __DIR__ . '/../vendor/autoload.php'; -$loader->addPsr4('Liquid\\', __DIR__ . '/../src/Liquid'); +require __DIR__ . '/../vendor/autoload.php'; use Liquid\Liquid; use Liquid\Template; diff --git a/examples/index.php b/examples/index.php index cdf707c4..19e2cd03 100644 --- a/examples/index.php +++ b/examples/index.php @@ -9,8 +9,7 @@ * @package Liquid */ -$loader = require __DIR__ . '/../vendor/autoload.php'; -$loader->addPsr4('Liquid\\', __DIR__ . '/../src/Liquid'); +require __DIR__ . '/../vendor/autoload.php'; use Liquid\Liquid; use Liquid\Template; diff --git a/examples/simple.php b/examples/simple.php index d14a69ae..66ec0f9e 100644 --- a/examples/simple.php +++ b/examples/simple.php @@ -9,8 +9,7 @@ * @package Liquid */ -$loader = require __DIR__ . '/../vendor/autoload.php'; -$loader->addPsr4('Liquid\\', __DIR__ . '/../src/Liquid'); +require __DIR__ . '/../vendor/autoload.php'; use Liquid\Liquid; use Liquid\Template; From 01d71b104beb6c33b051d6edc5987a6b94db535e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:35:28 +0900 Subject: [PATCH 070/296] Test extends and include tags with cache --- tests/Liquid/Tag/LiquidTestFileSystem.php | 4 ++++ tests/Liquid/Tag/TagExtendsTest.php | 15 +++++++++++++++ tests/Liquid/Tag/TagIncludeTest.php | 15 +++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/tests/Liquid/Tag/LiquidTestFileSystem.php b/tests/Liquid/Tag/LiquidTestFileSystem.php index 6e28d8db..5adecdc9 100644 --- a/tests/Liquid/Tag/LiquidTestFileSystem.php +++ b/tests/Liquid/Tag/LiquidTestFileSystem.php @@ -28,6 +28,10 @@ public function readTemplateFile($templatePath) { return "Inner: {{ inner }}{{ other }}"; } + if ($templatePath == 'example') { + return "Example: {% include 'inner' %}"; + } + if ($templatePath == 'base') { return "{% block content %}{% endblock %}{% block footer %}{% endblock %}"; } diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 5a8c1289..9fe2e238 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -13,6 +13,7 @@ use Liquid\TestCase; use Liquid\Template; +use Liquid\Cache\Local; /** * @see TagExtends @@ -47,6 +48,20 @@ public function testDeepExtends() $this->assertEquals("Hello! I am a footer.", $output); } + public function testWithCache() { + $template = new Template(); + $template->setFileSystem(new LiquidTestFileSystem()); + $template->setCache(new Local()); + + foreach (array("Before cache", "With cache") as $type) { + $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); + $output = $template->render(array("hello" => "$type")); + $this->assertEquals($type, $output); + } + + $template->setCache(null); + } + /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index f88f081d..3cea8a69 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -14,6 +14,7 @@ use Liquid\TestCase; use Liquid\Template; use Liquid\Liquid; +use Liquid\Cache\Local; class TagIncludeTest extends TestCase { @@ -71,6 +72,20 @@ public function testIncludeTagNoWith() { $this->assertEquals("Outer-Inner: orig-Outer-Inner: orig23", $output); } + public function testWithCache() { + $template = new Template(); + $template->setFileSystem(new LiquidTestFileSystem()); + $template->setCache(new Local()); + + foreach (array("Before cache:", "With cache:") as $type) { + $template->parse("{{ type }} {% for item in list %}{% include 'example' inner:item %} {% endfor %}"); + $template->render(array("inner" => "foo", "list" => array(1, 2, 3)), array()); + $this->assertEquals("$type Example: Inner: 1 Example: Inner: 2 ", $template->render(array("type" => $type, "inner" => "bar", "list" => array(1, 2)))); + } + + $template->setCache(null); + } + public function testIncludeTemplateFile() { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); From 3f0fe9430442ff641d907df3f1b999e92c7ab255 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:36:04 +0900 Subject: [PATCH 071/296] Document: removed redundant is_object checks --- src/Liquid/Document.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 5aacb0c7..70cdadca 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -37,12 +37,10 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) { */ public function checkIncludes() { foreach ($this->nodelist as $token) { - if (is_object($token)) { - if ($token instanceof TagInclude || $token instanceof TagExtends) { - /** @var TagInclude|TagExtends $token */ - if ($token->checkIncludes() == true) { - return true; - } + if ($token instanceof TagInclude || $token instanceof TagExtends) { + /** @var TagInclude|TagExtends $token */ + if ($token->checkIncludes() == true) { + return true; } } } From 3e03727185e99591891752d1107a73a77a2971f3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:38:15 +0900 Subject: [PATCH 072/296] Compare hashes in extends and include in an exact way --- src/Liquid/Tag/TagExtends.php | 2 +- src/Liquid/Tag/TagInclude.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 574350dc..1e9eaa42 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -184,7 +184,7 @@ public function checkIncludes() { $source = $this->fileSystem->readTemplateFile($this->templateName); - if ($cache->exists(md5($source)) && $this->hash == md5($source)) { + if ($cache->exists(md5($source)) && $this->hash === md5($source)) { return false; } diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 71320283..87b2d441 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -139,7 +139,7 @@ public function checkIncludes() { $source = $this->fileSystem->readTemplateFile($this->templateName); - if ($cache->exists(md5($source)) && $this->hash == md5($source)) { + if ($cache->exists(md5($source)) && $this->hash === md5($source)) { return false; } From 9e65b6a5302fe0909f8098837a58a363282d56e6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Sep 2017 18:46:51 +0900 Subject: [PATCH 073/296] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a528f11..7d6d3d02 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ To find more examples have a look at the `examples` directory or at the original ## Requirements - * PHP 5.3+ + * PHP 5.4+ ## Issues From ffb17e22e9485804556bd0e13e2d787ed25b6116 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 10:20:28 +0900 Subject: [PATCH 074/296] Refactor concrete LocalFileSystem into own namespace --- src/Liquid/FileSystem/Local.php | 104 ++++++++++++++++++++++++++++++++ src/Liquid/LocalFileSystem.php | 86 +------------------------- 2 files changed, 106 insertions(+), 84 deletions(-) create mode 100644 src/Liquid/FileSystem/Local.php diff --git a/src/Liquid/FileSystem/Local.php b/src/Liquid/FileSystem/Local.php new file mode 100644 index 00000000..49cd283c --- /dev/null +++ b/src/Liquid/FileSystem/Local.php @@ -0,0 +1,104 @@ +root = $root; + } + + /** + * Retrieve a template file + * + * @param string $templatePath + * + * @return string template content + */ + public function readTemplateFile($templatePath) { + return file_get_contents($this->fullPath($templatePath)); + } + + /** + * Resolves a given path to a full template file path, making sure it's valid + * + * @param string $templatePath + * + * @throws LiquidException + * @return string + */ + public function fullPath($templatePath) { + if (empty($templatePath)) { + throw new LiquidException("Empty template name"); + } + + $nameRegex = Liquid::get('INCLUDE_ALLOW_EXT') + ? new Regexp('/^[^.\/][a-zA-Z0-9_\.\/]+$/') + : new Regexp('/^[^.\/][a-zA-Z0-9_\/]+$/'); + + if (!$nameRegex->match($templatePath)) { + throw new LiquidException("Illegal template name '$templatePath'"); + } + + $templateDir = dirname($templatePath); + $templateFile = basename($templatePath); + + if (!Liquid::get('INCLUDE_ALLOW_EXT')) { + $templateFile = Liquid::get('INCLUDE_PREFIX') . $templateFile . '.' . Liquid::get('INCLUDE_SUFFIX'); + } + + $fullPath = join(DIRECTORY_SEPARATOR, array($this->root, $templateDir, $templateFile)); + + $realFullPath = realpath($fullPath); + if ($realFullPath === false) { + throw new LiquidException("File not found: $fullPath"); + } + + if (strpos($realFullPath, $this->root) !== 0) { + throw new LiquidException("Illegal template full path: {$realFullPath} not under {$this->root}"); + } + + return $realFullPath; + } +} diff --git a/src/Liquid/LocalFileSystem.php b/src/Liquid/LocalFileSystem.php index 7a8c583f..9f2913fb 100644 --- a/src/Liquid/LocalFileSystem.php +++ b/src/Liquid/LocalFileSystem.php @@ -12,88 +12,6 @@ namespace Liquid; /** - * This implements an abstract file system which retrieves template files named in a manner similar to Rails partials, - * ie. with the template name prefixed with an underscore. The extension ".liquid" is also added. - * - * For security reasons, template paths are only allowed to contain letters, numbers, and underscore. + * @deprecated Left for backward compatibility reasons. Use \Liquid\FileSystem\Local instead. */ -class LocalFileSystem implements FileSystem -{ - /** - * The root path - * - * @var string - */ - private $root; - - /** - * Constructor - * - * @param string $root The root path for templates - */ - public function __construct($root) { - // since root path can only be set from constructor, we check it once right here - if (!empty($root)) { - $realRoot = realpath($root); - if ($realRoot === false) { - throw new LiquidException("Root path could not be found: '$root'"); - } - $root = $realRoot; - } - - $this->root = $root; - } - - /** - * Retrieve a template file - * - * @param string $templatePath - * - * @return string template content - */ - public function readTemplateFile($templatePath) { - return file_get_contents($this->fullPath($templatePath)); - } - - /** - * Resolves a given path to a full template file path, making sure it's valid - * - * @param string $templatePath - * - * @throws LiquidException - * @return string - */ - public function fullPath($templatePath) { - if (empty($templatePath)) { - throw new LiquidException("Empty template name"); - } - - $nameRegex = Liquid::get('INCLUDE_ALLOW_EXT') - ? new Regexp('/^[^.\/][a-zA-Z0-9_\.\/]+$/') - : new Regexp('/^[^.\/][a-zA-Z0-9_\/]+$/'); - - if (!$nameRegex->match($templatePath)) { - throw new LiquidException("Illegal template name '$templatePath'"); - } - - $templateDir = dirname($templatePath); - $templateFile = basename($templatePath); - - if (!Liquid::get('INCLUDE_ALLOW_EXT')) { - $templateFile = Liquid::get('INCLUDE_PREFIX') . $templateFile . '.' . Liquid::get('INCLUDE_SUFFIX'); - } - - $fullPath = join(DIRECTORY_SEPARATOR, array($this->root, $templateDir, $templateFile)); - - $realFullPath = realpath($fullPath); - if ($realFullPath === false) { - throw new LiquidException("File not found: $fullPath"); - } - - if (strpos($realFullPath, $this->root) !== 0) { - throw new LiquidException("Illegal template full path: {$realFullPath} not under {$this->root}"); - } - - return $realFullPath; - } -} +class LocalFileSystem extends \Liquid\FileSystem\Local {} \ No newline at end of file From 3444a256af5104b851fe94f136c1fffd48cade97 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 11:44:43 +0900 Subject: [PATCH 075/296] FileSystem/Virtual - a virtual file system with actual code used to find files injected from outside, thus achieving inversion of control --- src/Liquid/FileSystem/Virtual.php | 52 ++++++++++++++++++++++++++ tests/Liquid/VirtualFileSystemTest.php | 43 +++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/Liquid/FileSystem/Virtual.php create mode 100644 tests/Liquid/VirtualFileSystemTest.php diff --git a/src/Liquid/FileSystem/Virtual.php b/src/Liquid/FileSystem/Virtual.php new file mode 100644 index 00000000..667c0ab8 --- /dev/null +++ b/src/Liquid/FileSystem/Virtual.php @@ -0,0 +1,52 @@ +callback = $callback; + } + + /** + * Retrieve a template file + * + * @param string $templatePath + * + * @return string template content + */ + public function readTemplateFile($templatePath) { + return call_user_func($this->callback, $templatePath); + } +} \ No newline at end of file diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php new file mode 100644 index 00000000..2649e4d2 --- /dev/null +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -0,0 +1,43 @@ +assertEquals('Contents of foo', $fs->readTemplateFile('foo')); + $this->assertEquals('Bar', $fs->readTemplateFile('bar')); + $this->assertEquals('', $fs->readTemplateFile('nothing')); + } +} From e3369d8d58a5209323f5408d9151d17f3e9a422d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 11:53:03 +0900 Subject: [PATCH 076/296] Replace LiquidTestFileSystem with FileSystem\Virtual in tests --- tests/Liquid/Tag/LiquidTestFileSystem.php | 45 ----------------------- tests/Liquid/Tag/TagExtendsTest.php | 25 ++++++++++--- tests/Liquid/Tag/TagIncludeTest.php | 20 ++++++++-- 3 files changed, 37 insertions(+), 53 deletions(-) delete mode 100644 tests/Liquid/Tag/LiquidTestFileSystem.php diff --git a/tests/Liquid/Tag/LiquidTestFileSystem.php b/tests/Liquid/Tag/LiquidTestFileSystem.php deleted file mode 100644 index 5adecdc9..00000000 --- a/tests/Liquid/Tag/LiquidTestFileSystem.php +++ /dev/null @@ -1,45 +0,0 @@ -fs = new Virtual(function ($templatePath) { + if ($templatePath == 'base') { + return "{% block content %}{% endblock %}{% block footer %}{% endblock %}"; + } + + if ($templatePath == 'sub-base') { + return "{% extends 'base' %}{% block content %}{% endblock %}{% block footer %} Boo! {% endblock %}"; + } + }); + } + public function testBasicExtends() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); $output = $template->render(array("hello" => "Hello!")); $this->assertEquals("Hello!", $output); @@ -32,25 +47,25 @@ public function testBasicExtends() public function testDefaultContentExtends() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->parse("{% block content %}{{ hello }}{% endblock %}\n{% extends 'sub-base' %}"); $output = $template->render(array("hello" => "Hello!")); $this->assertEquals("Hello!\n Boo! ", $output); } - public function testDeepExtends() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->parse('{% extends "sub-base" %}{% block content %}{{ hello }}{% endblock %}{% block footer %} I am a footer.{% endblock %}'); + $output = $template->render(array("hello" => "Hello!")); $this->assertEquals("Hello! I am a footer.", $output); } public function testWithCache() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->setCache(new Local()); foreach (array("Before cache", "With cache") as $type) { diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 3cea8a69..7ffb7b88 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -15,9 +15,23 @@ use Liquid\Template; use Liquid\Liquid; use Liquid\Cache\Local; +use Liquid\FileSystem\Virtual; class TagIncludeTest extends TestCase { + private $fs; + + protected function setUp() { + $this->fs = new Virtual(function ($templatePath) { + if ($templatePath == 'inner') { + return "Inner: {{ inner }}{{ other }}"; + } + + if ($templatePath == 'example') { + return "Example: {% include 'inner' %}"; + } + }); + } /** * @expectedException \Liquid\LiquidException */ @@ -52,7 +66,7 @@ public function testInvalidSyntaxNoObjectCollection() { public function testIncludeTag() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->parse("Outer-{% include 'inner' with 'value' other:23 %}-Outer{% include 'inner' for var other:'loop' %}"); @@ -63,7 +77,7 @@ public function testIncludeTag() { public function testIncludeTagNoWith() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->parse("Outer-{% include 'inner' %}-Outer-{% include 'inner' other:'23' %}"); @@ -74,7 +88,7 @@ public function testIncludeTagNoWith() { public function testWithCache() { $template = new Template(); - $template->setFileSystem(new LiquidTestFileSystem()); + $template->setFileSystem($this->fs); $template->setCache(new Local()); foreach (array("Before cache:", "With cache:") as $type) { From fcebd8b6f82c2524a8c50cddd068117237e2c4ca Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 12:46:40 +0900 Subject: [PATCH 077/296] Changelog for 1.3.1 --- CHANGELOG | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 771f7971..849db7a2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,15 @@ +* 1.3.1 (2017-09-23) + + * Support for numeric and variable array indicies + * Support loop break and continue + * Allow looping over extended ranges + * Math filters now work with floats + * Fixed 'default' filter + * Local cache with data stored in a private variable + * Virtual file system to get inversion of control and DI + * Lots of tests with the coverage upped to 97% + * Small bug fixes and various enhancements + * 1.3.0 (2017-07-17) * Support Traversable loops and filters From 7452aed833b6e45c20d819b340ac648c6242a53f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 12:51:01 +0900 Subject: [PATCH 078/296] composer.json: align formatting I used: jq -M --indent 4 < composer.json --- composer.json | 55 +++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index e9260ec0..ebd305a7 100644 --- a/composer.json +++ b/composer.json @@ -1,38 +1,41 @@ { "name": "liquid/liquid", "description": "Liquid template engine for PHP", - "keywords": ["liquid", "template"], - "homepage": "https://github.com/kalimatas/php-liquid", + "keywords": [ + "liquid", + "template" + ], + "homepage": "https://github.com/kalimatas/php-liquid", "license": "MIT", - "type": "library", + "type": "library", "authors": [ { "name": "Guz Alexander", "email": "kalimatas@gmail.com", - "homepage": "http://guzalexander.com" + "homepage": "http://guzalexander.com" + }, + { + "name": "Harald Hanek" }, - { - "name": "Harald Hanek" - }, - { - "name": "Mateo Murphy" - } + { + "name": "Mateo Murphy" + } ], "require": { - "php": ">= 5.3" - }, - "require-dev": { - "phpunit/phpunit": "<6", - "satooshi/php-coveralls": "^1.0" - }, - "autoload": { - "psr-4": { - "Liquid\\": "src/Liquid" - } - }, - "autoload-dev": { - "psr-4": { - "Liquid\\": "tests/Liquid" - } - } + "php": ">= 5.3" + }, + "require-dev": { + "phpunit/phpunit": "<6", + "satooshi/php-coveralls": "^1.0" + }, + "autoload": { + "psr-4": { + "Liquid\\": "src/Liquid" + } + }, + "autoload-dev": { + "psr-4": { + "Liquid\\": "tests/Liquid" + } + } } From 5da5c7828a00e96ea4c36771354c49e1fc4ea751 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 12:54:35 +0900 Subject: [PATCH 079/296] composer.json: added yours truly --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index ebd305a7..88865c54 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,11 @@ }, { "name": "Mateo Murphy" + }, + { + "name": "Alexey Kopytko", + "email": "alexey@kopytko.com", + "homepage": "https://www.alexeykopytko.com/" } ], "require": { From 92cb6f42e329aec7e0f8e134c73f06b89f4e5c5b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 12:56:07 +0900 Subject: [PATCH 080/296] Starting now we will require PHP 5.6 no less --- .travis.yml | 2 -- README.md | 2 +- composer.json | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95e5e282..bc28b189 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ sudo: false language: php php: - - 5.4 - - 5.5 - 5.6 - 7.0 - 7.1 diff --git a/README.md b/README.md index 7d6d3d02..8a37384c 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ To find more examples have a look at the `examples` directory or at the original ## Requirements - * PHP 5.4+ + * PHP 5.6+ ## Issues diff --git a/composer.json b/composer.json index 88865c54..8da992c2 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ } ], "require": { - "php": ">= 5.3" + "php": ">= 5.6" }, "require-dev": { "phpunit/phpunit": "<6", From 797e10ac3adf952c9c84c8976adaeff6f1a18cdd Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 13:01:24 +0900 Subject: [PATCH 081/296] Partial changelog for the next minor release --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 849db7a2..5b85d35b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +* master + + * Dropped support for EOL'ed versions of PHP (< 5.6) + * 1.3.1 (2017-09-23) * Support for numeric and variable array indicies From efcfd1528ca506c9fb15c44366037a27ee980dab Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 13:19:18 +0900 Subject: [PATCH 082/296] A note about version 1.3 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8a37384c..eb185f8f 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,8 @@ To find more examples have a look at the `examples` directory or at the original * PHP 5.6+ +Package versions below 1.4 could be used with PHP 5.3/5.4/5.5. + ## Issues Have a bug? Please create an issue here on GitHub! From 18585c3a787a2f82b0b6f64428a2448a5dd240de Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 13:33:25 +0900 Subject: [PATCH 083/296] LocalFileSystem tells exacty which file is not found Fixes #15 --- tests/Liquid/LocalFileSystemTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index de6a66cd..d5d36247 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -105,6 +105,7 @@ public function testValidPathWithCustomExtension() { /** * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage File not found */ public function testReadIllegalTemplatePathNoFileExists() { $fileSystem = new LocalFileSystem(dirname(__DIR__)); From e750a94c486b773a7e0206490c3965232752733f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 14:06:08 +0900 Subject: [PATCH 084/296] A note about typical advanced usage Documentation: [ci skip] --- README.md | 33 +++++++++++++++++++++ examples/advanced.php | 33 +++++++++++++++++++++ examples/protected/templates/honorific.html | 1 + 3 files changed, 67 insertions(+) create mode 100644 examples/advanced.php create mode 100644 examples/protected/templates/honorific.html diff --git a/README.md b/README.md index eb185f8f..2d94024b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,39 @@ The main class is `Liquid::Template` class. There are two separate stages of wor To find more examples have a look at the `examples` directory or at the original Ruby implementation repository's [wiki page](https://github.com/Shopify/liquid/wiki). +## Advanced usage + +You would probably want to add a caching layer (at very least a request-wide one), enable context-aware automatic escaping, and do load includes from disk with full file names. + + use Liquid\Liquid; + use Liquid\Template; + use Liquid\Cache\Local; + + Liquid::set('INCLUDE_SUFFIX', ''); + Liquid::set('INCLUDE_PREFIX', ''); + Liquid::set('INCLUDE_ALLOW_EXT', true); + Liquid::set('ESCAPE_BY_DEFAULT', true); + + $template = new Template(__DIR__.'/protected/templates/'); + + $template->parse("Hello, {% include 'honorific.html' %}{{ plain-html | raw }} {{ comment-with-xss }}"); + $template->setCache(new Local()); + + echo $template->render([ + 'name' => 'Alex', + 'plain-html' => 'Your comment was:', + 'comment-with-xss' => '', + ]); + +Will output: + + Hello, Mx. Alex + Your comment was: <script>alert();</script> + +Note that automatic escaping is not a standard Liquid feature: use with care. + +You should probably extend `Liquid\Template` to initialize everything in one place. + ## Requirements * PHP 5.6+ diff --git a/examples/advanced.php b/examples/advanced.php new file mode 100644 index 00000000..f0224227 --- /dev/null +++ b/examples/advanced.php @@ -0,0 +1,33 @@ +parse("Hello, {% include 'honorific.html' %}{{ plain-html | raw }} {{ comment-with-xss }}\n"); +$template->setCache(new Local()); + +echo $template->render([ + 'name' => 'Alex', + 'plain-html' => 'Your comment was:', + 'comment-with-xss' => '', +]); + diff --git a/examples/protected/templates/honorific.html b/examples/protected/templates/honorific.html new file mode 100644 index 00000000..a935dd27 --- /dev/null +++ b/examples/protected/templates/honorific.html @@ -0,0 +1 @@ +Mx. {{ name }} From 2f2d674d4211b3c6b295a87ed1efbd71dd21cfda Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 15:08:10 +0900 Subject: [PATCH 085/296] Virtual file system with a Closure as a callback cannot be used with a serializing cache --- src/Liquid/FileSystem/Virtual.php | 9 +++++++++ tests/Liquid/VirtualFileSystemTest.php | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Liquid/FileSystem/Virtual.php b/src/Liquid/FileSystem/Virtual.php index 667c0ab8..7eba72c4 100644 --- a/src/Liquid/FileSystem/Virtual.php +++ b/src/Liquid/FileSystem/Virtual.php @@ -49,4 +49,13 @@ public function __construct($callback) { public function readTemplateFile($templatePath) { return call_user_func($this->callback, $templatePath); } + + public function __sleep() { + // we cannot serialize a closure + if ($this->callback instanceof \Closure) { + throw new LiquidException("Virtual file system with a Closure as a callback cannot be used with a serializing cache"); + } + + return array_keys(get_object_vars($this)); + } } \ No newline at end of file diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 2649e4d2..8ddfe25f 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -12,6 +12,7 @@ namespace Liquid; use Liquid\FileSystem\Virtual; +use Liquid\Cache\File; class VirtualFileSystemTest extends TestCase { @@ -40,4 +41,19 @@ public function testFeadTemplateFile() { $this->assertEquals('Bar', $fs->readTemplateFile('bar')); $this->assertEquals('', $fs->readTemplateFile('nothing')); } -} + + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage cannot be used with a serializing cache + */ + public function testWithFileCache() { + $template = new Template(); + $template->setFileSystem(new Virtual(function ($templatePath) { + return ''; + })); + $template->setCache(new File(array( + 'cache_dir' => __DIR__, + ))); + $template->parse("Hello"); + } +} \ No newline at end of file From 4a19e80dad0f7d7e3ed57d4af4df065ae18f7a0a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 20:26:42 +0900 Subject: [PATCH 086/296] Unset FS in include/extends tags tests If not do it, PHP goes totally nuts replacing instances here and there --- tests/Liquid/Tag/TagExtendsTest.php | 5 +++++ tests/Liquid/Tag/TagIncludeTest.php | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index eabb29ee..6933b4fe 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -35,6 +35,11 @@ protected function setUp() { }); } + protected function tearDown() { + // PHP goes nuts unless we unset it + unset($this->fs); + } + public function testBasicExtends() { $template = new Template(); diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 7ffb7b88..fefc9255 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -32,6 +32,12 @@ protected function setUp() { } }); } + + protected function tearDown() { + // PHP goes nuts unless we unset it + unset($this->fs); + } + /** * @expectedException \Liquid\LiquidException */ From 9963e308a77ed85f0e0867a44fcd6057ff1fce58 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 20:04:42 +0900 Subject: [PATCH 087/296] VirtualFileSystemTest with a regular serializable callback --- tests/Liquid/VirtualFileSystemTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 8ddfe25f..0ddb58c7 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -56,4 +56,19 @@ public function testWithFileCache() { ))); $template->parse("Hello"); } + + public function virtualFileSystemCallback($templatePath) { + return 'OK'; + } + + public function testWithRegularCallback() { + $template = new Template(); + $template->setFileSystem(new Virtual(array($this, 'virtualFileSystemCallback'), true)); + $template->setCache(new File(array( + 'cache_dir' => __DIR__.'/cache_dir/', + ))); + + $template->parse("Test: {% include 'hello' %}"); + $this->assertEquals('Test: OK', $template->render()); + } } \ No newline at end of file From 0f61cd8b848c326e067d5cc198558a0cd25d46ed Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 23 Sep 2017 20:28:26 +0900 Subject: [PATCH 088/296] DropTest: do not expect an exception when using trigger_error (in the next version of PHPUnit there will be none) --- tests/Liquid/DropTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index 61fd9377..7d61c423 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -39,7 +39,7 @@ public function beforeMethod($method) { class ProductDrop extends Drop { public function top_sales() { - trigger_error('worked', E_USER_ERROR); + throw new \Exception("worked"); } public function texts() { @@ -62,7 +62,7 @@ public function callmenot() { class DropTest extends TestCase { /** - * @expectedException \PHPUnit_Framework_Error + * @expectedException \Exception * @expectedExceptionMessage worked */ public function testProductDrop() { From 966592c7a5721ad4b4bd42131f2c5e4259e2ceec Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 10:44:15 +0900 Subject: [PATCH 089/296] VirtualFileSystemTest: typo --- tests/Liquid/VirtualFileSystemTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 0ddb58c7..614862be 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -24,7 +24,7 @@ public function testInvalidCallback() { new Virtual(''); } - public function testFeadTemplateFile() { + public function testReadTemplateFile() { $fs = new Virtual(function ($templatePath) { if ($templatePath == 'foo') { return "Contents of foo"; From 043cbf884f36e333569aa9da988bc007f57cc2a4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 12:15:11 +0900 Subject: [PATCH 090/296] AbstractTag should have abstract content: children must implement it --- src/Liquid/AbstractTag.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index bd70f71b..25572849 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -66,9 +66,7 @@ public function parse(array &$tokens) { * * @return string */ - public function render(Context $context) { - return ''; - } + abstract public function render(Context $context); /** * Extracts tag attributes from a markup string. From 8bd037cbcdf563349f8a1e827e9465a8b1c8d0b9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 12:14:38 +0900 Subject: [PATCH 091/296] TagCaseTest: check with toLiquid --- tests/Liquid/Tag/TagCaseTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index 22023dbd..9ef6d395 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -20,6 +20,13 @@ public function __toString() { } } +class HasToLiquid +{ + public function toLiquid() { + return "100"; + } +} + class TagCaseTest extends TestCase { public function testCase() { @@ -78,4 +85,8 @@ public function testObject() { public function testStringable() { $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new Stringable())); } + + public function testToLiquid() { + $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new HasToLiquid())); + } } From 29753b35c331d43ce8a8179d085620fcce65060b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 11:43:24 +0900 Subject: [PATCH 092/296] TestFileSystem: simplified test wrapper for 'Virtual' file system --- tests/Liquid/TestFileSystem.php | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/Liquid/TestFileSystem.php diff --git a/tests/Liquid/TestFileSystem.php b/tests/Liquid/TestFileSystem.php new file mode 100644 index 00000000..bee5a164 --- /dev/null +++ b/tests/Liquid/TestFileSystem.php @@ -0,0 +1,29 @@ + Date: Mon, 25 Sep 2017 11:47:19 +0900 Subject: [PATCH 093/296] TagIncludeTest: use TestFileSystem --- tests/Liquid/Tag/TagIncludeTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index fefc9255..f1720ce6 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -16,21 +16,17 @@ use Liquid\Liquid; use Liquid\Cache\Local; use Liquid\FileSystem\Virtual; +use Liquid\TestFileSystem; class TagIncludeTest extends TestCase { private $fs; protected function setUp() { - $this->fs = new Virtual(function ($templatePath) { - if ($templatePath == 'inner') { - return "Inner: {{ inner }}{{ other }}"; - } - - if ($templatePath == 'example') { - return "Example: {% include 'inner' %}"; - } - }); + $this->fs = TestFileSystem::fromArray(array( + 'inner' => "Inner: {{ inner }}{{ other }}", + 'example' => "Example: {% include 'inner' %}", + )); } protected function tearDown() { From 29cf039eb5ecf93d2930cb194196d8b6fddf858a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 12:04:27 +0900 Subject: [PATCH 094/296] Context: defer object-to-string conversion, delegate it to Decision::stringValue/AbstractBlock::renderAll This way complex objects could be passed between templates and to filters. --- src/Liquid/AbstractBlock.php | 8 +++++- src/Liquid/Context.php | 30 ++++++++++++---------- src/Liquid/Decision.php | 4 ++- tests/Liquid/ContextTest.php | 7 ++--- tests/Liquid/Tag/TagIncludeTest.php | 40 +++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 21 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 5d3e6372..b05ce443 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -114,7 +114,13 @@ protected function renderAll(array $list, Context $context) { $result = ''; foreach ($list as $token) { - $result .= (is_object($token) && method_exists($token, 'render')) ? $token->render($context) : $token; + if (method_exists($token, 'render')) { + $value = $token->render($context); + } else { + $value = $token; + } + + $result .= $value; if (isset($context->registers['break'])) { break; diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index ded4fefb..29c1bdc1 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -234,6 +234,9 @@ private function fetch($key) { * * @param string $key * + * @see Decision::stringValue + * @see AbstractBlock::renderAll + * * @throws LiquidException * @return mixed */ @@ -333,23 +336,22 @@ private function variable($key) { // we'll try casting this object in the next iteration } - // Traversable objects are taken care of inside filters - if ($object instanceof \Traversable) { - return $object; - } - - // finally, resolve an object to a string or a plain value - if (method_exists($object, '__toString')) { - $object = (string) $object; - } elseif (method_exists($object, 'toLiquid')) { + // lastly, try to get an embedded value of an object + // value could be of any type, not just string, so we have to do this + // conversion here, not laster in AbstractBlock::renderAll + if (method_exists($object, 'toLiquid')) { $object = $object->toLiquid(); } - // if everything else fails, throw up - if (is_object($object)) { - $class = get_class($object); - throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` methods"); - } + /* + * Before here were checks for object types and object to string conversion. + * + * Now we just return what we have: + * - Traversable objects are taken care of inside filters + * - Object-to-string conversion is handled at the last moment in Decision::stringValue, and in AbstractBlock::renderAll + * + * This way complex objects could be passed between templates and to filters + */ return $object; } diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index c9e10dda..9a0d86cf 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -44,7 +44,9 @@ private function stringValue($value) { if (method_exists($value, '__toString')) { $value = (string) $value; } else { - throw new LiquidException("Cannot convert $value to string"); // harry + // toLiquid is handled in Context::variable + $class = get_class($value); + throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` methods"); } } diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index db1a9535..6561f9ed 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -166,12 +166,9 @@ public function testGetSetObject() { $this->assertNull($this->context->get('object.invalid')); } - /** - * @expectedException \Liquid\LiquidException - */ - public function testFinalVariableIsObject() { + public function testFinalVariableCanBeObject() { $this->context->set('test', (object) array('value' => (object) array())); - $this->context->get('test.value'); + $this->assertInstanceOf(\stdClass::class, $this->context->get('test.value')); } public function testVariables() { diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index f1720ce6..1957ba0c 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -111,4 +111,44 @@ public function testIncludeTemplateFile() { // template include inserts a new line $this->assertEquals("test content\n", $template->render()); } + + public function testIncludePassPlainValue() { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'inner' => "[{{ other }}]", + 'example' => "({% include 'inner' other:var %})", + ))); + + $template->parse("{% include 'example' %}"); + + $output = $template->render(array("var" => "test")); + $this->assertEquals("([test])", $output); + } + + public function testIncludePassArrayWithIndex() { + + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'inner' => "[{{ other[0] }}]", + 'example' => "({% include 'inner' other:var %})", + ))); + + $template->parse("{% include 'example' %}"); + + $output = $template->render(array("var" => array("a", "b", "c"))); + $this->assertEquals("([a])", $output); + } + + public function testIncludePassObjectValue() { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'inner' => "[{{ other.a }}]", + 'example' => "({% include 'inner' other:var %})", + ))); + + $template->parse("{% include 'example' %}"); + + $output = $template->render(array("var" => (object) array('a' => 'b'))); + $this->assertEquals("([b])", $output); + } } From 37ff1059490e5e0b6074b85ded897e6ce2349a90 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 12:06:14 +0900 Subject: [PATCH 095/296] AbstractBlock: refuse to render arrays (before they were silently cast as 'Array') --- src/Liquid/AbstractBlock.php | 4 ++++ tests/Liquid/Tag/TagIncludeTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index b05ce443..64d54ce2 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -120,6 +120,10 @@ protected function renderAll(array $list, Context $context) { $value = $token; } + if (is_array($value)) { + throw new LiquidException("Implicit rendering of arrays not supported. Use index operator."); + } + $result .= $value; if (isset($context->registers['break'])) { diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 1957ba0c..adb9342f 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -125,6 +125,22 @@ public function testIncludePassPlainValue() { $this->assertEquals("([test])", $output); } + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage Use index operator + */ + public function testIncludePassArrayWithoutIndex() { + + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'inner' => "[{{ other }}]", + 'example' => "({% include 'inner' other:var %})", + ))); + + $template->parse("{% include 'example' %}"); + $template->render(array("var" => array("a", "b", "c"))); + } + public function testIncludePassArrayWithIndex() { $template = new Template(); From 3d96a0f1d3877794256cefd56f226e5265d89f39 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 12:34:29 +0900 Subject: [PATCH 096/296] CHANGELOG for the next version --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5b85d35b..19f6bca8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,11 @@ * master +* 1.4.0 (2017-09-25) + * Dropped support for EOL'ed versions of PHP (< 5.6) + * Arrays won't be silently cast to string as 'Array' anymore + * Complex objects could now be passed between templates and to filters + * Additional test coverage * 1.3.1 (2017-09-23) From 082479c00696d5a1eba3a0c2c81396264f7da863 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 14:13:33 +0900 Subject: [PATCH 097/296] Test an invalid variable with a new line inside --- tests/Liquid/OutputTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 7b1038e2..1a3ecd31 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -129,4 +129,13 @@ public function testLinkTo() { $this->assertTemplateResult($expected, $text, $this->assigns); } + + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage was not properly terminated + */ + public function testVariableWithANewLine() { + $text = "{{ aaa\n }}"; + $this->assertTemplateResult('', $text, $this->assigns); + } } From b45fb693ac3f42f71043158ef2f6f2b45c334b4b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 14:19:30 +0900 Subject: [PATCH 098/296] AbstractBlock: removed redundant array check --- src/Liquid/AbstractBlock.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 64d54ce2..85cef922 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -43,10 +43,6 @@ public function parse(array &$tokens) { $this->nodelist = array(); - if (!is_array($tokens)) { - return; - } - $tags = Template::getTags(); while (count($tokens)) { From f76942647e19f767b4dd7ad8c09474a54ff22aa9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:00:29 +0900 Subject: [PATCH 099/296] ContextTest: additional cases for `null` returned from toLiquid --- tests/Liquid/ContextTest.php | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 6561f9ed..86c880f9 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -43,6 +43,14 @@ public function __toString() { } } +class ToLiquidWrapper { + public $value = null; + + public function toLiquid() { + return $this->value; + } +} + class NestedObject { public $property; @@ -58,6 +66,21 @@ public function toLiquid() { } } +class ToArrayObject +{ + public $property; + public $value = -1; + + public function toArray() { + // we intentionally made the value different so + // that we could see where it is coming from + return array( + 'property' => $this->property, + 'value' => 42, + ); + } +} + class GetSetObject { public function field_exists($name) { @@ -151,6 +174,20 @@ public function testVariableIsObjectWithNoToLiquid() { $this->assertEquals("example", $this->context->get('test.name')); } + public function testToLiquidNull() { + $object = new ToLiquidWrapper(); + $this->context->set('object', $object); + $this->assertNull($this->context->get('object.key')); + } + + public function testToLiquidStringKeyMustBeNull() { + $object = new ToLiquidWrapper(); + $object->value = 'foo'; + $this->context->set('object', $object); + $this->assertNull($this->context->get('object.foo')); + $this->assertNull($this->context->get('object.foo.bar')); + } + public function testNestedObject() { $object = new NestedObject(); $object->property = new NestedObject(); @@ -160,6 +197,15 @@ public function testNestedObject() { $this->assertNull($this->context->get('object.property.value.invalid')); } + public function testToArrayObject() { + $object = new ToArrayObject(); + $object->property = new ToArrayObject(); + $this->context->set('object', $object); + $this->assertEquals(42, $this->context->get('object.value')); + $this->assertEquals(42, $this->context->get('object.property.value')); + $this->assertNull($this->context->get('object.property.value.invalid')); + } + public function testGetSetObject() { $this->context->set('object', new GetSetObject()); $this->assertEquals(42, $this->context->get('object.answer')); From 19217201091c07e2818cec9ea98ca793b092df1f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:05:53 +0900 Subject: [PATCH 100/296] DropTest: make sure hasKey gets called --- tests/Liquid/DropTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index 7d61c423..c2031517 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -57,6 +57,10 @@ public function context() { public function callmenot() { return "protected"; } + + public function hasKey($name) { + return $name != 'unknown' && $name != 'false'; + } } class DropTest extends TestCase @@ -71,6 +75,13 @@ public function testProductDrop() { $template->render(array('product' => new ProductDrop)); } + public function testNoKeyDrop() { + $template = new Template(); + $template->parse(' {{ product.invalid.unknown }}{{ product.false }} '); + $output = $template->render(array('product' => new ProductDrop)); + $this->assertEquals(' ', $output); + } + public function testTextDrop() { $template = new Template(); $template->parse(' {{ product.texts.text }} '); From 04b0a4178f332f019e9d2539b5fd376452cea2e0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:08:10 +0900 Subject: [PATCH 101/296] Test for Context::hasKey --- tests/Liquid/ContextTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 86c880f9..45061b1c 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -219,6 +219,8 @@ public function testFinalVariableCanBeObject() { public function testVariables() { $this->context->set('test', 'test'); + $this->assertTrue($this->context->hasKey('test')); + $this->assertFalse($this->context->hasKey('test.foo')); $this->assertEquals('test', $this->context->get('test')); // We add this text to make sure we can return values that evaluate to false properly From 37a356a91651aca00b8c84c6ee1d30c90fc9f2ab Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:10:37 +0900 Subject: [PATCH 102/296] Test for Drop::__toString --- tests/Liquid/DropTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index c2031517..e6d2aec3 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -115,4 +115,9 @@ public function testNestedContextDrop() { $output = $template->render(array('product' => new ProductDrop(), 'foo' => 'monkey')); $this->assertEquals(' monkey ', $output); } + + public function testToString() + { + $this->assertEquals(ProductDrop::class, strval(new ProductDrop())); + } } From 397c52b71aaed2b4a6d15fa2782fb16237ca517f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:46:39 +0900 Subject: [PATCH 103/296] Adopt PHP-CS-Fixer with closest possible config to the currently used coding standard We can't have both braces on the next line after classes, and on the same for functions. If we only would have to change braces by classes, that would be least possible change in terms of lines changed. --- .php_cs.dist | 23 +++++++++++++++++++++++ .travis.yml | 4 ++++ composer.json | 3 ++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .php_cs.dist diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 00000000..5a2dd56b --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,23 @@ +setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'braces' => ['position_after_functions_and_oop_constructs' => 'same'], + ]) + ->setIndent("\t") + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ) +; diff --git a/.travis.yml b/.travis.yml index bc28b189..80806450 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,5 +13,9 @@ cache: install: - composer install --prefer-dist +script: + - vendor/bin/phpunit --verbose || travis_terminate 1 + - vendor/bin/php-cs-fixer --diff --dry-run --stop-on-violation --verbose fix + after_success: - travis_retry php vendor/bin/coveralls diff --git a/composer.json b/composer.json index 8da992c2..127eebaf 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ }, "require-dev": { "phpunit/phpunit": "<6", - "satooshi/php-coveralls": "^1.0" + "satooshi/php-coveralls": "^1.0", + "friendsofphp/php-cs-fixer": "^2.6" }, "autoload": { "psr-4": { From cea52b119d4e2dc2605c30c6c5abd6a952f420c3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:55:42 +0900 Subject: [PATCH 104/296] src/ fixed with PHP-CS-Fixer --- src/Liquid/AbstractBlock.php | 5 +--- src/Liquid/AbstractTag.php | 3 +-- src/Liquid/Cache.php | 3 +-- src/Liquid/Cache/Apc.php | 6 ++--- src/Liquid/Cache/File.php | 6 ++--- src/Liquid/Cache/Local.php | 5 ++-- src/Liquid/Context.php | 17 ++++++------ src/Liquid/CustomFilters.php | 4 +-- src/Liquid/Decision.php | 5 +--- src/Liquid/Document.php | 3 +-- src/Liquid/Drop.php | 3 +-- src/Liquid/FileSystem.php | 3 +-- src/Liquid/FileSystem/Local.php | 3 +-- src/Liquid/FileSystem/Virtual.php | 5 ++-- src/Liquid/Filterbank.php | 3 +-- src/Liquid/Liquid.php | 3 +-- src/Liquid/LiquidException.php | 3 +-- src/Liquid/LocalFileSystem.php | 3 ++- src/Liquid/Regexp.php | 3 +-- src/Liquid/StandardFilters.php | 43 +++++++++++++++---------------- src/Liquid/Tag/TagAssign.php | 3 +-- src/Liquid/Tag/TagBlock.php | 3 +-- src/Liquid/Tag/TagBreak.php | 5 ++-- src/Liquid/Tag/TagCapture.php | 3 +-- src/Liquid/Tag/TagCase.php | 4 +-- src/Liquid/Tag/TagComment.php | 3 +-- src/Liquid/Tag/TagContinue.php | 5 ++-- src/Liquid/Tag/TagCycle.php | 3 +-- src/Liquid/Tag/TagDecrement.php | 3 +-- src/Liquid/Tag/TagExtends.php | 9 +++---- src/Liquid/Tag/TagFor.php | 10 ++----- src/Liquid/Tag/TagIf.php | 7 ++--- src/Liquid/Tag/TagIfchanged.php | 4 +-- src/Liquid/Tag/TagInclude.php | 3 +-- src/Liquid/Tag/TagIncrement.php | 3 +-- src/Liquid/Tag/TagPaginate.php | 21 +++++---------- src/Liquid/Tag/TagRaw.php | 3 +-- src/Liquid/Tag/TagTablerow.php | 3 +-- src/Liquid/Tag/TagUnless.php | 7 +++-- src/Liquid/Template.php | 3 +-- src/Liquid/Variable.php | 4 +-- 41 files changed, 90 insertions(+), 148 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 85cef922..1db6c75a 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -14,8 +14,7 @@ /** * Base class for blocks. */ -class AbstractBlock extends AbstractTag -{ +class AbstractBlock extends AbstractTag { /** * @var AbstractTag[] */ @@ -75,10 +74,8 @@ public function parse(array &$tokens) { } else { throw new LiquidException("Tag $token was not properly terminated"); // harry } - } elseif ($variableStartRegexp->match($token)) { $this->nodelist[] = $this->createVariable($token); - } elseif ($token != '') { $this->nodelist[] = $token; } diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index 25572849..9238e61e 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -14,8 +14,7 @@ /** * Base class for tags. */ -abstract class AbstractTag -{ +abstract class AbstractTag { /** * The markup for the tag * diff --git a/src/Liquid/Cache.php b/src/Liquid/Cache.php index 83b5bdee..0fe81853 100644 --- a/src/Liquid/Cache.php +++ b/src/Liquid/Cache.php @@ -14,8 +14,7 @@ /** * Base class for Cache. */ -abstract class Cache -{ +abstract class Cache { /** @var int */ protected $expire = 3600; /** @var string */ diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index 538a1c3f..76b418f5 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -19,8 +19,7 @@ * * @codeCoverageIgnore */ -class Apc extends Cache -{ +class Apc extends Cache { /** * Constructor. * @@ -33,8 +32,9 @@ class Apc extends Cache public function __construct(array $options = array()) { parent::__construct($options); - if (!function_exists('apc_fetch')) + if (!function_exists('apc_fetch')) { throw new LiquidException(get_class($this).' requires PHP apc extension or similar to be loaded.'); + } } /** diff --git a/src/Liquid/Cache/File.php b/src/Liquid/Cache/File.php index 0cea260d..51f24547 100644 --- a/src/Liquid/Cache/File.php +++ b/src/Liquid/Cache/File.php @@ -17,8 +17,7 @@ /** * Implements cache stored in files. */ -class File extends Cache -{ +class File extends Cache { /** * Constructor. * @@ -42,8 +41,9 @@ public function __construct(array $options = array()) { * {@inheritdoc} */ public function read($key, $unserialize = true) { - if (!$this->exists($key)) + if (!$this->exists($key)) { return false; + } if ($unserialize) { return unserialize(file_get_contents($this->path . $this->prefix . $key)); diff --git a/src/Liquid/Cache/Local.php b/src/Liquid/Cache/Local.php index ee7d88a5..7d4c12e2 100644 --- a/src/Liquid/Cache/Local.php +++ b/src/Liquid/Cache/Local.php @@ -16,8 +16,7 @@ /** * Implements cache with data stored in an embedded variable with no handling of expiration dates for simplicity */ -class Local extends Cache -{ +class Local extends Cache { private $cache = array(); /** @@ -53,4 +52,4 @@ public function flush($expiredOnly = false) { $this->cache = array(); return true; } -} \ No newline at end of file +} diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 29c1bdc1..3b28d487 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -14,8 +14,7 @@ /** * Context keeps the variable stack and resolves variables, as well as keywords. */ -class Context -{ +class Context { /** * Local scopes * @@ -243,13 +242,13 @@ private function fetch($key) { private function variable($key) { // Support numeric and variable array indicies if (preg_match("|\[[0-9]+\]|", $key)) { - $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); - } else if (preg_match("|\[[0-9a-z._]+\]|", $key, $matches)) { - $index = $this->get(str_replace(array("[","]"),"", $matches[0])); - if ( strlen($index) ) { - $key = preg_replace("|\[([0-9a-z._]+)\]|", ".$index", $key); - } - } + $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); + } elseif (preg_match("|\[[0-9a-z._]+\]|", $key, $matches)) { + $index = $this->get(str_replace(array("[","]"), "", $matches[0])); + if (strlen($index)) { + $key = preg_replace("|\[([0-9a-z._]+)\]|", ".$index", $key); + } + } $parts = explode(Liquid::get('VARIABLE_ATTRIBUTE_SEPARATOR'), $key); diff --git a/src/Liquid/CustomFilters.php b/src/Liquid/CustomFilters.php index e2d3dd1e..e8b73b9d 100644 --- a/src/Liquid/CustomFilters.php +++ b/src/Liquid/CustomFilters.php @@ -14,8 +14,7 @@ /** * A selection of custom filters. */ -class CustomFilters -{ +class CustomFilters { /** * Sort an array by key. @@ -28,5 +27,4 @@ public static function sort_key(array $input) { ksort($input); return $input; } - } diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index 9a0d86cf..35c0939b 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -14,8 +14,7 @@ /** * Base class for blocks that make logical decisions. */ -class Decision extends AbstractBlock -{ +class Decision extends AbstractBlock { /** * The current left variable to compare * @@ -95,11 +94,9 @@ protected function interpretCondition($left, $right, $op = null, Context $contex if ($right == 'empty' && is_array($context->get($left))) { $left = count($context->get($left)); $right = 0; - } elseif ($left == 'empty' && is_array($context->get($right))) { $right = count($context->get($right)); $left = 0; - } else { $left = $context->get($left); $right = $context->get($right); diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 70cdadca..3673c517 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -17,8 +17,7 @@ /** * This class represents the entire template document. */ -class Document extends AbstractBlock -{ +class Document extends AbstractBlock { /** * Constructor. * diff --git a/src/Liquid/Drop.php b/src/Liquid/Drop.php index cc2ef511..40428808 100644 --- a/src/Liquid/Drop.php +++ b/src/Liquid/Drop.php @@ -32,8 +32,7 @@ * Your drop can either implement the methods sans any parameters or implement the beforeMethod(name) method which is a * catch all. */ -abstract class Drop -{ +abstract class Drop { /** * @var Context */ diff --git a/src/Liquid/FileSystem.php b/src/Liquid/FileSystem.php index 70e110a4..2ffa54e2 100644 --- a/src/Liquid/FileSystem.php +++ b/src/Liquid/FileSystem.php @@ -19,8 +19,7 @@ * * You can add additional instance variables, arguments, or methods as needed. */ -interface FileSystem -{ +interface FileSystem { /** * Retrieve a template file. * diff --git a/src/Liquid/FileSystem/Local.php b/src/Liquid/FileSystem/Local.php index 49cd283c..59c81266 100644 --- a/src/Liquid/FileSystem/Local.php +++ b/src/Liquid/FileSystem/Local.php @@ -22,8 +22,7 @@ * * For security reasons, template paths are only allowed to contain letters, numbers, and underscore. */ -class Local implements FileSystem -{ +class Local implements FileSystem { /** * The root path * diff --git a/src/Liquid/FileSystem/Virtual.php b/src/Liquid/FileSystem/Virtual.php index 7eba72c4..3b7d9251 100644 --- a/src/Liquid/FileSystem/Virtual.php +++ b/src/Liquid/FileSystem/Virtual.php @@ -17,8 +17,7 @@ /** * This implements a virtual file system with actual code used to find files injected from outside thus achieving inversion of control. */ -class Virtual implements FileSystem -{ +class Virtual implements FileSystem { /** * @var callable */ @@ -58,4 +57,4 @@ public function __sleep() { return array_keys(get_object_vars($this)); } -} \ No newline at end of file +} diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 6a1498cb..2c1cc887 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -15,8 +15,7 @@ * The filter bank is where all registered filters are stored, and where filter invocation is handled * it supports a variety of different filter types; objects, class, and simple methods. */ -class Filterbank -{ +class Filterbank { /** * The registered filter objects * diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index ddf6c7d4..a3320a6a 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -14,8 +14,7 @@ /** * Liquid for PHP. */ -class Liquid -{ +class Liquid { /** * We cannot make settings constants, because we cannot create compound * constants in PHP (before 5.6). diff --git a/src/Liquid/LiquidException.php b/src/Liquid/LiquidException.php index 198e2353..f16cfecd 100644 --- a/src/Liquid/LiquidException.php +++ b/src/Liquid/LiquidException.php @@ -14,6 +14,5 @@ /** * LiquidException class. */ -class LiquidException extends \Exception -{ +class LiquidException extends \Exception { } diff --git a/src/Liquid/LocalFileSystem.php b/src/Liquid/LocalFileSystem.php index 9f2913fb..13e38959 100644 --- a/src/Liquid/LocalFileSystem.php +++ b/src/Liquid/LocalFileSystem.php @@ -14,4 +14,5 @@ /** * @deprecated Left for backward compatibility reasons. Use \Liquid\FileSystem\Local instead. */ -class LocalFileSystem extends \Liquid\FileSystem\Local {} \ No newline at end of file +class LocalFileSystem extends \Liquid\FileSystem\Local { +} diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index 82103e41..16f7733a 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -15,8 +15,7 @@ * A support class for regular expressions and * non liquid specific support classes and functions. */ -class Regexp -{ +class Regexp { /** * The regexp pattern * diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index df9722a8..12e70cab 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -14,8 +14,7 @@ /** * A selection of standard filters. */ -class StandardFilters -{ +class StandardFilters { /** * Add one string to another @@ -38,10 +37,10 @@ public static function append($input, $string) { * @return string */ public static function capitalize($input) { - return preg_replace_callback("/(^|[^\p{L}'])([\p{Ll}])/u", function($matches) { + return preg_replace_callback("/(^|[^\p{L}'])([\p{Ll}])/u", function ($matches) { return $matches[1] . ucfirst($matches[2]); }, ucwords($input)); - } + } /** @@ -67,12 +66,12 @@ public static function date($input, $format) { $input = strtotime($input); } - if ($format == 'r') + if ($format == 'r') { return date($format, $input); + } return strftime($format, $input); - - } + } /** @@ -163,7 +162,7 @@ public static function first($input) { return $input->current(); } return is_array($input) ? reset($input) : $input; - } + } /** @@ -173,7 +172,7 @@ public static function first($input) { */ public static function floor($input) { return (int) floor((float)$input); - } + } /** @@ -209,13 +208,13 @@ public static function join($input, $glue = ' ') { public static function last($input) { if ($input instanceof \Traversable) { $last = null; - foreach ($input as $elem){ + foreach ($input as $elem) { $last = $elem; } return $last; } return is_array($input) ? end($input) : $input; - } + } /** @@ -225,7 +224,7 @@ public static function last($input) { */ public static function lstrip($input) { return ltrim($input); - } + } /** @@ -287,10 +286,10 @@ public static function modulo($input, $operand) { * * @return string */ - public static function newline_to_br($input) { - return is_string($input) ? str_replace("\n", "
\n", $input) : $input; - } - + public static function newline_to_br($input) { + return is_string($input) ? str_replace("\n", "
\n", $input) : $input; + } + /** * addition @@ -345,7 +344,7 @@ public static function remove_first($input, $string) { } return $input; - } + } /** @@ -405,7 +404,7 @@ public static function reverse($input) { */ public static function round($input, $n = 0) { return round((float)$input, (int)$n); - } + } /** @@ -490,7 +489,7 @@ public static function sort($input, $property = null) { } else { $first = reset($input); if ($first !== false && is_array($first) && array_key_exists($property, $first)) { - uasort($input, function($a, $b) use ($property) { + uasort($input, function ($a, $b) use ($property) { if ($a[$property] == $b[$property]) { return 0; } @@ -501,7 +500,7 @@ public static function sort($input, $property = null) { } return $input; - } + } /** @@ -550,7 +549,7 @@ public static function strip_newlines($input) { return is_string($input) ? str_replace(array( "\n", "\r" ), '', $input) : $input; - } + } /** @@ -605,7 +604,7 @@ public static function truncatewords($input, $words = 3, $ending = '...') { } return $input; - } + } /** diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index a9af9781..876c0190 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -26,8 +26,7 @@ * {% assign var = var %} * {% assign var = "hello" | upcase %} */ -class TagAssign extends AbstractTag -{ +class TagAssign extends AbstractTag { /** * @var string The variable to assign from */ diff --git a/src/Liquid/Tag/TagBlock.php b/src/Liquid/Tag/TagBlock.php index 982e468d..56f42e84 100644 --- a/src/Liquid/Tag/TagBlock.php +++ b/src/Liquid/Tag/TagBlock.php @@ -23,8 +23,7 @@ * * {% block foo %} bar {% endblock %} */ -class TagBlock extends AbstractBlock -{ +class TagBlock extends AbstractBlock { /** * The variable to assign to * diff --git a/src/Liquid/Tag/TagBreak.php b/src/Liquid/Tag/TagBreak.php index 15c9e3af..783e29c4 100644 --- a/src/Liquid/Tag/TagBreak.php +++ b/src/Liquid/Tag/TagBreak.php @@ -26,8 +26,7 @@ * {{ i }} * {% endfor %} */ -class TagBreak extends AbstractTag -{ +class TagBreak extends AbstractTag { /** * Renders the tag * @@ -38,4 +37,4 @@ class TagBreak extends AbstractTag public function render(Context $context) { $context->registers['break'] = true; } -} \ No newline at end of file +} diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index 8d8c7536..30cff5f8 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -24,8 +24,7 @@ * * {% capture foo %} bar {% endcapture %} */ -class TagCapture extends AbstractBlock -{ +class TagCapture extends AbstractBlock { /** * The variable to assign to * diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 092dac99..7086cf52 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -25,8 +25,7 @@ * * {% case condition %}{% when foo %} foo {% else %} bar {% endcase %} */ -class TagCase extends Decision -{ +class TagCase extends Decision { /** * Stack of nodelists * @@ -105,7 +104,6 @@ public function unknownTag($tag, $params, array $tokens) { $this->pushNodelist(); $this->right = $whenSyntaxRegexp->matches[0]; $this->nodelist = array(); - } else { throw new LiquidException("Syntax Error in tag 'case' - Valid when condition: when [condition]"); // harry } diff --git a/src/Liquid/Tag/TagComment.php b/src/Liquid/Tag/TagComment.php index 0451fb12..624ca8a2 100644 --- a/src/Liquid/Tag/TagComment.php +++ b/src/Liquid/Tag/TagComment.php @@ -21,8 +21,7 @@ * * {% comment %} This will be ignored {% endcomment %} */ -class TagComment extends AbstractBlock -{ +class TagComment extends AbstractBlock { /** * Renders the block * diff --git a/src/Liquid/Tag/TagContinue.php b/src/Liquid/Tag/TagContinue.php index a5edb301..df6a1bbb 100644 --- a/src/Liquid/Tag/TagContinue.php +++ b/src/Liquid/Tag/TagContinue.php @@ -26,8 +26,7 @@ * {{ i }} * {% endfor %} */ -class TagContinue extends AbstractTag -{ +class TagContinue extends AbstractTag { /** * Renders the tag * @@ -38,4 +37,4 @@ class TagContinue extends AbstractTag public function render(Context $context) { $context->registers['continue'] = true; } -} \ No newline at end of file +} diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index a3b0487b..87823798 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -34,8 +34,7 @@ * will return * one one two two */ -class TagCycle extends AbstractTag -{ +class TagCycle extends AbstractTag { /** * @var string The name of the cycle; if none is given one is created using the value list */ diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index 4c481c4e..a9ea5b53 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -27,8 +27,7 @@ * * @author Viorel Dram */ -class TagDecrement extends AbstractTag -{ +class TagDecrement extends AbstractTag { /** * Name of the variable to decrement * diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 1e9eaa42..71434767 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -27,8 +27,7 @@ * * {% extends "base" %} */ -class TagExtends extends AbstractTag -{ +class TagExtends extends AbstractTag { /** * @var string The name of the template */ @@ -81,7 +80,7 @@ private function findBlocks(array $tokens) { if ($blockstartRegexp->match($token)) { $name = $blockstartRegexp->matches[1]; $b[$name] = array(); - } else if ($blockendRegexp->match($token)) { + } elseif ($blockendRegexp->match($token)) { $name = null; } else { if ($name !== null) { @@ -112,11 +111,12 @@ public function parse(array &$tokens) { $maintokens = Template::tokenize($source); $eRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*extends (.*)?' . Liquid::get('TAG_END') . '$/'); - foreach ($maintokens as $maintoken) + foreach ($maintokens as $maintoken) { if ($eRegexp->match($maintoken)) { $m = $eRegexp->matches[1]; break; } + } if (isset($m)) { $rest = array_merge($maintokens, $tokens); @@ -142,7 +142,6 @@ public function parse(array &$tokens) { array_push($rest, $item); } } - } if (!$keep) { array_push($rest, $maintokens[$i]); diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index 6489898d..a1003d84 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -33,8 +33,7 @@ * {%for i in (1..variable)%} {{i}} {%endfor%} * */ -class TagFor extends AbstractBlock -{ +class TagFor extends AbstractBlock { /** * @var array The collection to loop over */ @@ -70,14 +69,11 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $syntaxRegexp = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntaxRegexp->match($markup)) { - $this->variableName = $syntaxRegexp->matches[1]; $this->collectionName = $syntaxRegexp->matches[2]; $this->name = $syntaxRegexp->matches[1] . '-' . $syntaxRegexp->matches[2]; $this->extractAttributes($markup); - } else { - $syntaxRegexp = new Regexp('/(\w+)\s+in\s+\((\d+|' . Liquid::get('VARIABLE_NAME') . ')\s*\.\.\s*(\d+|' . Liquid::get('VARIABLE_NAME') . ')\)/'); if ($syntaxRegexp->match($markup)) { $this->type = 'digit'; @@ -100,12 +96,11 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * @return null|string */ public function render(Context $context) { - if (!isset($context->registers['for'])) { $context->registers['for'] = array(); } - switch ($this->type){ + switch ($this->type) { case 'collection': @@ -193,7 +188,6 @@ public function render(Context $context) { $index = 0; $length = $range[1] - $range[0]; for ($i=$range[0]; $i<=$range[1]; $i++) { - $context->set($this->variableName, $i); $context->set('forloop', array( 'name' => $this->name, diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index 7bbbaeca..c773a72d 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -28,8 +28,7 @@ * will return: * YES */ -class TagIf extends Decision -{ +class TagIf extends Decision { /** * Array holding the nodes to render for each logical block * @@ -73,7 +72,6 @@ public function unknownTag($tag, $params, array $tokens) { $this->nodelistHolders[count($this->blocks) + 1] = array(); array_push($this->blocks, array($tag, $params, &$this->nodelist)); - } else { parent::unknownTag($tag, $params, $tokens); } @@ -137,7 +135,6 @@ public function render(Context $context) { $display = ($display || $this->interpretCondition($conditions[$k + 1]['left'], $conditions[$k + 1]['right'], $conditions[$k + 1]['operator'], $context)); } } - } else { // If statement is a single condition $display = $this->interpretCondition($conditions[0]['left'], $conditions[0]['right'], $conditions[0]['operator'], $context); @@ -155,4 +152,4 @@ public function render(Context $context) { return $result; } -} \ No newline at end of file +} diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index aea8bf2a..8e1b85f2 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -18,8 +18,7 @@ /** * Quickly create a table from a collection */ -class TagIfchanged extends AbstractBlock -{ +class TagIfchanged extends AbstractBlock { /** * The last value * @@ -56,6 +55,5 @@ public function render(Context $context) { $this->lastValue = $output; return $this->lastValue; } - } } diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 87b2d441..f73f738d 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -38,8 +38,7 @@ * Will loop over all the values of bar, including the template foo, passing a variable called foo * with each value of bar */ -class TagInclude extends AbstractTag -{ +class TagInclude extends AbstractTag { /** * @var string The name of the template */ diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index 2c105b60..2c993735 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -27,8 +27,7 @@ * * @author Viorel Dram */ -class TagIncrement extends AbstractTag -{ +class TagIncrement extends AbstractTag { /** * Name of the variable to increment * diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index e44fa69e..98e393da 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -31,8 +31,7 @@ * */ -class TagPaginate extends AbstractBlock -{ +class TagPaginate extends AbstractBlock { /** * @var array The collection to paginate */ @@ -81,7 +80,6 @@ class TagPaginate extends AbstractBlock * */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - parent::__construct($markup, $tokens, $fileSystem); $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')\s+by\s+(\w+)/'); @@ -93,7 +91,6 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu } else { throw new LiquidException("Syntax Error - Valid syntax: paginate [collection] by [items]"); } - } /** @@ -105,8 +102,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * */ public function render(Context $context) { - - $this->currentPage = ( is_numeric($context->get('page')) ) ? $context->get('page') : 1; + $this->currentPage = (is_numeric($context->get('page'))) ? $context->get('page') : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); if ($this->collection instanceof \Traversable) { @@ -132,13 +128,12 @@ public function render(Context $context) { 'items' => $this->collectionSize ); - if ( $this->currentPage != 1 ) { + if ($this->currentPage != 1) { $paginate['previous']['title'] = 'Previous'; $paginate['previous']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage - 1); - } - if ( $this->currentPage != $this->totalPages ) { + if ($this->currentPage != $this->totalPages) { $paginate['next']['title'] = 'Next'; $paginate['next']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage + 1); } @@ -146,7 +141,6 @@ public function render(Context $context) { $context->set('paginate', $paginate); return parent::render($context); - } /** @@ -158,15 +152,14 @@ public function render(Context $context) { * */ public function currentUrl($context) { - $uri = explode('?', $context->get('REQUEST_URI')); $url = 'http'; - if ($context->get('HTTPS') == 'on') $url .= 's'; + if ($context->get('HTTPS') == 'on') { + $url .= 's'; + } $url .= '://' . $context->get('HTTP_HOST') . reset($uri); return $url; - } - } diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index 9bd7f04f..7c21fa37 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -25,8 +25,7 @@ * will return: * {{ 5 | plus: 6 }} is equal to 11. */ -class TagRaw extends AbstractBlock -{ +class TagRaw extends AbstractBlock { /** * @param array $tokens */ diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index ca71fbe4..54d763ff 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -21,8 +21,7 @@ /** * Quickly create a table from a collection */ -class TagTablerow extends AbstractBlock -{ +class TagTablerow extends AbstractBlock { /** * The variable name of the table tag * diff --git a/src/Liquid/Tag/TagUnless.php b/src/Liquid/Tag/TagUnless.php index 1cbe8af9..60968587 100644 --- a/src/Liquid/Tag/TagUnless.php +++ b/src/Liquid/Tag/TagUnless.php @@ -24,7 +24,7 @@ * NO */ -class TagUnless extends TagIf{ +class TagUnless extends TagIf { /** * Replace first found key in $subject to value @@ -35,7 +35,7 @@ class TagUnless extends TagIf{ */ protected function strReplaceOne($replacer, $subject) { $res = $subject; - foreach($replacer as $from => $to) { + foreach ($replacer as $from => $to) { $res = str_ireplace($from, $to, $subject, $count); if ($count > 0) { break; @@ -98,5 +98,4 @@ public function render(Context $context) { $res = parent::render($context); return $res; } - -} \ No newline at end of file +} diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 058b30ee..1ac83bcd 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -20,8 +20,7 @@ * $tpl->parse(template_source); * $tpl->render(array('foo'=>1, 'bar'=>2); */ -class Template -{ +class Template { /** * @var Document The root of the node tree */ diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index de77fb3c..2a0afdc9 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -14,8 +14,7 @@ /** * Implements a template variable. */ -class Variable -{ +class Variable { /** * @var array The filters to execute on the variable */ @@ -61,7 +60,6 @@ public function __construct($markup) { $this->filters[] = array($filtername, $matches); } - } else { $this->filters = array(); } From 224060eb19f82284a6cbe3c12fd67814ac661693 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:57:14 +0900 Subject: [PATCH 105/296] tests/ fixed with PHP-CS-Fixer --- tests/Liquid/Cache/ApcTest.php | 4 +- tests/Liquid/Cache/FileTest.php | 3 +- tests/Liquid/Cache/LocalTest.php | 5 +- tests/Liquid/ContextTest.php | 29 ++++------ tests/Liquid/CustomFiltersTest.php | 6 +-- tests/Liquid/DropTest.php | 18 +++---- tests/Liquid/EscapeByDefaultTest.php | 5 +- tests/Liquid/FilterbankTest.php | 6 +-- tests/Liquid/LiquidTest.php | 3 +- tests/Liquid/LocalFileSystemTest.php | 3 +- tests/Liquid/OutputTest.php | 6 +-- tests/Liquid/ParsingQuirksTest.php | 3 +- tests/Liquid/RegexpTest.php | 3 +- tests/Liquid/StandardFiltersTest.php | 71 ++++++++++++------------- tests/Liquid/Tag/NoTransformTest.php | 9 ++-- tests/Liquid/Tag/TagAssignTest.php | 3 +- tests/Liquid/Tag/TagBlockTest.php | 3 +- tests/Liquid/Tag/TagBreakTest.php | 54 ++++++++++--------- tests/Liquid/Tag/TagCaptureTest.php | 3 +- tests/Liquid/Tag/TagCaseTest.php | 9 ++-- tests/Liquid/Tag/TagCommentTest.php | 9 ++-- tests/Liquid/Tag/TagContinueTest.php | 14 ++--- tests/Liquid/Tag/TagCycleTest.php | 3 +- tests/Liquid/Tag/TagDecrementTest.php | 3 +- tests/Liquid/Tag/TagExtendsTest.php | 12 ++--- tests/Liquid/Tag/TagForTest.php | 3 +- tests/Liquid/Tag/TagIfTest.php | 5 +- tests/Liquid/Tag/TagIfchangedTest.php | 4 +- tests/Liquid/Tag/TagIncludeTest.php | 5 +- tests/Liquid/Tag/TagIncrementTest.php | 3 +- tests/Liquid/Tag/TagPaginateTest.php | 6 +-- tests/Liquid/Tag/TagRawTest.php | 6 +-- tests/Liquid/Tag/TagTablerowTest.php | 22 ++++---- tests/Liquid/Tag/TagUnlessTest.php | 5 +- tests/Liquid/TemplateTest.php | 3 +- tests/Liquid/TestCase.php | 3 +- tests/Liquid/TestFileSystem.php | 8 ++- tests/Liquid/VariableResolutionTest.php | 3 +- tests/Liquid/VariableTest.php | 4 +- tests/Liquid/VirtualFileSystemTest.php | 5 +- 40 files changed, 156 insertions(+), 216 deletions(-) diff --git a/tests/Liquid/Cache/ApcTest.php b/tests/Liquid/Cache/ApcTest.php index 09ff6da2..05b83180 100644 --- a/tests/Liquid/Cache/ApcTest.php +++ b/tests/Liquid/Cache/ApcTest.php @@ -14,8 +14,7 @@ use Liquid\TestCase; use \Liquid\Cache\Apc; -class ApcTest extends TestCase -{ +class ApcTest extends TestCase { /** @var \Liquid\Cache\Apc */ protected $cache; @@ -48,4 +47,3 @@ public function testSetGetFlush() { $this->assertFalse($this->cache->read('test')); } } - diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index dbe8b497..082b50cd 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class FileTest extends TestCase -{ +class FileTest extends TestCase { /** @var \Liquid\Cache\File */ protected $cache; protected $cacheDir; diff --git a/tests/Liquid/Cache/LocalTest.php b/tests/Liquid/Cache/LocalTest.php index e75a6890..35bef443 100644 --- a/tests/Liquid/Cache/LocalTest.php +++ b/tests/Liquid/Cache/LocalTest.php @@ -14,8 +14,7 @@ use Liquid\TestCase; use \Liquid\Cache\Local; -class LocalTest extends TestCase -{ +class LocalTest extends TestCase { /** @var \Liquid\Cache\Local */ protected $cache; @@ -39,4 +38,4 @@ public function testSetGetFlush() { $this->assertTrue($this->cache->flush()); $this->assertFalse($this->cache->read('test')); } -} \ No newline at end of file +} diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 45061b1c..4e6b243b 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -11,15 +11,13 @@ namespace Liquid; -class HundredCentes -{ +class HundredCentes { public function toLiquid() { return 100; } } -class CentsDrop extends Drop -{ +class CentsDrop extends Drop { public function amount() { return new HundredCentes(); } @@ -51,8 +49,7 @@ public function toLiquid() { } } -class NestedObject -{ +class NestedObject { public $property; public $value = -1; @@ -66,8 +63,7 @@ public function toLiquid() { } } -class ToArrayObject -{ +class ToArrayObject { public $property; public $value = -1; @@ -81,8 +77,7 @@ public function toArray() { } } -class GetSetObject -{ +class GetSetObject { public function field_exists($name) { return $name == 'answer'; } @@ -94,31 +89,27 @@ public function get($prop) { } } -class HiFilter -{ +class HiFilter { public function hi($value) { return $value . ' hi!'; } } -class GlobalFilter -{ +class GlobalFilter { public function notice($value) { return "Global $value"; } } -class LocalFilter -{ +class LocalFilter { public function notice($value) { return "Local $value"; } } -class ContextTest extends TestCase -{ +class ContextTest extends TestCase { /** @var Context */ - var $context; + public $context; public function setup() { parent::setUp(); diff --git a/tests/Liquid/CustomFiltersTest.php b/tests/Liquid/CustomFiltersTest.php index f5697a6d..d982b04f 100644 --- a/tests/Liquid/CustomFiltersTest.php +++ b/tests/Liquid/CustomFiltersTest.php @@ -11,14 +11,13 @@ namespace Liquid; -class CustomFiltersTest extends TestCase -{ +class CustomFiltersTest extends TestCase { /** * The current context * * @var Context */ - var $context; + public $context; protected function setup() { parent::setUp(); @@ -42,5 +41,4 @@ public function testSortKey() { $this->assertEquals($item[1], CustomFilters::sort_key($item[0])); } } - } diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index e6d2aec3..ce345f59 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -11,15 +11,13 @@ namespace Liquid; -class ContextDrop extends Drop -{ +class ContextDrop extends Drop { public function beforeMethod($method) { return $this->context->get($method); } } -class TextDrop extends Drop -{ +class TextDrop extends Drop { public function get_array() { return array('text1', 'text2'); } @@ -29,15 +27,13 @@ public function text() { } } -class CatchallDrop extends Drop -{ +class CatchallDrop extends Drop { public function beforeMethod($method) { return 'method: ' . $method; } } -class ProductDrop extends Drop -{ +class ProductDrop extends Drop { public function top_sales() { throw new \Exception("worked"); } @@ -63,8 +59,7 @@ public function hasKey($name) { } } -class DropTest extends TestCase -{ +class DropTest extends TestCase { /** * @expectedException \Exception * @expectedExceptionMessage worked @@ -116,8 +111,7 @@ public function testNestedContextDrop() { $this->assertEquals(' monkey ', $output); } - public function testToString() - { + public function testToString() { $this->assertEquals(ProductDrop::class, strval(new ProductDrop())); } } diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index ffdd7e31..85c5b4f4 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class EscapeByDefaultTest extends TestCase -{ +class EscapeByDefaultTest extends TestCase { const XSS = ""; const XSS_FAILED = "<script>alert()</script>"; @@ -88,4 +87,4 @@ public function tearDown() { // reset to the default after each test Liquid::set('ESCAPE_BY_DEFAULT', self::$escapeDefault); } -} \ No newline at end of file +} diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index dbb84e86..0c281cab 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -25,8 +25,7 @@ function functionFilter($value) { /** * Global filter class */ -class ClassFilter -{ +class ClassFilter { private $variable = 'not set'; public static function static_test() { @@ -47,8 +46,7 @@ public function instance_test_two() { namespace Liquid { -class FilterbankTest extends TestCase -{ +class FilterbankTest extends TestCase { /** @var FilterBank */ private $filterBank; diff --git a/tests/Liquid/LiquidTest.php b/tests/Liquid/LiquidTest.php index c8ee9ce9..2c589892 100644 --- a/tests/Liquid/LiquidTest.php +++ b/tests/Liquid/LiquidTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class LiquidTest extends TestCase -{ +class LiquidTest extends TestCase { public function testGetNonExistingPropery() { $this->assertNull(Liquid::get('no_such_value')); } diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index d5d36247..3e1ef3c8 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class LocalFileSystemTest extends TestCase -{ +class LocalFileSystemTest extends TestCase { protected $root; protected function setUp() { diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 1a3ecd31..2634052f 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class FunnyFilter -{ +class FunnyFilter { public function make_funny($input) { return 'LOL'; } @@ -38,8 +37,7 @@ public function link_to($name, $url, $protocol) { } } -class OutputTest extends TestCase -{ +class OutputTest extends TestCase { protected $assigns = array(); protected function setup() { diff --git a/tests/Liquid/ParsingQuirksTest.php b/tests/Liquid/ParsingQuirksTest.php index bcd530c1..d735ead5 100644 --- a/tests/Liquid/ParsingQuirksTest.php +++ b/tests/Liquid/ParsingQuirksTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class ParsingQuirksTest extends TestCase -{ +class ParsingQuirksTest extends TestCase { public function testErrorWithCss() { $text = " div { font-weight: bold; } "; $template = new Template(); diff --git a/tests/Liquid/RegexpTest.php b/tests/Liquid/RegexpTest.php index e462972a..9fce8880 100644 --- a/tests/Liquid/RegexpTest.php +++ b/tests/Liquid/RegexpTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class RegexpTest extends TestCase -{ +class RegexpTest extends TestCase { /** @var Regexp */ protected $regexp; diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 0588e40f..66b04de8 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class MoneyFilter -{ +class MoneyFilter { public function money($value) { return sprintf(' %d$ ', $value); } @@ -22,15 +21,13 @@ public function money_with_underscore($value) { } } -class CanadianMoneyFilter -{ +class CanadianMoneyFilter { public function money($value) { return sprintf(' %d$ CAD ', $value); } } -class SizeClass -{ +class SizeClass { const SIZE = 42; public function toLiquid() { @@ -43,14 +40,13 @@ public function size() { } -class StandardFiltersTest extends TestCase -{ +class StandardFiltersTest extends TestCase { /** * The current context * * @var Context */ - var $context; + public $context; protected function setup() { parent::setUp(); @@ -137,8 +133,7 @@ public function testUrlDecode() { } - public function testRaw() - { + public function testRaw() { $data = array( "Anything" => "Anything", 3 => 3, @@ -511,27 +506,27 @@ public function testSort() { $this->assertEquals($expected, StandardFilters::sort(new \ArrayIterator($original), 'b'), '', 0, 10, true); } -/* - - I've commented this out as its not one of the Ruby Standard Filters - - public function testSortKey() { - $data = array( - array( - array(), - array(), - ), - array( - array('b' => 1, 'c' => 5, 'a' => 3, 'z' => 4, 'h' => 2), - array('a' => 3, 'b' => 1, 'c' => 5, 'h' => 2, 'z' => 4), - ), - ); + /* - foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::sort_key($item[0])); + I've commented this out as its not one of the Ruby Standard Filters + + public function testSortKey() { + $data = array( + array( + array(), + array(), + ), + array( + array('b' => 1, 'c' => 5, 'a' => 3, 'z' => 4, 'h' => 2), + array('a' => 3, 'b' => 1, 'c' => 5, 'h' => 2, 'z' => 4), + ), + ); + + foreach ($data as $item) { + $this->assertEquals($item[1], StandardFilters::sort_key($item[0])); + } } - } -*/ + */ public function testDefault() { $this->assertEquals('hello', StandardFilters::_default('', 'hello')); @@ -602,7 +597,7 @@ public function testMap() { ), array( array( - function() { + function () { return 'from function '; }, array( @@ -618,7 +613,7 @@ function() { ), array( new \ArrayIterator(array( - function() { + function () { return 'from function '; }, array( @@ -835,9 +830,9 @@ public function testMinus() { -1.2, ), array( - 3.1, - 3.1, - 0 + 3.1, + 3.1, + 0 ) ); @@ -864,9 +859,9 @@ public function testTimes() { 4.05, ), array( - 7.5, - 0, - 0 + 7.5, + 0, + 0 ) ); diff --git a/tests/Liquid/Tag/NoTransformTest.php b/tests/Liquid/Tag/NoTransformTest.php index 29da3130..06f6e6f6 100644 --- a/tests/Liquid/Tag/NoTransformTest.php +++ b/tests/Liquid/Tag/NoTransformTest.php @@ -13,11 +13,12 @@ use Liquid\TestCase; -class NoTransformTest extends TestCase -{ +class NoTransformTest extends TestCase { public function testNoTransform() { - $this->assertTemplateResult('this text should come out of the template without change...', - 'this text should come out of the template without change...'); + $this->assertTemplateResult( + 'this text should come out of the template without change...', + 'this text should come out of the template without change...' + ); $this->assertTemplateResult('blah', 'blah'); $this->assertTemplateResult('', ''); diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index b1c173c7..e2562450 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -18,8 +18,7 @@ * Basic tests for the assignment of one variable to another. This also tests the * assignment of filtered values to another variable. */ -class TagAssignTest extends TestCase -{ +class TagAssignTest extends TestCase { /** * Tests the normal behavior of throwing an exception when the assignment is incorrect * diff --git a/tests/Liquid/Tag/TagBlockTest.php b/tests/Liquid/Tag/TagBlockTest.php index 310a345f..49d4d0f0 100644 --- a/tests/Liquid/Tag/TagBlockTest.php +++ b/tests/Liquid/Tag/TagBlockTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagBlockTest extends TestCase -{ +class TagBlockTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagBreakTest.php b/tests/Liquid/Tag/TagBreakTest.php index cdcaca1a..4da7c845 100644 --- a/tests/Liquid/Tag/TagBreakTest.php +++ b/tests/Liquid/Tag/TagBreakTest.php @@ -13,32 +13,34 @@ use Liquid\TestCase; -class TagBreakTest extends TestCase -{ - public function testFor() { - $this->assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); - } +class TagBreakTest extends TestCase { + public function testFor() { + $this->assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); + } - public function testRange() { - $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%break%} yo {%endfor%}'); - $this->assertTemplateResult(' yo ', '{%for item in (3..6)%} yo {%break%} {%endfor%}'); - $this->assertTemplateResult(' 3 4 ', '{%for item in (3..6)%} {%if item == 5%} {%break%} {%endif%} {{ item }} {%endfor%}'); - } + public function testRange() { + $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%break%} yo {%endfor%}'); + $this->assertTemplateResult(' yo ', '{%for item in (3..6)%} yo {%break%} {%endfor%}'); + $this->assertTemplateResult(' 3 4 ', '{%for item in (3..6)%} {%if item == 5%} {%break%} {%endif%} {{ item }} {%endfor%}'); + } - public function testTablerow() { - $this->assertTemplateResult( - "\n\n", - '{%tablerow item in array%} {%break%} yo {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult( - "\n yo \n", - '{%tablerow item in array%} yo {%break%} {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult( - "\n 1 2 \n", - '{%tablerow item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); - } + public function testTablerow() { + $this->assertTemplateResult( + "\n\n", + '{%tablerow item in array%} {%break%} yo {%endtablerow%}', + array('array' => array(1, 2, 3, 4)) + ); + $this->assertTemplateResult( + "\n yo \n", + '{%tablerow item in array%} yo {%break%} {%endtablerow%}', + array('array' => array(1, 2, 3, 4)) + ); + $this->assertTemplateResult( + "\n 1 2 \n", + '{%tablerow item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endtablerow%}', + array('array' => array(1, 2, 3, 4)) + ); + } } diff --git a/tests/Liquid/Tag/TagCaptureTest.php b/tests/Liquid/Tag/TagCaptureTest.php index 23cf337a..ea9b45ba 100644 --- a/tests/Liquid/Tag/TagCaptureTest.php +++ b/tests/Liquid/Tag/TagCaptureTest.php @@ -14,8 +14,7 @@ use Liquid\TestCase; use Liquid\Template; -class TagCaptureTest extends TestCase -{ +class TagCaptureTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index 9ef6d395..af0f370c 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -13,22 +13,19 @@ use Liquid\TestCase; -class Stringable -{ +class Stringable { public function __toString() { return "100"; } } -class HasToLiquid -{ +class HasToLiquid { public function toLiquid() { return "100"; } } -class TagCaseTest extends TestCase -{ +class TagCaseTest extends TestCase { public function testCase() { $assigns = array('condition' => 2); $this->assertTemplateResult(' its 2 ', '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', $assigns); diff --git a/tests/Liquid/Tag/TagCommentTest.php b/tests/Liquid/Tag/TagCommentTest.php index 650c40f7..9f1a3339 100644 --- a/tests/Liquid/Tag/TagCommentTest.php +++ b/tests/Liquid/Tag/TagCommentTest.php @@ -13,11 +13,12 @@ use Liquid\TestCase; -class TagCommentTest extends TestCase -{ +class TagCommentTest extends TestCase { public function testHasABlockWhichDoesNothing() { - $this->assertTemplateResult("the comment block should be removed .. right?", - "the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?"); + $this->assertTemplateResult( + "the comment block should be removed .. right?", + "the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?" + ); $this->assertTemplateResult('', '{%comment%}{%endcomment%}'); $this->assertTemplateResult('', '{%comment%}{% endcomment %}'); diff --git a/tests/Liquid/Tag/TagContinueTest.php b/tests/Liquid/Tag/TagContinueTest.php index 383cfad6..c8ef192a 100644 --- a/tests/Liquid/Tag/TagContinueTest.php +++ b/tests/Liquid/Tag/TagContinueTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagContinueTest extends TestCase -{ +class TagContinueTest extends TestCase { public function testFor() { $this->assertTemplateResult(' ', '{%for item in array%} {%continue%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%continue%} {%endfor%}', array('array' => array(1, 2, 3, 4))); @@ -31,14 +30,17 @@ public function testTablerow() { $this->assertTemplateResult( "\n\n", '{%tablerow item in array%} {%continue%} yo {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); + array('array' => array(1, 2, 3, 4)) + ); $this->assertTemplateResult( "\n yo yo yo yo \n", '{%tablerow item in array%} yo {%continue%} {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); + array('array' => array(1, 2, 3, 4)) + ); $this->assertTemplateResult( "\n 1 2 4 \n", '{%tablerow item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endtablerow%}', - array('array' => array(1, 2, 3, 4))); + array('array' => array(1, 2, 3, 4)) + ); } -} \ No newline at end of file +} diff --git a/tests/Liquid/Tag/TagCycleTest.php b/tests/Liquid/Tag/TagCycleTest.php index d525b679..e530980c 100644 --- a/tests/Liquid/Tag/TagCycleTest.php +++ b/tests/Liquid/Tag/TagCycleTest.php @@ -14,8 +14,7 @@ use Liquid\TestCase; use Liquid\Template; -class TagCycleTest extends TestCase -{ +class TagCycleTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index 28d1c1af..2c90e12c 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagDecrementTest extends TestCase -{ +class TagDecrementTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 6933b4fe..fba1fa83 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -19,8 +19,7 @@ /** * @see TagExtends */ -class TagExtendsTest extends TestCase -{ +class TagExtendsTest extends TestCase { private $fs; protected function setUp() { @@ -40,8 +39,7 @@ protected function tearDown() { unset($this->fs); } - public function testBasicExtends() - { + public function testBasicExtends() { $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); @@ -49,8 +47,7 @@ public function testBasicExtends() $this->assertEquals("Hello!", $output); } - public function testDefaultContentExtends() - { + public function testDefaultContentExtends() { $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% block content %}{{ hello }}{% endblock %}\n{% extends 'sub-base' %}"); @@ -58,8 +55,7 @@ public function testDefaultContentExtends() $this->assertEquals("Hello!\n Boo! ", $output); } - public function testDeepExtends() - { + public function testDeepExtends() { $template = new Template(); $template->setFileSystem($this->fs); $template->parse('{% extends "sub-base" %}{% block content %}{{ hello }}{% endblock %}{% block footer %} I am a footer.{% endblock %}'); diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 15e2123d..013b250c 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -14,8 +14,7 @@ use Liquid\TestCase; use Liquid\Template; -class TagForTest extends TestCase -{ +class TagForTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index f268540c..3caeca0f 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagIfTest extends TestCase -{ +class TagIfTest extends TestCase { public function testTrueEqlTrue() { $text = " {% if true == true %} true {% else %} false {% endif %} "; $expected = " true "; @@ -238,6 +237,4 @@ public function testSyntaxErrorElse() { public function testSyntaxErrorUnknown() { $this->assertTemplateResult('', '{% unknown-tag %}'); } - - } diff --git a/tests/Liquid/Tag/TagIfchangedTest.php b/tests/Liquid/Tag/TagIfchangedTest.php index 162074e6..1d78acf2 100644 --- a/tests/Liquid/Tag/TagIfchangedTest.php +++ b/tests/Liquid/Tag/TagIfchangedTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagIfchangedTest extends TestCase -{ +class TagIfchangedTest extends TestCase { public function testWorks() { $text = "{% for i in array %}{% ifchanged %} {{ i }} {% endifchanged %}{% endfor %}"; $expected = " 1 2 3 "; @@ -26,5 +25,4 @@ public function testFails() { $expected = " 1 2 1 "; $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 2, 1))); } - } diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index adb9342f..dd48b68a 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -18,8 +18,7 @@ use Liquid\FileSystem\Virtual; use Liquid\TestFileSystem; -class TagIncludeTest extends TestCase -{ +class TagIncludeTest extends TestCase { private $fs; protected function setUp() { @@ -130,7 +129,6 @@ public function testIncludePassPlainValue() { * @expectedExceptionMessage Use index operator */ public function testIncludePassArrayWithoutIndex() { - $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other }}]", @@ -142,7 +140,6 @@ public function testIncludePassArrayWithoutIndex() { } public function testIncludePassArrayWithIndex() { - $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other[0] }}]", diff --git a/tests/Liquid/Tag/TagIncrementTest.php b/tests/Liquid/Tag/TagIncrementTest.php index e39e1c95..d48eaeb6 100644 --- a/tests/Liquid/Tag/TagIncrementTest.php +++ b/tests/Liquid/Tag/TagIncrementTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagIncrementTest extends TestCase -{ +class TagIncrementTest extends TestCase { /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 0e5b68ac..d3f90f76 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagPaginateTest extends TestCase -{ +class TagPaginateTest extends TestCase { public function testWorks() { $text = "{% paginate products by 3 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; $expected = " 1 2 3 "; @@ -27,8 +26,7 @@ public function testVariables() { $this->assertTemplateResult($expected, $text, array('search' => array('products' => new \ArrayIterator(array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))))); } - public function testNextPage() - { + public function testNextPage() { $text = "{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; $expected = " 2 "; $this->assertTemplateResult($expected, $text, array('page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); diff --git a/tests/Liquid/Tag/TagRawTest.php b/tests/Liquid/Tag/TagRawTest.php index 33a501e9..71d9a1a5 100644 --- a/tests/Liquid/Tag/TagRawTest.php +++ b/tests/Liquid/Tag/TagRawTest.php @@ -13,12 +13,12 @@ use Liquid\TestCase; -class TagRawTest extends TestCase -{ +class TagRawTest extends TestCase { public function testRaw() { $this->assertTemplateResult( '{{ y | plus: x }}{{{hello}}} is equal to 11.', - '{% raw %}{{ y | plus: x }}{{{hello}}}{% endraw %} is equal to 11.', array('x' => 5, 'y' => 6) + '{% raw %}{{ y | plus: x }}{{{hello}}}{% endraw %} is equal to 11.', + array('x' => 5, 'y' => 6) ); $this->assertTemplateResult('', '{% raw %}{% endraw %}'); diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index 08e4d80c..8fd6b9b7 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -13,13 +13,13 @@ use Liquid\TestCase; -class TagTablerowTest extends TestCase -{ +class TagTablerowTest extends TestCase { public function testTablerow() { $this->assertTemplateResult( ''."\n".' yo yo yo yo '."\n", '{% tablerow item in array %} yo {% endtablerow %}', - array('array' => array(1, 2, 3, 4))); + array('array' => array(1, 2, 3, 4)) + ); $this->assertTemplateResult( ' @@ -28,31 +28,33 @@ public function testTablerow() { item 2 ', '{% tablerow item in array cols:1 %} item {{ item }} {% endtablerow %}', - array('array' => array(1, 2))); + array('array' => array(1, 2)) + ); $this->assertTemplateResult( ''."\n".' 2 3 '."\n", '{% tablerow item in array limit:2 offset:1 %} {{ item }} {% endtablerow %}', - array('array' => array(1, 2, 3, 4))); + array('array' => array(1, 2, 3, 4)) + ); $this->assertTemplateResult( ''."\n".' yo yo '."\n", '{%tablerow item in array%} yo {%endtablerow%}', - array('array' => new \ArrayIterator(array(1, 2)))); + array('array' => new \ArrayIterator(array(1, 2))) + ); } /** * @expectedException \Liquid\LiquidException */ public function testInvalidSyntax() { - $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); + $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); } /** * @expectedException \Liquid\LiquidException */ public function testNotArray() { - $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); + $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); } - -} \ No newline at end of file +} diff --git a/tests/Liquid/Tag/TagUnlessTest.php b/tests/Liquid/Tag/TagUnlessTest.php index 7a57e561..8f95f0da 100644 --- a/tests/Liquid/Tag/TagUnlessTest.php +++ b/tests/Liquid/Tag/TagUnlessTest.php @@ -13,8 +13,7 @@ use Liquid\TestCase; -class TagUnlessTest extends TestCase -{ +class TagUnlessTest extends TestCase { public function testTrueEqlTrue() { $text = " {% unless true == true %} true {% else %} false {% endunless %} "; $expected = " false "; @@ -32,4 +31,4 @@ public function testWithVariable() { $expected = " false "; $this->assertTemplateResult($expected, $text, array('variable' => true)); } -} \ No newline at end of file +} diff --git a/tests/Liquid/TemplateTest.php b/tests/Liquid/TemplateTest.php index 9a671d34..f895c136 100644 --- a/tests/Liquid/TemplateTest.php +++ b/tests/Liquid/TemplateTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class TemplateTest extends TestCase -{ +class TemplateTest extends TestCase { const CACHE_DIR = 'cache_dir'; /** @var string full path to cache dir */ diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 1fbbeb4c..b114914d 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -11,8 +11,7 @@ namespace Liquid; -class TestCase extends \PHPUnit_Framework_TestCase -{ +class TestCase extends \PHPUnit_Framework_TestCase { const TEMPLATES_DIR = 'templates'; /** diff --git a/tests/Liquid/TestFileSystem.php b/tests/Liquid/TestFileSystem.php index bee5a164..4d608506 100644 --- a/tests/Liquid/TestFileSystem.php +++ b/tests/Liquid/TestFileSystem.php @@ -13,11 +13,9 @@ use Liquid\FileSystem\Virtual; -class TestFileSystem extends Virtual -{ +class TestFileSystem extends Virtual { /** @return TestFileSystem */ - public static function fromArray($array) - { + public static function fromArray($array) { return new static(function ($path) use ($array) { if (isset($array[$path])) { return $array[$path]; @@ -26,4 +24,4 @@ public static function fromArray($array) return ''; }); } -} \ No newline at end of file +} diff --git a/tests/Liquid/VariableResolutionTest.php b/tests/Liquid/VariableResolutionTest.php index 13448ec9..a35a1f7c 100644 --- a/tests/Liquid/VariableResolutionTest.php +++ b/tests/Liquid/VariableResolutionTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class VariableResolutionTest extends TestCase -{ +class VariableResolutionTest extends TestCase { public function testSimpleVariable() { $template = new Template(); $template->parse("{{test}}"); diff --git a/tests/Liquid/VariableTest.php b/tests/Liquid/VariableTest.php index e76d7885..2416781b 100644 --- a/tests/Liquid/VariableTest.php +++ b/tests/Liquid/VariableTest.php @@ -11,8 +11,7 @@ namespace Liquid; -class VariableTest extends TestCase -{ +class VariableTest extends TestCase { public function testVariable() { $var = new Variable('hello'); $this->assertEquals('hello', $var->getName()); @@ -106,4 +105,3 @@ public function testStringDot() { $this->assertEquals('test.test', $var->getName()); } } - diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 614862be..060b12d2 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -14,8 +14,7 @@ use Liquid\FileSystem\Virtual; use Liquid\Cache\File; -class VirtualFileSystemTest extends TestCase -{ +class VirtualFileSystemTest extends TestCase { /** * @expectedException \Liquid\LiquidException * @expectedExceptionMessage Not a callback @@ -71,4 +70,4 @@ public function testWithRegularCallback() { $template->parse("Test: {% include 'hello' %}"); $this->assertEquals('Test: OK', $template->render()); } -} \ No newline at end of file +} From 66d83dcae91f412dddd8ec7239a21a38083b6197 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 15:57:23 +0900 Subject: [PATCH 106/296] examples/ fixed with PHP-CS-Fixer --- examples/advanced.php | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/advanced.php b/examples/advanced.php index f0224227..d71a9c24 100644 --- a/examples/advanced.php +++ b/examples/advanced.php @@ -30,4 +30,3 @@ 'plain-html' => 'Your comment was:', 'comment-with-xss' => '', ]); - From 2688d6473a2726949e5074268cc796d743afb082 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:27:55 +0900 Subject: [PATCH 107/296] TagPaginateTest: missing tests for https --- tests/Liquid/Tag/TagPaginateTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index d3f90f76..019c8b0b 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -21,15 +21,15 @@ public function testWorks() { } public function testVariables() { - $text = " {% paginate search.products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {% endpaginate %}"; - $expected = " 3 1 0 2 5 "; + $text = " {% paginate search.products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {{ paginate.next.url }}{% endpaginate %}"; + $expected = " 3 1 0 2 5 http://?page=2"; $this->assertTemplateResult($expected, $text, array('search' => array('products' => new \ArrayIterator(array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))))); } public function testNextPage() { - $text = "{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; - $expected = " 2 "; - $this->assertTemplateResult($expected, $text, array('page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + $text = '{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{{ paginate.next.title }}{% endpaginate %}'; + $expected = ' 2 Next'; + $this->assertTemplateResult($expected, $text, array('HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); } /** From 80dd907f102e65c4409457038d83ce2f2ed0fb6a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:46:08 +0900 Subject: [PATCH 108/296] Full-on PSR-2 for all code --- src/Liquid/AbstractBlock.php | 33 +++-- src/Liquid/AbstractTag.php | 15 ++- src/Liquid/Cache.php | 6 +- src/Liquid/Cache/Apc.php | 18 ++- src/Liquid/Cache/File.php | 21 ++- src/Liquid/Cache/Local.php | 15 ++- src/Liquid/Context.php | 39 ++++-- src/Liquid/CustomFilters.php | 6 +- src/Liquid/Decision.php | 12 +- src/Liquid/Document.php | 15 ++- src/Liquid/Drop.php | 21 ++- src/Liquid/FileSystem.php | 3 +- src/Liquid/FileSystem/Local.php | 12 +- src/Liquid/FileSystem/Virtual.php | 12 +- src/Liquid/Filterbank.php | 12 +- src/Liquid/Liquid.php | 12 +- src/Liquid/LiquidException.php | 3 +- src/Liquid/LocalFileSystem.php | 3 +- src/Liquid/Regexp.php | 21 ++- src/Liquid/StandardFilters.php | 129 ++++++++++++------ src/Liquid/Tag/TagAssign.php | 9 +- src/Liquid/Tag/TagBlock.php | 6 +- src/Liquid/Tag/TagBreak.php | 6 +- src/Liquid/Tag/TagCapture.php | 9 +- src/Liquid/Tag/TagCase.php | 18 ++- src/Liquid/Tag/TagComment.php | 6 +- src/Liquid/Tag/TagContinue.php | 6 +- src/Liquid/Tag/TagCycle.php | 12 +- src/Liquid/Tag/TagDecrement.php | 9 +- src/Liquid/Tag/TagExtends.php | 18 ++- src/Liquid/Tag/TagFor.php | 9 +- src/Liquid/Tag/TagIf.php | 12 +- src/Liquid/Tag/TagIfchanged.php | 9 +- src/Liquid/Tag/TagInclude.php | 15 ++- src/Liquid/Tag/TagIncrement.php | 9 +- src/Liquid/Tag/TagPaginate.php | 12 +- src/Liquid/Tag/TagRaw.php | 6 +- src/Liquid/Tag/TagTablerow.php | 9 +- src/Liquid/Tag/TagUnless.php | 12 +- src/Liquid/Template.php | 36 +++-- src/Liquid/Variable.php | 15 ++- tests/Liquid/Cache/ApcTest.php | 15 ++- tests/Liquid/Cache/FileTest.php | 48 ++++--- tests/Liquid/Cache/LocalTest.php | 15 ++- tests/Liquid/ContextTest.php | 156 ++++++++++++++-------- tests/Liquid/CustomFiltersTest.php | 9 +- tests/Liquid/DropTest.php | 66 ++++++---- tests/Liquid/EscapeByDefaultTest.php | 33 +++-- tests/Liquid/FilterbankTest.php | 39 ++++-- tests/Liquid/LiquidTest.php | 21 ++- tests/Liquid/LocalFileSystemTest.php | 39 ++++-- tests/Liquid/OutputTest.php | 63 ++++++--- tests/Liquid/ParsingQuirksTest.php | 6 +- tests/Liquid/RegexpTest.php | 30 +++-- tests/Liquid/StandardFiltersTest.php | 168 ++++++++++++++++-------- tests/Liquid/Tag/NoTransformTest.php | 6 +- tests/Liquid/Tag/TagAssignTest.php | 15 ++- tests/Liquid/Tag/TagBlockTest.php | 9 +- tests/Liquid/Tag/TagBreakTest.php | 12 +- tests/Liquid/Tag/TagCaptureTest.php | 9 +- tests/Liquid/Tag/TagCaseTest.php | 39 ++++-- tests/Liquid/Tag/TagCommentTest.php | 6 +- tests/Liquid/Tag/TagContinueTest.php | 12 +- tests/Liquid/Tag/TagCycleTest.php | 18 ++- tests/Liquid/Tag/TagDecrementTest.php | 18 ++- tests/Liquid/Tag/TagExtendsTest.php | 33 +++-- tests/Liquid/Tag/TagForTest.php | 48 ++++--- tests/Liquid/Tag/TagIfTest.php | 87 ++++++++---- tests/Liquid/Tag/TagIfchangedTest.php | 9 +- tests/Liquid/Tag/TagIncludeTest.php | 45 ++++--- tests/Liquid/Tag/TagIncrementTest.php | 15 ++- tests/Liquid/Tag/TagPaginateTest.php | 15 ++- tests/Liquid/Tag/TagRawTest.php | 6 +- tests/Liquid/Tag/TagTablerowTest.php | 12 +- tests/Liquid/Tag/TagUnlessTest.php | 12 +- tests/Liquid/TemplateTest.php | 48 ++++--- tests/Liquid/TestCase.php | 9 +- tests/Liquid/TestFileSystem.php | 6 +- tests/Liquid/VariableResolutionTest.php | 18 ++- tests/Liquid/VariableTest.php | 33 +++-- tests/Liquid/VirtualFileSystemTest.php | 18 ++- 81 files changed, 1278 insertions(+), 639 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 1db6c75a..e645fdfe 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -14,7 +14,8 @@ /** * Base class for blocks. */ -class AbstractBlock extends AbstractTag { +class AbstractBlock extends AbstractTag +{ /** * @var AbstractTag[] */ @@ -23,7 +24,8 @@ class AbstractBlock extends AbstractTag { /** * @return array */ - public function getNodelist() { + public function getNodelist() + { return $this->nodelist; } @@ -35,7 +37,8 @@ public function getNodelist() { * @throws \Liquid\LiquidException * @return void */ - public function parse(array &$tokens) { + public function parse(array &$tokens) + { $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); @@ -91,7 +94,8 @@ public function parse(array &$tokens) { * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { return $this->renderAll($this->nodelist, $context); } @@ -103,7 +107,8 @@ public function render(Context $context) { * * @return string */ - protected function renderAll(array $list, Context $context) { + protected function renderAll(array $list, Context $context) + { $result = ''; foreach ($list as $token) { @@ -133,7 +138,8 @@ protected function renderAll(array $list, Context $context) { /** * An action to execute when the end tag is reached */ - protected function endTag() { + protected function endTag() + { // Do nothing by default } @@ -146,7 +152,8 @@ protected function endTag() { * * @throws \Liquid\LiquidException */ - protected function unknownTag($tag, $params, array $tokens) { + protected function unknownTag($tag, $params, array $tokens) + { switch ($tag) { case 'else': throw new LiquidException($this->blockName() . " does not expect else tag"); @@ -164,7 +171,8 @@ protected function unknownTag($tag, $params, array $tokens) { * @throws \Liquid\LiquidException * @return bool */ - protected function assertMissingDelimitation() { + protected function assertMissingDelimitation() + { throw new LiquidException($this->blockName() . " tag was never closed"); } @@ -173,7 +181,8 @@ protected function assertMissingDelimitation() { * * @return string */ - protected function blockDelimiter() { + protected function blockDelimiter() + { return "end" . $this->blockName(); } @@ -182,7 +191,8 @@ protected function blockDelimiter() { * * @return string */ - private function blockName() { + private function blockName() + { $reflection = new \ReflectionClass($this); return str_replace('tag', '', strtolower($reflection->getShortName())); } @@ -195,7 +205,8 @@ private function blockName() { * @throws \Liquid\LiquidException * @return Variable */ - private function createVariable($token) { + private function createVariable($token) + { $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '(.*)' . Liquid::get('VARIABLE_END') . '$/'); if ($variableRegexp->match($token)) { return new Variable($variableRegexp->matches[1]); diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index 9238e61e..68504ddc 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -14,7 +14,8 @@ /** * Base class for tags. */ -abstract class AbstractTag { +abstract class AbstractTag +{ /** * The markup for the tag * @@ -43,7 +44,8 @@ abstract class AbstractTag { * @param array $tokens * @param FileSystem $fileSystem */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $this->markup = $markup; $this->fileSystem = $fileSystem; $this->parse($tokens); @@ -54,7 +56,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @param array $tokens */ - public function parse(array &$tokens) { + public function parse(array &$tokens) + { // Do nothing by default } @@ -72,7 +75,8 @@ abstract public function render(Context $context); * * @param string $markup */ - protected function extractAttributes($markup) { + protected function extractAttributes($markup) + { $this->attributes = array(); $attributeRegexp = new Regexp(Liquid::get('TAG_ATTRIBUTES')); @@ -89,7 +93,8 @@ protected function extractAttributes($markup) { * * @return string */ - protected function name() { + protected function name() + { return strtolower(get_class($this)); } } diff --git a/src/Liquid/Cache.php b/src/Liquid/Cache.php index 0fe81853..1e8e7960 100644 --- a/src/Liquid/Cache.php +++ b/src/Liquid/Cache.php @@ -14,7 +14,8 @@ /** * Base class for Cache. */ -abstract class Cache { +abstract class Cache +{ /** @var int */ protected $expire = 3600; /** @var string */ @@ -25,7 +26,8 @@ abstract class Cache { /** * @param array $options */ - public function __construct(array $options = array()) { + public function __construct(array $options = array()) + { if (isset($options['cache_expire'])) { $this->expire = $options['cache_expire']; } diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index 76b418f5..f007aeec 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -19,7 +19,8 @@ * * @codeCoverageIgnore */ -class Apc extends Cache { +class Apc extends Cache +{ /** * Constructor. * @@ -29,7 +30,8 @@ class Apc extends Cache { * * @throws LiquidException if APC cache extension is not loaded or is disabled. */ - public function __construct(array $options = array()) { + public function __construct(array $options = array()) + { parent::__construct($options); if (!function_exists('apc_fetch')) { @@ -40,14 +42,16 @@ public function __construct(array $options = array()) { /** * {@inheritdoc} */ - public function read($key, $unserialize = true) { + public function read($key, $unserialize = true) + { return apc_fetch($this->prefix . $key); } /** * {@inheritdoc} */ - public function exists($key) { + public function exists($key) + { apc_fetch($this->prefix . $key, $success); return (bool) $success; } @@ -55,14 +59,16 @@ public function exists($key) { /** * {@inheritdoc} */ - public function write($key, $value, $serialize = true) { + public function write($key, $value, $serialize = true) + { return apc_store($this->prefix . $key, $value, $this->expire); } /** * {@inheritdoc} */ - public function flush($expiredOnly = false) { + public function flush($expiredOnly = false) + { return apc_clear_cache('user'); } } diff --git a/src/Liquid/Cache/File.php b/src/Liquid/Cache/File.php index 51f24547..1fb73a38 100644 --- a/src/Liquid/Cache/File.php +++ b/src/Liquid/Cache/File.php @@ -17,7 +17,8 @@ /** * Implements cache stored in files. */ -class File extends Cache { +class File extends Cache +{ /** * Constructor. * @@ -27,7 +28,8 @@ class File extends Cache { * * @throws LiquidException if Cachedir not exists. */ - public function __construct(array $options = array()) { + public function __construct(array $options = array()) + { parent::__construct($options); if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) { @@ -40,7 +42,8 @@ public function __construct(array $options = array()) { /** * {@inheritdoc} */ - public function read($key, $unserialize = true) { + public function read($key, $unserialize = true) + { if (!$this->exists($key)) { return false; } @@ -55,7 +58,8 @@ public function read($key, $unserialize = true) { /** * {@inheritdoc} */ - public function exists($key) { + public function exists($key) + { $cacheFile = $this->path . $this->prefix . $key; if (!file_exists($cacheFile) || filemtime($cacheFile) + $this->expire < time()) { @@ -68,7 +72,8 @@ public function exists($key) { /** * {@inheritdoc} */ - public function write($key, $value, $serialize = true) { + public function write($key, $value, $serialize = true) + { $bytes = file_put_contents($this->path . $this->prefix . $key, $serialize ? serialize($value) : $value); $this->gc(); @@ -78,7 +83,8 @@ public function write($key, $value, $serialize = true) { /** * {@inheritdoc} */ - public function flush($expiredOnly = false) { + public function flush($expiredOnly = false) + { foreach (glob($this->path . $this->prefix . '*') as $file) { if ($expiredOnly) { if (filemtime($file) + $this->expire < time()) { @@ -93,7 +99,8 @@ public function flush($expiredOnly = false) { /** * {@inheritdoc} */ - protected function gc() { + protected function gc() + { $this->flush(true); } } diff --git a/src/Liquid/Cache/Local.php b/src/Liquid/Cache/Local.php index 7d4c12e2..7e041024 100644 --- a/src/Liquid/Cache/Local.php +++ b/src/Liquid/Cache/Local.php @@ -16,13 +16,15 @@ /** * Implements cache with data stored in an embedded variable with no handling of expiration dates for simplicity */ -class Local extends Cache { +class Local extends Cache +{ private $cache = array(); /** * {@inheritdoc} */ - public function read($key, $unserialize = true) { + public function read($key, $unserialize = true) + { if (isset($this->cache[$key])) { return $this->cache[$key]; } @@ -33,14 +35,16 @@ public function read($key, $unserialize = true) { /** * {@inheritdoc} */ - public function exists($key) { + public function exists($key) + { return isset($this->cache[$key]); } /** * {@inheritdoc} */ - public function write($key, $value, $serialize = true) { + public function write($key, $value, $serialize = true) + { $this->cache[$key] = $value; return true; } @@ -48,7 +52,8 @@ public function write($key, $value, $serialize = true) { /** * {@inheritdoc} */ - public function flush($expiredOnly = false) { + public function flush($expiredOnly = false) + { $this->cache = array(); return true; } diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 3b28d487..163d58c5 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -14,7 +14,8 @@ /** * Context keeps the variable stack and resolves variables, as well as keywords. */ -class Context { +class Context +{ /** * Local scopes * @@ -49,7 +50,8 @@ class Context { * @param array $assigns * @param array $registers */ - public function __construct(array $assigns = array(), array $registers = array()) { + public function __construct(array $assigns = array(), array $registers = array()) + { $this->assigns = array($assigns); $this->registers = $registers; $this->filterbank = new Filterbank($this); @@ -62,7 +64,8 @@ public function __construct(array $assigns = array(), array $registers = array() * * @param mixed $filter */ - public function addFilters($filter) { + public function addFilters($filter) + { $this->filterbank->addFilter($filter); } @@ -75,7 +78,8 @@ public function addFilters($filter) { * * @return string */ - public function invoke($name, $value, array $args = array()) { + public function invoke($name, $value, array $args = array()) + { return $this->filterbank->invoke($name, $value, $args); } @@ -84,7 +88,8 @@ public function invoke($name, $value, array $args = array()) { * * @param array $newAssigns */ - public function merge($newAssigns) { + public function merge($newAssigns) + { $this->assigns[0] = array_merge($this->assigns[0], $newAssigns); } @@ -93,7 +98,8 @@ public function merge($newAssigns) { * * @return bool */ - public function push() { + public function push() + { array_unshift($this->assigns, array()); return true; } @@ -104,7 +110,8 @@ public function push() { * @throws LiquidException * @return bool */ - public function pop() { + public function pop() + { if (count($this->assigns) == 1) { throw new LiquidException('No elements to pop'); } @@ -119,7 +126,8 @@ public function pop() { * * @return mixed */ - public function get($key) { + public function get($key) + { return $this->resolve($key); } @@ -130,7 +138,8 @@ public function get($key) { * @param mixed $value * @param bool $global */ - public function set($key, $value, $global = false) { + public function set($key, $value, $global = false) + { if ($global) { for ($i = 0; $i < count($this->assigns); $i++) { $this->assigns[$i][$key] = $value; @@ -147,7 +156,8 @@ public function set($key, $value, $global = false) { * * @return bool */ - public function hasKey($key) { + public function hasKey($key) + { return (!is_null($this->resolve($key))); } @@ -161,7 +171,8 @@ public function hasKey($key) { * @throws LiquidException * @return mixed */ - private function resolve($key) { + private function resolve($key) + { // This shouldn't happen if (is_array($key)) { throw new LiquidException("Cannot resolve arrays as key"); @@ -205,7 +216,8 @@ private function resolve($key) { * * @return mixed */ - private function fetch($key) { + private function fetch($key) + { // TagDecrement depends on environments being checked before assigns foreach ($this->environments as $environment) { if (array_key_exists($key, $environment)) { @@ -239,7 +251,8 @@ private function fetch($key) { * @throws LiquidException * @return mixed */ - private function variable($key) { + private function variable($key) + { // Support numeric and variable array indicies if (preg_match("|\[[0-9]+\]|", $key)) { $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); diff --git a/src/Liquid/CustomFilters.php b/src/Liquid/CustomFilters.php index e8b73b9d..e9f5e00c 100644 --- a/src/Liquid/CustomFilters.php +++ b/src/Liquid/CustomFilters.php @@ -14,7 +14,8 @@ /** * A selection of custom filters. */ -class CustomFilters { +class CustomFilters +{ /** * Sort an array by key. @@ -23,7 +24,8 @@ class CustomFilters { * * @return array */ - public static function sort_key(array $input) { + public static function sort_key(array $input) + { ksort($input); return $input; } diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index 35c0939b..11d377bf 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -14,7 +14,8 @@ /** * Base class for blocks that make logical decisions. */ -class Decision extends AbstractBlock { +class Decision extends AbstractBlock +{ /** * The current left variable to compare * @@ -37,7 +38,8 @@ class Decision extends AbstractBlock { * @throws \Liquid\LiquidException * @return string */ - private function stringValue($value) { + private function stringValue($value) + { // Objects should have a __toString method to get a value to compare to if (is_object($value)) { if (method_exists($value, '__toString')) { @@ -66,7 +68,8 @@ private function stringValue($value) { * * @return bool */ - protected function equalVariables($left, $right, Context $context) { + protected function equalVariables($left, $right, Context $context) + { $left = $this->stringValue($context->get($left)); $right = $this->stringValue($context->get($right)); @@ -84,7 +87,8 @@ protected function equalVariables($left, $right, Context $context) { * @throws \Liquid\LiquidException * @return bool */ - protected function interpretCondition($left, $right, $op = null, Context $context) { + protected function interpretCondition($left, $right, $op = null, Context $context) + { if (is_null($op)) { $value = $this->stringValue($context->get($left)); return $value; diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 3673c517..30eed152 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -17,14 +17,16 @@ /** * This class represents the entire template document. */ -class Document extends AbstractBlock { +class Document extends AbstractBlock +{ /** * Constructor. * * @param array $tokens * @param FileSystem $fileSystem */ - public function __construct(array &$tokens, FileSystem $fileSystem = null) { + public function __construct(array &$tokens, FileSystem $fileSystem = null) + { $this->fileSystem = $fileSystem; $this->parse($tokens); } @@ -34,7 +36,8 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) { * * @return string */ - public function checkIncludes() { + public function checkIncludes() + { foreach ($this->nodelist as $token) { if ($token instanceof TagInclude || $token instanceof TagExtends) { /** @var TagInclude|TagExtends $token */ @@ -52,13 +55,15 @@ public function checkIncludes() { * * @return string */ - protected function blockDelimiter() { + protected function blockDelimiter() + { return ''; } /** * Document blocks don't need to be terminated since they are not actually opened */ - protected function assertMissingDelimitation() { + protected function assertMissingDelimitation() + { } } diff --git a/src/Liquid/Drop.php b/src/Liquid/Drop.php index 40428808..cf3888ab 100644 --- a/src/Liquid/Drop.php +++ b/src/Liquid/Drop.php @@ -32,7 +32,8 @@ * Your drop can either implement the methods sans any parameters or implement the beforeMethod(name) method which is a * catch all. */ -abstract class Drop { +abstract class Drop +{ /** * @var Context */ @@ -45,14 +46,16 @@ abstract class Drop { * * @return null */ - protected function beforeMethod($method) { + protected function beforeMethod($method) + { return null; } /** * @param Context $context */ - public function setContext(Context $context) { + public function setContext(Context $context) + { $this->context = $context; } @@ -63,7 +66,8 @@ public function setContext(Context $context) { * * @return mixed */ - public function invokeDrop($method) { + public function invokeDrop($method) + { $result = $this->beforeMethod($method); if (is_null($result) && is_callable(array($this, $method))) { @@ -80,21 +84,24 @@ public function invokeDrop($method) { * * @return bool */ - public function hasKey($name) { + public function hasKey($name) + { return true; } /** * @return Drop */ - public function toLiquid() { + public function toLiquid() + { return $this; } /** * @return string */ - public function __toString() { + public function __toString() + { return get_class($this); } } diff --git a/src/Liquid/FileSystem.php b/src/Liquid/FileSystem.php index 2ffa54e2..70e110a4 100644 --- a/src/Liquid/FileSystem.php +++ b/src/Liquid/FileSystem.php @@ -19,7 +19,8 @@ * * You can add additional instance variables, arguments, or methods as needed. */ -interface FileSystem { +interface FileSystem +{ /** * Retrieve a template file. * diff --git a/src/Liquid/FileSystem/Local.php b/src/Liquid/FileSystem/Local.php index 59c81266..ba22e748 100644 --- a/src/Liquid/FileSystem/Local.php +++ b/src/Liquid/FileSystem/Local.php @@ -22,7 +22,8 @@ * * For security reasons, template paths are only allowed to contain letters, numbers, and underscore. */ -class Local implements FileSystem { +class Local implements FileSystem +{ /** * The root path * @@ -35,7 +36,8 @@ class Local implements FileSystem { * * @param string $root The root path for templates */ - public function __construct($root) { + public function __construct($root) + { // since root path can only be set from constructor, we check it once right here if (!empty($root)) { $realRoot = realpath($root); @@ -55,7 +57,8 @@ public function __construct($root) { * * @return string template content */ - public function readTemplateFile($templatePath) { + public function readTemplateFile($templatePath) + { return file_get_contents($this->fullPath($templatePath)); } @@ -67,7 +70,8 @@ public function readTemplateFile($templatePath) { * @throws LiquidException * @return string */ - public function fullPath($templatePath) { + public function fullPath($templatePath) + { if (empty($templatePath)) { throw new LiquidException("Empty template name"); } diff --git a/src/Liquid/FileSystem/Virtual.php b/src/Liquid/FileSystem/Virtual.php index 3b7d9251..955cf7ab 100644 --- a/src/Liquid/FileSystem/Virtual.php +++ b/src/Liquid/FileSystem/Virtual.php @@ -17,7 +17,8 @@ /** * This implements a virtual file system with actual code used to find files injected from outside thus achieving inversion of control. */ -class Virtual implements FileSystem { +class Virtual implements FileSystem +{ /** * @var callable */ @@ -29,7 +30,8 @@ class Virtual implements FileSystem { * @param callable $callback Callback is responsible for providing content of requested templates. Should return template's text. * @throws LiquidException */ - public function __construct($callback) { + public function __construct($callback) + { // Since a callback can only be set from the constructor, we check it once right here. if (!is_callable($callback)) { throw new LiquidException("Not a callback provided"); @@ -45,11 +47,13 @@ public function __construct($callback) { * * @return string template content */ - public function readTemplateFile($templatePath) { + public function readTemplateFile($templatePath) + { return call_user_func($this->callback, $templatePath); } - public function __sleep() { + public function __sleep() + { // we cannot serialize a closure if ($this->callback instanceof \Closure) { throw new LiquidException("Virtual file system with a Closure as a callback cannot be used with a serializing cache"); diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 2c1cc887..44543d82 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -15,7 +15,8 @@ * The filter bank is where all registered filters are stored, and where filter invocation is handled * it supports a variety of different filter types; objects, class, and simple methods. */ -class Filterbank { +class Filterbank +{ /** * The registered filter objects * @@ -42,7 +43,8 @@ class Filterbank { * * @param $context */ - public function __construct(Context $context) { + public function __construct(Context $context) + { $this->context = $context; $this->addFilter('\Liquid\StandardFilters'); @@ -58,7 +60,8 @@ public function __construct(Context $context) { * @throws LiquidException * @return bool */ - public function addFilter($filter) { + public function addFilter($filter) + { // If the passed filter was an object, store the object for future reference. if (is_object($filter)) { $filter->context = $this->context; @@ -100,7 +103,8 @@ public function addFilter($filter) { * * @return string */ - public function invoke($name, $value, array $args = array()) { + public function invoke($name, $value, array $args = array()) + { // workaround for a single standard filter being a reserved keyword - we can't use overloading for static calls if ($name == 'default') { $name = '_default'; diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index a3320a6a..91241270 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -14,7 +14,8 @@ /** * Liquid for PHP. */ -class Liquid { +class Liquid +{ /** * We cannot make settings constants, because we cannot create compound * constants in PHP (before 5.6). @@ -80,7 +81,8 @@ class Liquid { * * @return string */ - public static function get($key) { + public static function get($key) + { // backward compatibility if ($key === 'ALLOWED_VARIABLE_CHARS') { return substr(self::$config['VARIABLE_NAME'], 0, -1); @@ -110,7 +112,8 @@ public static function get($key) { * @param string $key * @param string $value */ - public static function set($key, $value) { + public static function set($key, $value) + { // backward compatibility if ($key === 'ALLOWED_VARIABLE_CHARS') { $key = 'VARIABLE_NAME'; @@ -126,7 +129,8 @@ public static function set($key, $value) { * * @return array */ - public static function arrayFlatten($array) { + public static function arrayFlatten($array) + { $return = array(); foreach ($array as $element) { diff --git a/src/Liquid/LiquidException.php b/src/Liquid/LiquidException.php index f16cfecd..198e2353 100644 --- a/src/Liquid/LiquidException.php +++ b/src/Liquid/LiquidException.php @@ -14,5 +14,6 @@ /** * LiquidException class. */ -class LiquidException extends \Exception { +class LiquidException extends \Exception +{ } diff --git a/src/Liquid/LocalFileSystem.php b/src/Liquid/LocalFileSystem.php index 13e38959..12ebf639 100644 --- a/src/Liquid/LocalFileSystem.php +++ b/src/Liquid/LocalFileSystem.php @@ -14,5 +14,6 @@ /** * @deprecated Left for backward compatibility reasons. Use \Liquid\FileSystem\Local instead. */ -class LocalFileSystem extends \Liquid\FileSystem\Local { +class LocalFileSystem extends \Liquid\FileSystem\Local +{ } diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index 16f7733a..5e91906c 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -15,7 +15,8 @@ * A support class for regular expressions and * non liquid specific support classes and functions. */ -class Regexp { +class Regexp +{ /** * The regexp pattern * @@ -37,7 +38,8 @@ class Regexp { * * @return Regexp */ - public function __construct($pattern) { + public function __construct($pattern) + { $this->pattern = (substr($pattern, 0, 1) != '/') ? '/' . $this->quote($pattern) . '/' : $pattern; @@ -50,7 +52,8 @@ public function __construct($pattern) { * * @return string */ - public function quote($string) { + public function quote($string) + { return preg_quote($string, '/'); } @@ -61,7 +64,8 @@ public function quote($string) { * * @return array */ - public function scan($string) { + public function scan($string) + { preg_match_all($this->pattern, $string, $matches); if (count($matches) == 1) { @@ -88,7 +92,8 @@ public function scan($string) { * * @return int 1 if there was a match, 0 if there wasn't */ - public function match($string) { + public function match($string) + { return preg_match($this->pattern, $string, $this->matches); } @@ -99,7 +104,8 @@ public function match($string) { * * @return int The number of matches */ - public function matchAll($string) { + public function matchAll($string) + { return preg_match_all($this->pattern, $string, $this->matches); } @@ -111,7 +117,8 @@ public function matchAll($string) { * * @return array */ - public function split($string, $limit = null) { + public function split($string, $limit = null) + { return preg_split($this->pattern, $string, $limit); } } diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 12e70cab..0502ce97 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -14,7 +14,8 @@ /** * A selection of standard filters. */ -class StandardFilters { +class StandardFilters +{ /** * Add one string to another @@ -24,7 +25,8 @@ class StandardFilters { * * @return string */ - public static function append($input, $string) { + public static function append($input, $string) + { return $input . $string; } @@ -36,7 +38,8 @@ public static function append($input, $string) { * * @return string */ - public static function capitalize($input) { + public static function capitalize($input) + { return preg_replace_callback("/(^|[^\p{L}'])([\p{Ll}])/u", function ($matches) { return $matches[1] . ucfirst($matches[2]); }, ucwords($input)); @@ -48,7 +51,8 @@ public static function capitalize($input) { * * @return int */ - public static function ceil($input) { + public static function ceil($input) + { return (int) ceil((float)$input); } @@ -61,7 +65,8 @@ public static function ceil($input) { * * @return string */ - public static function date($input, $format) { + public static function date($input, $format) + { if (!is_numeric($input)) { $input = strtotime($input); } @@ -82,7 +87,8 @@ public static function date($input, $format) { * * @return string */ - public static function _default($input, $default_value) { + public static function _default($input, $default_value) + { $isBlank = $input == '' || $input === false || $input === null; return $isBlank ? $default_value : $input; } @@ -96,7 +102,8 @@ public static function _default($input, $default_value) { * * @return float */ - public static function divided_by($input, $operand) { + public static function divided_by($input, $operand) + { return (float)$input / (float)$operand; } @@ -108,7 +115,8 @@ public static function divided_by($input, $operand) { * * @return string */ - public static function downcase($input) { + public static function downcase($input) + { return is_string($input) ? strtolower($input) : $input; } @@ -120,7 +128,8 @@ public static function downcase($input) { * * @return string */ - public static function raw($input) { + public static function raw($input) + { return $input; } @@ -132,7 +141,8 @@ public static function raw($input) { * * @return string */ - public static function escape($input) { + public static function escape($input) + { return is_string($input) ? htmlentities($input, ENT_QUOTES) : $input; } @@ -144,7 +154,8 @@ public static function escape($input) { * * @return string */ - public static function escape_once($input) { + public static function escape_once($input) + { return is_string($input) ? htmlentities($input, ENT_QUOTES, null, false) : $input; } @@ -156,7 +167,8 @@ public static function escape_once($input) { * * @return mixed */ - public static function first($input) { + public static function first($input) + { if ($input instanceof \Iterator) { $input->rewind(); return $input->current(); @@ -170,7 +182,8 @@ public static function first($input) { * * @return int */ - public static function floor($input) { + public static function floor($input) + { return (int) floor((float)$input); } @@ -183,7 +196,8 @@ public static function floor($input) { * * @return string */ - public static function join($input, $glue = ' ') { + public static function join($input, $glue = ' ') + { if ($input instanceof \Traversable) { $str = ''; foreach ($input as $elem) { @@ -205,7 +219,8 @@ public static function join($input, $glue = ' ') { * * @return mixed */ - public static function last($input) { + public static function last($input) + { if ($input instanceof \Traversable) { $last = null; foreach ($input as $elem) { @@ -222,7 +237,8 @@ public static function last($input) { * * @return string */ - public static function lstrip($input) { + public static function lstrip($input) + { return ltrim($input); } @@ -235,7 +251,8 @@ public static function lstrip($input) { * * @return string */ - public static function map($input, $property) { + public static function map($input, $property) + { if ($input instanceof \Traversable) { $input = iterator_to_array($input); } @@ -261,7 +278,8 @@ public static function map($input, $property) { * * @return float */ - public static function minus($input, $operand) { + public static function minus($input, $operand) + { return (float)$input - (float)$operand; } @@ -274,7 +292,8 @@ public static function minus($input, $operand) { * * @return float */ - public static function modulo($input, $operand) { + public static function modulo($input, $operand) + { return fmod((float)$input, (float)$operand); } @@ -286,7 +305,8 @@ public static function modulo($input, $operand) { * * @return string */ - public static function newline_to_br($input) { + public static function newline_to_br($input) + { return is_string($input) ? str_replace("\n", "
\n", $input) : $input; } @@ -299,7 +319,8 @@ public static function newline_to_br($input) { * * @return float */ - public static function plus($input, $operand) { + public static function plus($input, $operand) + { return (float)$input + (float)$operand; } @@ -312,7 +333,8 @@ public static function plus($input, $operand) { * * @return string */ - public static function prepend($input, $string) { + public static function prepend($input, $string) + { return $string . $input; } @@ -325,7 +347,8 @@ public static function prepend($input, $string) { * * @return string */ - public static function remove($input, $string) { + public static function remove($input, $string) + { return str_replace($string, '', $input); } @@ -338,7 +361,8 @@ public static function remove($input, $string) { * * @return string */ - public static function remove_first($input, $string) { + public static function remove_first($input, $string) + { if (($pos = strpos($input, $string)) !== false) { $input = substr_replace($input, '', $pos, strlen($string)); } @@ -356,7 +380,8 @@ public static function remove_first($input, $string) { * * @return string */ - public static function replace($input, $string, $replacement = '') { + public static function replace($input, $string, $replacement = '') + { return str_replace($string, $replacement, $input); } @@ -370,7 +395,8 @@ public static function replace($input, $string, $replacement = '') { * * @return string */ - public static function replace_first($input, $string, $replacement = '') { + public static function replace_first($input, $string, $replacement = '') + { if (($pos = strpos($input, $string)) !== false) { $input = substr_replace($input, $replacement, $pos, strlen($string)); } @@ -386,7 +412,8 @@ public static function replace_first($input, $string, $replacement = '') { * * @return array */ - public static function reverse($input) { + public static function reverse($input) + { if ($input instanceof \Traversable) { $input = iterator_to_array($input); } @@ -402,7 +429,8 @@ public static function reverse($input) { * * @return float */ - public static function round($input, $n = 0) { + public static function round($input, $n = 0) + { return round((float)$input, (int)$n); } @@ -412,7 +440,8 @@ public static function round($input, $n = 0) { * * @return string */ - public static function rstrip($input) { + public static function rstrip($input) + { return rtrim($input); } @@ -424,7 +453,8 @@ public static function rstrip($input) { * * @return int */ - public static function size($input) { + public static function size($input) + { if ($input instanceof \Iterator) { return iterator_count($input); } @@ -456,7 +486,8 @@ public static function size($input) { * * @return array|\Iterator|string */ - public static function slice($input, $offset, $length = null) { + public static function slice($input, $offset, $length = null) + { if ($input instanceof \Iterator) { $input = iterator_to_array($input); } @@ -480,7 +511,8 @@ public static function slice($input, $offset, $length = null) { * * @return array */ - public static function sort($input, $property = null) { + public static function sort($input, $property = null) + { if ($input instanceof \Traversable) { $input = iterator_to_array($input); } @@ -511,7 +543,8 @@ public static function sort($input, $property = null) { * * @return array */ - public static function split($input, $pattern) { + public static function split($input, $pattern) + { return explode($pattern, $input); } @@ -521,7 +554,8 @@ public static function split($input, $pattern) { * * @return string */ - public static function strip($input) { + public static function strip($input) + { return trim($input); } @@ -533,7 +567,8 @@ public static function strip($input) { * * @return string */ - public static function strip_html($input) { + public static function strip_html($input) + { return is_string($input) ? strip_tags($input) : $input; } @@ -545,7 +580,8 @@ public static function strip_html($input) { * * @return string */ - public static function strip_newlines($input) { + public static function strip_newlines($input) + { return is_string($input) ? str_replace(array( "\n", "\r" ), '', $input) : $input; @@ -560,7 +596,8 @@ public static function strip_newlines($input) { * * @return float */ - public static function times($input, $operand) { + public static function times($input, $operand) + { return (float)$input * (float)$operand; } @@ -574,7 +611,8 @@ public static function times($input, $operand) { * * @return string */ - public static function truncate($input, $characters = 100, $ending = '...') { + public static function truncate($input, $characters = 100, $ending = '...') + { if (is_string($input) || is_numeric($input)) { if (strlen($input) > $characters) { return substr($input, 0, $characters) . $ending; @@ -594,7 +632,8 @@ public static function truncate($input, $characters = 100, $ending = '...') { * * @return string */ - public static function truncatewords($input, $words = 3, $ending = '...') { + public static function truncatewords($input, $words = 3, $ending = '...') + { if (is_string($input)) { $wordlist = explode(" ", $input); @@ -614,7 +653,8 @@ public static function truncatewords($input, $words = 3, $ending = '...') { * * @return array */ - public static function uniq($input) { + public static function uniq($input) + { if ($input instanceof \Traversable) { $input = iterator_to_array($input); } @@ -629,7 +669,8 @@ public static function uniq($input) { * * @return string */ - public static function upcase($input) { + public static function upcase($input) + { return is_string($input) ? strtoupper($input) : $input; } @@ -641,7 +682,8 @@ public static function upcase($input) { * * @return string */ - public static function url_encode($input) { + public static function url_encode($input) + { return urlencode($input); } @@ -652,7 +694,8 @@ public static function url_encode($input) { * * @return string */ - public static function url_decode($input) { + public static function url_decode($input) + { return urldecode($input); } } diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index 876c0190..26330464 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -26,7 +26,8 @@ * {% assign var = var %} * {% assign var = "hello" | upcase %} */ -class TagAssign extends AbstractTag { +class TagAssign extends AbstractTag +{ /** * @var string The variable to assign from */ @@ -46,7 +47,8 @@ class TagAssign extends AbstractTag { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $syntaxRegexp = new Regexp('/(\w+)\s*=\s*(' . Liquid::get('QUOTED_FRAGMENT') . '+)/'); $filterSeperatorRegexp = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '\s*(.*)/'); @@ -85,7 +87,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string|void */ - public function render(Context $context) { + public function render(Context $context) + { $output = $context->get($this->from); foreach ($this->filters as $filter) { diff --git a/src/Liquid/Tag/TagBlock.php b/src/Liquid/Tag/TagBlock.php index 56f42e84..64fcc0d8 100644 --- a/src/Liquid/Tag/TagBlock.php +++ b/src/Liquid/Tag/TagBlock.php @@ -23,7 +23,8 @@ * * {% block foo %} bar {% endblock %} */ -class TagBlock extends AbstractBlock { +class TagBlock extends AbstractBlock +{ /** * The variable to assign to * @@ -41,7 +42,8 @@ class TagBlock extends AbstractBlock { * @throws \Liquid\LiquidException * @return \Liquid\Tag\TagBlock */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $syntaxRegexp = new Regexp('/(\w+)/'); if ($syntaxRegexp->match($markup)) { diff --git a/src/Liquid/Tag/TagBreak.php b/src/Liquid/Tag/TagBreak.php index 783e29c4..f8112a1b 100644 --- a/src/Liquid/Tag/TagBreak.php +++ b/src/Liquid/Tag/TagBreak.php @@ -26,7 +26,8 @@ * {{ i }} * {% endfor %} */ -class TagBreak extends AbstractTag { +class TagBreak extends AbstractTag +{ /** * Renders the tag * @@ -34,7 +35,8 @@ class TagBreak extends AbstractTag { * * @return string|void */ - public function render(Context $context) { + public function render(Context $context) + { $context->registers['break'] = true; } } diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index 30cff5f8..ad3e31b2 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -24,7 +24,8 @@ * * {% capture foo %} bar {% endcapture %} */ -class TagCapture extends AbstractBlock { +class TagCapture extends AbstractBlock +{ /** * The variable to assign to * @@ -41,7 +42,8 @@ class TagCapture extends AbstractBlock { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $syntaxRegexp = new Regexp('/(\w+)/'); if ($syntaxRegexp->match($markup)) { @@ -59,7 +61,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $output = parent::render($context); $context->set($this->to, $output); diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 7086cf52..84cee55c 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -25,7 +25,8 @@ * * {% case condition %}{% when foo %} foo {% else %} bar {% endcase %} */ -class TagCase extends Decision { +class TagCase extends Decision +{ /** * Stack of nodelists * @@ -63,7 +64,8 @@ class TagCase extends Decision { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $this->nodelists = array(); $this->elseNodelist = array(); @@ -81,7 +83,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu /** * Pushes the last nodelist onto the stack */ - public function endTag() { + public function endTag() + { $this->pushNodelist(); } @@ -94,7 +97,8 @@ public function endTag() { * * @throws \Liquid\LiquidException */ - public function unknownTag($tag, $params, array $tokens) { + public function unknownTag($tag, $params, array $tokens) + { $whenSyntaxRegexp = new Regexp('/' . Liquid::get('QUOTED_FRAGMENT') . '/'); switch ($tag) { @@ -125,7 +129,8 @@ public function unknownTag($tag, $params, array $tokens) { /** * Pushes the current right value and nodelist into the nodelist stack */ - public function pushNodelist() { + public function pushNodelist() + { if (!is_null($this->right)) { $this->nodelists[] = array($this->right, $this->nodelist); } @@ -138,7 +143,8 @@ public function pushNodelist() { * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $output = ''; // array(); $runElseBlock = true; diff --git a/src/Liquid/Tag/TagComment.php b/src/Liquid/Tag/TagComment.php index 624ca8a2..9822ee0f 100644 --- a/src/Liquid/Tag/TagComment.php +++ b/src/Liquid/Tag/TagComment.php @@ -21,7 +21,8 @@ * * {% comment %} This will be ignored {% endcomment %} */ -class TagComment extends AbstractBlock { +class TagComment extends AbstractBlock +{ /** * Renders the block * @@ -29,7 +30,8 @@ class TagComment extends AbstractBlock { * * @return string empty string */ - public function render(Context $context) { + public function render(Context $context) + { return ''; } } diff --git a/src/Liquid/Tag/TagContinue.php b/src/Liquid/Tag/TagContinue.php index df6a1bbb..f297fd18 100644 --- a/src/Liquid/Tag/TagContinue.php +++ b/src/Liquid/Tag/TagContinue.php @@ -26,7 +26,8 @@ * {{ i }} * {% endfor %} */ -class TagContinue extends AbstractTag { +class TagContinue extends AbstractTag +{ /** * Renders the tag * @@ -34,7 +35,8 @@ class TagContinue extends AbstractTag { * * @return string|void */ - public function render(Context $context) { + public function render(Context $context) + { $context->registers['continue'] = true; } } diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index 87823798..dfa18f7b 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -34,7 +34,8 @@ * will return * one one two two */ -class TagCycle extends AbstractTag { +class TagCycle extends AbstractTag +{ /** * @var string The name of the cycle; if none is given one is created using the value list */ @@ -54,7 +55,8 @@ class TagCycle extends AbstractTag { * * @throws LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $simpleSyntax = new Regexp("/" . Liquid::get('QUOTED_FRAGMENT') . "/"); $namedSyntax = new Regexp("/(" . Liquid::get('QUOTED_FRAGMENT') . ")\s*\:\s*(.*)/"); @@ -75,7 +77,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * @var Context $context * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $context->push(); $key = $context->get($this->name); @@ -108,7 +111,8 @@ public function render(Context $context) { * * @return array; */ - private function variablesFromString($markup) { + private function variablesFromString($markup) + { $regexp = new Regexp('/\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')\s*/'); $parts = explode(',', $markup); $result = array(); diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index a9ea5b53..94f56b27 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -27,7 +27,8 @@ * * @author Viorel Dram */ -class TagDecrement extends AbstractTag { +class TagDecrement extends AbstractTag +{ /** * Name of the variable to decrement * @@ -44,7 +45,8 @@ class TagDecrement extends AbstractTag { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { @@ -61,7 +63,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string|void */ - public function render(Context $context) { + public function render(Context $context) + { // if the value is not set in the environment check to see if it // exists in the context, and if not set it to 0 if (!isset($context->environments[0][$this->toDecrement])) { diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 71434767..63b519ab 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -27,7 +27,8 @@ * * {% extends "base" %} */ -class TagExtends extends AbstractTag { +class TagExtends extends AbstractTag +{ /** * @var string The name of the template */ @@ -52,7 +53,8 @@ class TagExtends extends AbstractTag { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $regex = new Regexp('/("[^"]+"|\'[^\']+\')?/'); if ($regex->match($markup) && isset($regex->matches[1])) { @@ -69,7 +71,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return array */ - private function findBlocks(array $tokens) { + private function findBlocks(array $tokens) + { $blockstartRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*block (\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); $blockendRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*endblock\s*?' . Liquid::get('TAG_END') . '$/'); @@ -99,7 +102,8 @@ private function findBlocks(array $tokens) { * * @throws \Liquid\LiquidException */ - public function parse(array &$tokens) { + public function parse(array &$tokens) + { if ($this->fileSystem === null) { throw new LiquidException("No file system"); } @@ -174,7 +178,8 @@ public function parse(array &$tokens) { * * @return boolean */ - public function checkIncludes() { + public function checkIncludes() + { $cache = Template::getCache(); if ($this->document->checkIncludes() == true) { @@ -197,7 +202,8 @@ public function checkIncludes() { * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $context->push(); $result = $this->document->render($context); $context->pop(); diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index a1003d84..41884cbe 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -33,7 +33,8 @@ * {%for i in (1..variable)%} {{i}} {%endfor%} * */ -class TagFor extends AbstractBlock { +class TagFor extends AbstractBlock +{ /** * @var array The collection to loop over */ @@ -63,7 +64,8 @@ class TagFor extends AbstractBlock { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { parent::__construct($markup, $tokens, $fileSystem); $syntaxRegexp = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); @@ -95,7 +97,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return null|string */ - public function render(Context $context) { + public function render(Context $context) + { if (!isset($context->registers['for'])) { $context->registers['for'] = array(); } diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index c773a72d..e9b095ee 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -28,7 +28,8 @@ * will return: * YES */ -class TagIf extends Decision { +class TagIf extends Decision +{ /** * Array holding the nodes to render for each logical block * @@ -50,7 +51,8 @@ class TagIf extends Decision { * @param array $tokens * @param FileSystem $fileSystem */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $this->nodelist = & $this->nodelistHolders[count($this->blocks)]; array_push($this->blocks, array('if', $markup, &$this->nodelist)); @@ -65,7 +67,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * @param array $params * @param array $tokens */ - public function unknownTag($tag, $params, array $tokens) { + public function unknownTag($tag, $params, array $tokens) + { if ($tag == 'else' || $tag == 'elsif') { // Update reference to nodelistHolder for this block $this->nodelist = & $this->nodelistHolders[count($this->blocks) + 1]; @@ -85,7 +88,8 @@ public function unknownTag($tag, $params, array $tokens) { * @throws \Liquid\LiquidException * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $context->push(); $logicalRegex = new Regexp('/\s+(and|or)\s+/'); diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index 8e1b85f2..62144c8c 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -18,7 +18,8 @@ /** * Quickly create a table from a collection */ -class TagIfchanged extends AbstractBlock { +class TagIfchanged extends AbstractBlock +{ /** * The last value * @@ -35,7 +36,8 @@ class TagIfchanged extends AbstractBlock { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { parent::__construct($markup, $tokens, $fileSystem); } @@ -46,7 +48,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $output = parent::render($context); if ($this->lastValue == $output) { diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index f73f738d..a61929c1 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -38,7 +38,8 @@ * Will loop over all the values of bar, including the template foo, passing a variable called foo * with each value of bar */ -class TagInclude extends AbstractTag { +class TagInclude extends AbstractTag +{ /** * @var string The name of the template */ @@ -73,7 +74,8 @@ class TagInclude extends AbstractTag { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $regex = new Regexp('/("[^"]+"|\'[^\']+\')(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); if ($regex->match($markup)) { @@ -99,7 +101,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @throws \Liquid\LiquidException */ - public function parse(array &$tokens) { + public function parse(array &$tokens) + { if ($this->fileSystem === null) { throw new LiquidException("No file system"); } @@ -129,7 +132,8 @@ public function parse(array &$tokens) { * * @return boolean */ - public function checkIncludes() { + public function checkIncludes() + { $cache = Template::getCache(); if ($this->document->checkIncludes() == true) { @@ -152,7 +156,8 @@ public function checkIncludes() { * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $result = ''; $variable = $context->get($this->variable); diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index 2c993735..4ed78145 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -27,7 +27,8 @@ * * @author Viorel Dram */ -class TagIncrement extends AbstractTag { +class TagIncrement extends AbstractTag +{ /** * Name of the variable to increment * @@ -44,7 +45,8 @@ class TagIncrement extends AbstractTag { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { @@ -61,7 +63,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string|void */ - public function render(Context $context) { + public function render(Context $context) + { // If the value is not set in the environment check to see if it // exists in the context, and if not set it to -1 if (!isset($context->environments[0][$this->toIncrement])) { diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 98e393da..6ab536c2 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -31,7 +31,8 @@ * */ -class TagPaginate extends AbstractBlock { +class TagPaginate extends AbstractBlock +{ /** * @var array The collection to paginate */ @@ -79,7 +80,8 @@ class TagPaginate extends AbstractBlock { * @throws \Liquid\LiquidException * */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { parent::__construct($markup, $tokens, $fileSystem); $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')\s+by\s+(\w+)/'); @@ -101,7 +103,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * @return string * */ - public function render(Context $context) { + public function render(Context $context) + { $this->currentPage = (is_numeric($context->get('page'))) ? $context->get('page') : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); @@ -151,7 +154,8 @@ public function render(Context $context) { * @return string * */ - public function currentUrl($context) { + public function currentUrl($context) + { $uri = explode('?', $context->get('REQUEST_URI')); $url = 'http'; diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index 7c21fa37..090692d2 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -25,11 +25,13 @@ * will return: * {{ 5 | plus: 6 }} is equal to 11. */ -class TagRaw extends AbstractBlock { +class TagRaw extends AbstractBlock +{ /** * @param array $tokens */ - public function parse(array &$tokens) { + public function parse(array &$tokens) + { $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); $this->nodelist = array(); diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 54d763ff..6c27981d 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -21,7 +21,8 @@ /** * Quickly create a table from a collection */ -class TagTablerow extends AbstractBlock { +class TagTablerow extends AbstractBlock +{ /** * The variable name of the table tag * @@ -52,7 +53,8 @@ class TagTablerow extends AbstractBlock { * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { + public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + { parent::__construct($markup, $tokens, $fileSystem); $syntax = new Regexp('/(\w+)\s+in\s+(' . Liquid::get('VARIABLE_NAME') . ')/'); @@ -74,7 +76,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $collection = $context->get($this->collectionName); if ($collection instanceof \Traversable) { diff --git a/src/Liquid/Tag/TagUnless.php b/src/Liquid/Tag/TagUnless.php index 60968587..a1a9e0b0 100644 --- a/src/Liquid/Tag/TagUnless.php +++ b/src/Liquid/Tag/TagUnless.php @@ -24,7 +24,8 @@ * NO */ -class TagUnless extends TagIf { +class TagUnless extends TagIf +{ /** * Replace first found key in $subject to value @@ -33,7 +34,8 @@ class TagUnless extends TagIf { * @param string $subject * @return string */ - protected function strReplaceOne($replacer, $subject) { + protected function strReplaceOne($replacer, $subject) + { $res = $subject; foreach ($replacer as $from => $to) { $res = str_ireplace($from, $to, $subject, $count); @@ -51,7 +53,8 @@ protected function strReplaceOne($replacer, $subject) { * after * a != 1 or b != 2 */ - protected function revertOperators() { + protected function revertOperators() + { // replace $replacerOperators = array( @@ -93,7 +96,8 @@ protected function revertOperators() { * @throws \Liquid\LiquidException * @return string */ - public function render(Context $context) { + public function render(Context $context) + { $this->revertOperators(); $res = parent::render($context); return $res; diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 1ac83bcd..6fb5aa41 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -20,7 +20,8 @@ * $tpl->parse(template_source); * $tpl->render(array('foo'=>1, 'bar'=>2); */ -class Template { +class Template +{ /** * @var Document The root of the node tree */ @@ -54,7 +55,8 @@ class Template { * * @return Template */ - public function __construct($path = null, $cache = null) { + public function __construct($path = null, $cache = null) + { $this->fileSystem = $path !== null ? new LocalFileSystem($path) : null; @@ -65,7 +67,8 @@ public function __construct($path = null, $cache = null) { /** * @param FileSystem $fileSystem */ - public function setFileSystem(FileSystem $fileSystem) { + public function setFileSystem(FileSystem $fileSystem) + { $this->fileSystem = $fileSystem; } @@ -74,7 +77,8 @@ public function setFileSystem(FileSystem $fileSystem) { * * @throws LiquidException */ - public function setCache($cache) { + public function setCache($cache) + { if (is_array($cache)) { if (isset($cache['cache']) && class_exists('\Liquid\Cache\\' . ucwords($cache['cache']))) { $classname = '\Liquid\Cache\\' . ucwords($cache['cache']); @@ -96,14 +100,16 @@ public function setCache($cache) { /** * @return Cache */ - public static function getCache() { + public static function getCache() + { return self::$cache; } /** * @return Document */ - public function getRoot() { + public function getRoot() + { return $this->root; } @@ -113,14 +119,16 @@ public function getRoot() { * @param string $name * @param string $class */ - public function registerTag($name, $class) { + public function registerTag($name, $class) + { self::$tags[$name] = $class; } /** * @return array */ - public static function getTags() { + public static function getTags() + { return self::$tags; } @@ -129,7 +137,8 @@ public static function getTags() { * * @param string $filter */ - public function registerFilter($filter) { + public function registerFilter($filter) + { $this->filters[] = $filter; } @@ -140,7 +149,8 @@ public function registerFilter($filter) { * * @return array */ - public static function tokenize($source) { + public static function tokenize($source) + { return empty($source) ? array() : preg_split(Liquid::get('TOKENIZATION_REGEXP'), $source, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); @@ -153,7 +163,8 @@ public static function tokenize($source) { * * @return Template */ - public function parse($source) { + public function parse($source) + { if (self::$cache !== null) { if (($this->root = self::$cache->read(md5($source))) != false && $this->root->checkIncludes() != true) { } else { @@ -178,7 +189,8 @@ public function parse($source) { * * @return string */ - public function render(array $assigns = array(), $filters = null, array $registers = array()) { + public function render(array $assigns = array(), $filters = null, array $registers = array()) + { $context = new Context($assigns, $registers); if (!is_null($filters)) { diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index 2a0afdc9..07d16816 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -14,7 +14,8 @@ /** * Implements a template variable. */ -class Variable { +class Variable +{ /** * @var array The filters to execute on the variable */ @@ -35,7 +36,8 @@ class Variable { * * @param string $markup */ - public function __construct($markup) { + public function __construct($markup) + { $this->markup = $markup; $quotedFragmentRegexp = new Regexp('/\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')/'); @@ -94,7 +96,8 @@ public function __construct($markup) { * * @return string The name of the variable */ - public function getName() { + public function getName() + { return $this->name; } @@ -103,7 +106,8 @@ public function getName() { * * @return array */ - public function getFilters() { + public function getFilters() + { return $this->filters; } @@ -114,7 +118,8 @@ public function getFilters() { * * @return mixed|string */ - public function render(Context $context) { + public function render(Context $context) + { $output = $context->get($this->name); foreach ($this->filters as $filter) { diff --git a/tests/Liquid/Cache/ApcTest.php b/tests/Liquid/Cache/ApcTest.php index 05b83180..8b38126a 100644 --- a/tests/Liquid/Cache/ApcTest.php +++ b/tests/Liquid/Cache/ApcTest.php @@ -14,11 +14,13 @@ use Liquid\TestCase; use \Liquid\Cache\Apc; -class ApcTest extends TestCase { +class ApcTest extends TestCase +{ /** @var \Liquid\Cache\Apc */ protected $cache; - protected function setUp() { + protected function setUp() + { parent::setUp(); if (!function_exists('apc_fetch')) { @@ -32,15 +34,18 @@ protected function setUp() { $this->cache = new Apc(); } - public function testNotExists() { + public function testNotExists() + { $this->assertFalse($this->cache->exists('no_such_key')); } - public function testReadNotExisting() { + public function testReadNotExisting() + { $this->assertFalse($this->cache->read('no_such_key')); } - public function testSetGetFlush() { + public function testSetGetFlush() + { $this->assertTrue($this->cache->write('test', 'example'), "Failed to set value."); $this->assertSame('example', $this->cache->read('test')); $this->assertTrue($this->cache->flush()); diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index 082b50cd..a231fb6e 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -13,12 +13,14 @@ use Liquid\TestCase; -class FileTest extends TestCase { +class FileTest extends TestCase +{ /** @var \Liquid\Cache\File */ protected $cache; protected $cacheDir; - protected function setUp() { + protected function setUp() + { parent::setUp(); $this->cacheDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache_dir'; @@ -29,7 +31,8 @@ protected function setUp() { )); } - protected function tearDown() { + protected function tearDown() + { parent::tearDown(); // Remove tmp cache files @@ -39,36 +42,42 @@ protected function tearDown() { /** * @expectedException \Liquid\LiquidException */ - public function testConstructInvalidOptions() { + public function testConstructInvalidOptions() + { new File(); } /** * @expectedException \Liquid\LiquidException */ - public function testConstructNoSuchDirOrNotWritable() { + public function testConstructNoSuchDirOrNotWritable() + { new File(array('cache_dir' => '/no/such/dir/liquid/cache')); } - public function testGetExistsNoFile() { + public function testGetExistsNoFile() + { $this->assertFalse($this->cache->exists('no_key')); } - public function testGetExistsExpired() { + public function testGetExistsExpired() + { $key = 'test'; $cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_' . $key; touch($cacheFile, time() - 1000000); // long ago $this->assertFalse($this->cache->exists($key)); } - public function testGetExistsNotExpired() { + public function testGetExistsNotExpired() + { $key = 'test'; $cacheFile = $this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_' . $key; touch($cacheFile); $this->assertTrue($this->cache->exists($key)); } - public function testFlushAll() { + public function testFlushAll() + { touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test'); touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test_two'); @@ -79,7 +88,8 @@ public function testFlushAll() { $this->assertCount(0, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); } - public function testFlushExpired() { + public function testFlushExpired() + { touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test'); touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test_two', time() - 1000000); @@ -90,7 +100,8 @@ public function testFlushExpired() { $this->assertCount(1, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); } - public function testWriteNoSerialize() { + public function testWriteNoSerialize() + { $key = 'test'; $value = 'test_value'; @@ -99,7 +110,8 @@ public function testWriteNoSerialize() { $this->assertEquals($value, file_get_contents($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_' . $key)); } - public function testWriteSerialized() { + public function testWriteSerialized() + { $key = 'test'; $value = 'test_value'; @@ -108,7 +120,8 @@ public function testWriteSerialized() { $this->assertEquals(serialize($value), file_get_contents($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_' . $key)); } - public function testWriteGc() { + public function testWriteGc() + { $key = 'test'; $value = 'test_value'; @@ -120,11 +133,13 @@ public function testWriteGc() { $this->assertCount(1, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); } - public function testReadNonExisting() { + public function testReadNonExisting() + { $this->assertFalse($this->cache->read('no_such_key')); } - public function testReadNoUnserialize() { + public function testReadNoUnserialize() + { $key = 'test'; $value = 'test_value'; @@ -133,7 +148,8 @@ public function testReadNoUnserialize() { $this->assertSame($value, $this->cache->read($key, false)); } - public function testReadSerialize() { + public function testReadSerialize() + { $key = 'test'; $value = 'test_value'; diff --git a/tests/Liquid/Cache/LocalTest.php b/tests/Liquid/Cache/LocalTest.php index 35bef443..2673e0f1 100644 --- a/tests/Liquid/Cache/LocalTest.php +++ b/tests/Liquid/Cache/LocalTest.php @@ -14,25 +14,30 @@ use Liquid\TestCase; use \Liquid\Cache\Local; -class LocalTest extends TestCase { +class LocalTest extends TestCase +{ /** @var \Liquid\Cache\Local */ protected $cache; - protected function setUp() { + protected function setUp() + { parent::setUp(); $this->cache = new Local(); } - public function testNotExists() { + public function testNotExists() + { $this->assertFalse($this->cache->exists('no_such_key')); } - public function testReadNotExisting() { + public function testReadNotExisting() + { $this->assertFalse($this->cache->read('no_such_key')); } - public function testSetGetFlush() { + public function testSetGetFlush() + { $this->assertTrue($this->cache->write('test', 'example')); $this->assertSame('example', $this->cache->read('test')); $this->assertTrue($this->cache->flush()); diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 4e6b243b..d1e9e65d 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -11,49 +11,61 @@ namespace Liquid; -class HundredCentes { - public function toLiquid() { +class HundredCentes +{ + public function toLiquid() + { return 100; } } -class CentsDrop extends Drop { - public function amount() { +class CentsDrop extends Drop +{ + public function amount() + { return new HundredCentes(); } } -class NoToLiquid { +class NoToLiquid +{ public $answer = 42; private $name = null; - public function name() { + public function name() + { return 'example'; } - public function count() { + public function count() + { return 1; } - public function __toString() { + public function __toString() + { return "forty two"; } } -class ToLiquidWrapper { +class ToLiquidWrapper +{ public $value = null; - public function toLiquid() { + public function toLiquid() + { return $this->value; } } -class NestedObject { +class NestedObject +{ public $property; public $value = -1; - public function toLiquid() { + public function toLiquid() + { // we intentionally made the value different so // that we could see where it is coming from return array( @@ -63,11 +75,13 @@ public function toLiquid() { } } -class ToArrayObject { +class ToArrayObject +{ public $property; public $value = -1; - public function toArray() { + public function toArray() + { // we intentionally made the value different so // that we could see where it is coming from return array( @@ -77,47 +91,59 @@ public function toArray() { } } -class GetSetObject { - public function field_exists($name) { +class GetSetObject +{ + public function field_exists($name) + { return $name == 'answer'; } - public function get($prop) { + public function get($prop) + { if ($prop == 'answer') { return 42; } } } -class HiFilter { - public function hi($value) { +class HiFilter +{ + public function hi($value) + { return $value . ' hi!'; } } -class GlobalFilter { - public function notice($value) { +class GlobalFilter +{ + public function notice($value) + { return "Global $value"; } } -class LocalFilter { - public function notice($value) { +class LocalFilter +{ + public function notice($value) + { return "Local $value"; } } -class ContextTest extends TestCase { +class ContextTest extends TestCase +{ /** @var Context */ public $context; - public function setup() { + public function setup() + { parent::setUp(); $this->context = new Context(); } - public function testScoping() { + public function testScoping() + { $this->context->push(); $this->assertNull($this->context->pop()); } @@ -125,18 +151,21 @@ public function testScoping() { /** * @expectedException \Liquid\LiquidException */ - public function testNoScopeToPop() { + public function testNoScopeToPop() + { $this->context->pop(); } /** * @expectedException \Liquid\LiquidException */ - public function testGetArray() { + public function testGetArray() + { $this->context->get(array()); } - public function testGetNotVariable() { + public function testGetNotVariable() + { $data = array( null => null, 'null' => null, @@ -153,11 +182,13 @@ public function testGetNotVariable() { $this->assertEquals(42.00, $this->context->get(42.00)); } - public function testVariablesNotExisting() { + public function testVariablesNotExisting() + { $this->assertNull($this->context->get('test')); } - public function testVariableIsObjectWithNoToLiquid() { + public function testVariableIsObjectWithNoToLiquid() + { $this->context->set('test', new NoToLiquid()); $this->assertEquals(42, $this->context->get('test.answer')); $this->assertEquals(1, $this->context->get('test.count')); @@ -165,13 +196,15 @@ public function testVariableIsObjectWithNoToLiquid() { $this->assertEquals("example", $this->context->get('test.name')); } - public function testToLiquidNull() { + public function testToLiquidNull() + { $object = new ToLiquidWrapper(); $this->context->set('object', $object); $this->assertNull($this->context->get('object.key')); } - public function testToLiquidStringKeyMustBeNull() { + public function testToLiquidStringKeyMustBeNull() + { $object = new ToLiquidWrapper(); $object->value = 'foo'; $this->context->set('object', $object); @@ -179,7 +212,8 @@ public function testToLiquidStringKeyMustBeNull() { $this->assertNull($this->context->get('object.foo.bar')); } - public function testNestedObject() { + public function testNestedObject() + { $object = new NestedObject(); $object->property = new NestedObject(); $this->context->set('object', $object); @@ -188,7 +222,8 @@ public function testNestedObject() { $this->assertNull($this->context->get('object.property.value.invalid')); } - public function testToArrayObject() { + public function testToArrayObject() + { $object = new ToArrayObject(); $object->property = new ToArrayObject(); $this->context->set('object', $object); @@ -197,18 +232,21 @@ public function testToArrayObject() { $this->assertNull($this->context->get('object.property.value.invalid')); } - public function testGetSetObject() { + public function testGetSetObject() + { $this->context->set('object', new GetSetObject()); $this->assertEquals(42, $this->context->get('object.answer')); $this->assertNull($this->context->get('object.invalid')); } - public function testFinalVariableCanBeObject() { + public function testFinalVariableCanBeObject() + { $this->context->set('test', (object) array('value' => (object) array())); $this->assertInstanceOf(\stdClass::class, $this->context->get('test.value')); } - public function testVariables() { + public function testVariables() + { $this->context->set('test', 'test'); $this->assertTrue($this->context->hasKey('test')); $this->assertFalse($this->context->hasKey('test.foo')); @@ -219,27 +257,32 @@ public function testVariables() { $this->assertEquals('0', $this->context->get('test_0')); } - public function testLengthQuery() { + public function testLengthQuery() + { $this->context->set('numbers', array(1, 2, 3, 4)); $this->assertEquals(4, $this->context->get('numbers.size')); } - public function testOverrideSize() { + public function testOverrideSize() + { $this->context->set('hash', array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'size' => '5000')); $this->assertEquals(5000, $this->context->get('hash.size')); } - public function testHierchalData() { + public function testHierchalData() + { $this->context->set('hash', array('name' => 'tobi')); $this->assertEquals('tobi', $this->context->get('hash.name')); } - public function testHierchalDataNoKey() { + public function testHierchalDataNoKey() + { $this->context->set('hash', array('name' => 'tobi')); $this->assertNotNull('tobi', $this->context->get('hash.no_key')); } - public function testAddFilter() { + public function testAddFilter() + { $context = new Context(); $context->addFilters(new HiFilter()); $this->assertEquals('hi? hi!', $context->invoke('hi', 'hi?')); @@ -251,7 +294,8 @@ public function testAddFilter() { $this->assertEquals('hi? hi!', $context->invoke('hi', 'hi?')); } - public function testOverrideGlobalFilter() { + public function testOverrideGlobalFilter() + { $template = new Template(); $template->registerFilter(new GlobalFilter()); @@ -260,7 +304,8 @@ public function testOverrideGlobalFilter() { $this->assertEquals('Local test', $template->render(array(), new LocalFilter())); } - public function testAddItemInOuterScope() { + public function testAddItemInOuterScope() + { $this->context->set('test', 'test'); $this->context->push(); $this->assertEquals('test', $this->context->get('test')); @@ -268,7 +313,8 @@ public function testAddItemInOuterScope() { $this->assertEquals('test', $this->context->get('test')); } - public function testAddItemInInnerScope() { + public function testAddItemInInnerScope() + { $this->context->push(); $this->context->set('test', 'test'); $this->assertEquals('test', $this->context->get('test')); @@ -276,7 +322,8 @@ public function testAddItemInInnerScope() { $this->assertEquals(null, $this->context->get('test')); } - public function testMerge() { + public function testMerge() + { $this->context->merge(array('test' => 'test')); $this->assertEquals('test', $this->context->get('test')); @@ -285,12 +332,14 @@ public function testMerge() { $this->assertEquals('bar', $this->context->get('foo')); } - public function testCents() { + public function testCents() + { $this->context->merge(array('cents' => new HundredCentes())); $this->assertEquals(100, $this->context->get('cents')); } - public function testNestedCents() { + public function testNestedCents() + { $this->context->merge(array('cents' => array('amount' => new HundredCentes()))); $this->assertEquals(100, $this->context->get('cents.amount')); @@ -298,12 +347,14 @@ public function testNestedCents() { $this->assertEquals(100, $this->context->get('cents.cents.amount')); } - public function testCentsThroughDrop() { + public function testCentsThroughDrop() + { $this->context->merge(array('cents' => new CentsDrop())); $this->assertEquals(100, $this->context->get('cents.amount')); } - public function testCentsThroughDropNestedly() { + public function testCentsThroughDropNestedly() + { $this->context->merge(array('cents' => array('cents' => new CentsDrop()))); $this->assertEquals(100, $this->context->get('cents.cents.amount')); @@ -311,7 +362,8 @@ public function testCentsThroughDropNestedly() { $this->assertEquals(100, $this->context->get('cents.cents.cents.amount')); } - public function testGetNoOverride() { + public function testGetNoOverride() + { $_GET['test'] = ''; // Previously $_GET would override directly set values // It happend during class construction - we need to create a brand new instance right here diff --git a/tests/Liquid/CustomFiltersTest.php b/tests/Liquid/CustomFiltersTest.php index d982b04f..9634098b 100644 --- a/tests/Liquid/CustomFiltersTest.php +++ b/tests/Liquid/CustomFiltersTest.php @@ -11,7 +11,8 @@ namespace Liquid; -class CustomFiltersTest extends TestCase { +class CustomFiltersTest extends TestCase +{ /** * The current context * @@ -19,13 +20,15 @@ class CustomFiltersTest extends TestCase { */ public $context; - protected function setup() { + protected function setup() + { parent::setUp(); $this->context = new Context(); } - public function testSortKey() { + public function testSortKey() + { $data = array( array( array(), diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index ce345f59..0f3df5ea 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -11,73 +11,91 @@ namespace Liquid; -class ContextDrop extends Drop { - public function beforeMethod($method) { +class ContextDrop extends Drop +{ + public function beforeMethod($method) + { return $this->context->get($method); } } -class TextDrop extends Drop { - public function get_array() { +class TextDrop extends Drop +{ + public function get_array() + { return array('text1', 'text2'); } - public function text() { + public function text() + { return 'text1'; } } -class CatchallDrop extends Drop { - public function beforeMethod($method) { +class CatchallDrop extends Drop +{ + public function beforeMethod($method) + { return 'method: ' . $method; } } -class ProductDrop extends Drop { - public function top_sales() { +class ProductDrop extends Drop +{ + public function top_sales() + { throw new \Exception("worked"); } - public function texts() { + public function texts() + { return new TextDrop(); } - public function catchall() { + public function catchall() + { return new CatchallDrop(); } - public function context() { + public function context() + { return new ContextDrop(); } - public function callmenot() { + public function callmenot() + { return "protected"; } - public function hasKey($name) { + public function hasKey($name) + { return $name != 'unknown' && $name != 'false'; } } -class DropTest extends TestCase { +class DropTest extends TestCase +{ /** * @expectedException \Exception * @expectedExceptionMessage worked */ - public function testProductDrop() { + public function testProductDrop() + { $template = new Template(); $template->parse(' {{ product.top_sales }} '); $template->render(array('product' => new ProductDrop)); } - public function testNoKeyDrop() { + public function testNoKeyDrop() + { $template = new Template(); $template->parse(' {{ product.invalid.unknown }}{{ product.false }} '); $output = $template->render(array('product' => new ProductDrop)); $this->assertEquals(' ', $output); } - public function testTextDrop() { + public function testTextDrop() + { $template = new Template(); $template->parse(' {{ product.texts.text }} '); $output = $template->render(array('product' => new ProductDrop())); @@ -89,7 +107,8 @@ public function testTextDrop() { $this->assertEquals(' method: unknown ', $output); } - public function testTextArrayDrop() { + public function testTextArrayDrop() + { $template = new Template(); $template->parse('{% for text in product.texts.get_array %} {{text}} {% endfor %}'); $output = $template->render(array('product' => new ProductDrop())); @@ -97,21 +116,24 @@ public function testTextArrayDrop() { $this->assertEquals(' text1 text2 ', $output); } - public function testContextDrop() { + public function testContextDrop() + { $template = new Template(); $template->parse(' {{ context.bar }} '); $output = $template->render(array('context' => new ContextDrop(), 'bar' => 'carrot')); $this->assertEquals(' carrot ', $output); } - public function testNestedContextDrop() { + public function testNestedContextDrop() + { $template = new Template(); $template->parse(' {{ product.context.foo }} '); $output = $template->render(array('product' => new ProductDrop(), 'foo' => 'monkey')); $this->assertEquals(' monkey ', $output); } - public function testToString() { + public function testToString() + { $this->assertEquals(ProductDrop::class, strval(new ProductDrop())); } } diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index 85c5b4f4..e3e4b0e6 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -11,13 +11,15 @@ namespace Liquid; -class EscapeByDefaultTest extends TestCase { +class EscapeByDefaultTest extends TestCase +{ const XSS = ""; const XSS_FAILED = "<script>alert()</script>"; protected $assigns = array(); - protected function setup() { + protected function setup() + { parent::setUp(); $this->assigns = array( @@ -25,25 +27,29 @@ protected function setup() { ); } - public function testUnescaped() { + public function testUnescaped() + { $text = "{{ xss }}"; $expected = self::XSS; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testEscapedManually() { + public function testEscapedManually() + { $text = "{{ xss | escape }}"; $expected = self::XSS_FAILED; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testRawWithoutAutoEscape() { + public function testRawWithoutAutoEscape() + { $text = "{{ xss | raw }}"; $expected = self::XSS; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testEscapedAutomatically() { + public function testEscapedAutomatically() + { Liquid::set('ESCAPE_BY_DEFAULT', true); $text = "{{ xss }}"; @@ -51,7 +57,8 @@ public function testEscapedAutomatically() { $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testEscapedManuallyInAutoMode() { + public function testEscapedManuallyInAutoMode() + { Liquid::set('ESCAPE_BY_DEFAULT', true); // text should only be escaped once @@ -60,7 +67,8 @@ public function testEscapedManuallyInAutoMode() { $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testRawInAutoMode() { + public function testRawInAutoMode() + { Liquid::set('ESCAPE_BY_DEFAULT', true); $text = "{{ xss | raw }}"; @@ -68,7 +76,8 @@ public function testRawInAutoMode() { $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testNlToBr() { + public function testNlToBr() + { Liquid::set('ESCAPE_BY_DEFAULT', true); $text = "{{ xss | newline_to_br }}"; $expected = self::XSS."
\n".self::XSS; @@ -78,12 +87,14 @@ public function testNlToBr() { /** System default value for the escape flag */ private static $escapeDefault; - public static function setUpBeforeClass() { + public static function setUpBeforeClass() + { // save system default value for the escape flag before all tests self::$escapeDefault = Liquid::get('ESCAPE_BY_DEFAULT'); } - public function tearDown() { + public function tearDown() + { // reset to the default after each test Liquid::set('ESCAPE_BY_DEFAULT', self::$escapeDefault); } diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 0c281cab..0285def8 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -18,26 +18,31 @@ * * @return string */ -function functionFilter($value) { +function functionFilter($value) +{ return 'worked'; } /** * Global filter class */ -class ClassFilter { +class ClassFilter +{ private $variable = 'not set'; - public static function static_test() { + public static function static_test() + { return "worked"; } - public function instance_test_one() { + public function instance_test_one() + { $this->variable = 'set'; return 'set'; } - public function instance_test_two() { + public function instance_test_two() + { return $this->variable; } } @@ -46,14 +51,16 @@ public function instance_test_two() { namespace Liquid { -class FilterbankTest extends TestCase { +class FilterbankTest extends TestCase +{ /** @var FilterBank */ private $filterBank; /** @var Context */ private $context; - protected function setup() { + protected function setup() + { parent::setUp(); $this->context = new Context(); @@ -63,18 +70,21 @@ protected function setup() { /** * @expectedException \Liquid\LiquidException */ - public function testAddFilterNotObjectAndString() { + public function testAddFilterNotObjectAndString() + { $this->filterBank->addFilter(array()); } /** * @expectedException \Liquid\LiquidException */ - public function testAddFilterNoFunctionOrClass() { + public function testAddFilterNoFunctionOrClass() + { $this->filterBank->addFilter('no_such_function_or_class'); } - public function testInvokeNoFilter() { + public function testInvokeNoFilter() + { $value = 'value'; $this->assertEquals($value, $this->filterBank->invoke('non_existing_filter', $value)); } @@ -82,7 +92,8 @@ public function testInvokeNoFilter() { /** * Test using a simple function */ - public function testFunctionFilter() { + public function testFunctionFilter() + { $var = new Variable('var | functionFilter'); $this->context->set('var', 1000); $this->context->addFilters('functionFilter'); @@ -92,7 +103,8 @@ public function testFunctionFilter() { /** * Test using a static class */ - public function testStaticClassFilter() { + public function testStaticClassFilter() + { $var = new Variable('var | static_test'); $this->context->set('var', 1000); $this->context->addFilters('\ClassFilter'); @@ -103,7 +115,8 @@ public function testStaticClassFilter() { * Test using an object as a filter; an object fiter will retain its state * between calls to its filters. */ - public function testObjectFilter() { + public function testObjectFilter() + { $var = new Variable('var | instance_test_one'); $this->context->set('var', 1000); $this->context->addFilters(new \ClassFilter()); diff --git a/tests/Liquid/LiquidTest.php b/tests/Liquid/LiquidTest.php index 2c589892..10db5856 100644 --- a/tests/Liquid/LiquidTest.php +++ b/tests/Liquid/LiquidTest.php @@ -11,29 +11,35 @@ namespace Liquid; -class LiquidTest extends TestCase { - public function testGetNonExistingPropery() { +class LiquidTest extends TestCase +{ + public function testGetNonExistingPropery() + { $this->assertNull(Liquid::get('no_such_value')); } - public function testSetProperty() { + public function testSetProperty() + { $key = 'test_key'; $value = 'test_value'; Liquid::set($key, $value); $this->assertSame($value, Liquid::get($key)); } - public function testGetSetAllowedChars() { + public function testGetSetAllowedChars() + { Liquid::set('ALLOWED_VARIABLE_CHARS', 'abc'); $this->assertSame('abc', Liquid::get('ALLOWED_VARIABLE_CHARS')); $this->assertSame('abc+', Liquid::get('VARIABLE_NAME')); } - public function testArrayFlattenEmptyArray() { + public function testArrayFlattenEmptyArray() + { $this->assertSame(array(), Liquid::arrayFlatten(array())); } - public function testArrayFlattenFlatArray() { + public function testArrayFlattenFlatArray() + { $object = new \stdClass(); // Method does not maintain keys. @@ -52,7 +58,8 @@ public function testArrayFlattenFlatArray() { $this->assertEquals($expected, Liquid::arrayFlatten($original)); } - public function testArrayFlattenNestedArray() { + public function testArrayFlattenNestedArray() + { $object = new \stdClass(); // Method does not maintain keys. diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 3e1ef3c8..7bd22fca 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -11,10 +11,12 @@ namespace Liquid; -class LocalFileSystemTest extends TestCase { +class LocalFileSystemTest extends TestCase +{ protected $root; - protected function setUp() { + protected function setUp() + { $this->root = __DIR__ . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; // reset to defaults Liquid::set('INCLUDE_ALLOW_EXT', false); @@ -23,7 +25,8 @@ protected function setUp() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalTemplateNameEmpty() { + public function testIllegalTemplateNameEmpty() + { $fileSystem = new LocalFileSystem(''); $fileSystem->fullPath(''); } @@ -31,7 +34,8 @@ public function testIllegalTemplateNameEmpty() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalRootPath() { + public function testIllegalRootPath() + { $fileSystem = new LocalFileSystem('invalid/not/found'); $fileSystem->fullPath(''); } @@ -39,7 +43,8 @@ public function testIllegalRootPath() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalTemplateNameIncludeExtension() { + public function testIllegalTemplateNameIncludeExtension() + { Liquid::set('INCLUDE_ALLOW_EXT', false); $fileSystem = new LocalFileSystem(''); @@ -49,7 +54,8 @@ public function testIllegalTemplateNameIncludeExtension() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalTemplateNameNotIncludeExtension() { + public function testIllegalTemplateNameNotIncludeExtension() + { Liquid::set('INCLUDE_ALLOW_EXT', true); $fileSystem = new LocalFileSystem(''); @@ -59,7 +65,8 @@ public function testIllegalTemplateNameNotIncludeExtension() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalTemplatePathNoRoot() { + public function testIllegalTemplatePathNoRoot() + { $fileSystem = new LocalFileSystem(''); $fileSystem->fullPath('mypartial'); } @@ -67,7 +74,8 @@ public function testIllegalTemplatePathNoRoot() { /** * @expectedException \Liquid\LiquidException */ - public function testIllegalTemplatePathNoFileExists() { + public function testIllegalTemplatePathNoFileExists() + { $fileSystem = new LocalFileSystem(dirname(__DIR__)); $fileSystem->fullPath('no_such_file_exists'); } @@ -76,7 +84,8 @@ public function testIllegalTemplatePathNoFileExists() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage not under */ - public function testIllegalTemplatePathNotUnderTemplateRoot() { + public function testIllegalTemplatePathNotUnderTemplateRoot() + { Liquid::set('INCLUDE_ALLOW_EXT', true); $fileSystem = new LocalFileSystem(dirname($this->root)); // find any fail under deeper under the root, so all other checks would pass @@ -85,14 +94,16 @@ public function testIllegalTemplatePathNotUnderTemplateRoot() { $fileSystem->fullPath(self::TEMPLATES_DIR."/../../../{$filesUnderCurrentDir[0]}"); } - public function testValidPathWithDefaultExtension() { + public function testValidPathWithDefaultExtension() + { $templateName = 'mypartial'; $fileSystem = new LocalFileSystem($this->root); $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } - public function testValidPathWithCustomExtension() { + public function testValidPathWithCustomExtension() + { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); @@ -106,12 +117,14 @@ public function testValidPathWithCustomExtension() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage File not found */ - public function testReadIllegalTemplatePathNoFileExists() { + public function testReadIllegalTemplatePathNoFileExists() + { $fileSystem = new LocalFileSystem(dirname(__DIR__)); $fileSystem->readTemplateFile('no_such_file_exists'); } - public function testReadTemplateFile() { + public function testReadTemplateFile() + { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 2634052f..23503ea2 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -11,36 +11,45 @@ namespace Liquid; -class FunnyFilter { - public function make_funny($input) { +class FunnyFilter +{ + public function make_funny($input) + { return 'LOL'; } - public function cite_funny($input) { + public function cite_funny($input) + { return 'LOL: ' . $input; } - public function add_smiley($input, $smiley = ":-)") { + public function add_smiley($input, $smiley = ":-)") + { return $input . ' ' . $smiley; } - public function add_tag($input, $tag = "p", $id = "foo") { + public function add_tag($input, $tag = "p", $id = "foo") + { return "<" . $tag . " id=\"" . $id . "\">" . $input . ""; } - public function paragraph($input) { + public function paragraph($input) + { return "

" . $input . "

"; } - public function link_to($name, $url, $protocol) { + public function link_to($name, $url, $protocol) + { return "" . $name . ""; } } -class OutputTest extends TestCase { +class OutputTest extends TestCase +{ protected $assigns = array(); - protected function setup() { + protected function setup() + { parent::setUp(); $this->assigns = array( @@ -51,77 +60,88 @@ protected function setup() { $this->filters = new FunnyFilter(); } - public function testVariable() { + public function testVariable() + { $text = " {{best_cars}} "; $expected = " bmw "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariableTrasversing() { + public function testVariableTrasversing() + { $text = " {{car.bmw}} {{car.gm}} {{car.bmw}} "; $expected = " good bad good "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariablePiping() { + public function testVariablePiping() + { $text = " {{ car.gm | make_funny }} "; $expected = " LOL "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariablePipingWithInput() { + public function testVariablePipingWithInput() + { $text = " {{ car.gm | cite_funny }} "; $expected = " LOL: bad "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariablePipingWithArgs() { + public function testVariablePipingWithArgs() + { $text = " {{ car.gm | add_smiley : '=(' }} "; $expected = " bad =( "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function textVariablePipingWithNoArgs() { + public function textVariablePipingWithNoArgs() + { $text = " {{ car.gm | add_smile }} "; $expected = " bad =( "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testMultipleVariablePipingWithArgs() { + public function testMultipleVariablePipingWithArgs() + { $text = " {{ car.gm | add_smiley : '=(' | add_smiley : '=('}} "; $expected = " bad =( =( "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariablePipingWithTwoArgs() { + public function testVariablePipingWithTwoArgs() + { $text = " {{ car.gm | add_tag : 'span', 'bar'}} "; $expected = " bad "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testVariablePipingWithVariableArgs() { + public function testVariablePipingWithVariableArgs() + { $text = " {{ car.gm | add_tag : 'span', car.bmw}} "; $expected = " bad "; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testMultiplePipings() { + public function testMultiplePipings() + { $text = " {{ best_cars | cite_funny | paragraph }} "; $expected = "

LOL: bmw

"; $this->assertTemplateResult($expected, $text, $this->assigns); } - public function testLinkTo() { + public function testLinkTo() + { $text = " {{ 'Typo' | link_to: 'typo.leetsoft.com':'http' }} "; $expected = " Typo "; @@ -132,7 +152,8 @@ public function testLinkTo() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage was not properly terminated */ - public function testVariableWithANewLine() { + public function testVariableWithANewLine() + { $text = "{{ aaa\n }}"; $this->assertTemplateResult('', $text, $this->assigns); } diff --git a/tests/Liquid/ParsingQuirksTest.php b/tests/Liquid/ParsingQuirksTest.php index d735ead5..05a3752b 100644 --- a/tests/Liquid/ParsingQuirksTest.php +++ b/tests/Liquid/ParsingQuirksTest.php @@ -11,8 +11,10 @@ namespace Liquid; -class ParsingQuirksTest extends TestCase { - public function testErrorWithCss() { +class ParsingQuirksTest extends TestCase +{ + public function testErrorWithCss() + { $text = " div { font-weight: bold; } "; $template = new Template(); $template->parse($text); diff --git a/tests/Liquid/RegexpTest.php b/tests/Liquid/RegexpTest.php index 9fce8880..712295aa 100644 --- a/tests/Liquid/RegexpTest.php +++ b/tests/Liquid/RegexpTest.php @@ -11,47 +11,57 @@ namespace Liquid; -class RegexpTest extends TestCase { +class RegexpTest extends TestCase +{ /** @var Regexp */ protected $regexp; - protected function setup() { + protected function setup() + { parent::setUp(); $this->regexp = new Regexp('/' . Liquid::get('QUOTED_FRAGMENT') . '/'); } - public function testEmpty() { + public function testEmpty() + { $this->assertEquals(array(), $this->regexp->scan('')); } - public function testQuote() { + public function testQuote() + { $this->assertEquals(array('"arg 1"'), $this->regexp->scan('"arg 1"')); } - public function testWords() { + public function testWords() + { $this->assertEquals(array('arg1', 'arg2'), $this->regexp->scan('arg1 arg2')); } - public function testQuotedWords() { + public function testQuotedWords() + { $this->assertEquals(array('arg1', 'arg2', '"arg 3"'), $this->regexp->scan('arg1 arg2 "arg 3"')); } - public function testQuotedWords2() { + public function testQuotedWords2() + { $this->assertEquals(array('arg1', 'arg2', "'arg 3'"), $this->regexp->scan('arg1 arg2 \'arg 3\'')); } - public function testQuotedWordsInTheMiddle() { + public function testQuotedWordsInTheMiddle() + { $this->assertEquals(array('arg1', 'arg2', '"arg 3"', 'arg4'), $this->regexp->scan('arg1 arg2 "arg 3" arg4 ')); } - public function testPregQuote() { + public function testPregQuote() + { $this->assertEquals('', $this->regexp->quote('')); $this->assertEquals('abc', $this->regexp->quote('abc')); $this->assertEquals('\/\(\{\}\)\/', $this->regexp->quote('/({})/')); } - public function testNoDelimiter() { + public function testNoDelimiter() + { $regexp = new Regexp('(example)'); $this->assertEquals(array('(example)'), $regexp->scan('(example)')); $this->assertEquals(array(), $regexp->scan('nothing')); diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 66b04de8..0e0cf2ce 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -11,36 +11,45 @@ namespace Liquid; -class MoneyFilter { - public function money($value) { +class MoneyFilter +{ + public function money($value) + { return sprintf(' %d$ ', $value); } - public function money_with_underscore($value) { + public function money_with_underscore($value) + { return sprintf(' %d$ ', $value); } } -class CanadianMoneyFilter { - public function money($value) { +class CanadianMoneyFilter +{ + public function money($value) + { return sprintf(' %d$ CAD ', $value); } } -class SizeClass { +class SizeClass +{ const SIZE = 42; - public function toLiquid() { + public function toLiquid() + { return $this; } - public function size() { + public function size() + { return self::SIZE; } } -class StandardFiltersTest extends TestCase { +class StandardFiltersTest extends TestCase +{ /** * The current context * @@ -48,13 +57,15 @@ class StandardFiltersTest extends TestCase { */ public $context; - protected function setup() { + protected function setup() + { parent::setUp(); $this->context = new Context(); } - public function testSize() { + public function testSize() + { $data = array( 4 => 1000, 3 => 100, @@ -72,11 +83,13 @@ public function testSize() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage cannot be estimated */ - public function testSizeObject() { + public function testSizeObject() + { StandardFilters::size((object) array()); } - public function testDowncase() { + public function testDowncase() + { $data = array( 'UpperCaseMiXed' => 'uppercasemixed', 3 => 3, @@ -87,7 +100,8 @@ public function testDowncase() { } } - public function testUpcase() { + public function testUpcase() + { $data = array( 'UpperCaseMiXed' => 'UPPERCASEMIXED', 3 => 3, @@ -98,7 +112,8 @@ public function testUpcase() { } } - public function testCapitalize() { + public function testCapitalize() + { $data = array( 'one Word not' => 'One Word Not', '1test' => '1Test', @@ -110,7 +125,8 @@ public function testCapitalize() { } } - public function testUrlEncode() { + public function testUrlEncode() + { $data = array( 'nothing' => 'nothing', '%#&^' => '%25%23%26%5E', @@ -122,7 +138,8 @@ public function testUrlEncode() { } - public function testUrlDecode() { + public function testUrlDecode() + { $data = array( '%25%23%26%5E' => '%#&^', ); @@ -133,7 +150,8 @@ public function testUrlDecode() { } - public function testRaw() { + public function testRaw() + { $data = array( "Anything" => "Anything", 3 => 3, @@ -144,7 +162,8 @@ public function testRaw() { } } - public function testEscape() { + public function testEscape() + { $data = array( "one Word's not" => "one Word's not", "&><\"'" => "&><"'", @@ -155,7 +174,8 @@ public function testEscape() { } } - public function testEscapeOnce() { + public function testEscapeOnce() + { $data = array( "" => "<b><script>alert()</script>", "a < b & c" => "a < b & c", @@ -168,7 +188,8 @@ public function testEscapeOnce() { } } - public function testStripNewLines() { + public function testStripNewLines() + { $data = array( "one Word\r\n not\r\n\r\n" => "one Word not", 'test' => 'test', @@ -180,7 +201,8 @@ public function testStripNewLines() { } } - public function testNewLineToBr() { + public function testNewLineToBr() + { $data = array( "one Word\n not\n" => "one Word
\n not
\n", 'test' => 'test', @@ -192,7 +214,8 @@ public function testNewLineToBr() { } } - public function testReplace() { + public function testReplace() + { // Replace for empty string $data = array( "one Word not Word" => "one not ", @@ -216,7 +239,8 @@ public function testReplace() { } } - public function testReplaceFirst() { + public function testReplaceFirst() + { // Replace for empty string $data = array( "one Word not Word" => "one not Word", @@ -240,7 +264,8 @@ public function testReplaceFirst() { } } - public function testRemove() { + public function testRemove() + { $data = array( "one Word not Word" => "one not ", 'test' => 'test', @@ -252,7 +277,8 @@ public function testRemove() { } } - public function testRemoveFirst() { + public function testRemoveFirst() + { $data = array( "one Word not Word" => "one not Word", 'test' => 'test', @@ -264,7 +290,8 @@ public function testRemoveFirst() { } } - public function testAppend() { + public function testAppend() + { $data = array( "one Word not Word" => "one Word not Word appended", '' => ' appended', @@ -276,7 +303,8 @@ public function testAppend() { } } - public function testPrepend() { + public function testPrepend() + { $data = array( "one Word not Word" => "prepended one Word not Word", '' => 'prepended ', @@ -288,7 +316,8 @@ public function testPrepend() { } } - public function testSlice() { + public function testSlice() + { // Slice up to the end $data = array( array( @@ -374,7 +403,8 @@ public function testSlice() { } } - public function testTruncate() { + public function testTruncate() + { // Truncate with default ending $data = array( '' => '', @@ -394,7 +424,8 @@ public function testTruncate() { $this->assertEquals('abcend', StandardFilters::truncate('abcdef', 3, 'end')); } - public function testTruncateWords() { + public function testTruncateWords() + { // Truncate with default ending $data = array( '' => '', @@ -414,7 +445,8 @@ public function testTruncateWords() { $this->assertEquals('helloend', StandardFilters::truncatewords('hello from string', 1, 'end')); } - public function testStripHtml() { + public function testStripHtml() + { $data = array( '' => '', 'test no html tags' => 'test no html tags', @@ -427,7 +459,8 @@ public function testStripHtml() { } } - public function testJoin() { + public function testJoin() + { $data = array( array( array(), @@ -464,7 +497,8 @@ public function testJoin() { $this->assertEquals('1-2-3', StandardFilters::join(new \ArrayIterator(array(1, 2, 3)), '-')); } - public function testSort() { + public function testSort() + { $data = array( array( array(), @@ -528,14 +562,16 @@ public function testSortKey() { } */ - public function testDefault() { + public function testDefault() + { $this->assertEquals('hello', StandardFilters::_default('', 'hello')); $this->assertEquals('world', StandardFilters::_default('world', 'hello')); // check that our workaround for 'default' works as it should $this->assertTemplateResult('something', '{{ nothing | default: "something" }}'); } - public function testUnique() { + public function testUnique() + { $data = array( array( array(), @@ -560,7 +596,8 @@ public function testUnique() { } } - public function testReverse() { + public function testReverse() + { $data = array( array( array(), @@ -585,7 +622,8 @@ public function testReverse() { } } - public function testMap() { + public function testMap() + { $data = array( array( array(), @@ -642,7 +680,8 @@ function () { } } - public function testFirst() { + public function testFirst() + { $data = array( array( array(), @@ -675,7 +714,8 @@ public function testFirst() { } } - public function testLast() { + public function testLast() + { $data = array( array( array(), @@ -708,7 +748,8 @@ public function testLast() { } } - public function testSplit() { + public function testSplit() + { $data = array( array( '', @@ -725,7 +766,8 @@ public function testSplit() { } } - public function testStrip() { + public function testStrip() + { $data = array( array( '', @@ -746,7 +788,8 @@ public function testStrip() { } } - public function testLStrip() { + public function testLStrip() + { $data = array( array( '', @@ -767,7 +810,8 @@ public function testLStrip() { } } - public function testRStrip() { + public function testRStrip() + { $data = array( array( '', @@ -788,7 +832,8 @@ public function testRStrip() { } } - public function testPlus() { + public function testPlus() + { $data = array( array( '', @@ -812,7 +857,8 @@ public function testPlus() { } } - public function testMinus() { + public function testMinus() + { $data = array( array( '', @@ -841,7 +887,8 @@ public function testMinus() { } } - public function testTimes() { + public function testTimes() + { $data = array( array( '', @@ -870,7 +917,8 @@ public function testTimes() { } } - public function testDivideBy() { + public function testDivideBy() + { $data = array( array( '20', @@ -899,7 +947,8 @@ public function testDivideBy() { } } - public function testModulo() { + public function testModulo() + { $data = array( array( '20', @@ -933,7 +982,8 @@ public function testModulo() { } } - public function testRound() { + public function testRound() + { $data = array( array( '20.003', @@ -957,7 +1007,8 @@ public function testRound() { } } - public function testCeil() { + public function testCeil() + { $data = array( array( '20.003', @@ -978,7 +1029,8 @@ public function testCeil() { } } - public function testFloor() { + public function testFloor() + { $data = array( array( '20.003', @@ -1003,21 +1055,24 @@ public function testFloor() { } } - public function testLocalFilter() { + public function testLocalFilter() + { $var = new Variable('var | money'); $this->context->set('var', 1000); $this->context->addFilters(new MoneyFilter()); $this->assertEquals(' 1000$ ', $var->render($this->context)); } - public function testUnderscoreInFilterName() { + public function testUnderscoreInFilterName() + { $var = new Variable('var | money_with_underscore '); $this->context->set('var', 1000); $this->context->addFilters(new MoneyFilter()); $this->assertEquals(' 1000$ ', $var->render($this->context)); } - public function testSecondFilterOverwritesFirst() { + public function testSecondFilterOverwritesFirst() + { $var = new Variable('var | money '); $this->context->set('var', 1000); $this->context->addFilters(new MoneyFilter(), 'money'); @@ -1025,7 +1080,8 @@ public function testSecondFilterOverwritesFirst() { $this->assertEquals(' 1000$ CAD ', $var->render($this->context)); } - public function testDate() { + public function testDate() + { $var = new Variable('var | date, "%Y"'); $this->context->set('var', '2017-07-01 21:00:00'); $this->assertEquals('2017', $var->render($this->context)); diff --git a/tests/Liquid/Tag/NoTransformTest.php b/tests/Liquid/Tag/NoTransformTest.php index 06f6e6f6..709ac42d 100644 --- a/tests/Liquid/Tag/NoTransformTest.php +++ b/tests/Liquid/Tag/NoTransformTest.php @@ -13,8 +13,10 @@ use Liquid\TestCase; -class NoTransformTest extends TestCase { - public function testNoTransform() { +class NoTransformTest extends TestCase +{ + public function testNoTransform() + { $this->assertTemplateResult( 'this text should come out of the template without change...', 'this text should come out of the template without change...' diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index e2562450..f5be7852 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -18,13 +18,15 @@ * Basic tests for the assignment of one variable to another. This also tests the * assignment of filtered values to another variable. */ -class TagAssignTest extends TestCase { +class TagAssignTest extends TestCase +{ /** * Tests the normal behavior of throwing an exception when the assignment is incorrect * * @expectedException \Liquid\LiquidException */ - public function testInvalidAssign() { + public function testInvalidAssign() + { $template = new Template(); $template->parse('{% assign test %}'); @@ -33,7 +35,8 @@ public function testInvalidAssign() { /** * Tests a simple assignment with no filters */ - public function testSimpleAssign() { + public function testSimpleAssign() + { $template = new Template(); $template->parse('{% assign test = "hello" %}{{ test }}'); @@ -43,7 +46,8 @@ public function testSimpleAssign() { /** * Tests filtered value assignment */ - public function testAssignWithFilters() { + public function testAssignWithFilters() + { $template = new Template(); $template->parse('{% assign test = "hello" | upcase %}{{ test }}'); @@ -68,7 +72,8 @@ public function testAssignWithFilters() { /** * Tests a simple assignment with numbers */ - public function testNumbersAssign() { + public function testNumbersAssign() + { $this->assertTemplateResult('42', '{% assign i = 42 %}{{ i }}'); $this->assertTemplateResult('3.14', '{% assign i = 3.14 %}{{ i }}'); $this->assertTemplateResult('-100', '{% assign i = -100 %}{{ i }}'); diff --git a/tests/Liquid/Tag/TagBlockTest.php b/tests/Liquid/Tag/TagBlockTest.php index 49d4d0f0..b38bdeb5 100644 --- a/tests/Liquid/Tag/TagBlockTest.php +++ b/tests/Liquid/Tag/TagBlockTest.php @@ -13,15 +13,18 @@ use Liquid\TestCase; -class TagBlockTest extends TestCase { +class TagBlockTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxError() { + public function testSyntaxError() + { $this->assertTemplateResult('', '{% block %}'); } - public function testCreateBlock() { + public function testCreateBlock() + { $this->assertTemplateResult('block content', '{% block foo %}block content{% endblock %}'); } } diff --git a/tests/Liquid/Tag/TagBreakTest.php b/tests/Liquid/Tag/TagBreakTest.php index 4da7c845..a88c9f23 100644 --- a/tests/Liquid/Tag/TagBreakTest.php +++ b/tests/Liquid/Tag/TagBreakTest.php @@ -13,20 +13,24 @@ use Liquid\TestCase; -class TagBreakTest extends TestCase { - public function testFor() { +class TagBreakTest extends TestCase +{ + public function testFor() + { $this->assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); } - public function testRange() { + public function testRange() + { $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%break%} yo {%endfor%}'); $this->assertTemplateResult(' yo ', '{%for item in (3..6)%} yo {%break%} {%endfor%}'); $this->assertTemplateResult(' 3 4 ', '{%for item in (3..6)%} {%if item == 5%} {%break%} {%endif%} {{ item }} {%endfor%}'); } - public function testTablerow() { + public function testTablerow() + { $this->assertTemplateResult( "\n\n", '{%tablerow item in array%} {%break%} yo {%endtablerow%}', diff --git a/tests/Liquid/Tag/TagCaptureTest.php b/tests/Liquid/Tag/TagCaptureTest.php index ea9b45ba..44ee72fc 100644 --- a/tests/Liquid/Tag/TagCaptureTest.php +++ b/tests/Liquid/Tag/TagCaptureTest.php @@ -14,16 +14,19 @@ use Liquid\TestCase; use Liquid\Template; -class TagCaptureTest extends TestCase { +class TagCaptureTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntax() { + public function testInvalidSyntax() + { $template = new Template(); $template->parse("{% capture %} hello"); } - public function testCapture() { + public function testCapture() + { $assigns = array('var' => 'content'); $this->assertTemplateResult('content foo content foo ', '{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', $assigns); } diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index af0f370c..87e2e147 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -13,20 +13,26 @@ use Liquid\TestCase; -class Stringable { - public function __toString() { +class Stringable +{ + public function __toString() + { return "100"; } } -class HasToLiquid { - public function toLiquid() { +class HasToLiquid +{ + public function toLiquid() + { return "100"; } } -class TagCaseTest extends TestCase { - public function testCase() { +class TagCaseTest extends TestCase +{ + public function testCase() + { $assigns = array('condition' => 2); $this->assertTemplateResult(' its 2 ', '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', $assigns); @@ -43,7 +49,8 @@ public function testCase() { $this->assertTemplateResult('', '{% case condition %}{% when "string here" %} hit {% endcase %}', $assigns); } - public function testCaseWithElse() { + public function testCaseWithElse() + { $assigns = array('condition' => 5); $this->assertTemplateResult(' hit ', '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', $assigns); @@ -54,36 +61,42 @@ public function testCaseWithElse() { /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxErrorCase() { + public function testSyntaxErrorCase() + { $this->assertTemplateResult('', '{% case %}{% when 5 %}{% endcase %}'); } /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxErrorWhen() { + public function testSyntaxErrorWhen() + { $this->assertTemplateResult('', '{% case condition %}{% when %}{% endcase %}'); } /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxErrorEnd() { + public function testSyntaxErrorEnd() + { $this->assertTemplateResult('', '{% case condition %}{% end %}'); } /** * @expectedException \Liquid\LiquidException */ - public function testObject() { + public function testObject() + { $this->assertTemplateResult('', '{% case variable %}{% when 5 %}{% endcase %}', array('variable' => (object) array())); } - public function testStringable() { + public function testStringable() + { $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new Stringable())); } - public function testToLiquid() { + public function testToLiquid() + { $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new HasToLiquid())); } } diff --git a/tests/Liquid/Tag/TagCommentTest.php b/tests/Liquid/Tag/TagCommentTest.php index 9f1a3339..bf20bc5b 100644 --- a/tests/Liquid/Tag/TagCommentTest.php +++ b/tests/Liquid/Tag/TagCommentTest.php @@ -13,8 +13,10 @@ use Liquid\TestCase; -class TagCommentTest extends TestCase { - public function testHasABlockWhichDoesNothing() { +class TagCommentTest extends TestCase +{ + public function testHasABlockWhichDoesNothing() + { $this->assertTemplateResult( "the comment block should be removed .. right?", "the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?" diff --git a/tests/Liquid/Tag/TagContinueTest.php b/tests/Liquid/Tag/TagContinueTest.php index c8ef192a..e8603fe5 100644 --- a/tests/Liquid/Tag/TagContinueTest.php +++ b/tests/Liquid/Tag/TagContinueTest.php @@ -13,20 +13,24 @@ use Liquid\TestCase; -class TagContinueTest extends TestCase { - public function testFor() { +class TagContinueTest extends TestCase +{ + public function testFor() + { $this->assertTemplateResult(' ', '{%for item in array%} {%continue%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%continue%} {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' 1 2 4 ', '{%for item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); } - public function testRange() { + public function testRange() + { $this->assertTemplateResult(' ', '{%for item in (3..6)%} {%continue%} yo {%endfor%}'); $this->assertTemplateResult(' yo yo yo yo ', '{%for item in (3..6)%} yo {%continue%} {%endfor%}'); $this->assertTemplateResult(' 3 4 6 ', '{%for item in (3..6)%} {%if item == 5%} {%continue%} {%endif%} {{ item }} {%endfor%}'); } - public function testTablerow() { + public function testTablerow() + { $this->assertTemplateResult( "\n\n", '{%tablerow item in array%} {%continue%} yo {%endtablerow%}', diff --git a/tests/Liquid/Tag/TagCycleTest.php b/tests/Liquid/Tag/TagCycleTest.php index e530980c..4e6490f4 100644 --- a/tests/Liquid/Tag/TagCycleTest.php +++ b/tests/Liquid/Tag/TagCycleTest.php @@ -14,30 +14,36 @@ use Liquid\TestCase; use Liquid\Template; -class TagCycleTest extends TestCase { +class TagCycleTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntax() { + public function testInvalidSyntax() + { $template = new Template(); $template->parse("{% cycle %}"); } - public function testCycle() { + public function testCycle() + { $this->assertTemplateResult('one', '{%cycle "one", "two"%}'); $this->assertTemplateResult('one two', '{%cycle "one", "two"%} {%cycle "one", "two"%}'); $this->assertTemplateResult('one two one', '{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}'); } - public function testMultipleCycles() { + public function testMultipleCycles() + { $this->assertTemplateResult('1 2 1 1 2 3 1', '{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}'); } - public function testMultipleNamedCycles() { + public function testMultipleNamedCycles() + { $this->assertTemplateResult('one one two two one one', '{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}'); } - public function testMultipleNamedCyclesWithNamesFromContext() { + public function testMultipleNamedCyclesWithNamesFromContext() + { $assigns = array("var1" => 1, "var2" => 2); $this->assertTemplateResult('one one two two one one', '{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', $assigns); } diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index 2c90e12c..62af2feb 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -13,30 +13,36 @@ use Liquid\TestCase; -class TagDecrementTest extends TestCase { +class TagDecrementTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxError() { + public function testSyntaxError() + { $this->assertTemplateResult('', '{% decrement %}'); } /** * Undefined variable will become -1 */ - public function testDecrementNonExistingVariable() { + public function testDecrementNonExistingVariable() + { $this->assertTemplateResult(-1, '{% decrement no_such_var %}{{ no_such_var }}'); } - public function testDecrementVariable() { + public function testDecrementVariable() + { $this->assertTemplateResult(42, '{% decrement var %}{{ var }}', array('var' => 43)); } - public function testDecrementNestedVariable() { + public function testDecrementNestedVariable() + { $this->assertTemplateResult(42, '{% for var in vars %}{% decrement var %}{{ var }}{% endfor %}', array('vars' => array(43))); } - public function testVariableNameContainingNumber() { + public function testVariableNameContainingNumber() + { $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', array('var123' => 43)); } } diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index fba1fa83..1afacedc 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -19,10 +19,12 @@ /** * @see TagExtends */ -class TagExtendsTest extends TestCase { +class TagExtendsTest extends TestCase +{ private $fs; - protected function setUp() { + protected function setUp() + { $this->fs = new Virtual(function ($templatePath) { if ($templatePath == 'base') { return "{% block content %}{% endblock %}{% block footer %}{% endblock %}"; @@ -34,12 +36,14 @@ protected function setUp() { }); } - protected function tearDown() { + protected function tearDown() + { // PHP goes nuts unless we unset it unset($this->fs); } - public function testBasicExtends() { + public function testBasicExtends() + { $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); @@ -47,7 +51,8 @@ public function testBasicExtends() { $this->assertEquals("Hello!", $output); } - public function testDefaultContentExtends() { + public function testDefaultContentExtends() + { $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% block content %}{{ hello }}{% endblock %}\n{% extends 'sub-base' %}"); @@ -55,7 +60,8 @@ public function testDefaultContentExtends() { $this->assertEquals("Hello!\n Boo! ", $output); } - public function testDeepExtends() { + public function testDeepExtends() + { $template = new Template(); $template->setFileSystem($this->fs); $template->parse('{% extends "sub-base" %}{% block content %}{{ hello }}{% endblock %}{% block footer %} I am a footer.{% endblock %}'); @@ -64,7 +70,8 @@ public function testDeepExtends() { $this->assertEquals("Hello! I am a footer.", $output); } - public function testWithCache() { + public function testWithCache() + { $template = new Template(); $template->setFileSystem($this->fs); $template->setCache(new Local()); @@ -81,7 +88,8 @@ public function testWithCache() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxNoTemplateName() { + public function testInvalidSyntaxNoTemplateName() + { $template = new Template(); $template->parse("{% extends %}"); } @@ -89,7 +97,8 @@ public function testInvalidSyntaxNoTemplateName() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxNotQuotedTemplateName() { + public function testInvalidSyntaxNotQuotedTemplateName() + { $template = new Template(); $template->parse("{% extends base %}"); } @@ -97,7 +106,8 @@ public function testInvalidSyntaxNotQuotedTemplateName() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxEmptyTemplateName() { + public function testInvalidSyntaxEmptyTemplateName() + { $template = new Template(); $template->parse("{% extends '' %}"); } @@ -105,7 +115,8 @@ public function testInvalidSyntaxEmptyTemplateName() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxInvalidKeyword() { + public function testInvalidSyntaxInvalidKeyword() + { $template = new Template(); $template->parse("{% extends 'base' nothing-should-be-here %}"); } diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 013b250c..edc59f37 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -14,16 +14,19 @@ use Liquid\TestCase; use Liquid\Template; -class TagForTest extends TestCase { +class TagForTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testForInvalidSyntax() { + public function testForInvalidSyntax() + { $template = new Template(); $template->parse("{% for elem %}{% endfor %}"); } - public function testFor() { + public function testFor() + { $this->assertTemplateResult('', '{%for item in array%} yo {%endfor%}', array('array' => array())); $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); $this->assertTemplateResult(' boo boo boo boo ', '{%for item in array%} boo {%endfor%}', array('array' => new \ArrayIterator(array(1, 2, 3, 4)))); @@ -48,7 +51,8 @@ public function testFor() { $this->assertTemplateResult($expected, $template, array('array' => array(1, 2, 3))); } - public function testForWithVariable() { + public function testForWithVariable() + { $this->assertTemplateResult(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', array('array' => array(1, 2, 3))); $this->assertTemplateResult('123', '{%for item in array%}{{item}}{%endfor%}', array('array' => array(1, 2, 3))); $this->assertTemplateResult('123', '{% for item in array %}{{item}}{% endfor %}', array('array' => array(1, 2, 3))); @@ -57,11 +61,13 @@ public function testForWithVariable() { $this->assertTemplateResult('abc', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', '', 'b', '', 'c'))); } - public function testForWithHash() { + public function testForWithHash() + { $this->assertTemplateResult('a=b c=d e=f ', '{%for item in array%}{{item[0]}}={{item[1]}} {%endfor%}', array('array' => array('a' => 'b', 'c' => 'd', 'e' => 'f'))); } - public function testForHelpers() { + public function testForHelpers() + { $assigns = array('array' => array(1, 2, 3)); $this->assertTemplateResult(' 1/3 2/3 3/3 ', '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}', $assigns); @@ -73,7 +79,8 @@ public function testForHelpers() { $this->assertTemplateResult(' 0 0 1 ', '{%for item in array%} {{forloop.last}} {%endfor%}', $assigns); } - public function testForHelpersWithOffsetAndLimit() { + public function testForHelpersWithOffsetAndLimit() + { $assigns = array('array' => array(0, 1, 2, 3, 4)); $this->assertTemplateResult(' 1/3 2/3 3/3 ', '{%for item in array offset:1 limit:3%} {{forloop.index}}/{{forloop.length}} {%endfor%}', $assigns); @@ -85,14 +92,16 @@ public function testForHelpersWithOffsetAndLimit() { $this->assertTemplateResult(' 0 0 1 ', '{%for item in array offset:1 limit:3%} {{forloop.last}} {%endfor%}', $assigns); } - public function testForAndIf() { + public function testForAndIf() + { $assigns = array('array' => array(1, 2, 3)); $this->assertTemplateResult(' yay ', '{%for item in array%} {% if forloop.first %}yay{% endif %} {%endfor%}', $assigns); $this->assertTemplateResult(' yay boo boo ', '{%for item in array%} {% if forloop.first %}yay{% else %}boo{% endif %} {%endfor%}', $assigns); $this->assertTemplateResult(' boo boo ', '{%for item in array%} {% if forloop.first %}{% else %}boo{% endif %} {%endfor%}', $assigns); } - public function testLimiting() { + public function testLimiting() + { $assigns = array('array' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); $this->assertTemplateResult('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('1234567890', '{%for i in array limit:20 %}{{ i }}{%endfor%}', $assigns); @@ -105,17 +114,20 @@ public function testLimiting() { $this->assertTemplateResult('34', '{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}', $assigns); } - public function testNestedFor() { + public function testNestedFor() + { $assigns = array('array' => array(array(1, 2), array(3, 4), array(5, 6))); $this->assertTemplateResult('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', $assigns); } - public function testOffsetOnly() { + public function testOffsetOnly() + { $assigns = array('array' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); $this->assertTemplateResult('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', $assigns); } - public function testPauseResume() { + public function testPauseResume() + { $assigns = array('array' => array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); $markup = <<assertTemplateResult($expected, $markup, $assigns); } - public function testPauseResumeLimit() { + public function testPauseResumeLimit() + { $assigns = array('array' => array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); $markup = <<assertTemplateResult($expected, $markup, $assigns); } - public function testPauseResumeBIGLimit() { + public function testPauseResumeBIGLimit() + { $assigns = array('array' => array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); $markup = <<assertTemplateResult($expected, $markup, $assigns); } - public function testPauseResumeBIGOffset() { + public function testPauseResumeBIGOffset() + { $assigns = array('array' => array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); $markup = <<assertTemplateResult($expected, $markup, $assigns); } - public function testForWithRanges() { + public function testForWithRanges() + { $this->assertTemplateResult('123456789', '{%for i in (1..9)%}{{i}}{%endfor%}'); $this->assertTemplateResult(' 9 10 11', '{%for i in (9..11)%} {{i}}{%endfor%}'); $this->assertTemplateResult('9991000', '{%for i in (999..1000)%}{{i}}{%endfor%}'); diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 3caeca0f..0675986c 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -13,44 +13,52 @@ use Liquid\TestCase; -class TagIfTest extends TestCase { - public function testTrueEqlTrue() { +class TagIfTest extends TestCase +{ + public function testTrueEqlTrue() + { $text = " {% if true == true %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testTrueNotEqlTrue() { + public function testTrueNotEqlTrue() + { $text = " {% if true != true %} true {% else %} false {% endif %} "; $expected = " false "; $this->assertTemplateResult($expected, $text); } - public function testTrueLqTrue() { + public function testTrueLqTrue() + { $text = " {% if 0 > 0 %} true {% else %} false {% endif %} "; $expected = " false "; $this->assertTemplateResult($expected, $text); } - public function testOneLqZero() { + public function testOneLqZero() + { $text = " {% if 1 > 0 %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testZeroLqOne() { + public function testZeroLqOne() + { $text = " {% if 0 < 1 %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testZeroLqOrEqualOne() { + public function testZeroLqOrEqualOne() + { $text = " {% if 0 <= 0 %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testZeroLqOrEqualOneInvolvingNil() { + public function testZeroLqOrEqualOneInvolvingNil() + { $text = " {% if null <= 0 %} true {% else %} false {% endif %} "; $expected = " false "; $this->assertTemplateResult($expected, $text); @@ -61,49 +69,57 @@ public function testZeroLqOrEqualOneInvolvingNil() { $this->assertTemplateResult($expected, $text); } - public function testZeroLqqOrEqualOne() { + public function testZeroLqqOrEqualOne() + { $text = " {% if 0 >= 0 %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testStrings() { + public function testStrings() + { $text = " {% if 'test' == 'test' %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testStringsNotEqual() { + public function testStringsNotEqual() + { $text = " {% if 'test' != 'test' %} true {% else %} false {% endif %} "; $expected = " false "; $this->assertTemplateResult($expected, $text); } - public function testVarStringsEqual() { + public function testVarStringsEqual() + { $text = " {% if var == \"hello there!\" %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); } - public function testVarStringsAreNotEqual() { + public function testVarStringsAreNotEqual() + { $text = " {% if \"hello there!\" == var %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); } - public function testVarAndLongStringAreEqual() { + public function testVarAndLongStringAreEqual() + { $text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); } - public function testVarAndLongStringAreEqualBackwards() { + public function testVarAndLongStringAreEqualBackwards() + { $text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); } - public function testIsCollectionEmpty() { + public function testIsCollectionEmpty() + { $text = " {% if array == empty %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('array' => array())); @@ -113,13 +129,15 @@ public function testIsCollectionEmpty() { $this->assertTemplateResult($expected, $text, array('array' => array())); } - public function testIsNotCollectionEmpty() { + public function testIsNotCollectionEmpty() + { $text = " {% if array == empty %} true {% else %} false {% endif %} "; $expected = " false "; $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 3))); } - public function testNil() { + public function testNil() + { $text = " {% if var == null %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => null)); @@ -129,7 +147,8 @@ public function testNil() { $this->assertTemplateResult($expected, $text, array('var' => null)); } - public function testNotNil() { + public function testNotNil() + { $text = " {% if var != null %} true {% else %} false {% endif %} "; $expected = " true "; $this->assertTemplateResult($expected, $text, array('var' => 1)); @@ -139,7 +158,8 @@ public function testNotNil() { $this->assertTemplateResult($expected, $text, array('var' => 1)); } - public function testIfFromVariable() { + public function testIfFromVariable() + { $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => false)); $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => null)); $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', array('foo' => array('bar' => false))); @@ -167,7 +187,8 @@ public function testIfFromVariable() { $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', array('notfoo' => array('bar' => true))); } - public function testNestedIf() { + public function testNestedIf() + { $this->assertTemplateResult('', '{% if false %}{% if false %} NO {% endif %}{% endif %}'); $this->assertTemplateResult('', '{% if false %}{% if true %} NO {% endif %}{% endif %}'); $this->assertTemplateResult('', '{% if true %}{% if false %} NO {% endif %}{% endif %}'); @@ -178,14 +199,16 @@ public function testNestedIf() { $this->assertTemplateResult(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}'); } - public function testComplexConditions() { + public function testComplexConditions() + { $this->assertTemplateResult('true', '{% if 10 == 10 and "h" == "h" %}true{% else %}false{% endif %}'); $this->assertTemplateResult('true', '{% if 8 == 10 or "h" == "h" %}true{% else %}false{% endif %}'); $this->assertTemplateResult('false', '{% if 8 == 10 and "h" == "h" %}true{% else %}false{% endif %}'); $this->assertTemplateResult('true', '{% if 10 == 10 or "h" == "k" or "k" == "k" %}true{% else %}false{% endif %}'); } - public function testContains() { + public function testContains() + { $this->assertTemplateResult('true', '{% if foo contains "h" %}true{% else %}false{% endif %}', array('foo' => array('k', 'h', 'z'))); $this->assertTemplateResult('false', '{% if foo contains "y" %}true{% else %}false{% endif %}', array('foo' => array('k', 'h', 'z'))); $this->assertTemplateResult('true', '{% if foo contains "e" %}true{% else %}false{% endif %}', array('foo' => 'abcedf')); @@ -197,28 +220,32 @@ public function testContains() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage if tag was never closed */ - public function testSyntaxErrorNotClosed() { + public function testSyntaxErrorNotClosed() + { $this->assertTemplateResult('', '{% if jerry == 1 %}'); } /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxErrorEnd() { + public function testSyntaxErrorEnd() + { $this->assertTemplateResult('', '{% if jerry == 1 %}{% end %}'); } /** * @expectedException \Liquid\LiquidException */ - public function testInvalidOperator() { + public function testInvalidOperator() + { $this->assertTemplateResult('', '{% if foo === y %}true{% else %}false{% endif %}', array('foo' => true, 'y' => true)); } /** * @expectedException \Liquid\LiquidException */ - public function testIncomparable() { + public function testIncomparable() + { $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', array('foo' => (object) array())); } @@ -226,7 +253,8 @@ public function testIncomparable() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage does not expect else tag */ - public function testSyntaxErrorElse() { + public function testSyntaxErrorElse() + { $this->assertTemplateResult('', '{% if foo == 1 %}{% endif %}{% else %}'); } @@ -234,7 +262,8 @@ public function testSyntaxErrorElse() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage Unknown tag */ - public function testSyntaxErrorUnknown() { + public function testSyntaxErrorUnknown() + { $this->assertTemplateResult('', '{% unknown-tag %}'); } } diff --git a/tests/Liquid/Tag/TagIfchangedTest.php b/tests/Liquid/Tag/TagIfchangedTest.php index 1d78acf2..e787668f 100644 --- a/tests/Liquid/Tag/TagIfchangedTest.php +++ b/tests/Liquid/Tag/TagIfchangedTest.php @@ -13,14 +13,17 @@ use Liquid\TestCase; -class TagIfchangedTest extends TestCase { - public function testWorks() { +class TagIfchangedTest extends TestCase +{ + public function testWorks() + { $text = "{% for i in array %}{% ifchanged %} {{ i }} {% endifchanged %}{% endfor %}"; $expected = " 1 2 3 "; $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 3))); } - public function testFails() { + public function testFails() + { $text = "{% for i in array %}{% ifchanged %} {{ i }} {% endifchanged %}{% endfor %}"; $expected = " 1 2 1 "; $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 2, 1))); diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index dd48b68a..273f2730 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -18,17 +18,20 @@ use Liquid\FileSystem\Virtual; use Liquid\TestFileSystem; -class TagIncludeTest extends TestCase { +class TagIncludeTest extends TestCase +{ private $fs; - protected function setUp() { + protected function setUp() + { $this->fs = TestFileSystem::fromArray(array( 'inner' => "Inner: {{ inner }}{{ other }}", 'example' => "Example: {% include 'inner' %}", )); } - protected function tearDown() { + protected function tearDown() + { // PHP goes nuts unless we unset it unset($this->fs); } @@ -36,7 +39,8 @@ protected function tearDown() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxNoTemplateName() { + public function testInvalidSyntaxNoTemplateName() + { $template = new Template(); $template->parse("{% include %}"); } @@ -44,7 +48,8 @@ public function testInvalidSyntaxNoTemplateName() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxNotQuotedTemplateName() { + public function testInvalidSyntaxNotQuotedTemplateName() + { $template = new Template(); $template->parse("{% include hello %}"); } @@ -52,7 +57,8 @@ public function testInvalidSyntaxNotQuotedTemplateName() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxInvalidKeyword() { + public function testInvalidSyntaxInvalidKeyword() + { $template = new Template(); $template->parse("{% include 'hello' no_keyword %}"); } @@ -60,12 +66,14 @@ public function testInvalidSyntaxInvalidKeyword() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntaxNoObjectCollection() { + public function testInvalidSyntaxNoObjectCollection() + { $template = new Template(); $template->parse("{% include 'hello' with %}"); } - public function testIncludeTag() { + public function testIncludeTag() + { $template = new Template(); $template->setFileSystem($this->fs); @@ -76,7 +84,8 @@ public function testIncludeTag() { $this->assertEquals("Outer-Inner: value23-OuterInner: 1loopInner: 2loopInner: 3loop", $output); } - public function testIncludeTagNoWith() { + public function testIncludeTagNoWith() + { $template = new Template(); $template->setFileSystem($this->fs); @@ -87,7 +96,8 @@ public function testIncludeTagNoWith() { $this->assertEquals("Outer-Inner: orig-Outer-Inner: orig23", $output); } - public function testWithCache() { + public function testWithCache() + { $template = new Template(); $template->setFileSystem($this->fs); $template->setCache(new Local()); @@ -101,7 +111,8 @@ public function testWithCache() { $template->setCache(null); } - public function testIncludeTemplateFile() { + public function testIncludeTemplateFile() + { Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); @@ -111,7 +122,8 @@ public function testIncludeTemplateFile() { $this->assertEquals("test content\n", $template->render()); } - public function testIncludePassPlainValue() { + public function testIncludePassPlainValue() + { $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other }}]", @@ -128,7 +140,8 @@ public function testIncludePassPlainValue() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage Use index operator */ - public function testIncludePassArrayWithoutIndex() { + public function testIncludePassArrayWithoutIndex() + { $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other }}]", @@ -139,7 +152,8 @@ public function testIncludePassArrayWithoutIndex() { $template->render(array("var" => array("a", "b", "c"))); } - public function testIncludePassArrayWithIndex() { + public function testIncludePassArrayWithIndex() + { $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other[0] }}]", @@ -152,7 +166,8 @@ public function testIncludePassArrayWithIndex() { $this->assertEquals("([a])", $output); } - public function testIncludePassObjectValue() { + public function testIncludePassObjectValue() + { $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other.a }}]", diff --git a/tests/Liquid/Tag/TagIncrementTest.php b/tests/Liquid/Tag/TagIncrementTest.php index d48eaeb6..0d4449c8 100644 --- a/tests/Liquid/Tag/TagIncrementTest.php +++ b/tests/Liquid/Tag/TagIncrementTest.php @@ -13,26 +13,31 @@ use Liquid\TestCase; -class TagIncrementTest extends TestCase { +class TagIncrementTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxError() { + public function testSyntaxError() + { $this->assertTemplateResult('', '{% increment %}'); } /** * Undefined variable will become 0 */ - public function testIncrementNonExistingVariable() { + public function testIncrementNonExistingVariable() + { $this->assertTemplateResult(0, '{% increment no_such_var %}{{ no_such_var }}'); } - public function testIncrementVariable() { + public function testIncrementVariable() + { $this->assertTemplateResult(42, '{% increment var %}{{ var }}', array('var' => 41)); } - public function testIncrementNestedVariable() { + public function testIncrementNestedVariable() + { $this->assertTemplateResult(42, '{% for var in vars %}{% increment var %}{{ var }}{% endfor %}', array('vars' => array(41))); } } diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 019c8b0b..701e58fd 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -13,20 +13,24 @@ use Liquid\TestCase; -class TagPaginateTest extends TestCase { - public function testWorks() { +class TagPaginateTest extends TestCase +{ + public function testWorks() + { $text = "{% paginate products by 3 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; $expected = " 1 2 3 "; $this->assertTemplateResult($expected, $text, array('products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); } - public function testVariables() { + public function testVariables() + { $text = " {% paginate search.products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {{ paginate.next.url }}{% endpaginate %}"; $expected = " 3 1 0 2 5 http://?page=2"; $this->assertTemplateResult($expected, $text, array('search' => array('products' => new \ArrayIterator(array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))))); } - public function testNextPage() { + public function testNextPage() + { $text = '{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{{ paginate.next.title }}{% endpaginate %}'; $expected = ' 2 Next'; $this->assertTemplateResult($expected, $text, array('HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); @@ -35,7 +39,8 @@ public function testNextPage() { /** * @expectedException \Liquid\LiquidException */ - public function testSyntaxErrorCase() { + public function testSyntaxErrorCase() + { $this->assertTemplateResult('', '{% paginate products %}{% endpaginate %}'); } } diff --git a/tests/Liquid/Tag/TagRawTest.php b/tests/Liquid/Tag/TagRawTest.php index 71d9a1a5..37ac7877 100644 --- a/tests/Liquid/Tag/TagRawTest.php +++ b/tests/Liquid/Tag/TagRawTest.php @@ -13,8 +13,10 @@ use Liquid\TestCase; -class TagRawTest extends TestCase { - public function testRaw() { +class TagRawTest extends TestCase +{ + public function testRaw() + { $this->assertTemplateResult( '{{ y | plus: x }}{{{hello}}} is equal to 11.', '{% raw %}{{ y | plus: x }}{{{hello}}}{% endraw %} is equal to 11.', diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index 8fd6b9b7..738495f3 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -13,8 +13,10 @@ use Liquid\TestCase; -class TagTablerowTest extends TestCase { - public function testTablerow() { +class TagTablerowTest extends TestCase +{ + public function testTablerow() + { $this->assertTemplateResult( ''."\n".' yo yo yo yo '."\n", '{% tablerow item in array %} yo {% endtablerow %}', @@ -47,14 +49,16 @@ public function testTablerow() { /** * @expectedException \Liquid\LiquidException */ - public function testInvalidSyntax() { + public function testInvalidSyntax() + { $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); } /** * @expectedException \Liquid\LiquidException */ - public function testNotArray() { + public function testNotArray() + { $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); } } diff --git a/tests/Liquid/Tag/TagUnlessTest.php b/tests/Liquid/Tag/TagUnlessTest.php index 8f95f0da..7132a9bc 100644 --- a/tests/Liquid/Tag/TagUnlessTest.php +++ b/tests/Liquid/Tag/TagUnlessTest.php @@ -13,20 +13,24 @@ use Liquid\TestCase; -class TagUnlessTest extends TestCase { - public function testTrueEqlTrue() { +class TagUnlessTest extends TestCase +{ + public function testTrueEqlTrue() + { $text = " {% unless true == true %} true {% else %} false {% endunless %} "; $expected = " false "; $this->assertTemplateResult($expected, $text); } - public function testTrueNotEqlTrue() { + public function testTrueNotEqlTrue() + { $text = " {% unless true != true %} true {% else %} false {% endunless %} "; $expected = " true "; $this->assertTemplateResult($expected, $text); } - public function testWithVariable() { + public function testWithVariable() + { $text = " {% unless variable %} true {% else %} false {% endunless %} "; $expected = " false "; $this->assertTemplateResult($expected, $text, array('variable' => true)); diff --git a/tests/Liquid/TemplateTest.php b/tests/Liquid/TemplateTest.php index f895c136..df243cc0 100644 --- a/tests/Liquid/TemplateTest.php +++ b/tests/Liquid/TemplateTest.php @@ -11,19 +11,22 @@ namespace Liquid; -class TemplateTest extends TestCase { +class TemplateTest extends TestCase +{ const CACHE_DIR = 'cache_dir'; /** @var string full path to cache dir */ protected $cacheDir; - protected function setUp() { + protected function setUp() + { parent::setUp(); $this->cacheDir = __DIR__ . DIRECTORY_SEPARATOR . self::CACHE_DIR; } - protected function tearDown() { + protected function tearDown() + { parent::tearDown(); // Remove tmp cache files @@ -33,7 +36,8 @@ protected function tearDown() { /** * @expectedException \Liquid\LiquidException */ - public function testSetCacheInvalidKey() { + public function testSetCacheInvalidKey() + { $template = new Template(); $template->setCache(array()); } @@ -41,44 +45,51 @@ public function testSetCacheInvalidKey() { /** * @expectedException \Liquid\LiquidException */ - public function testSetCacheInvalidClass() { + public function testSetCacheInvalidClass() + { $template = new Template(); $template->setCache(array('cache' => 'no_such_class')); } - public function testSetCacheThroughArray() { + public function testSetCacheThroughArray() + { $template = new Template(); $template->setCache(array('cache' => 'file', 'cache_dir' => $this->cacheDir)); $this->assertInstanceOf('\Liquid\Cache\File', $template::getCache()); } - public function testSetCacheThroughCacheObject() { + public function testSetCacheThroughCacheObject() + { $template = new Template(); $cache = new Cache\File(array('cache_dir' => $this->cacheDir)); $template->setCache($cache); $this->assertEquals($cache, $template::getCache()); } - public function testTokenizeStrings() { + public function testTokenizeStrings() + { $this->assertEquals(array(' '), Template::tokenize(' ')); $this->assertEquals(array('hello world'), Template::tokenize('hello world')); } - public function testTokenizeVariables() { + public function testTokenizeVariables() + { $this->assertEquals(array('{{funk}}'), Template::tokenize('{{funk}}')); $this->assertEquals(array(' ', '{{funk}}', ' '), Template::tokenize(' {{funk}} ')); $this->assertEquals(array(' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '), Template::tokenize(' {{funk}} {{so}} {{brother}} ')); $this->assertEquals(array(' ', '{{ funk }}', ' '), Template::tokenize(' {{ funk }} ')); } - public function testTokenizeBlocks() { + public function testTokenizeBlocks() + { $this->assertEquals(array('{%comment%}'), Template::tokenize('{%comment%}')); $this->assertEquals(array(' ', '{%comment%}', ' '), Template::tokenize(' {%comment%} ')); $this->assertEquals(array(' ', '{%comment%}', ' ', '{%endcomment%}', ' '), Template::tokenize(' {%comment%} {%endcomment%} ')); $this->assertEquals(array(' ', '{% comment %}', ' ', '{% endcomment %}', ' '), Template::tokenize(" {% comment %} {% endcomment %} ")); } - public function testBlackspace() { + public function testBlackspace() + { $template = new Template(); $template->parse(' '); @@ -87,7 +98,8 @@ public function testBlackspace() { $this->assertEquals(array(' '), $nodelist); } - public function testVariableBeginning() { + public function testVariableBeginning() + { $template = new Template(); $template->parse('{{funk}} '); @@ -98,7 +110,8 @@ public function testVariableBeginning() { $this->assertInternalType('string', $nodelist[1]); } - public function testVariableEnd() { + public function testVariableEnd() + { $template = new Template(); $template->parse(' {{funk}}'); @@ -109,7 +122,8 @@ public function testVariableEnd() { $this->assertInstanceOf('\Liquid\Variable', $nodelist[1]); } - public function testVariableMiddle() { + public function testVariableMiddle() + { $template = new Template(); $template->parse(' {{funk}} '); @@ -121,7 +135,8 @@ public function testVariableMiddle() { $this->assertInternalType('string', $nodelist[2]); } - public function testVariableManyEmbeddedFragments() { + public function testVariableManyEmbeddedFragments() + { $template = new Template(); $template->parse(' {{funk}} {{soul}} {{brother}} '); @@ -137,7 +152,8 @@ public function testVariableManyEmbeddedFragments() { $this->assertInternalType('string', $nodelist[6]); } - public function testWithBlock() { + public function testWithBlock() + { $template = new Template(); $template->parse(' {% comment %} {% endcomment %} '); diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index b114914d..9887bc30 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -11,7 +11,8 @@ namespace Liquid; -class TestCase extends \PHPUnit_Framework_TestCase { +class TestCase extends \PHPUnit_Framework_TestCase +{ const TEMPLATES_DIR = 'templates'; /** @@ -19,7 +20,8 @@ class TestCase extends \PHPUnit_Framework_TestCase { */ public $filters; - protected function setUp() { + protected function setUp() + { parent::setUp(); $defaultConfig = array( @@ -51,7 +53,8 @@ protected function setUp() { * @param array $assigns * @param string $message */ - public function assertTemplateResult($expected, $templateString, array $assigns = array(), $message = "%s") { + public function assertTemplateResult($expected, $templateString, array $assigns = array(), $message = "%s") + { $template = new Template(); $template->parse($templateString); diff --git a/tests/Liquid/TestFileSystem.php b/tests/Liquid/TestFileSystem.php index 4d608506..899eee9e 100644 --- a/tests/Liquid/TestFileSystem.php +++ b/tests/Liquid/TestFileSystem.php @@ -13,9 +13,11 @@ use Liquid\FileSystem\Virtual; -class TestFileSystem extends Virtual { +class TestFileSystem extends Virtual +{ /** @return TestFileSystem */ - public static function fromArray($array) { + public static function fromArray($array) + { return new static(function ($path) use ($array) { if (isset($array[$path])) { return $array[$path]; diff --git a/tests/Liquid/VariableResolutionTest.php b/tests/Liquid/VariableResolutionTest.php index a35a1f7c..b3105cba 100644 --- a/tests/Liquid/VariableResolutionTest.php +++ b/tests/Liquid/VariableResolutionTest.php @@ -11,14 +11,17 @@ namespace Liquid; -class VariableResolutionTest extends TestCase { - public function testSimpleVariable() { +class VariableResolutionTest extends TestCase +{ + public function testSimpleVariable() + { $template = new Template(); $template->parse("{{test}}"); $this->assertEquals('worked', $template->render(array('test' => 'worked'))); } - public function testSimpleWithWhitespaces() { + public function testSimpleWithWhitespaces() + { $template = new Template(); $template->parse(' {{ test }} '); @@ -26,21 +29,24 @@ public function testSimpleWithWhitespaces() { $this->assertEquals(' worked wonderfully ', $template->render(array('test' => 'worked wonderfully'))); } - public function testIgnoreUnknown() { + public function testIgnoreUnknown() + { $template = new Template(); $template->parse('{{ test }}'); $this->assertEquals('', $template->render()); } - public function testArrayScoping() { + public function testArrayScoping() + { $template = new Template(); $template->parse('{{ test.test }}'); $this->assertEquals('worked', $template->render(array('test' => array('test' => 'worked')))); } - public function testVariableArrayIndices() { + public function testVariableArrayIndices() + { $template = new Template(); $template->parse("{% assign days = 'Mon,Tue,Wed,Thu,Fri,Sat,Sun' | split: ',' %}{% for i in (0..6) %}{{ days[i] }} {% endfor %}"); diff --git a/tests/Liquid/VariableTest.php b/tests/Liquid/VariableTest.php index 2416781b..1faf83e8 100644 --- a/tests/Liquid/VariableTest.php +++ b/tests/Liquid/VariableTest.php @@ -11,13 +11,16 @@ namespace Liquid; -class VariableTest extends TestCase { - public function testVariable() { +class VariableTest extends TestCase +{ + public function testVariable() + { $var = new Variable('hello'); $this->assertEquals('hello', $var->getName()); } - public function testFilters() { + public function testFilters() + { $var = new Variable('hello | textileze'); $this->assertEquals('hello', $var->getName()); $this->assertEquals(array(array('textileze', array())), $var->getFilters()); @@ -59,7 +62,8 @@ public function testFilters() { $this->assertEquals(array(array('things', array('"%Y, okay?"', "'the other one'"))), $var->getFilters()); } - public function testFiltersWithoutWhitespace() { + public function testFiltersWithoutWhitespace() + { $var = new Variable('hello | textileze | paragraph'); $this->assertEquals('hello', $var->getName()); $this->assertEquals(array(array('textileze', array()), array('paragraph', array())), $var->getFilters()); @@ -69,38 +73,45 @@ public function testFiltersWithoutWhitespace() { $this->assertEquals(array(array('textileze', array()), array('paragraph', array())), $var->getFilters()); } - public function testSymbol() { + public function testSymbol() + { $var = new Variable("http://disney.com/logo.gif | image: 'med' "); $this->assertEquals('http://disney.com/logo.gif', $var->getName()); $this->assertEquals(array(array('image', array("'med'"))), $var->getFilters()); } - public function testStringSingleQuoted() { + public function testStringSingleQuoted() + { $var = new Variable(' "hello" '); $this->assertEquals('"hello"', $var->getName()); } - public function testStringDoubleQuoted() { + public function testStringDoubleQuoted() + { $var = new Variable(" 'hello' "); $this->assertEquals("'hello'", $var->getName()); } - public function testInteger() { + public function testInteger() + { $var = new Variable(' 1000 '); $this->assertEquals('1000', $var->getName()); } - public function testFloat() { + public function testFloat() + { $var = new Variable(' 1000.01 '); $this->assertEquals('1000.01', $var->getName()); } - public function testStringWithSpecialChars() { + public function testStringWithSpecialChars() + { $var = new Variable("'hello! $!@.;\"ddasd\" ' "); $this->assertEquals("'hello! $!@.;\"ddasd\" '", $var->getName()); } - public function testStringDot() { + public function testStringDot() + { $var = new Variable(" test.test "); $this->assertEquals('test.test', $var->getName()); } diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 060b12d2..f271d825 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -14,16 +14,19 @@ use Liquid\FileSystem\Virtual; use Liquid\Cache\File; -class VirtualFileSystemTest extends TestCase { +class VirtualFileSystemTest extends TestCase +{ /** * @expectedException \Liquid\LiquidException * @expectedExceptionMessage Not a callback */ - public function testInvalidCallback() { + public function testInvalidCallback() + { new Virtual(''); } - public function testReadTemplateFile() { + public function testReadTemplateFile() + { $fs = new Virtual(function ($templatePath) { if ($templatePath == 'foo') { return "Contents of foo"; @@ -45,7 +48,8 @@ public function testReadTemplateFile() { * @expectedException \Liquid\LiquidException * @expectedExceptionMessage cannot be used with a serializing cache */ - public function testWithFileCache() { + public function testWithFileCache() + { $template = new Template(); $template->setFileSystem(new Virtual(function ($templatePath) { return ''; @@ -56,11 +60,13 @@ public function testWithFileCache() { $template->parse("Hello"); } - public function virtualFileSystemCallback($templatePath) { + public function virtualFileSystemCallback($templatePath) + { return 'OK'; } - public function testWithRegularCallback() { + public function testWithRegularCallback() + { $template = new Template(); $template->setFileSystem(new Virtual(array($this, 'virtualFileSystemCallback'), true)); $template->setCache(new File(array( From 164f4244b002b07e542485d09f8757445bee0e8e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:46:47 +0900 Subject: [PATCH 109/296] .php_cs.dist - removed braces exception; we should now follow PSR-2 in everything except padding --- .php_cs.dist | 1 - 1 file changed, 1 deletion(-) diff --git a/.php_cs.dist b/.php_cs.dist index 5a2dd56b..94e87f61 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -13,7 +13,6 @@ return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, - 'braces' => ['position_after_functions_and_oop_constructs' => 'same'], ]) ->setIndent("\t") ->setFinder( From 935b5868c490d1f1507822f0fdbf48edf21f9acc Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:49:09 +0900 Subject: [PATCH 110/296] Context: missing phpdoc --- src/Liquid/Context.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 163d58c5..3b56514f 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -123,6 +123,7 @@ public function pop() * Replaces [] * * @param string + * @param mixed $key * * @return mixed */ From 1ed2479f0fc380cb5ebd429d87b2afdffd98efe7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:49:34 +0900 Subject: [PATCH 111/296] Decision: arguments with default values before non-default ones --- src/Liquid/Decision.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index 11d377bf..2c9087fa 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -87,7 +87,7 @@ protected function equalVariables($left, $right, Context $context) * @throws \Liquid\LiquidException * @return bool */ - protected function interpretCondition($left, $right, $op = null, Context $context) + protected function interpretCondition($left, $right, $op, Context $context) { if (is_null($op)) { $value = $this->stringValue($context->get($left)); From f128bf8aaba14adc4e02f5bfa3305c9163642c80 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:50:51 +0900 Subject: [PATCH 112/296] Removed useless else --- src/Liquid/Filterbank.php | 3 +-- src/Liquid/Liquid.php | 7 +++---- src/Liquid/Tag/TagIfchanged.php | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 44543d82..e51031e1 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -124,9 +124,8 @@ public function invoke($name, $value, array $args = array()) // If we're calling a function if ($class === false) { return call_user_func_array($name, $args); - } else { - return call_user_func_array(array($class, $name), $args); } + return call_user_func_array(array($class, $name), $args); } return $value; diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 91241270..8efcd212 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -89,9 +89,9 @@ public static function get($key) } if (array_key_exists($key, self::$config)) { return self::$config[$key]; - } else { - // This case is needed for compound settings - switch ($key) { + } + // This case is needed for compound settings + switch ($key) { case 'QUOTED_FRAGMENT': return self::$config['QUOTED_STRING'] . '|(?:[^\s,\|\'"]|' . self::$config['QUOTED_STRING'] . ')+'; case 'QUOTED_FRAGMENT_FILTER_ARGUMENT': @@ -103,7 +103,6 @@ public static function get($key) default: return null; } - } } /** diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index 62144c8c..595fff76 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -54,9 +54,8 @@ public function render(Context $context) if ($this->lastValue == $output) { return ''; - } else { - $this->lastValue = $output; - return $this->lastValue; } + $this->lastValue = $output; + return $this->lastValue; } } From f3767eaa95c1bec42fb8f2ff62b6925eb5e8c4a2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:52:20 +0900 Subject: [PATCH 113/296] .php_cs.dist - checks for dead code --- .php_cs.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.php_cs.dist b/.php_cs.dist index 94e87f61..10c9f212 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -13,6 +13,11 @@ return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, + 'no_unreachable_default_argument_value' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'phpdoc_add_missing_param_annotation' => true, + 'semicolon_after_instruction' => true, ]) ->setIndent("\t") ->setFinder( From 38b18434a913b4020bbd3149ca16abe11ab822da Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:54:42 +0900 Subject: [PATCH 114/296] Standard comment in all files --- examples/advanced.php | 2 +- examples/block.php | 2 +- examples/index.php | 2 +- examples/simple.php | 2 +- src/Liquid/AbstractBlock.php | 2 +- src/Liquid/AbstractTag.php | 2 +- src/Liquid/Cache.php | 2 +- src/Liquid/Cache/Apc.php | 2 +- src/Liquid/Cache/File.php | 2 +- src/Liquid/Cache/Local.php | 2 +- src/Liquid/Context.php | 2 +- src/Liquid/CustomFilters.php | 2 +- src/Liquid/Decision.php | 2 +- src/Liquid/Document.php | 2 +- src/Liquid/Drop.php | 2 +- src/Liquid/FileSystem.php | 2 +- src/Liquid/FileSystem/Local.php | 2 +- src/Liquid/FileSystem/Virtual.php | 2 +- src/Liquid/Filterbank.php | 2 +- src/Liquid/Liquid.php | 2 +- src/Liquid/LiquidException.php | 2 +- src/Liquid/LocalFileSystem.php | 2 +- src/Liquid/Regexp.php | 2 +- src/Liquid/StandardFilters.php | 2 +- src/Liquid/Tag/TagAssign.php | 2 +- src/Liquid/Tag/TagBlock.php | 2 +- src/Liquid/Tag/TagBreak.php | 2 +- src/Liquid/Tag/TagCapture.php | 2 +- src/Liquid/Tag/TagCase.php | 2 +- src/Liquid/Tag/TagComment.php | 2 +- src/Liquid/Tag/TagContinue.php | 2 +- src/Liquid/Tag/TagCycle.php | 2 +- src/Liquid/Tag/TagDecrement.php | 2 +- src/Liquid/Tag/TagExtends.php | 2 +- src/Liquid/Tag/TagFor.php | 2 +- src/Liquid/Tag/TagIf.php | 2 +- src/Liquid/Tag/TagIfchanged.php | 2 +- src/Liquid/Tag/TagInclude.php | 2 +- src/Liquid/Tag/TagIncrement.php | 2 +- src/Liquid/Tag/TagPaginate.php | 2 +- src/Liquid/Tag/TagRaw.php | 2 +- src/Liquid/Tag/TagTablerow.php | 2 +- src/Liquid/Tag/TagUnless.php | 2 +- src/Liquid/Template.php | 2 +- src/Liquid/Variable.php | 2 +- tests/Liquid/Cache/ApcTest.php | 2 +- tests/Liquid/Cache/FileTest.php | 2 +- tests/Liquid/Cache/LocalTest.php | 2 +- tests/Liquid/ContextTest.php | 2 +- tests/Liquid/CustomFiltersTest.php | 2 +- tests/Liquid/DropTest.php | 2 +- tests/Liquid/EscapeByDefaultTest.php | 2 +- tests/Liquid/FilterbankTest.php | 2 +- tests/Liquid/LiquidTest.php | 2 +- tests/Liquid/LocalFileSystemTest.php | 2 +- tests/Liquid/OutputTest.php | 2 +- tests/Liquid/ParsingQuirksTest.php | 2 +- tests/Liquid/RegexpTest.php | 2 +- tests/Liquid/StandardFiltersTest.php | 2 +- tests/Liquid/Tag/NoTransformTest.php | 2 +- tests/Liquid/Tag/TagAssignTest.php | 2 +- tests/Liquid/Tag/TagBlockTest.php | 2 +- tests/Liquid/Tag/TagBreakTest.php | 2 +- tests/Liquid/Tag/TagCaptureTest.php | 2 +- tests/Liquid/Tag/TagCaseTest.php | 2 +- tests/Liquid/Tag/TagCommentTest.php | 2 +- tests/Liquid/Tag/TagContinueTest.php | 2 +- tests/Liquid/Tag/TagCycleTest.php | 2 +- tests/Liquid/Tag/TagDecrementTest.php | 2 +- tests/Liquid/Tag/TagExtendsTest.php | 2 +- tests/Liquid/Tag/TagForTest.php | 2 +- tests/Liquid/Tag/TagIfTest.php | 2 +- tests/Liquid/Tag/TagIfchangedTest.php | 2 +- tests/Liquid/Tag/TagIncludeTest.php | 2 +- tests/Liquid/Tag/TagIncrementTest.php | 2 +- tests/Liquid/Tag/TagPaginateTest.php | 2 +- tests/Liquid/Tag/TagRawTest.php | 2 +- tests/Liquid/Tag/TagTablerowTest.php | 2 +- tests/Liquid/Tag/TagUnlessTest.php | 2 +- tests/Liquid/TemplateTest.php | 2 +- tests/Liquid/TestCase.php | 2 +- tests/Liquid/TestFileSystem.php | 2 +- tests/Liquid/VariableResolutionTest.php | 2 +- tests/Liquid/VariableTest.php | 2 +- tests/Liquid/VirtualFileSystemTest.php | 2 +- 85 files changed, 85 insertions(+), 85 deletions(-) diff --git a/examples/advanced.php b/examples/advanced.php index d71a9c24..5b89f3b5 100644 --- a/examples/advanced.php +++ b/examples/advanced.php @@ -1,6 +1,6 @@ Date: Mon, 25 Sep 2017 16:55:06 +0900 Subject: [PATCH 115/296] .php_cs.dist - enforce standard comment --- .php_cs.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/.php_cs.dist b/.php_cs.dist index 10c9f212..9ba91471 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -18,6 +18,7 @@ return PhpCsFixer\Config::create() 'no_useless_return' => true, 'phpdoc_add_missing_param_annotation' => true, 'semicolon_after_instruction' => true, + 'header_comment' => ['header' => $header], ]) ->setIndent("\t") ->setFinder( From 622eca8a3eaf81d94e9cde4221167ac9310d9af4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 16:56:13 +0900 Subject: [PATCH 116/296] .php_cs.dist - enforce PHPDoc argument order --- .php_cs.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/.php_cs.dist b/.php_cs.dist index 9ba91471..3c56d8d4 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -17,6 +17,7 @@ return PhpCsFixer\Config::create() 'no_useless_else' => true, 'no_useless_return' => true, 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_order' => true, 'semicolon_after_instruction' => true, 'header_comment' => ['header' => $header], ]) From c8762ffebe0174837c2dadc08655c8a7f3c168c6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:03:13 +0900 Subject: [PATCH 117/296] .php_cs.dist - adjust to the same standard --- .php_cs.dist | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index 3c56d8d4..362562ee 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -10,20 +10,20 @@ file that was distributed with this source code. EOF; return PhpCsFixer\Config::create() - ->setRiskyAllowed(true) - ->setRules([ - '@PSR2' => true, - 'no_unreachable_default_argument_value' => true, - 'no_useless_else' => true, - 'no_useless_return' => true, - 'phpdoc_add_missing_param_annotation' => true, - 'phpdoc_order' => true, - 'semicolon_after_instruction' => true, - 'header_comment' => ['header' => $header], - ]) - ->setIndent("\t") - ->setFinder( - PhpCsFixer\Finder::create() - ->in(__DIR__) - ) + ->setRiskyAllowed(true) + ->setRules([ + '@PSR2' => true, + 'no_unreachable_default_argument_value' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_order' => true, + 'semicolon_after_instruction' => true, + 'header_comment' => ['header' => $header], + ]) + ->setIndent("\t") + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ) ; From 9624451c5355ccf1bd34840716d5bb8ac11bfe32 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:03:48 +0900 Subject: [PATCH 118/296] .php_cs.dist - enforce PSR-4 (we're following it anyway) --- .php_cs.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/.php_cs.dist b/.php_cs.dist index 362562ee..fe4b94b2 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -13,6 +13,7 @@ return PhpCsFixer\Config::create() ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, + 'psr4' => true, 'no_unreachable_default_argument_value' => true, 'no_useless_else' => true, 'no_useless_return' => true, From d976e0d216af440c60cc331d5a94a6b60b428563 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:08:38 +0900 Subject: [PATCH 119/296] Space after comma in arrays --- .php_cs.dist | 1 + examples/block.php | 4 ++-- examples/index.php | 20 ++++++++++---------- src/Liquid/Context.php | 2 +- tests/Liquid/StandardFiltersTest.php | 20 ++++++++++---------- tests/Liquid/Tag/TagPaginateTest.php | 2 +- 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.php_cs.dist b/.php_cs.dist index fe4b94b2..6f600034 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -20,6 +20,7 @@ return PhpCsFixer\Config::create() 'phpdoc_add_missing_param_annotation' => true, 'phpdoc_order' => true, 'semicolon_after_instruction' => true, + 'whitespace_after_comma_in_array' => true, 'header_comment' => ['header' => $header], ]) ->setIndent("\t") diff --git a/examples/block.php b/examples/block.php index b35cb5dc..b7832d0e 100644 --- a/examples/block.php +++ b/examples/block.php @@ -32,8 +32,8 @@ 'document' => array( 'title' => 'This is php-liquid', 'content' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.', - 'copyright' => '© Copyright 2014 Guz Alexander - All rights reserved.' - ) + 'copyright' => '© Copyright 2014 Guz Alexander - All rights reserved.', + ), ); echo $liquid->render($assigns); diff --git a/examples/index.php b/examples/index.php index 0d3fa80a..850fe42c 100644 --- a/examples/index.php +++ b/examples/index.php @@ -33,7 +33,7 @@ 'document' => array( 'title' => 'This is php-liquid', 'content' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.', - 'copyright' => 'Guz Alexander - All rights reserved.' + 'copyright' => 'Guz Alexander - All rights reserved.', ), 'blog' => array( array( @@ -43,9 +43,9 @@ 'comments' => array( array( 'title' => 'First Comment', - 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr' - ) - ) + 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', + ), + ), ), array( 'title' => 'Blog Title 2', @@ -54,17 +54,17 @@ 'comments' => array( array( 'title' => 'First Comment', - 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr' + 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', ), array( 'title' => 'Second Comment', - 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr' - ) - ) - ) + 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', + ), + ), + ), ), - 'array' => array('one', 'two', 'three', 'four') + 'array' => array('one', 'two', 'three', 'four'), ); echo $liquid->render($assigns); diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index b783fd55..6587b85c 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -258,7 +258,7 @@ private function variable($key) if (preg_match("|\[[0-9]+\]|", $key)) { $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); } elseif (preg_match("|\[[0-9a-z._]+\]|", $key, $matches)) { - $index = $this->get(str_replace(array("[","]"), "", $matches[0])); + $index = $this->get(str_replace(array("[", "]"), "", $matches[0])); if (strlen($index)) { $key = preg_replace("|\[([0-9a-z._]+)\]|", ".$index", $key); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index ad92a580..23739545 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -333,12 +333,12 @@ public function testSlice() '', ), array( - array(1,2,3,4,5), - array(3,4,5), + array(1, 2, 3, 4, 5), + array(3, 4, 5), ), array( - new \ArrayIterator(array(1,2,3,4,5)), - array(3,4,5), + new \ArrayIterator(array(1, 2, 3, 4, 5)), + array(3, 4, 5), ), array( '12345', @@ -377,12 +377,12 @@ public function testSlice() '', ), array( - array(1,2,3,4,5), - array(3,4), + array(1, 2, 3, 4, 5), + array(3, 4), ), array( - new \ArrayIterator(array(1,2,3,4,5)), - array(3,4), + new \ArrayIterator(array(1, 2, 3, 4, 5)), + array(3, 4), ), array( '12345', @@ -475,11 +475,11 @@ public function testJoin() '', ), array( - array(1,2,3,4,5), + array(1, 2, 3, 4, 5), '1 2 3 4 5' ), array( - new \ArrayIterator(array(1,2,3,4,5)), + new \ArrayIterator(array(1, 2, 3, 4, 5)), '1 2 3 4 5' ), array( diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 2ea5978b..9c575113 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -33,7 +33,7 @@ public function testNextPage() { $text = '{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{{ paginate.next.title }}{% endpaginate %}'; $expected = ' 2 Next'; - $this->assertTemplateResult($expected, $text, array('HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2,'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + $this->assertTemplateResult($expected, $text, array('HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2, 'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); } /** From cfc24849389560afc9a9c1162697bb9ebc37388e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:23:28 +0900 Subject: [PATCH 120/296] Template::parseFile - Parses the given template file Closes #16 --- src/Liquid/Template.php | 16 ++++++++++++++++ tests/Liquid/LocalFileSystemTest.php | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 82a73b34..95d6f42d 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -180,6 +180,22 @@ public function parse($source) return $this; } + /** + * Parses the given template file + * + * @param string $templatePath + * + * @return Template + */ + public function parseFile($templatePath) + { + if (!$this->fileSystem) { + throw new LiquidException("Could not load a template without an initialized file system"); + } + + return $this->parse($this->fileSystem->readTemplateFile($templatePath)); + } + /** * Renders the current template * diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 55c85895..07f331ca 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -131,4 +131,23 @@ public function testReadTemplateFile() $fileSystem = new LocalFileSystem($this->root); $this->assertEquals('test content', trim($fileSystem->readTemplateFile('mypartial'))); } + + public function testParseTemplateFile() + { + Liquid::set('INCLUDE_PREFIX', ''); + Liquid::set('INCLUDE_SUFFIX', 'tpl'); + + $template = new Template($this->root); + $this->assertEquals("test content\n", $template->parseFile('mypartial')->render()); + } + + /** + * @expectedException \Liquid\LiquidException + * @expectedExceptionMessage Could not load a template + */ + public function testParseTemplateFileError() + { + $template = new Template(); + $template->parseFile('mypartial'); + } } From 7f0db748835d4d9c18aa2df27e8333f458e5f7de Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:24:37 +0900 Subject: [PATCH 121/296] Test FileSystem\Local instead of LocalFileSystem, check that the latter still exists --- tests/Liquid/LocalFileSystemTest.php | 29 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 07f331ca..d38d8721 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -11,6 +11,8 @@ namespace Liquid; +use Liquid\FileSystem\Local; + class LocalFileSystemTest extends TestCase { protected $root; @@ -27,7 +29,7 @@ protected function setUp() */ public function testIllegalTemplateNameEmpty() { - $fileSystem = new LocalFileSystem(''); + $fileSystem = new Local(''); $fileSystem->fullPath(''); } @@ -36,7 +38,7 @@ public function testIllegalTemplateNameEmpty() */ public function testIllegalRootPath() { - $fileSystem = new LocalFileSystem('invalid/not/found'); + $fileSystem = new Local('invalid/not/found'); $fileSystem->fullPath(''); } @@ -47,7 +49,7 @@ public function testIllegalTemplateNameIncludeExtension() { Liquid::set('INCLUDE_ALLOW_EXT', false); - $fileSystem = new LocalFileSystem(''); + $fileSystem = new Local(''); $fileSystem->fullPath('has_extension.ext'); } @@ -58,7 +60,7 @@ public function testIllegalTemplateNameNotIncludeExtension() { Liquid::set('INCLUDE_ALLOW_EXT', true); - $fileSystem = new LocalFileSystem(''); + $fileSystem = new Local(''); $fileSystem->fullPath('has_extension'); } @@ -67,7 +69,7 @@ public function testIllegalTemplateNameNotIncludeExtension() */ public function testIllegalTemplatePathNoRoot() { - $fileSystem = new LocalFileSystem(''); + $fileSystem = new Local(''); $fileSystem->fullPath('mypartial'); } @@ -76,7 +78,7 @@ public function testIllegalTemplatePathNoRoot() */ public function testIllegalTemplatePathNoFileExists() { - $fileSystem = new LocalFileSystem(dirname(__DIR__)); + $fileSystem = new Local(dirname(__DIR__)); $fileSystem->fullPath('no_such_file_exists'); } @@ -87,7 +89,7 @@ public function testIllegalTemplatePathNoFileExists() public function testIllegalTemplatePathNotUnderTemplateRoot() { Liquid::set('INCLUDE_ALLOW_EXT', true); - $fileSystem = new LocalFileSystem(dirname($this->root)); + $fileSystem = new Local(dirname($this->root)); // find any fail under deeper under the root, so all other checks would pass $filesUnderCurrentDir = array_map('basename', glob(dirname(__DIR__).'/../*')); // path relative to root; we can't start it with a dot since it isn't allowed anyway @@ -98,7 +100,7 @@ public function testValidPathWithDefaultExtension() { $templateName = 'mypartial'; - $fileSystem = new LocalFileSystem($this->root); + $fileSystem = new Local($this->root); $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } @@ -109,7 +111,7 @@ public function testValidPathWithCustomExtension() $templateName = 'mypartial'; - $fileSystem = new LocalFileSystem($this->root); + $fileSystem = new Local($this->root); $this->assertEquals($this->root . Liquid::get('INCLUDE_PREFIX') . $templateName . '.' . Liquid::get('INCLUDE_SUFFIX'), $fileSystem->fullPath($templateName)); } @@ -119,7 +121,7 @@ public function testValidPathWithCustomExtension() */ public function testReadIllegalTemplatePathNoFileExists() { - $fileSystem = new LocalFileSystem(dirname(__DIR__)); + $fileSystem = new Local(dirname(__DIR__)); $fileSystem->readTemplateFile('no_such_file_exists'); } @@ -128,10 +130,15 @@ public function testReadTemplateFile() Liquid::set('INCLUDE_PREFIX', ''); Liquid::set('INCLUDE_SUFFIX', 'tpl'); - $fileSystem = new LocalFileSystem($this->root); + $fileSystem = new Local($this->root); $this->assertEquals('test content', trim($fileSystem->readTemplateFile('mypartial'))); } + public function testDeprecatedLocalFileSystemExists() + { + $this->assertInstanceOf(Local::class, new LocalFileSystem($this->root)); + } + public function testParseTemplateFile() { Liquid::set('INCLUDE_PREFIX', ''); From fd8fe3f4c04d07e4ccbdcc3ade606074b0c54c70 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 17:56:00 +0900 Subject: [PATCH 122/296] Update README.md --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d94024b..47f29be0 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,17 @@ Will output: Note that automatic escaping is not a standard Liquid feature: use with care. -You should probably extend `Liquid\Template` to initialize everything in one place. +Similarly, the following snippet will parse and render `templates/home.liquid` while storing parsing results in a class-local cache: + + \Liquid\Liquid::set('INCLUDE_PREFIX', ''); + + $template = new \Liquid\Template(__DIR__ . '/protected/templates'); + $template->setCache(new \Liquid\Cache\Local()); + echo $template->parseFile('home')->render(); + +If you render the same template over and over for at least a dozen of times, the class-local cache will give you a slight speed up in range of some milliseconds per render depending on a complexity of your template. + +You should probably extend `Liquid\Template` to initialize everything you do with `Liquid::set` in one place. ## Requirements From a907e9a26e0ab5f8b83dbf0565b6f5250bb3c443 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 25 Sep 2017 18:26:50 +0900 Subject: [PATCH 123/296] Update README.md Icon with downloads counter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47f29be0..dd4e6528 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Liquid template engine for PHP [![Build Status](https://travis-ci.org/kalimatas/php-liquid.svg?branch=master)](https://travis-ci.org/kalimatas/php-liquid) [![Coverage Status](https://coveralls.io/repos/github/kalimatas/php-liquid/badge.svg?branch=master)](https://coveralls.io/github/kalimatas/php-liquid?branch=master) +# Liquid template engine for PHP [![Build Status](https://travis-ci.org/kalimatas/php-liquid.svg?branch=master)](https://travis-ci.org/kalimatas/php-liquid) [![Coverage Status](https://coveralls.io/repos/github/kalimatas/php-liquid/badge.svg?branch=master)](https://coveralls.io/github/kalimatas/php-liquid?branch=master) [![Total Downloads](https://poser.pugx.org/liquid/liquid/downloads.svg)](https://packagist.org/packages/liquid/liquid) Liquid is a PHP port of the [Liquid template engine for Ruby](https://github.com/Shopify/liquid), which was written by Tobias Lutke. Although there are many other templating engines for PHP, including Smarty (from which Liquid was partially inspired), Liquid had some advantages that made porting worthwhile: From f779df5953bd27e6b6349015458bbd6b45566626 Mon Sep 17 00:00:00 2001 From: jfoucher Date: Tue, 26 Sep 2017 18:43:29 +0200 Subject: [PATCH 124/296] Can use unquoted template name in include tag. --- src/Liquid/Tag/TagInclude.php | 12 +++++++++--- tests/Liquid/Tag/TagIncludeTest.php | 24 +++++++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index ec51ff84..b7855281 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -76,11 +76,17 @@ class TagInclude extends AbstractTag */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - $regex = new Regexp('/("[^"]+"|\'[^\']+\')(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); + $regex = new Regexp('/("[^"]+"|\'[^\']+\'|[^\'"\s]+)(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); if ($regex->match($markup)) { - $this->templateName = substr($regex->matches[1], 1, strlen($regex->matches[1]) - 2); - + $unquoted = (strpos($regex->matches[1], '"') === false && strpos($regex->matches[1], "'") === false); + $start = 1; + $len = strlen($regex->matches[1]) - 2; + if ($unquoted) { + $start = 0; + $len = strlen($regex->matches[1]); + } + $this->templateName = substr($regex->matches[1], $start, $len); if (isset($regex->matches[1])) { $this->collection = (isset($regex->matches[3])) ? ($regex->matches[3] == "for") : null; $this->variable = (isset($regex->matches[4])) ? $regex->matches[4] : null; diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 8e1650b7..34f2f530 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -45,15 +45,6 @@ public function testInvalidSyntaxNoTemplateName() $template->parse("{% include %}"); } - /** - * @expectedException \Liquid\LiquidException - */ - public function testInvalidSyntaxNotQuotedTemplateName() - { - $template = new Template(); - $template->parse("{% include hello %}"); - } - /** * @expectedException \Liquid\LiquidException */ @@ -179,4 +170,19 @@ public function testIncludePassObjectValue() $output = $template->render(array("var" => (object) array('a' => 'b'))); $this->assertEquals("([b])", $output); } + + + public function testIncludeWithoutQuotes() + { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'inner' => "[{{ other }}]", + 'example' => "{%include inner other:var %} ({{var}})", + ))); + + $template->parse("{% include example other:var %}"); + + $output = $template->render(array("var" => "test")); + $this->assertEquals("[test] (test)", $output); + } } From 2ada3be5c7ebb45fb2053cab86a3da600f91ff4b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 26 Sep 2017 14:45:33 +0900 Subject: [PATCH 125/296] TagIncludeTest: deep includes --- tests/Liquid/Tag/TagIncludeTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 34f2f530..1e6d2a7d 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -25,6 +25,10 @@ class TagIncludeTest extends TestCase protected function setUp() { $this->fs = TestFileSystem::fromArray(array( + 'a' => "{% include 'b' %}", + 'b' => "{% include 'c' %}", + 'c' => "{% include 'd' %}", + 'd' => '({{ inner }})', 'inner' => "Inner: {{ inner }}{{ other }}", 'example' => "Example: {% include 'inner' %}", )); @@ -94,9 +98,9 @@ public function testWithCache() $template->setCache(new Local()); foreach (array("Before cache:", "With cache:") as $type) { - $template->parse("{{ type }} {% for item in list %}{% include 'example' inner:item %} {% endfor %}"); + $template->parse("{{ type }} {% for item in list %}{% include 'example' inner:item %} {% endfor %}{% include 'a' %}"); $template->render(array("inner" => "foo", "list" => array(1, 2, 3)), array()); - $this->assertEquals("$type Example: Inner: 1 Example: Inner: 2 ", $template->render(array("type" => $type, "inner" => "bar", "list" => array(1, 2)))); + $this->assertEquals("$type Example: Inner: 1 Example: Inner: 2 (bar)", $template->render(array("type" => $type, "inner" => "bar", "list" => array(1, 2)))); } $template->setCache(null); From fd00dcb2df2ea55059ca53f252e00bc5614fd512 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 26 Sep 2017 16:02:18 +0900 Subject: [PATCH 126/296] Refactored checkIncludes() and related functions --- src/Liquid/Document.php | 12 ++++--- src/Liquid/Tag/TagExtends.php | 22 ++++++------- src/Liquid/Tag/TagInclude.php | 62 +++++++++++++++++++---------------- src/Liquid/Template.php | 36 ++++++++++++++------ 4 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 9a6b38b7..6f6b120c 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -39,11 +39,13 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) public function checkIncludes() { foreach ($this->nodelist as $token) { - if ($token instanceof TagInclude || $token instanceof TagExtends) { - /** @var TagInclude|TagExtends $token */ - if ($token->checkIncludes() == true) { - return true; - } + // check any of the tokens for includes + if ($token instanceof TagInclude && $token->checkIncludes()) { + return true; + } + + if ($token instanceof TagExtends && $token->checkIncludes()) { + return true; } } diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 00705c88..4de08863 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -158,18 +158,20 @@ public function parse(array &$tokens) } } + $cache = Template::getCache(); + + if (!$cache) { + $this->document = new Document($rest, $this->fileSystem); + return; + } + $this->hash = md5($source); - $cache = Template::getCache(); + $this->document = $cache->read($this->hash); - if (isset($cache)) { - if (($this->document = $cache->read($this->hash)) != false && $this->document->checkIncludes() != true) { - } else { - $this->document = new Document($rest, $this->fileSystem); - $cache->write($this->hash, $this->document); - } - } else { + if ($this->document == false || $this->document->checkIncludes() == true) { $this->document = new Document($rest, $this->fileSystem); + $cache->write($this->hash, $this->document); } } @@ -180,15 +182,13 @@ public function parse(array &$tokens) */ public function checkIncludes() { - $cache = Template::getCache(); - if ($this->document->checkIncludes() == true) { return true; } $source = $this->fileSystem->readTemplateFile($this->templateName); - if ($cache->exists(md5($source)) && $this->hash === md5($source)) { + if (Template::getCache()->exists(md5($source)) && $this->hash === md5($source)) { return false; } diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index b7855281..5d5eb091 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -78,25 +78,29 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu { $regex = new Regexp('/("[^"]+"|\'[^\']+\'|[^\'"\s]+)(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); - if ($regex->match($markup)) { - $unquoted = (strpos($regex->matches[1], '"') === false && strpos($regex->matches[1], "'") === false); - $start = 1; - $len = strlen($regex->matches[1]) - 2; - if ($unquoted) { - $start = 0; - $len = strlen($regex->matches[1]); - } - $this->templateName = substr($regex->matches[1], $start, $len); - if (isset($regex->matches[1])) { - $this->collection = (isset($regex->matches[3])) ? ($regex->matches[3] == "for") : null; - $this->variable = (isset($regex->matches[4])) ? $regex->matches[4] : null; - } - - $this->extractAttributes($markup); - } else { + if (!$regex->match($markup)) { throw new LiquidException("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"); } + $unquoted = (strpos($regex->matches[1], '"') === false && strpos($regex->matches[1], "'") === false); + + $start = 1; + $len = strlen($regex->matches[1]) - 2; + + if ($unquoted) { + $start = 0; + $len = strlen($regex->matches[1]); + } + + $this->templateName = substr($regex->matches[1], $start, $len); + + if (isset($regex->matches[1])) { + $this->collection = (isset($regex->matches[3])) ? ($regex->matches[3] == "for") : null; + $this->variable = (isset($regex->matches[4])) ? $regex->matches[4] : null; + } + + $this->extractAttributes($markup); + parent::__construct($markup, $tokens, $fileSystem); } @@ -116,20 +120,22 @@ public function parse(array &$tokens) // read the source of the template and create a new sub document $source = $this->fileSystem->readTemplateFile($this->templateName); - $this->hash = md5($source); - $cache = Template::getCache(); - if (isset($cache)) { - if (($this->document = $cache->read($this->hash)) != false && $this->document->checkIncludes() != true) { - } else { - $templateTokens = Template::tokenize($source); - $this->document = new Document($templateTokens, $this->fileSystem); - $cache->write($this->hash, $this->document); - } - } else { + if (!$cache) { + // tokens in this new document + $templateTokens = Template::tokenize($source); + $this->document = new Document($templateTokens, $this->fileSystem); + return; + } + + $this->hash = md5($source); + $this->document = $cache->read($this->hash); + + if ($this->document == false || $this->document->checkIncludes() == true) { $templateTokens = Template::tokenize($source); $this->document = new Document($templateTokens, $this->fileSystem); + $cache->write($this->hash, $this->document); } } @@ -140,15 +146,13 @@ public function parse(array &$tokens) */ public function checkIncludes() { - $cache = Template::getCache(); - if ($this->document->checkIncludes() == true) { return true; } $source = $this->fileSystem->readTemplateFile($this->templateName); - if ($cache->exists(md5($source)) && $this->hash === md5($source)) { + if (Template::getCache()->exists(md5($source)) && $this->hash === md5($source)) { return false; } diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 95d6f42d..ca3c147c 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -165,21 +165,37 @@ public static function tokenize($source) */ public function parse($source) { - if (self::$cache !== null) { - if (($this->root = self::$cache->read(md5($source))) != false && $this->root->checkIncludes() != true) { - } else { - $tokens = Template::tokenize($source); - $this->root = new Document($tokens, $this->fileSystem); - self::$cache->write(md5($source), $this->root); - } - } else { - $tokens = Template::tokenize($source); - $this->root = new Document($tokens, $this->fileSystem); + if (!self::$cache) { + return $this->parseAlways($source); + } + + $hash = md5($source); + $this->root = self::$cache->read($hash); + + // if no cached version exists, or if it checks for includes + if ($this->root == false || $this->root->checkIncludes() == true) { + $this->parseAlways($source); + self::$cache->write($hash, $this->root); } return $this; } + /** + * Parses the given source string regardless of caching + * + * @param string $source + * + * @return Template + */ + private function parseAlways($source) + { + $tokens = Template::tokenize($source); + $this->root = new Document($tokens, $this->fileSystem); + + return $this; + } + /** * Parses the given template file * From a53e116b68d0ee554f67ac6de9cb13607c0c8d07 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 26 Sep 2017 16:54:52 +0900 Subject: [PATCH 127/296] TagExtendsTest: use TestFileSystem --- tests/Liquid/Tag/TagExtendsTest.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index c05d48ef..1f3feb6f 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -15,6 +15,7 @@ use Liquid\Template; use Liquid\Cache\Local; use Liquid\FileSystem\Virtual; +use Liquid\TestFileSystem; /** * @see TagExtends @@ -25,15 +26,10 @@ class TagExtendsTest extends TestCase protected function setUp() { - $this->fs = new Virtual(function ($templatePath) { - if ($templatePath == 'base') { - return "{% block content %}{% endblock %}{% block footer %}{% endblock %}"; - } - - if ($templatePath == 'sub-base') { - return "{% extends 'base' %}{% block content %}{% endblock %}{% block footer %} Boo! {% endblock %}"; - } - }); + $this->fs = TestFileSystem::fromArray(array( + 'base' => "{% block content %}{% endblock %}{% block footer %}{% endblock %}", + 'sub-base' => "{% extends 'base' %}{% block content %}{% endblock %}{% block footer %} Boo! {% endblock %}", + )); } protected function tearDown() From 42ffc13bbbd21b0546fe7054f5c5bd3329b73b51 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 10:17:39 +0900 Subject: [PATCH 128/296] Renamed checkIncludes() to hasIncludes(), added comment about use --- src/Liquid/Document.php | 10 ++++++---- src/Liquid/Tag/TagExtends.php | 9 +++++---- src/Liquid/Tag/TagInclude.php | 9 +++++---- src/Liquid/Template.php | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 6f6b120c..e6d097e9 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -32,19 +32,21 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) } /** - * Check for cached includes + * Check for cached includes; if there are - do not use cache * + * @see \Liquid\Tag\TagInclude::hasIncludes() + * @see \Liquid\Tag\TagExtends::hasIncludes() * @return string */ - public function checkIncludes() + public function hasIncludes() { foreach ($this->nodelist as $token) { // check any of the tokens for includes - if ($token instanceof TagInclude && $token->checkIncludes()) { + if ($token instanceof TagInclude && $token->hasIncludes()) { return true; } - if ($token instanceof TagExtends && $token->checkIncludes()) { + if ($token instanceof TagExtends && $token->hasIncludes()) { return true; } } diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 4de08863..386d7abb 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -169,20 +169,21 @@ public function parse(array &$tokens) $this->document = $cache->read($this->hash); - if ($this->document == false || $this->document->checkIncludes() == true) { + if ($this->document == false || $this->document->hasIncludes() == true) { $this->document = new Document($rest, $this->fileSystem); $cache->write($this->hash, $this->document); } } /** - * Check for cached includes + * Check for cached includes; if there are - do not use cache * + * @see Document::hasIncludes() * @return boolean */ - public function checkIncludes() + public function hasIncludes() { - if ($this->document->checkIncludes() == true) { + if ($this->document->hasIncludes() == true) { return true; } diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 5d5eb091..26889070 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -132,7 +132,7 @@ public function parse(array &$tokens) $this->hash = md5($source); $this->document = $cache->read($this->hash); - if ($this->document == false || $this->document->checkIncludes() == true) { + if ($this->document == false || $this->document->hasIncludes() == true) { $templateTokens = Template::tokenize($source); $this->document = new Document($templateTokens, $this->fileSystem); $cache->write($this->hash, $this->document); @@ -140,13 +140,14 @@ public function parse(array &$tokens) } /** - * check for cached includes + * Check for cached includes; if there are - do not use cache * + * @see Document::hasIncludes() * @return boolean */ - public function checkIncludes() + public function hasIncludes() { - if ($this->document->checkIncludes() == true) { + if ($this->document->hasIncludes() == true) { return true; } diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index ca3c147c..2eabf43a 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -173,7 +173,7 @@ public function parse($source) $this->root = self::$cache->read($hash); // if no cached version exists, or if it checks for includes - if ($this->root == false || $this->root->checkIncludes() == true) { + if ($this->root == false || $this->root->hasIncludes() == true) { $this->parseAlways($source); self::$cache->write($hash, $this->root); } From 26889dde30ff2de8cc2bc0764dd3b50fcf2051a2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 15:35:44 +0900 Subject: [PATCH 129/296] Document::hasIncludes() - this may be suboptimal, but if we re-render all 'blocks' we see, we avoid most if not all related caching quirks (has to fix #65) --- src/Liquid/Document.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index e6d097e9..9920c662 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -13,6 +13,7 @@ use Liquid\Tag\TagInclude; use Liquid\Tag\TagExtends; +use Liquid\Tag\TagBlock; /** * This class represents the entire template document. @@ -41,6 +42,12 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) public function hasIncludes() { foreach ($this->nodelist as $token) { + // this may be suboptimal, but if we re-render all blocks we see, + // we avoid most if not all related caching quirks + if ($token instanceof TagBlock) { + return true; + } + // check any of the tokens for includes if ($token instanceof TagInclude && $token->hasIncludes()) { return true; From bb86dee3a87e6867e59f96712355ddc9dd132346 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 26 Sep 2017 19:21:19 +0900 Subject: [PATCH 130/296] TagExtendsTest: test for issue #65 --- tests/Liquid/Tag/TagExtendsTest.php | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 1f3feb6f..12bad468 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -81,6 +81,41 @@ public function testWithCache() $template->setCache(null); } + /** + * Render calls in this test will give different results (and fail the test) with cache enabled + */ + public function testExtendsReplaceContentWithCache() + { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'outer' => "{% block content %}Content for outer block{% endblock %} / {% block footer %}Footer for outer block{% endblock %}", + 'inner' => "{% extends 'outer' %}{% block content %}Content for inner block{% endblock %}", + ))); + + $contentsWithoutCache = $template->parseFile('inner')->render(); + + $template->setCache(new Local()); + $template->parseFile('outer'); + + $this->assertEquals($contentsWithoutCache, $template->parseFile('inner')->render()); + } + + public function testExtendsReplaceContentWithVariables() + { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'outer' => "{% block content %}Outer{{ a }}{% endblock %}Spacer{{ a }}{% block footer %}Footer{{ a }}{% endblock %}", + 'middle' => "{% extends 'outer' %}{% block content %}Inner{{ a }}{% endblock %}", + ))); + + $template->setCache(new Local()); + + $template->parseFile('outer')->render(['a' => '0']); + $template->parseFile('middle')->render(['a' => '1']); + $template->parseFile('middle')->render(['a' => '2']); + $this->assertEquals('Inner3Spacer3Footer3', $template->parseFile('middle')->render(['a' => '3'])); + } + /** * @expectedException \Liquid\LiquidException */ From 2cdfcbea4cc1819db3a2d2ad22f41d0a6d8ad72a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 26 Sep 2017 13:58:09 +0900 Subject: [PATCH 131/296] TagIncludeTest: a test that fails with cache enabled, as in issue #65 --- tests/Liquid/Tag/TagIncludeTest.php | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 1e6d2a7d..0981787c 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -189,4 +189,34 @@ public function testIncludeWithoutQuotes() $output = $template->render(array("var" => "test")); $this->assertEquals("[test] (test)", $output); } + + /** + * Render calls in this test shall give same results with cache enabled + */ + public function testIncludeWithExtends() + { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'outer' => "{% block content %}Content for outer block{% endblock %} / {% block footer %}Footer for outer block{% endblock %}", + 'content' => 'Content for {{ name }} block', + 'middle' => "{% extends 'outer' %}{% block content %}{% include 'content' name:'middle' %}{% endblock %}", + 'main' => "Main: {% extends 'middle' %}{% block footer %}{% include 'footer-top' hello:message %}{% endblock %}", + 'footer-bottom' => "{{ name }} with message: {{ hello }}", + 'footer-top' => "Footer top and {% include 'footer-bottom' name:'bottom' %}", + ))); + + $template->setCache(new Local()); + + foreach (array("Before cache", "With cache") as $type) { + $this->assertEquals("Block with message: $type", $template->parseFile('footer-bottom')->render(array("name" => "Block", "hello" => $type))); + $this->assertEquals('Content for middle block / Footer for outer block', $template->parseFile('middle')->render()); + $this->assertEquals("Main: Content for middle block / Footer top and bottom with message: $type", $template->parseFile('main')->render(array("message" => $type))); + + $template->parse("{% include 'main' hello:message %}"); + $output = $template->render(array("message" => $type)); + $this->assertEquals("Main: Content for middle block / Footer top and bottom with message: $type", $output); + } + + $template->setCache(null); + } } From 65e8441e67df213fdd0df5a123e6e2a02e818744 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 17:23:46 +0900 Subject: [PATCH 132/296] TagIncludeTest for simple include without quotes --- tests/Liquid/Tag/TagIncludeTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 0981787c..1821d714 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -175,7 +175,6 @@ public function testIncludePassObjectValue() $this->assertEquals("([b])", $output); } - public function testIncludeWithoutQuotes() { $template = new Template(); @@ -188,6 +187,11 @@ public function testIncludeWithoutQuotes() $output = $template->render(array("var" => "test")); $this->assertEquals("[test] (test)", $output); + + $template->parse("{% include inner %}"); + + $output = $template->render(array("other" => "test")); + $this->assertEquals("[test]", $output); } /** From 12f20fb291cd72c3fc361514d0e6d564ab65af83 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 17:32:08 +0900 Subject: [PATCH 133/296] Changelog for 1.4.1 --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 19f6bca8..1cf7a15c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ * master +* 1.4.1 (2017-09-28) + + * Unquoted template names in 'include' tag, as in Jekyll + * Caching now works correctly with 'extends' tag + * 1.4.0 (2017-09-25) * Dropped support for EOL'ed versions of PHP (< 5.6) From 6a4adcaf599a84ade0bdde3f368ed44a2bf6b7a9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 17:51:27 +0900 Subject: [PATCH 134/296] Test for extends and include tags where a file changes from under the cache --- tests/Liquid/Tag/TagExtendsTest.php | 27 +++++++++++++++++++++++++++ tests/Liquid/Tag/TagIncludeTest.php | 20 ++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 12bad468..5e789c8d 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -116,6 +116,33 @@ public function testExtendsReplaceContentWithVariables() $this->assertEquals('Inner3Spacer3Footer3', $template->parseFile('middle')->render(['a' => '3'])); } + public function testCacheDiscardedIfFileChanges() + { + $template = new Template(); + $template->setCache(new Local()); + + $content = "[{{ name }}]"; + $template->setFileSystem(TestFileSystem::fromArray(array( + 'outer' => &$content, + 'inner' => "{% extends 'outer' %}" + ))); + + $template->parseFile('inner'); + $output = $template->render(array("name" => "Example")); + $this->assertEquals("[Example]", $output); + + // this should go from cache + $template->parse("{% extends 'outer' %}"); + $output = $template->render(array("name" => "Example")); + $this->assertEquals("[Example]", $output); + + // content change should trigger re-render + $content = "<{{ name }}>"; + $template->parseFile('inner'); + $output = $template->render(array("name" => "Example")); + $this->assertEquals("", $output); + } + /** * @expectedException \Liquid\LiquidException */ diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 1821d714..7724d4df 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -223,4 +223,24 @@ public function testIncludeWithExtends() $template->setCache(null); } + + public function testCacheDiscardedIfFileChanges() + { + $template = new Template(); + $template->setCache(new Local()); + + $content = "[{{ name }}]"; + $template->setFileSystem(TestFileSystem::fromArray(array( + 'example' => &$content, + ))); + + $template->parse("{% include 'example' %}"); + $output = $template->render(array("name" => "Example")); + $this->assertEquals("[Example]", $output); + + $content = "<{{ name }}>"; + $template->parse("{% include 'example' %}"); + $output = $template->render(array("name" => "Example")); + $this->assertEquals("", $output); + } } From 391e152657f742cdd8995c7db612ab7cc805f540 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 18:22:12 +0900 Subject: [PATCH 135/296] TagExtends: try to keep the base templates in cache (that not extend anything) --- src/Liquid/Document.php | 25 ++++++++++++++++++++----- tests/Liquid/Tag/TagExtendsTest.php | 6 ++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index 9920c662..ec7e3508 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -37,17 +37,32 @@ public function __construct(array &$tokens, FileSystem $fileSystem = null) * * @see \Liquid\Tag\TagInclude::hasIncludes() * @see \Liquid\Tag\TagExtends::hasIncludes() - * @return string + * @return bool if need to discard cache */ public function hasIncludes() { + $seenExtends = false; + $seenBlock = false; + foreach ($this->nodelist as $token) { - // this may be suboptimal, but if we re-render all blocks we see, - // we avoid most if not all related caching quirks - if ($token instanceof TagBlock) { - return true; + if ($token instanceof TagExtends) { + $seenExtends = true; + } elseif ($token instanceof TagBlock) { + $seenBlock = true; } + } + /* + * We try to keep the base templates in cache (that not extend anything). + * + * At the same time if we re-render all other blocks we see, we avoid most + * if not all related caching quirks. This may be suboptimal. + */ + if ($seenBlock && !$seenExtends) { + return true; + } + + foreach ($this->nodelist as $token) { // check any of the tokens for includes if ($token instanceof TagInclude && $token->hasIncludes()) { return true; diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 5e789c8d..22a6414b 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -105,7 +105,8 @@ public function testExtendsReplaceContentWithVariables() $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'outer' => "{% block content %}Outer{{ a }}{% endblock %}Spacer{{ a }}{% block footer %}Footer{{ a }}{% endblock %}", - 'middle' => "{% extends 'outer' %}{% block content %}Inner{{ a }}{% endblock %}", + 'middle' => "{% extends 'outer' %}{% block content %}Middle{{ a }}{% endblock %}", + 'inner' => "{% extends 'middle' %}{% block content %}Inner{{ a }}{% endblock %}", ))); $template->setCache(new Local()); @@ -113,7 +114,8 @@ public function testExtendsReplaceContentWithVariables() $template->parseFile('outer')->render(['a' => '0']); $template->parseFile('middle')->render(['a' => '1']); $template->parseFile('middle')->render(['a' => '2']); - $this->assertEquals('Inner3Spacer3Footer3', $template->parseFile('middle')->render(['a' => '3'])); + $this->assertEquals('Middle3Spacer3Footer3', $template->parseFile('middle')->render(['a' => '3'])); + $this->assertEquals('Inner4Spacer4Footer4', $template->parseFile('inner')->render(['a' => '4'])); } public function testCacheDiscardedIfFileChanges() From 5b18aec60165006dbbd391c4306ec58206289b10 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 18:30:58 +0900 Subject: [PATCH 136/296] Test that raw tag ignores other tags --- tests/Liquid/Tag/TagRawTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Liquid/Tag/TagRawTest.php b/tests/Liquid/Tag/TagRawTest.php index adf77921..21a90d95 100644 --- a/tests/Liquid/Tag/TagRawTest.php +++ b/tests/Liquid/Tag/TagRawTest.php @@ -18,8 +18,8 @@ class TagRawTest extends TestCase public function testRaw() { $this->assertTemplateResult( - '{{ y | plus: x }}{{{hello}}} is equal to 11.', - '{% raw %}{{ y | plus: x }}{{{hello}}}{% endraw %} is equal to 11.', + '{{ y | plus: x }}{% if %} is equal to 11.', + '{% raw %}{{ y | plus: x }}{% if %}{% endraw %} is equal to 11.', array('x' => 5, 'y' => 6) ); From c1dfbd596016075b2df5f01122bace55522178c6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 18:41:30 +0900 Subject: [PATCH 137/296] CustomTagTest - for Template::registerTag --- tests/Liquid/CustomTagTest.php | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/Liquid/CustomTagTest.php diff --git a/tests/Liquid/CustomTagTest.php b/tests/Liquid/CustomTagTest.php new file mode 100644 index 00000000..c6e86d91 --- /dev/null +++ b/tests/Liquid/CustomTagTest.php @@ -0,0 +1,39 @@ +parse('[ba{% foo %} Comment {% endfoo %}r]'); + } + + public function testCustomTag() + { + $template = new Template(); + $template->registerTag('foo', TagFoo::class); + $template->parse('[ba{% foo %} Comment {% endfoo %}r]'); + $this->assertEquals('[bar]', $template->render()); + } +} From 00af5988c842d3841e9b93d1074cd7e28e59a48c Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Sep 2017 19:25:14 +0900 Subject: [PATCH 138/296] Test case with fixtures --- tests/Liquid/FixturesTest.php | 43 ++++++++++++++++++++++++++++ tests/Liquid/fixtures/comment.html | 1 + tests/Liquid/fixtures/comment.liquid | 1 + tests/Liquid/fixtures/comment.php | 12 ++++++++ tests/Liquid/fixtures/include.html | 2 ++ tests/Liquid/fixtures/include.liquid | 2 ++ tests/Liquid/fixtures/include.php | 12 ++++++++ tests/Liquid/fixtures/output.html | 4 +++ tests/Liquid/fixtures/output.liquid | 4 +++ tests/Liquid/fixtures/output.php | 18 ++++++++++++ 10 files changed, 99 insertions(+) create mode 100644 tests/Liquid/FixturesTest.php create mode 100644 tests/Liquid/fixtures/comment.html create mode 100644 tests/Liquid/fixtures/comment.liquid create mode 100644 tests/Liquid/fixtures/comment.php create mode 100644 tests/Liquid/fixtures/include.html create mode 100644 tests/Liquid/fixtures/include.liquid create mode 100644 tests/Liquid/fixtures/include.php create mode 100644 tests/Liquid/fixtures/output.html create mode 100644 tests/Liquid/fixtures/output.liquid create mode 100644 tests/Liquid/fixtures/output.php diff --git a/tests/Liquid/FixturesTest.php b/tests/Liquid/FixturesTest.php new file mode 100644 index 00000000..d3d4ecda --- /dev/null +++ b/tests/Liquid/FixturesTest.php @@ -0,0 +1,43 @@ +setFileSystem(new Virtual(function ($filename) { + if (is_file(__DIR__.'/fixtures/'.$filename)) { + return file_get_contents(__DIR__.'/fixtures/'.$filename); + } + })); + + $template->parse(file_get_contents($liquid)); + $result = $template->render(include $data); + + $this->assertEquals(file_get_contents($expected), $result); + } + + public function fixtures() + { + return array_map(null, glob(__DIR__.'/fixtures/*.liquid'), glob(__DIR__.'/fixtures/*.php'), glob(__DIR__.'/fixtures/*.html')); + } +} diff --git a/tests/Liquid/fixtures/comment.html b/tests/Liquid/fixtures/comment.html new file mode 100644 index 00000000..9bdb7c0b --- /dev/null +++ b/tests/Liquid/fixtures/comment.html @@ -0,0 +1 @@ +We made 1 million dollars this year \ No newline at end of file diff --git a/tests/Liquid/fixtures/comment.liquid b/tests/Liquid/fixtures/comment.liquid new file mode 100644 index 00000000..83f8d6e7 --- /dev/null +++ b/tests/Liquid/fixtures/comment.liquid @@ -0,0 +1 @@ +We made 1 million dollars {% comment %} in losses {% endcomment %} this year \ No newline at end of file diff --git a/tests/Liquid/fixtures/comment.php b/tests/Liquid/fixtures/comment.php new file mode 100644 index 00000000..a1ea6892 --- /dev/null +++ b/tests/Liquid/fixtures/comment.php @@ -0,0 +1,12 @@ + 'Harald', + 'company' => 'DELACAP', + 'user' => array( + 'name' => 'Superuser' + ) +); From 4bc643cebecdd2035b03c1bf8722c2fc47a0d917 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 29 Sep 2017 10:02:48 +0900 Subject: [PATCH 139/296] Fixtures for 'case' and 'for' tags --- tests/Liquid/fixtures/case.html | 22 +++++++++ tests/Liquid/fixtures/case.liquid | 11 +++++ tests/Liquid/fixtures/case.php | 14 ++++++ tests/Liquid/fixtures/for.html | 80 +++++++++++++++++++++++++++++++ tests/Liquid/fixtures/for.liquid | 26 ++++++++++ tests/Liquid/fixtures/for.php | 17 +++++++ 6 files changed, 170 insertions(+) create mode 100644 tests/Liquid/fixtures/case.html create mode 100644 tests/Liquid/fixtures/case.liquid create mode 100644 tests/Liquid/fixtures/case.php create mode 100644 tests/Liquid/fixtures/for.html create mode 100644 tests/Liquid/fixtures/for.liquid create mode 100644 tests/Liquid/fixtures/for.php diff --git a/tests/Liquid/fixtures/case.html b/tests/Liquid/fixtures/case.html new file mode 100644 index 00000000..5f23814c --- /dev/null +++ b/tests/Liquid/fixtures/case.html @@ -0,0 +1,22 @@ + + + hit 1 + + + + hit 2 or 3 + + + + ... else ... + + + + ... else ... + + + + ... else ... + + + diff --git a/tests/Liquid/fixtures/case.liquid b/tests/Liquid/fixtures/case.liquid new file mode 100644 index 00000000..1fcbcd44 --- /dev/null +++ b/tests/Liquid/fixtures/case.liquid @@ -0,0 +1,11 @@ +{% for i in (1..max) %} + {% case i %} + {% when 1 %} + hit 1 + {% when 2 or 3 %} + hit 2 or 3 + {% else %} + ... else ... + {% endcase %} +{% endfor %} + diff --git a/tests/Liquid/fixtures/case.php b/tests/Liquid/fixtures/case.php new file mode 100644 index 00000000..c0ffa720 --- /dev/null +++ b/tests/Liquid/fixtures/case.php @@ -0,0 +1,14 @@ + 5, +); diff --git a/tests/Liquid/fixtures/for.html b/tests/Liquid/fixtures/for.html new file mode 100644 index 00000000..951b6232 --- /dev/null +++ b/tests/Liquid/fixtures/for.html @@ -0,0 +1,80 @@ +Helper variables: + + 1 => current item + 5 => length of the entire for loop + 1 => index of the current iteration + 0 => index of the current iteration (zero based) + 5 => how many items are still left? + 4 => how many items are still left? (zero based) + 1 => is this the first iteration? + 0 => is this the last iternation? + + 2 => current item + 5 => length of the entire for loop + 2 => index of the current iteration + 1 => index of the current iteration (zero based) + 4 => how many items are still left? + 3 => how many items are still left? (zero based) + 0 => is this the first iteration? + 0 => is this the last iternation? + + 3 => current item + 5 => length of the entire for loop + 3 => index of the current iteration + 2 => index of the current iteration (zero based) + 3 => how many items are still left? + 2 => how many items are still left? (zero based) + 0 => is this the first iteration? + 0 => is this the last iternation? + + 4 => current item + 5 => length of the entire for loop + 4 => index of the current iteration + 3 => index of the current iteration (zero based) + 2 => how many items are still left? + 1 => how many items are still left? (zero based) + 0 => is this the first iteration? + 0 => is this the last iternation? + + 5 => current item + 5 => length of the entire for loop + 5 => index of the current iteration + 4 => index of the current iteration (zero based) + 1 => how many items are still left? + 0 => how many items are still left? (zero based) + 0 => is this the first iteration? + 1 => is this the last iternation? + + +Limit and offset: + + 3 + + 4 + + +Reversing the loop: + + 1 + + 2 + + 3 + + 4 + + 5 + + +Range loop: + + 1 + + 2 + + 3 + + 4 + + 5 + diff --git a/tests/Liquid/fixtures/for.liquid b/tests/Liquid/fixtures/for.liquid new file mode 100644 index 00000000..e1e6834b --- /dev/null +++ b/tests/Liquid/fixtures/for.liquid @@ -0,0 +1,26 @@ +Helper variables: +{% for item in array %} + {{ item }} => current item + {{ forloop.length }} => length of the entire for loop + {{ forloop.index }} => index of the current iteration + {{ forloop.index0 }} => index of the current iteration (zero based) + {{ forloop.rindex }} => how many items are still left? + {{ forloop.rindex0 }} => how many items are still left? (zero based) + {{ forloop.first }} => is this the first iteration? + {{ forloop.last }} => is this the last iternation? +{% endfor %} + +Limit and offset: +{% for item in array limit:2 offset:2 %} + {{ item }} +{% endfor %} + +Reversing the loop: +{% for item in array reversed %} + {{ item }} +{% endfor %} + +Range loop: +{% for i in (1..item.quantity) %} + {{ i }} +{% endfor %} diff --git a/tests/Liquid/fixtures/for.php b/tests/Liquid/fixtures/for.php new file mode 100644 index 00000000..0b75cc66 --- /dev/null +++ b/tests/Liquid/fixtures/for.php @@ -0,0 +1,17 @@ + range(1, 5), + 'item' => array( + 'quantity' => 5, + ), +); From 8f3e4ab62f1c1272584f1d955e6467958b5704d2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 29 Sep 2017 10:53:21 +0900 Subject: [PATCH 140/296] Fixture for cycle tag --- tests/Liquid/fixtures/cycle.html | 9 +++++++++ tests/Liquid/fixtures/cycle.liquid | 9 +++++++++ tests/Liquid/fixtures/cycle.php | 12 ++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/Liquid/fixtures/cycle.html create mode 100644 tests/Liquid/fixtures/cycle.liquid create mode 100644 tests/Liquid/fixtures/cycle.php diff --git a/tests/Liquid/fixtures/cycle.html b/tests/Liquid/fixtures/cycle.html new file mode 100644 index 00000000..e605ecfb --- /dev/null +++ b/tests/Liquid/fixtures/cycle.html @@ -0,0 +1,9 @@ +one +two +three +one + +one +two +one +two \ No newline at end of file diff --git a/tests/Liquid/fixtures/cycle.liquid b/tests/Liquid/fixtures/cycle.liquid new file mode 100644 index 00000000..87bd5005 --- /dev/null +++ b/tests/Liquid/fixtures/cycle.liquid @@ -0,0 +1,9 @@ +{% cycle 'one', 'two', 'three' %} +{% cycle 'one', 'two', 'three' %} +{% cycle 'one', 'two', 'three' %} +{% cycle 'one', 'two', 'three' %} + +{% cycle 'group 1': 'one', 'two', 'three' %} +{% cycle 'group 1': 'one', 'two', 'three' %} +{% cycle 'group 2': 'one', 'two', 'three' %} +{% cycle 'group 2': 'one', 'two', 'three' %} \ No newline at end of file diff --git a/tests/Liquid/fixtures/cycle.php b/tests/Liquid/fixtures/cycle.php new file mode 100644 index 00000000..a1ea6892 --- /dev/null +++ b/tests/Liquid/fixtures/cycle.php @@ -0,0 +1,12 @@ + Date: Fri, 29 Sep 2017 10:54:00 +0900 Subject: [PATCH 141/296] Fixture for the bulk of filters --- tests/Liquid/fixtures/filters.html | 53 ++++++++++++++++++++++++++++ tests/Liquid/fixtures/filters.liquid | 50 ++++++++++++++++++++++++++ tests/Liquid/fixtures/filters.php | 19 ++++++++++ 3 files changed, 122 insertions(+) create mode 100644 tests/Liquid/fixtures/filters.html create mode 100644 tests/Liquid/fixtures/filters.liquid create mode 100644 tests/Liquid/fixtures/filters.php diff --git a/tests/Liquid/fixtures/filters.html b/tests/Liquid/fixtures/filters.html new file mode 100644 index 00000000..1e350943 --- /dev/null +++ b/tests/Liquid/fixtures/filters.html @@ -0,0 +1,53 @@ +Hello TOBI +Hello tobi has 4 letters! +Array has 3 elements. +Second element is: n +*TOBI* +1971 Jan +foobar +Tobi +tobi +5 #=> 5 +2 #=> 2 +0 #=> 0, not as is in the docs +2 #=> 2 +0 #=> 'foofoofoofoo' +20 #=> 20 +4 #=> 4 +4 #=> 4 +5 #=> 5 +<div>Read more</div> &rarr; +<div>Read more</div> → +Read more → +
Read more
→ +a%3Db%26c%3Dd +a=&b #=> 'a=&b' +Foo +[ Foo] +[Foo ] +OK +z +z, g, n +n +g-n-z +n-g-z +Foo
+Bar +FooBar +foobar +barbar #=> 'barbar' +foobar #=> 'foobar' +barbar #=> 'barbar' +bar #=> 'bar' +test... #=> 'test...' +Foo bar... #=> 'Foo bar...' +Foo #=> 'Foo' +Foo bar #=> 'Foo bar' + + + + + BazBar + + FooBar + diff --git a/tests/Liquid/fixtures/filters.liquid b/tests/Liquid/fixtures/filters.liquid new file mode 100644 index 00000000..7307cab4 --- /dev/null +++ b/tests/Liquid/fixtures/filters.liquid @@ -0,0 +1,50 @@ +Hello {{ 'tobi' | upcase }} +Hello tobi has {{ 'tobi' | size }} letters! +Array has {{ array | size }} elements. +Second element is: {{ array | slice: 2 | first }} +{{ '*tobi*' | textilize | upcase }} +{{ '1971-01-01' | date: "%Y %h" }} +{{ 'foo' | append:'bar' }} +{{ 'tobi' | capitalize }} +{{ 'Tobi' | downcase }} +{{ 10 | divided_by:2 }} #=> 5 +{{ 4 | minus:2 }} #=> 2 +{{ 'a' | plus:'b' }} #=> 0, not as is in the docs +{{ 1 | plus:1 }} #=> 2 +{{ 'foo' | times:4 }} #=> 'foofoofoofoo' +{{ 5 | times:4 }} #=> 20 +{{ 4.3 | round }} #=> 4 +{{ 4.8 | floor }} #=> 4 +{{ 4.3 | ceil }} #=> 5 +{{ '
Read more
→' | escape }} +{{ '
Read more
→' | escape_once }} +{{ '
Read more
→' | strip_html }} +{{ '
Read more
→' | raw }} +{{ 'a=b&c=d' | url_encode }} +{{ 'a%3D%26b' | url_decode }} #=> 'a=&b' +{{ ' Foo ' | strip }} +[{{ ' Foo ' | rstrip }}] +[{{ ' Foo ' | lstrip }}] +{{ '' | default: "OK" }} +{{ array | first }} +{{ array | join:', ' }} +{{ array | last }} +{{ array | sort | join:'-' }} +{{ array | reverse | join:'-' }} +{{ foobar | newline_to_br }} +{{ foobar | strip_newlines }} +{{ 'bar' | prepend:'foo' }} +{{ 'foofoo' | replace:'foo','bar' }} #=> 'barbar' +{{ 'barbar' | replace_first:'bar','foo' }} #=> 'foobar' +{{ 'foobarfoobar' | remove:'foo' }} #=> 'barbar' +{{ 'barbar' | remove_first:'bar' }} #=> 'bar' +{{ 'tests' | truncate:4 }} #=> 'test...' +{{ 'Foo bar bar' | truncatewords:2 }} #=> 'Foo bar...' +{{ 'Foo bar bar' | split: " " | first }} #=> 'Foo' +{{ 'Foo bar bar' | split: " " | uniq | join: " " }} #=> 'Foo bar' + + +{% assign titles = posts | sort: "id" | map: "title" %} +{% for title in titles %} + {{ title }} +{% endfor %} diff --git a/tests/Liquid/fixtures/filters.php b/tests/Liquid/fixtures/filters.php new file mode 100644 index 00000000..00b6a927 --- /dev/null +++ b/tests/Liquid/fixtures/filters.php @@ -0,0 +1,19 @@ + array('z', 'g', 'n'), + 'foobar' => "Foo\nBar", + 'posts' => array( + array('id' => 2, 'title'=> 'FooBar', 'tags' => array('foo', 'bar')), + array('id' => 1, 'title'=> 'BazBar', 'tags' => array('baz', 'bar')), + ), +); From c61a969ec6da6a7acd6dc7d1234cca2bebd998f1 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 29 Sep 2017 10:54:33 +0900 Subject: [PATCH 142/296] Test for extends without default block contents --- tests/Liquid/Tag/TagExtendsTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 22a6414b..14b8b8c1 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -118,6 +118,23 @@ public function testExtendsReplaceContentWithVariables() $this->assertEquals('Inner4Spacer4Footer4', $template->parseFile('inner')->render(['a' => '4'])); } + public function testExtendsWithEmptyDefaultContent() + { + $template = new Template(); + $template->setFileSystem(TestFileSystem::fromArray(array( + 'base' => "
{% block content %}{% endblock %}
", + 'extends' => "{% extends 'base' %}{% block content %}{{ test }}{% endblock %}", + ))); + + $template->setCache(new Local()); + + $template->parseFile('base')->render(); + $template->parseFile('extends')->render(['test' => 'Foo']); + $template->parseFile('extends')->render(['test' => 'Bar']); + $this->assertEquals('
Baz
', $template->parseFile('extends')->render(['test' => 'Baz'])); + $this->assertEquals('
', $template->parseFile('base')->render()); + } + public function testCacheDiscardedIfFileChanges() { $template = new Template(); From 02fedf7074ae3bace20411b283fbe730f3c836e8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 2 Oct 2017 22:33:43 +0900 Subject: [PATCH 143/296] Test for filters in assign See Shopify/liquid#975b17b529 --- tests/Liquid/fixtures/assign.html | 3 +++ tests/Liquid/fixtures/assign.liquid | 3 +++ tests/Liquid/fixtures/assign.php | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 tests/Liquid/fixtures/assign.html create mode 100644 tests/Liquid/fixtures/assign.liquid create mode 100644 tests/Liquid/fixtures/assign.php diff --git a/tests/Liquid/fixtures/assign.html b/tests/Liquid/fixtures/assign.html new file mode 100644 index 00000000..565a6c12 --- /dev/null +++ b/tests/Liquid/fixtures/assign.html @@ -0,0 +1,3 @@ + +First +Second diff --git a/tests/Liquid/fixtures/assign.liquid b/tests/Liquid/fixtures/assign.liquid new file mode 100644 index 00000000..9c17dfbb --- /dev/null +++ b/tests/Liquid/fixtures/assign.liquid @@ -0,0 +1,3 @@ +{% assign descriptions = product.description | split: '' %} +{{ descriptions[0] }} +{{ descriptions[1] }} diff --git a/tests/Liquid/fixtures/assign.php b/tests/Liquid/fixtures/assign.php new file mode 100644 index 00000000..b488a8ac --- /dev/null +++ b/tests/Liquid/fixtures/assign.php @@ -0,0 +1,16 @@ + array( + 'description' => 'FirstSecond', + ), +); From 3def71ee6f6cbf6a6d50ff2418fa5e4509e43054 Mon Sep 17 00:00:00 2001 From: jfoucher Date: Mon, 2 Oct 2017 04:54:53 +0200 Subject: [PATCH 144/296] Allow using `FILTER_SEPARATOR` as a split filter parameter in filters. Refactor TagAssign to use a `Variable` instance in the value assignment instead of a string. Remove `QUOTED_STRING` config from the TestCase as it was different from the default config for no reason that I could see. --- src/Liquid/Liquid.php | 2 -- src/Liquid/Tag/TagAssign.php | 40 +++--------------------- src/Liquid/Variable.php | 49 +++++++++++++++--------------- tests/Liquid/AbstractBlockTest.php | 25 +++++++++++++++ tests/Liquid/Tag/TagAssignTest.php | 14 +++++++++ tests/Liquid/TestCase.php | 1 - 6 files changed, 67 insertions(+), 64 deletions(-) create mode 100644 tests/Liquid/AbstractBlockTest.php diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 05599df2..c2cc8da2 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -94,8 +94,6 @@ public static function get($key) switch ($key) { case 'QUOTED_FRAGMENT': return self::$config['QUOTED_STRING'] . '|(?:[^\s,\|\'"]|' . self::$config['QUOTED_STRING'] . ')+'; - case 'QUOTED_FRAGMENT_FILTER_ARGUMENT': - return self::$config['QUOTED_STRING_FILTER_ARGUMENT'] . '|(?:[^\s:,\|\'"]|' . self::$config['QUOTED_STRING_FILTER_ARGUMENT'] . ')+'; case 'TAG_ATTRIBUTES': return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; case 'TOKENIZATION_REGEXP': diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index dddf8692..6e01c737 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -17,6 +17,7 @@ use Liquid\FileSystem; use Liquid\Regexp; use Liquid\Context; +use Liquid\Variable; /** * Performs an assignment of one variable to another @@ -49,32 +50,11 @@ class TagAssign extends AbstractTag */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { - $syntaxRegexp = new Regexp('/(\w+)\s*=\s*(' . Liquid::get('QUOTED_FRAGMENT') . '+)/'); - - $filterSeperatorRegexp = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '\s*(.*)/'); - $filterSplitRegexp = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '/'); - $filterNameRegexp = new Regexp('/\s*(\w+)/'); - $filterArgumentRegexp = new Regexp('/(?:' . Liquid::get('FILTER_ARGUMENT_SEPARATOR') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')/'); - - $this->filters = array(); - - if ($filterSeperatorRegexp->match($markup)) { - $filters = $filterSplitRegexp->split($filterSeperatorRegexp->matches[1]); - - foreach ($filters as $filter) { - $filterNameRegexp->match($filter); - $filtername = $filterNameRegexp->matches[1]; - - $filterArgumentRegexp->matchAll($filter); - $matches = Liquid::arrayFlatten($filterArgumentRegexp->matches[1]); - - array_push($this->filters, array($filtername, $matches)); - } - } + $syntaxRegexp = new Regexp('/(\w+)\s*=\s*(.*)\s*/'); if ($syntaxRegexp->match($markup)) { $this->to = $syntaxRegexp->matches[1]; - $this->from = $syntaxRegexp->matches[2]; + $this->from = new Variable($syntaxRegexp->matches[2]); } else { throw new LiquidException("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"); } @@ -89,19 +69,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu */ public function render(Context $context) { - $output = $context->get($this->from); - - foreach ($this->filters as $filter) { - list($filtername, $filterArgKeys) = $filter; - - $filterArgValues = array(); - - foreach ($filterArgKeys as $arg_key) { - $filterArgValues[] = $context->get($arg_key); - } - - $output = $context->invoke($filtername, $output, $filterArgValues); - } + $output = $this->from->render($context); $context->set($this->to, $output, true); } diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index 82abc5af..2ac3d89b 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -40,30 +40,30 @@ public function __construct($markup) { $this->markup = $markup; - $quotedFragmentRegexp = new Regexp('/\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')/'); - $filterSeperatorRegexp = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '\s*(.*)/'); - $filterSplitRegexp = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '/'); - $filterNameRegexp = new Regexp('/\s*(\w+)/'); - $filterArgumentRegexp = new Regexp('/(?:' . Liquid::get('FILTER_ARGUMENT_SEPARATOR') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')\s*(' . Liquid::get('QUOTED_FRAGMENT_FILTER_ARGUMENT') . ')/'); - - $quotedFragmentRegexp->match($markup); - - $this->name = (isset($quotedFragmentRegexp->matches[1])) ? $quotedFragmentRegexp->matches[1] : null; - - if ($filterSeperatorRegexp->match($markup)) { - $filters = $filterSplitRegexp->split($filterSeperatorRegexp->matches[1]); - - foreach ($filters as $filter) { - $filterNameRegexp->match($filter); - $filtername = $filterNameRegexp->matches[1]; - - $filterArgumentRegexp->matchAll($filter); - $matches = Liquid::arrayFlatten($filterArgumentRegexp->matches[1]); - - $this->filters[] = array($filtername, $matches); + $filterSep = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '\s*(.*)/m'); + $syntaxParser = new Regexp('/(' . Liquid::get('QUOTED_FRAGMENT') . ')(.*)/m'); + $filterParser = new Regexp('/(?:\s+|' . Liquid::get('QUOTED_FRAGMENT') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')+/'); + $filterArgsRegex = new Regexp('/(?:' . Liquid::get('FILTER_ARGUMENT_SEPARATOR') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')\s*((?:\w+\s*\:\s*)?' . Liquid::get('QUOTED_FRAGMENT') . ')/'); + + $this->filters = []; + if ($syntaxParser->match($markup)) { + $nameMarkup = $syntaxParser->matches[1]; + $this->name = $nameMarkup; + $filterMarkup = $syntaxParser->matches[2]; + + if ($filterSep->match($filterMarkup)) { + $filterParser->matchAll($filterSep->matches[1]); + + foreach ($filterParser->matches[0] as $filter) { + $filter = trim($filter); + if (preg_match('/\w+/', $filter, $matches)) { + $filterName = $matches[0]; + $filterArgsRegex->matchAll($filter); + $matches = Liquid::arrayFlatten($filterArgsRegex->matches[1]); + $this->filters[] = array($filterName, $matches); + } + } } - } else { - $this->filters = array(); } if (Liquid::get('ESCAPE_BY_DEFAULT')) { @@ -91,6 +91,7 @@ public function __construct($markup) } } + /** * Gets the variable name * @@ -121,7 +122,6 @@ public function getFilters() public function render(Context $context) { $output = $context->get($this->name); - foreach ($this->filters as $filter) { list($filtername, $filterArgKeys) = $filter; @@ -133,7 +133,6 @@ public function render(Context $context) $output = $context->invoke($filtername, $output, $filterArgValues); } - return $output; } } diff --git a/tests/Liquid/AbstractBlockTest.php b/tests/Liquid/AbstractBlockTest.php new file mode 100644 index 00000000..1b49ad9d --- /dev/null +++ b/tests/Liquid/AbstractBlockTest.php @@ -0,0 +1,25 @@ +assertTemplateResult('', '{% block }'); + } +} diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index e73d9549..b8ea652b 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -69,6 +69,20 @@ public function testAssignWithFilters() $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'a.b.c'); } + /** + * Tests filtered value assignment with separators + */ + public function testTagAssignWithSplit() + { + $template = new Template(); + + $template->parse('{% assign rows = "one|two|three,one|two|three" | upcase | split: "," %}{% for row in rows %}{% assign cols = row | split: "|" %}{% for col in cols %} {{col}}{%endfor%}{% endfor %}'); + $this->assertEquals($template->render(), ' ONE TWO THREE ONE TWO THREE'); + + $template->parse('{% assign issue_numbers = "1339|1338|1321" | split: "|" %}{% for issue in issue_numbers %} {{ issue }}{% endfor %}'); + $this->assertEquals($template->render(), ' 1339 1338 1321'); + } + /** * Tests a simple assignment with numbers */ diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 14fa9e95..bbe46aeb 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -39,7 +39,6 @@ protected function setUp() 'VARIABLE_START' => '{{', 'VARIABLE_END' => '}}', 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z0-9_.-]*', - 'QUOTED_STRING' => '"[^":]*"|\'[^\':]*\'', ); foreach ($defaultConfig as $configKey => $configValue) { From 24481328cdfe2cc7b228a33b4ade6111ab967824 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 4 Oct 2017 17:33:12 +0900 Subject: [PATCH 145/296] PHPUnit: create html report by default - helps quickly discover uncovered lines --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 320c95be..a24f730a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,5 +15,6 @@ + From 35b13c0657a6bb23d29f409c156968d18809a961 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 4 Oct 2017 15:40:04 +0900 Subject: [PATCH 146/296] Keep PHP CS Fixer cache between builds (about 20 seconds speed-up) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80806450..7f57c9eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,14 @@ php: cache: directories: - $HOME/.composer/cache + - build/cache install: - composer install --prefer-dist script: - vendor/bin/phpunit --verbose || travis_terminate 1 - - vendor/bin/php-cs-fixer --diff --dry-run --stop-on-violation --verbose fix + - mkdir -p build/cache && vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix after_success: - travis_retry php vendor/bin/coveralls From 51eb6bd42476c38daf519beecec04c9c14594242 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 4 Oct 2017 18:39:18 +0900 Subject: [PATCH 147/296] Test on PHP 7.2 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7f57c9eb..fbdb0109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 5.6 - 7.0 - 7.1 + - 7.2 cache: directories: From b73d29ccba1e8d75d2fffdfc802488f5c921ba58 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 4 Oct 2017 19:15:48 +0900 Subject: [PATCH 148/296] Pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..d5da21d1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +- [ ] I've run the tests with `vendor/bin/phpunit` +- [ ] None of the tests were found failing +- [ ] I've seen the coverage report at `build/coverage/index.html` +- [ ] Not a single line left uncovered by tests +- [ ] Any coding standards issues were fixed with `vendor/bin/php-cs-fixer fix` +- [ ] Hotfix-type commits were squashed with `git rebase -i` or `git commit --amend` +- [ ] All my work wasn't smushed into one large commit without necessity From af3b131628f8df64b7b1cca811e2acc7184b2cfa Mon Sep 17 00:00:00 2001 From: jfoucher Date: Thu, 5 Oct 2017 20:37:03 +0200 Subject: [PATCH 149/296] Throw different types of exception depending on the case instead of always throwing a `LiquidException` --- src/Liquid/AbstractBlock.php | 25 +++++++++++-------- src/Liquid/Cache/File.php | 6 ++--- src/Liquid/Decision.php | 10 +++++--- src/Liquid/Exception/CacheException.php | 21 ++++++++++++++++ src/Liquid/Exception/FilesystemException.php | 21 ++++++++++++++++ src/Liquid/Exception/NotFoundException.php | 21 ++++++++++++++++ src/Liquid/Exception/ParseException.php | 21 ++++++++++++++++ src/Liquid/Exception/RenderException.php | 21 ++++++++++++++++ .../Exception/WrongArgumentException.php | 21 ++++++++++++++++ src/Liquid/FileSystem/Local.php | 17 +++++++------ src/Liquid/FileSystem/Virtual.php | 8 +++--- src/Liquid/Filterbank.php | 8 +++--- src/Liquid/Tag/TagAssign.php | 6 ++--- src/Liquid/Tag/TagBlock.php | 6 ++--- src/Liquid/Tag/TagCapture.php | 6 ++--- src/Liquid/Tag/TagCase.php | 10 ++++---- src/Liquid/Tag/TagCycle.php | 6 ++--- src/Liquid/Tag/TagDecrement.php | 6 ++--- src/Liquid/Tag/TagExtends.php | 11 ++++---- src/Liquid/Tag/TagFor.php | 6 ++--- src/Liquid/Tag/TagIf.php | 6 ++--- src/Liquid/Tag/TagInclude.php | 10 +++++--- src/Liquid/Tag/TagIncrement.php | 6 ++--- src/Liquid/Tag/TagPaginate.php | 6 ++--- src/Liquid/Tag/TagTablerow.php | 11 ++++---- src/Liquid/Template.php | 11 +++++--- tests/Liquid/AbstractBlockTest.php | 2 +- tests/Liquid/Cache/FileTest.php | 4 +-- tests/Liquid/CustomTagTest.php | 2 +- tests/Liquid/FilterbankTest.php | 4 +-- tests/Liquid/OutputTest.php | 2 +- tests/Liquid/Tag/TagAssignTest.php | 2 +- tests/Liquid/Tag/TagBlockTest.php | 2 +- tests/Liquid/Tag/TagCaptureTest.php | 2 +- tests/Liquid/Tag/TagCaseTest.php | 8 +++--- tests/Liquid/Tag/TagCycleTest.php | 2 +- tests/Liquid/Tag/TagExtendsTest.php | 9 ++++--- tests/Liquid/Tag/TagForTest.php | 2 +- tests/Liquid/Tag/TagIfTest.php | 12 ++++----- tests/Liquid/Tag/TagIncludeTest.php | 10 ++++++-- tests/Liquid/Tag/TagIncrementTest.php | 2 +- tests/Liquid/Tag/TagPaginateTest.php | 2 +- tests/Liquid/Tag/TagTablerowTest.php | 4 +-- 43 files changed, 265 insertions(+), 113 deletions(-) create mode 100644 src/Liquid/Exception/CacheException.php create mode 100644 src/Liquid/Exception/FilesystemException.php create mode 100644 src/Liquid/Exception/NotFoundException.php create mode 100644 src/Liquid/Exception/ParseException.php create mode 100644 src/Liquid/Exception/RenderException.php create mode 100644 src/Liquid/Exception/WrongArgumentException.php diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 17a5063d..016fac93 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -11,6 +11,9 @@ namespace Liquid; +use Liquid\Exception\ParseException; +use Liquid\Exception\RenderException; + /** * Base class for blocks. */ @@ -75,7 +78,7 @@ public function parse(array &$tokens) $this->unknownTag($tagRegexp->matches[1], $tagRegexp->matches[2], $tokens); } } else { - throw new LiquidException("Tag $token was not properly terminated"); // harry + throw new ParseException("Tag $token was not properly terminated"); // harry } } elseif ($variableStartRegexp->match($token)) { $this->nodelist[] = $this->createVariable($token); @@ -119,7 +122,7 @@ protected function renderAll(array $list, Context $context) } if (is_array($value)) { - throw new LiquidException("Implicit rendering of arrays not supported. Use index operator."); + throw new RenderException("Implicit rendering of arrays not supported. Use index operator."); } $result .= $value; @@ -150,30 +153,30 @@ protected function endTag() * @param string $params * @param array $tokens * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ protected function unknownTag($tag, $params, array $tokens) { switch ($tag) { case 'else': - throw new LiquidException($this->blockName() . " does not expect else tag"); + throw new ParseException($this->blockName() . " does not expect else tag"); case 'end': - throw new LiquidException("'end' is not a valid delimiter for " . $this->blockName() . " tags. Use " . $this->blockDelimiter()); + throw new ParseException("'end' is not a valid delimiter for " . $this->blockName() . " tags. Use " . $this->blockDelimiter()); default: - throw new LiquidException("Unknown tag $tag"); + throw new ParseException("Unknown tag $tag"); } } /** - * This method is called at the end of parsing, and will through an error unless + * This method is called at the end of parsing, and will throw an error unless * this method is subclassed, like it is for Document * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException * @return bool */ protected function assertMissingDelimitation() { - throw new LiquidException($this->blockName() . " tag was never closed"); + throw new ParseException($this->blockName() . " tag was never closed"); } /** @@ -202,7 +205,7 @@ private function blockName() * * @param string $token * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException * @return Variable */ private function createVariable($token) @@ -212,6 +215,6 @@ private function createVariable($token) return new Variable($variableRegexp->matches[1]); } - throw new LiquidException("Variable $token was not properly terminated"); + throw new ParseException("Variable $token was not properly terminated"); } } diff --git a/src/Liquid/Cache/File.php b/src/Liquid/Cache/File.php index ef053ee6..ac0358ee 100644 --- a/src/Liquid/Cache/File.php +++ b/src/Liquid/Cache/File.php @@ -12,7 +12,7 @@ namespace Liquid\Cache; use Liquid\Cache; -use Liquid\LiquidException; +use Liquid\Exception\NotFoundException; /** * Implements cache stored in files. @@ -26,7 +26,7 @@ class File extends Cache * * @param array $options * - * @throws LiquidException if Cachedir not exists. + * @throws NotFoundException if Cachedir not exists. */ public function __construct(array $options = array()) { @@ -35,7 +35,7 @@ public function __construct(array $options = array()) if (isset($options['cache_dir']) && is_writable($options['cache_dir'])) { $this->path = realpath($options['cache_dir']) . DIRECTORY_SEPARATOR; } else { - throw new LiquidException('Cachedir not exists or not writable'); + throw new NotFoundException('Cachedir not exists or not writable'); } } diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index ba64f1ed..8713d5fd 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -11,6 +11,8 @@ namespace Liquid; +use Liquid\Exception\RenderException; + /** * Base class for blocks that make logical decisions. */ @@ -35,7 +37,7 @@ class Decision extends AbstractBlock * * @param mixed $value * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\RenderException * @return string */ private function stringValue($value) @@ -47,7 +49,7 @@ private function stringValue($value) } else { // toLiquid is handled in Context::variable $class = get_class($value); - throw new LiquidException("Value of type $class has no `toLiquid` nor `__toString` methods"); + throw new RenderException("Value of type $class has no `toLiquid` nor `__toString` methods"); } } @@ -84,7 +86,7 @@ protected function equalVariables($left, $right, Context $context) * @param string $op * @param Context $context * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\RenderException * @return bool */ protected function interpretCondition($left, $right, $op, Context $context) @@ -149,7 +151,7 @@ protected function interpretCondition($left, $right, $op, Context $context) return is_array($left) ? in_array($right, $left) : (strpos($left, $right) !== false); default: - throw new LiquidException("Error in tag '" . $this->name() . "' - Unknown operator $op"); + throw new RenderException("Error in tag '" . $this->name() . "' - Unknown operator $op"); } } } diff --git a/src/Liquid/Exception/CacheException.php b/src/Liquid/Exception/CacheException.php new file mode 100644 index 00000000..4ccb6b77 --- /dev/null +++ b/src/Liquid/Exception/CacheException.php @@ -0,0 +1,21 @@ +match($templatePath)) { - throw new LiquidException("Illegal template name '$templatePath'"); + throw new ParseException("Illegal template name '$templatePath'"); } $templateDir = dirname($templatePath); @@ -95,11 +98,11 @@ public function fullPath($templatePath) $realFullPath = realpath($fullPath); if ($realFullPath === false) { - throw new LiquidException("File not found: $fullPath"); + throw new NotFoundException("File not found: $fullPath"); } if (strpos($realFullPath, $this->root) !== 0) { - throw new LiquidException("Illegal template full path: {$realFullPath} not under {$this->root}"); + throw new NotFoundException("Illegal template full path: {$realFullPath} not under {$this->root}"); } return $realFullPath; diff --git a/src/Liquid/FileSystem/Virtual.php b/src/Liquid/FileSystem/Virtual.php index e261852b..3ceda2f1 100644 --- a/src/Liquid/FileSystem/Virtual.php +++ b/src/Liquid/FileSystem/Virtual.php @@ -11,8 +11,8 @@ namespace Liquid\FileSystem; +use Liquid\Exception\FilesystemException; use Liquid\FileSystem; -use Liquid\LiquidException; /** * This implements a virtual file system with actual code used to find files injected from outside thus achieving inversion of control. @@ -28,13 +28,13 @@ class Virtual implements FileSystem * Constructor * * @param callable $callback Callback is responsible for providing content of requested templates. Should return template's text. - * @throws LiquidException + * @throws \Liquid\Exception\FilesystemException */ public function __construct($callback) { // Since a callback can only be set from the constructor, we check it once right here. if (!is_callable($callback)) { - throw new LiquidException("Not a callback provided"); + throw new FilesystemException("Not a callback provided"); } $this->callback = $callback; @@ -56,7 +56,7 @@ public function __sleep() { // we cannot serialize a closure if ($this->callback instanceof \Closure) { - throw new LiquidException("Virtual file system with a Closure as a callback cannot be used with a serializing cache"); + throw new FilesystemException("Virtual file system with a Closure as a callback cannot be used with a serializing cache"); } return array_keys(get_object_vars($this)); diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index e2a8fcf1..89a27eb5 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -11,6 +11,8 @@ namespace Liquid; +use Liquid\Exception\WrongArgumentException; + /** * The filter bank is where all registered filters are stored, and where filter invocation is handled * it supports a variety of different filter types; objects, class, and simple methods. @@ -57,7 +59,7 @@ public function __construct(Context $context) * @param mixed $filter Can either be an object, the name of a class (in which case the * filters will be called statically) or the name of a function. * - * @throws LiquidException + * @throws \Liquid\Exception\WrongArgumentException * @return bool */ public function addFilter($filter) @@ -72,7 +74,7 @@ public function addFilter($filter) // If it wasn't an object an isn't a string either, it's a bad parameter if (!is_string($filter)) { - throw new LiquidException("Parameter passed to addFilter must be an object or a string"); + throw new WrongArgumentException("Parameter passed to addFilter must be an object or a string"); } // If the filter is a class, register all its methods @@ -91,7 +93,7 @@ public function addFilter($filter) return true; } - throw new LiquidException("Parameter passed to addFilter must a class or a function"); + throw new WrongArgumentException("Parameter passed to addFilter must a class or a function"); } /** diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index 6e01c737..76dabda2 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -12,8 +12,8 @@ namespace Liquid\Tag; use Liquid\AbstractTag; +use Liquid\Exception\ParseException; use Liquid\Liquid; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; use Liquid\Context; @@ -46,7 +46,7 @@ class TagAssign extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -56,7 +56,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->to = $syntaxRegexp->matches[1]; $this->from = new Variable($syntaxRegexp->matches[2]); } else { - throw new LiquidException("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"); + throw new ParseException("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]"); } } diff --git a/src/Liquid/Tag/TagBlock.php b/src/Liquid/Tag/TagBlock.php index e7b92cca..c1f63cbf 100644 --- a/src/Liquid/Tag/TagBlock.php +++ b/src/Liquid/Tag/TagBlock.php @@ -12,7 +12,7 @@ namespace Liquid\Tag; use Liquid\AbstractBlock; -use Liquid\LiquidException; +use Liquid\Exception\ParseException; use Liquid\FileSystem; use Liquid\Regexp; @@ -39,7 +39,7 @@ class TagBlock extends AbstractBlock * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException * @return \Liquid\Tag\TagBlock */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) @@ -50,7 +50,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->block = $syntaxRegexp->matches[1]; parent::__construct($markup, $tokens, $fileSystem); } else { - throw new LiquidException("Syntax Error in 'block' - Valid syntax: block [name]"); + throw new ParseException("Syntax Error in 'block' - Valid syntax: block [name]"); } } } diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index 5f2849e5..b9232b49 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -13,7 +13,7 @@ use Liquid\AbstractBlock; use Liquid\Context; -use Liquid\LiquidException; +use Liquid\Exception\ParseException; use Liquid\FileSystem; use Liquid\Regexp; @@ -40,7 +40,7 @@ class TagCapture extends AbstractBlock * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -50,7 +50,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->to = $syntaxRegexp->matches[1]; parent::__construct($markup, $tokens, $fileSystem); } else { - throw new LiquidException("Syntax Error in 'capture' - Valid syntax: capture [var] [value]"); + throw new ParseException("Syntax Error in 'capture' - Valid syntax: capture [var] [value]"); } } diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 23cdc582..9ed29a34 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -13,8 +13,8 @@ use Liquid\Decision; use Liquid\Context; +use Liquid\Exception\ParseException; use Liquid\Liquid; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -62,7 +62,7 @@ class TagCase extends Decision * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -76,7 +76,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu if ($syntaxRegexp->match($markup)) { $this->left = $syntaxRegexp->matches[0]; } else { - throw new LiquidException("Syntax Error in tag 'case' - Valid syntax: case [condition]"); // harry + throw new ParseException("Syntax Error in tag 'case' - Valid syntax: case [condition]"); // harry } } @@ -95,7 +95,7 @@ public function endTag() * @param string $params * @param array $tokens * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function unknownTag($tag, $params, array $tokens) { @@ -109,7 +109,7 @@ public function unknownTag($tag, $params, array $tokens) $this->right = $whenSyntaxRegexp->matches[0]; $this->nodelist = array(); } else { - throw new LiquidException("Syntax Error in tag 'case' - Valid when condition: when [condition]"); // harry + throw new ParseException("Syntax Error in tag 'case' - Valid when condition: when [condition]"); // harry } break; diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index 58a30208..21408474 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -12,9 +12,9 @@ namespace Liquid\Tag; use Liquid\AbstractTag; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\Regexp; use Liquid\Variable; use Liquid\FileSystem; @@ -53,7 +53,7 @@ class TagCycle extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -67,7 +67,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->variables = $this->variablesFromString($markup); $this->name = "'" . implode($this->variables) . "'"; } else { - throw new LiquidException("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]"); + throw new ParseException("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]"); } } diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index 8ae11922..2a768872 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -12,9 +12,9 @@ namespace Liquid\Tag; use Liquid\AbstractTag; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -43,7 +43,7 @@ class TagDecrement extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -52,7 +52,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu if ($syntax->match($markup)) { $this->toDecrement = $syntax->matches[0]; } else { - throw new LiquidException("Syntax Error in 'decrement' - Valid syntax: decrement [var]"); + throw new ParseException("Syntax Error in 'decrement' - Valid syntax: decrement [var]"); } } diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 386d7abb..a5df9cee 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -13,9 +13,10 @@ use Liquid\AbstractTag; use Liquid\Document; +use Liquid\Exception\FilesystemException; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; use Liquid\Template; @@ -51,7 +52,7 @@ class TagExtends extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -60,7 +61,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu if ($regex->match($markup) && isset($regex->matches[1])) { $this->templateName = substr($regex->matches[1], 1, strlen($regex->matches[1]) - 2); } else { - throw new LiquidException("Error in tag 'extends' - Valid syntax: extends '[template name]'"); + throw new ParseException("Error in tag 'extends' - Valid syntax: extends '[template name]'"); } parent::__construct($markup, $tokens, $fileSystem); @@ -100,12 +101,12 @@ private function findBlocks(array $tokens) * * @param array $tokens * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\FilesystemException */ public function parse(array &$tokens) { if ($this->fileSystem === null) { - throw new LiquidException("No file system"); + throw new FilesystemException("No file system"); } // read the source of the template and create a new sub document diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index 7aa2aa77..ba18df29 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -12,9 +12,9 @@ namespace Liquid\Tag; use Liquid\AbstractBlock; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -62,7 +62,7 @@ class TagFor extends AbstractBlock * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -85,7 +85,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->name = $syntaxRegexp->matches[1].'-digit'; $this->extractAttributes($markup); } else { - throw new LiquidException("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]"); + throw new ParseException("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]"); } } } diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index 5bdb68e9..95f54a85 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -13,8 +13,8 @@ use Liquid\Decision; use Liquid\Context; +use Liquid\Exception\ParseException; use Liquid\Liquid; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -85,7 +85,7 @@ public function unknownTag($tag, $params, array $tokens) * * @param Context $context * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException * @return string */ public function render(Context $context) @@ -126,7 +126,7 @@ public function render(Context $context) 'right' => $right )); } else { - throw new LiquidException("Syntax Error in tag 'if' - Valid syntax: if [condition]"); + throw new ParseException("Syntax Error in tag 'if' - Valid syntax: if [condition]"); } } if (count($logicalOperators)) { diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 26889070..27182fb6 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -14,6 +14,8 @@ use Liquid\AbstractTag; use Liquid\Document; use Liquid\Context; +use Liquid\Exception\FilesystemException; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\LiquidException; use Liquid\FileSystem; @@ -72,14 +74,14 @@ class TagInclude extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { $regex = new Regexp('/("[^"]+"|\'[^\']+\'|[^\'"\s]+)(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); if (!$regex->match($markup)) { - throw new LiquidException("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"); + throw new ParseException("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]"); } $unquoted = (strpos($regex->matches[1], '"') === false && strpos($regex->matches[1], "'") === false); @@ -109,12 +111,12 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @param array $tokens * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\FilesystemException */ public function parse(array &$tokens) { if ($this->fileSystem === null) { - throw new LiquidException("No file system"); + throw new FilesystemException("No file system"); } // read the source of the template and create a new sub document diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index 60dce41d..ed428c88 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -12,9 +12,9 @@ namespace Liquid\Tag; use Liquid\AbstractTag; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -43,7 +43,7 @@ class TagIncrement extends AbstractTag * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -52,7 +52,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu if ($syntax->match($markup)) { $this->toIncrement = $syntax->matches[0]; } else { - throw new LiquidException("Syntax Error in 'increment' - Valid syntax: increment [var]"); + throw new ParseException("Syntax Error in 'increment' - Valid syntax: increment [var]"); } } diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 032c8845..718850bd 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -12,9 +12,9 @@ namespace Liquid\Tag; use Liquid\AbstractBlock; +use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -77,7 +77,7 @@ class TagPaginate extends AbstractBlock * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException * */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) @@ -91,7 +91,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->numberItems = $syntax->matches[2]; $this->extractAttributes($markup); } else { - throw new LiquidException("Syntax Error - Valid syntax: paginate [collection] by [items]"); + throw new ParseException("Syntax Error - Valid syntax: paginate [collection] by [items]"); } } diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index ea1f9feb..13cf6e3d 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -12,9 +12,10 @@ namespace Liquid\Tag; use Liquid\AbstractBlock; +use Liquid\Exception\ParseException; +use Liquid\Exception\RenderException; use Liquid\Liquid; use Liquid\Context; -use Liquid\LiquidException; use Liquid\FileSystem; use Liquid\Regexp; @@ -51,7 +52,7 @@ class TagTablerow extends AbstractBlock * @param array $tokens * @param FileSystem $fileSystem * - * @throws \Liquid\LiquidException + * @throws \Liquid\Exception\ParseException */ public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) { @@ -65,7 +66,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu $this->extractAttributes($markup); } else { - throw new LiquidException("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols:3"); + throw new ParseException("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols:3"); } } @@ -73,7 +74,7 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * Renders the current node * * @param Context $context - * + * @throws \Liquid\Exception\RenderException * @return string */ public function render(Context $context) @@ -85,7 +86,7 @@ public function render(Context $context) } if (!is_array($collection)) { - throw new LiquidException("Not an array"); + throw new RenderException("Not an array"); } // discard keys diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 2eabf43a..c725a777 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -11,6 +11,9 @@ namespace Liquid; +use Liquid\Exception\CacheException; +use Liquid\Exception\FilesystemException; + /** * The Template class. * @@ -75,7 +78,7 @@ public function setFileSystem(FileSystem $fileSystem) /** * @param array|Cache $cache * - * @throws LiquidException + * @throws \Liquid\Exception\CacheException */ public function setCache($cache) { @@ -84,7 +87,7 @@ public function setCache($cache) $classname = '\Liquid\Cache\\' . ucwords($cache['cache']); self::$cache = new $classname($cache); } else { - throw new LiquidException('Invalid cache options!'); + throw new CacheException('Invalid cache options!'); } } @@ -200,13 +203,13 @@ private function parseAlways($source) * Parses the given template file * * @param string $templatePath - * + * @throws \Liquid\Exception\FilesystemException * @return Template */ public function parseFile($templatePath) { if (!$this->fileSystem) { - throw new LiquidException("Could not load a template without an initialized file system"); + throw new FilesystemException("Could not load a template without an initialized file system"); } return $this->parse($this->fileSystem->readTemplateFile($templatePath)); diff --git a/tests/Liquid/AbstractBlockTest.php b/tests/Liquid/AbstractBlockTest.php index 1b49ad9d..bd12a358 100644 --- a/tests/Liquid/AbstractBlockTest.php +++ b/tests/Liquid/AbstractBlockTest.php @@ -16,7 +16,7 @@ class AbstractBlockTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testUnterminatedBlockError() { diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index 06b0a1ae..2fbe92d7 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -40,7 +40,7 @@ protected function tearDown() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\FilesystemException */ public function testConstructInvalidOptions() { @@ -48,7 +48,7 @@ public function testConstructInvalidOptions() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\FilesystemException */ public function testConstructNoSuchDirOrNotWritable() { diff --git a/tests/Liquid/CustomTagTest.php b/tests/Liquid/CustomTagTest.php index c6e86d91..90d150b7 100644 --- a/tests/Liquid/CustomTagTest.php +++ b/tests/Liquid/CustomTagTest.php @@ -20,7 +20,7 @@ class TagFoo extends TagComment class CustomTagTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException * @expectedExceptionMessage Unknown tag foo */ public function testUnknownTag() diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 83dfc60a..99a29d51 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -68,7 +68,7 @@ protected function setup() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\WrongArgumentException */ public function testAddFilterNotObjectAndString() { @@ -76,7 +76,7 @@ public function testAddFilterNotObjectAndString() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\WrongArgumentException */ public function testAddFilterNoFunctionOrClass() { diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 72eebc83..feda47bf 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -149,7 +149,7 @@ public function testLinkTo() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException * @expectedExceptionMessage was not properly terminated */ public function testVariableWithANewLine() diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index b8ea652b..79214317 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -23,7 +23,7 @@ class TagAssignTest extends TestCase /** * Tests the normal behavior of throwing an exception when the assignment is incorrect * - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidAssign() { diff --git a/tests/Liquid/Tag/TagBlockTest.php b/tests/Liquid/Tag/TagBlockTest.php index cc626241..25c0e3c5 100644 --- a/tests/Liquid/Tag/TagBlockTest.php +++ b/tests/Liquid/Tag/TagBlockTest.php @@ -16,7 +16,7 @@ class TagBlockTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxError() { diff --git a/tests/Liquid/Tag/TagCaptureTest.php b/tests/Liquid/Tag/TagCaptureTest.php index 51aa2642..250790a4 100644 --- a/tests/Liquid/Tag/TagCaptureTest.php +++ b/tests/Liquid/Tag/TagCaptureTest.php @@ -17,7 +17,7 @@ class TagCaptureTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index 9c62ccc1..3dabd2a9 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -59,7 +59,7 @@ public function testCaseWithElse() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorCase() { @@ -67,7 +67,7 @@ public function testSyntaxErrorCase() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorWhen() { @@ -75,7 +75,7 @@ public function testSyntaxErrorWhen() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorEnd() { @@ -83,7 +83,7 @@ public function testSyntaxErrorEnd() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\RenderException */ public function testObject() { diff --git a/tests/Liquid/Tag/TagCycleTest.php b/tests/Liquid/Tag/TagCycleTest.php index e608797f..a4160f94 100644 --- a/tests/Liquid/Tag/TagCycleTest.php +++ b/tests/Liquid/Tag/TagCycleTest.php @@ -17,7 +17,7 @@ class TagCycleTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 14b8b8c1..aa7ea232 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -163,7 +163,7 @@ public function testCacheDiscardedIfFileChanges() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxNoTemplateName() { @@ -172,7 +172,7 @@ public function testInvalidSyntaxNoTemplateName() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxNotQuotedTemplateName() { @@ -181,15 +181,18 @@ public function testInvalidSyntaxNotQuotedTemplateName() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxEmptyTemplateName() { $template = new Template(); + $template->setFileSystem($this->fs); $template->parse("{% extends '' %}"); } /** + * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. + * * @expectedException \Liquid\LiquidException */ public function testInvalidSyntaxInvalidKeyword() diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 32544e31..435aa48a 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -17,7 +17,7 @@ class TagForTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testForInvalidSyntax() { diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 341985d9..a49bb29c 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -217,7 +217,7 @@ public function testContains() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException * @expectedExceptionMessage if tag was never closed */ public function testSyntaxErrorNotClosed() @@ -226,7 +226,7 @@ public function testSyntaxErrorNotClosed() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorEnd() { @@ -234,7 +234,7 @@ public function testSyntaxErrorEnd() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\RenderException */ public function testInvalidOperator() { @@ -242,7 +242,7 @@ public function testInvalidOperator() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\RenderException */ public function testIncomparable() { @@ -250,7 +250,7 @@ public function testIncomparable() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException * @expectedExceptionMessage does not expect else tag */ public function testSyntaxErrorElse() @@ -259,7 +259,7 @@ public function testSyntaxErrorElse() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException * @expectedExceptionMessage Unknown tag */ public function testSyntaxErrorUnknown() diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 7724d4df..7dcc7a76 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -41,24 +41,30 @@ protected function tearDown() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxNoTemplateName() { $template = new Template(); + $template->setFileSystem($this->fs); $template->parse("{% include %}"); } /** + * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. + * * @expectedException \Liquid\LiquidException */ public function testInvalidSyntaxInvalidKeyword() { + $this->markTestIncomplete('Throws not because the syntax is invalid, but because there is no filesystem for the include'); $template = new Template(); $template->parse("{% include 'hello' no_keyword %}"); } /** + * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. + * * @expectedException \Liquid\LiquidException */ public function testInvalidSyntaxNoObjectCollection() @@ -132,7 +138,7 @@ public function testIncludePassPlainValue() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\RenderException * @expectedExceptionMessage Use index operator */ public function testIncludePassArrayWithoutIndex() diff --git a/tests/Liquid/Tag/TagIncrementTest.php b/tests/Liquid/Tag/TagIncrementTest.php index 73a2685b..7208f170 100644 --- a/tests/Liquid/Tag/TagIncrementTest.php +++ b/tests/Liquid/Tag/TagIncrementTest.php @@ -16,7 +16,7 @@ class TagIncrementTest extends TestCase { /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxError() { diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 9c575113..fe72ac36 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -37,7 +37,7 @@ public function testNextPage() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorCase() { diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index 6b8fd64c..2b46a140 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -47,7 +47,7 @@ public function testTablerow() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { @@ -55,7 +55,7 @@ public function testInvalidSyntax() } /** - * @expectedException \Liquid\LiquidException + * @expectedException \Liquid\Exception\RenderException */ public function testNotArray() { From 3ea8667a64eedd0b7f027a6354c81ec3ae003350 Mon Sep 17 00:00:00 2001 From: jfoucher Date: Sun, 8 Oct 2017 21:22:37 +0200 Subject: [PATCH 150/296] - Change exception thrown in case of a missing filesystem - Throw RenderException in filters --- .../Exception/MissingFilesystemException.php | 22 +++++++++++++++++++ src/Liquid/StandardFilters.php | 6 +++-- src/Liquid/Tag/TagExtends.php | 6 ++--- src/Liquid/Tag/TagInclude.php | 6 ++--- src/Liquid/Template.php | 6 ++--- 5 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 src/Liquid/Exception/MissingFilesystemException.php diff --git a/src/Liquid/Exception/MissingFilesystemException.php b/src/Liquid/Exception/MissingFilesystemException.php new file mode 100644 index 00000000..3b97a187 --- /dev/null +++ b/src/Liquid/Exception/MissingFilesystemException.php @@ -0,0 +1,22 @@ +fileSystem === null) { - throw new FilesystemException("No file system"); + throw new MissingFilesystemException("No file system"); } // read the source of the template and create a new sub document diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 27182fb6..481cdbab 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -14,7 +14,7 @@ use Liquid\AbstractTag; use Liquid\Document; use Liquid\Context; -use Liquid\Exception\FilesystemException; +use Liquid\Exception\MissingFilesystemException; use Liquid\Exception\ParseException; use Liquid\Liquid; use Liquid\LiquidException; @@ -111,12 +111,12 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu * * @param array $tokens * - * @throws \Liquid\Exception\FilesystemException + * @throws \Liquid\Exception\MissingFilesystemException */ public function parse(array &$tokens) { if ($this->fileSystem === null) { - throw new FilesystemException("No file system"); + throw new MissingFilesystemException("No file system"); } // read the source of the template and create a new sub document diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index c725a777..2346de0d 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -12,7 +12,7 @@ namespace Liquid; use Liquid\Exception\CacheException; -use Liquid\Exception\FilesystemException; +use Liquid\Exception\MissingFilesystemException; /** * The Template class. @@ -203,13 +203,13 @@ private function parseAlways($source) * Parses the given template file * * @param string $templatePath - * @throws \Liquid\Exception\FilesystemException + * @throws \Liquid\Exception\MissingFilesystemException * @return Template */ public function parseFile($templatePath) { if (!$this->fileSystem) { - throw new FilesystemException("Could not load a template without an initialized file system"); + throw new MissingFilesystemException("Could not load a template without an initialized file system"); } return $this->parse($this->fileSystem->readTemplateFile($templatePath)); From 31adc047d0b5b7990749cce4b92011171cb27830 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 7 Oct 2017 12:39:02 +0900 Subject: [PATCH 151/296] Use ::class instead of literal class names where possible --- src/Liquid/AbstractBlock.php | 4 +++- src/Liquid/Filterbank.php | 4 ++-- src/Liquid/Template.php | 5 +++-- tests/Liquid/TemplateTest.php | 16 ++++++++-------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 016fac93..68ef51e6 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -19,6 +19,8 @@ */ class AbstractBlock extends AbstractTag { + const TAG_PREFIX = '\Liquid\Tag\Tag'; + /** * @var AbstractTag[] */ @@ -65,7 +67,7 @@ public function parse(array &$tokens) if (array_key_exists($tagRegexp->matches[1], $tags)) { $tagName = $tags[$tagRegexp->matches[1]]; } else { - $tagName = '\Liquid\Tag\Tag' . ucwords($tagRegexp->matches[1]); + $tagName = self::TAG_PREFIX . ucwords($tagRegexp->matches[1]); $tagName = (class_exists($tagName) === true) ? $tagName : null; } diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 89a27eb5..f16ede54 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -49,8 +49,8 @@ public function __construct(Context $context) { $this->context = $context; - $this->addFilter('\Liquid\StandardFilters'); - $this->addFilter('\Liquid\CustomFilters'); + $this->addFilter(\Liquid\StandardFilters::class); + $this->addFilter(\Liquid\CustomFilters::class); } /** diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 2346de0d..3a38f52c 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -25,6 +25,8 @@ */ class Template { + const CLASS_PREFIX = '\Liquid\Cache\\'; + /** * @var Document The root of the node tree */ @@ -83,8 +85,7 @@ public function setFileSystem(FileSystem $fileSystem) public function setCache($cache) { if (is_array($cache)) { - if (isset($cache['cache']) && class_exists('\Liquid\Cache\\' . ucwords($cache['cache']))) { - $classname = '\Liquid\Cache\\' . ucwords($cache['cache']); + if (isset($cache['cache']) && class_exists($classname = self::CLASS_PREFIX . ucwords($cache['cache']))) { self::$cache = new $classname($cache); } else { throw new CacheException('Invalid cache options!'); diff --git a/tests/Liquid/TemplateTest.php b/tests/Liquid/TemplateTest.php index db2ae689..88923d31 100644 --- a/tests/Liquid/TemplateTest.php +++ b/tests/Liquid/TemplateTest.php @@ -55,7 +55,7 @@ public function testSetCacheThroughArray() { $template = new Template(); $template->setCache(array('cache' => 'file', 'cache_dir' => $this->cacheDir)); - $this->assertInstanceOf('\Liquid\Cache\File', $template::getCache()); + $this->assertInstanceOf(\Liquid\Cache\File::class, $template::getCache()); } public function testSetCacheThroughCacheObject() @@ -106,7 +106,7 @@ public function testVariableBeginning() $nodelist = $template->getRoot()->getNodelist(); $this->assertEquals(2, count($nodelist)); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[0]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[0]); $this->assertInternalType('string', $nodelist[1]); } @@ -119,7 +119,7 @@ public function testVariableEnd() $this->assertEquals(2, count($nodelist)); $this->assertInternalType('string', $nodelist[0]); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[1]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); } public function testVariableMiddle() @@ -131,7 +131,7 @@ public function testVariableMiddle() $this->assertEquals(3, count($nodelist)); $this->assertInternalType('string', $nodelist[0]); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[1]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); $this->assertInternalType('string', $nodelist[2]); } @@ -144,11 +144,11 @@ public function testVariableManyEmbeddedFragments() $this->assertEquals(7, count($nodelist)); $this->assertInternalType('string', $nodelist[0]); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[1]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); $this->assertInternalType('string', $nodelist[2]); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[3]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[3]); $this->assertInternalType('string', $nodelist[4]); - $this->assertInstanceOf('\Liquid\Variable', $nodelist[5]); + $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[5]); $this->assertInternalType('string', $nodelist[6]); } @@ -161,7 +161,7 @@ public function testWithBlock() $this->assertEquals(3, count($nodelist)); $this->assertInternalType('string', $nodelist[0]); - $this->assertInstanceOf('\Liquid\Tag\TagComment', $nodelist[1]); + $this->assertInstanceOf(\Liquid\Tag\TagComment::class, $nodelist[1]); $this->assertInternalType('string', $nodelist[2]); } } From 40e133bf59444c48113eabe93aa31cb3eb15ed6a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 7 Oct 2017 12:40:55 +0900 Subject: [PATCH 152/296] Removed unused imports --- tests/Liquid/Cache/ApcTest.php | 1 - tests/Liquid/Cache/LocalTest.php | 1 - tests/Liquid/Tag/TagExtendsTest.php | 1 - tests/Liquid/Tag/TagIncludeTest.php | 1 - 4 files changed, 4 deletions(-) diff --git a/tests/Liquid/Cache/ApcTest.php b/tests/Liquid/Cache/ApcTest.php index 65102a06..3e2b1be0 100644 --- a/tests/Liquid/Cache/ApcTest.php +++ b/tests/Liquid/Cache/ApcTest.php @@ -12,7 +12,6 @@ namespace Liquid\Cache; use Liquid\TestCase; -use \Liquid\Cache\Apc; class ApcTest extends TestCase { diff --git a/tests/Liquid/Cache/LocalTest.php b/tests/Liquid/Cache/LocalTest.php index 42a9c00b..fd996c47 100644 --- a/tests/Liquid/Cache/LocalTest.php +++ b/tests/Liquid/Cache/LocalTest.php @@ -12,7 +12,6 @@ namespace Liquid\Cache; use Liquid\TestCase; -use \Liquid\Cache\Local; class LocalTest extends TestCase { diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index aa7ea232..dba782b5 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -14,7 +14,6 @@ use Liquid\TestCase; use Liquid\Template; use Liquid\Cache\Local; -use Liquid\FileSystem\Virtual; use Liquid\TestFileSystem; /** diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 7dcc7a76..0c14f607 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -15,7 +15,6 @@ use Liquid\Template; use Liquid\Liquid; use Liquid\Cache\Local; -use Liquid\FileSystem\Virtual; use Liquid\TestFileSystem; class TagIncludeTest extends TestCase From f88cc44c9949dccc2bc4a43427c3f60db0f4f4d3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 7 Oct 2017 13:27:33 +0900 Subject: [PATCH 153/296] Filterbank: do not try calling instance methods statically --- src/Liquid/Filterbank.php | 46 ++++++++++++++++++--------------- tests/Liquid/FilterbankTest.php | 16 +++++++++++- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index f16ede54..b10adde9 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -64,36 +64,38 @@ public function __construct(Context $context) */ public function addFilter($filter) { - // If the passed filter was an object, store the object for future reference. - if (is_object($filter)) { - $filter->context = $this->context; - $name = get_class($filter); - $this->filters[$name] = $filter; - $filter = $name; - } - - // If it wasn't an object an isn't a string either, it's a bad parameter - if (!is_string($filter)) { - throw new WrongArgumentException("Parameter passed to addFilter must be an object or a string"); - } - - // If the filter is a class, register all its methods - if (class_exists($filter)) { - $methods = array_flip(get_class_methods($filter)); - foreach ($methods as $method => $null) { - $this->methodMap[$method] = $filter; + // If the filter is a class, register all its static methods + if (is_string($filter) && class_exists($filter)) { + $reflection = new \ReflectionClass($filter); + foreach ($reflection->getMethods(\ReflectionMethod::IS_STATIC) as $method) { + $this->methodMap[$method->name] = $method->class; } return true; } - // If it's a function register it simply - if (function_exists($filter)) { + // If it's a global function, register it simply + if (is_string($filter) && function_exists($filter)) { $this->methodMap[$filter] = false; return true; } - throw new WrongArgumentException("Parameter passed to addFilter must a class or a function"); + // If it isn't an object an isn't a string either, it's a bad parameter + if (!is_object($filter)) { + throw new WrongArgumentException("Parameter passed to addFilter must be an object or a string"); + } + + // If the passed filter was an object, store the object for future reference. + $filter->context = $this->context; + $className = get_class($filter); + $this->filters[$className] = $filter; + + // Then register all public static and not methods as filters + foreach (get_class_methods($filter) as $method) { + $this->methodMap[$method] = $className; + } + + return true; } /** @@ -127,6 +129,8 @@ public function invoke($name, $value, array $args = array()) if ($class === false) { return call_user_func_array($name, $args); } + + // Call a class or an instance method return call_user_func_array(array($class, $name), $args); } diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 99a29d51..195bb342 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -107,10 +107,21 @@ public function testStaticClassFilter() { $var = new Variable('var | static_test'); $this->context->set('var', 1000); - $this->context->addFilters('\ClassFilter'); + $this->context->addFilters(\ClassFilter::class); $this->assertEquals('worked', $var->render($this->context)); } + /** + * Test with instance method on a static class + */ + public function testStaticMixedClassFilter() + { + $var = new Variable('var | instance_test_one'); + $this->context->set('var', 'foo'); + $this->context->addFilters(\ClassFilter::class); + $this->assertEquals('foo', $var->render($this->context)); + } + /** * Test using an object as a filter; an object fiter will retain its state * between calls to its filters. @@ -124,6 +135,9 @@ public function testObjectFilter() $var = new Variable('var | instance_test_two'); $this->assertEquals('set', $var->render($this->context)); + + $var = new Variable('var | static_test'); + $this->assertEquals('worked', $var->render($this->context)); } } From 0ca5bb5f844db3fa92561b24ca1e233046f11ced Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 10:40:54 +0900 Subject: [PATCH 154/296] Mark bogus tests as incomplete: is this an expected behavior? --- tests/Liquid/Tag/TagExtendsTest.php | 8 +++----- tests/Liquid/Tag/TagIncludeTest.php | 17 ++++++----------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index dba782b5..29b416d4 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -189,14 +189,12 @@ public function testInvalidSyntaxEmptyTemplateName() $template->parse("{% extends '' %}"); } - /** - * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. - * - * @expectedException \Liquid\LiquidException - */ public function testInvalidSyntaxInvalidKeyword() { $template = new Template(); + $template->setFileSystem($this->fs); $template->parse("{% extends 'base' nothing-should-be-here %}"); + + $this->markTestIncomplete("Exception is expected here"); } } diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 0c14f607..995e3c11 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -49,27 +49,22 @@ public function testInvalidSyntaxNoTemplateName() $template->parse("{% include %}"); } - /** - * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. - * - * @expectedException \Liquid\LiquidException - */ public function testInvalidSyntaxInvalidKeyword() { - $this->markTestIncomplete('Throws not because the syntax is invalid, but because there is no filesystem for the include'); $template = new Template(); + $template->setFileSystem($this->fs); $template->parse("{% include 'hello' no_keyword %}"); + + $this->markTestIncomplete("Exception is expected here"); } - /** - * This needs fixing because it currently throws A FilesystemException (because the template filesystem is not defined in the test) instead of a ParseException which it should logically throw if the syntax is invalid. - * - * @expectedException \Liquid\LiquidException - */ public function testInvalidSyntaxNoObjectCollection() { $template = new Template(); + $template->setFileSystem($this->fs); $template->parse("{% include 'hello' with %}"); + + $this->markTestIncomplete("Exception is expected here"); } public function testIncludeTag() From 1419dca0eab0a2d5dc56e4db5cddf999d2b650be Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 12:35:22 +0900 Subject: [PATCH 155/296] Tests for unconfigured filesystem --- tests/Liquid/Tag/TagExtendsTest.php | 11 +++++++++++ tests/Liquid/Tag/TagIncludeTest.php | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 29b416d4..08ffb785 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -172,6 +172,7 @@ public function testInvalidSyntaxNoTemplateName() /** * @expectedException \Liquid\Exception\ParseException + * @expectedExceptionMessage Error in tag */ public function testInvalidSyntaxNotQuotedTemplateName() { @@ -179,6 +180,16 @@ public function testInvalidSyntaxNotQuotedTemplateName() $template->parse("{% extends base %}"); } + /** + * @expectedException \Liquid\Exception\MissingFilesystemException + * @expectedExceptionMessage No file system + */ + public function testMissingFilesystem() + { + $template = new Template(); + $template->parse("{% extends 'base' %}"); + } + /** * @expectedException \Liquid\Exception\ParseException */ diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 995e3c11..bd2260af 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -49,6 +49,16 @@ public function testInvalidSyntaxNoTemplateName() $template->parse("{% include %}"); } + /** + * @expectedException \Liquid\Exception\MissingFilesystemException + * @expectedExceptionMessage No file system + */ + public function testMissingFilesystem() + { + $template = new Template(); + $template->parse("{% include 'hello' %}"); + } + public function testInvalidSyntaxInvalidKeyword() { $template = new Template(); From 422ae67ebea6d8411530f4848e7c9d3950387f67 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 10:52:29 +0900 Subject: [PATCH 156/296] FilterbankTest: filters should work with non-global classes --- tests/Liquid/FilterbankTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 195bb342..0732e136 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -51,6 +51,14 @@ public function instance_test_two() namespace Liquid { +class NamespacedClassFilter +{ + public static function static_test2() + { + return "good"; + } +} + class FilterbankTest extends TestCase { /** @var FilterBank */ @@ -100,6 +108,17 @@ public function testFunctionFilter() $this->assertEquals('worked', $var->render($this->context)); } + /** + * Test using a namespaced static class + */ + public function testNamespacedStaticClassFilter() + { + $var = new Variable('var | static_test2'); + $this->context->set('var', 1000); + $this->context->addFilters(NamespacedClassFilter::class); + $this->assertEquals('good', $var->render($this->context)); + } + /** * Test using a static class */ From 54f9c1773f92ac9aa96a15176e6785cb9bd6dec0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 10:52:58 +0900 Subject: [PATCH 157/296] TagIncludeTest: expect specific error message on syntax error --- tests/Liquid/FilterbankTest.php | 6 +++--- tests/Liquid/Tag/TagIncludeTest.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 0732e136..f5fae257 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -53,9 +53,9 @@ public function instance_test_two() class NamespacedClassFilter { - public static function static_test2() + public static function static_test2($var) { - return "good"; + return "good {$var}"; } } @@ -116,7 +116,7 @@ public function testNamespacedStaticClassFilter() $var = new Variable('var | static_test2'); $this->context->set('var', 1000); $this->context->addFilters(NamespacedClassFilter::class); - $this->assertEquals('good', $var->render($this->context)); + $this->assertEquals('good 1000', $var->render($this->context)); } /** diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index bd2260af..72645708 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -41,6 +41,7 @@ protected function tearDown() /** * @expectedException \Liquid\Exception\ParseException + * @expectedExceptionMessage Error in tag */ public function testInvalidSyntaxNoTemplateName() { From a6c98e5ea474f072c1aa52be1af7fea2456fbe8a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 11:07:31 +0900 Subject: [PATCH 158/296] StandardFiltersTest: addFilters takes just one argument --- tests/Liquid/StandardFiltersTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 23739545..05b2f64d 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -1075,8 +1075,8 @@ public function testSecondFilterOverwritesFirst() { $var = new Variable('var | money '); $this->context->set('var', 1000); - $this->context->addFilters(new MoneyFilter(), 'money'); - $this->context->addFilters(new CanadianMoneyFilter(), 'money'); + $this->context->addFilters(new MoneyFilter()); + $this->context->addFilters(new CanadianMoneyFilter()); $this->assertEquals(' 1000$ CAD ', $var->render($this->context)); } From 9f647ebc2cbc2d9855c6f754a87a94c325df0498 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 12:24:44 +0900 Subject: [PATCH 159/296] Template::setCache isn't using $this, should be allowed being called in static context --- src/Liquid/Template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 3a38f52c..4d27c7e1 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -82,7 +82,7 @@ public function setFileSystem(FileSystem $fileSystem) * * @throws \Liquid\Exception\CacheException */ - public function setCache($cache) + public static function setCache($cache) { if (is_array($cache)) { if (isset($cache['cache']) && class_exists($classname = self::CLASS_PREFIX . ucwords($cache['cache']))) { From 9aec4d55cb8d9444f375b5a8ae9478181b1ad283 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 12:06:41 +0900 Subject: [PATCH 160/296] TestCase: drop cache on every run --- tests/Liquid/TestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index bbe46aeb..b47dea9d 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -44,6 +44,8 @@ protected function setUp() foreach ($defaultConfig as $configKey => $configValue) { Liquid::set($configKey, $configValue); } + + Template::setCache(null); } /** From 7b5d951cee19894a72c649733c7351ab62ca9e20 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 12:17:54 +0900 Subject: [PATCH 161/296] Callback-type filters. Adding filters has never been easier. --- README.md | 14 ++++++++++++ examples/filters.php | 25 +++++++++++++++++++++ src/Liquid/Context.php | 4 ++-- src/Liquid/Filterbank.php | 39 +++++++++++++++++++++------------ src/Liquid/Template.php | 16 +++++++++++--- tests/Liquid/ContextTest.php | 11 ++++++++++ tests/Liquid/FilterbankTest.php | 38 ++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 examples/filters.php diff --git a/README.md b/README.md index dd4e6528..c61d6d1e 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,20 @@ If you render the same template over and over for at least a dozen of times, the You should probably extend `Liquid\Template` to initialize everything you do with `Liquid::set` in one place. +### Custom filters + +Adding filters has never been easier. + + $template = new Template(); + $template->registerFilter('absolute_url', function ($arg) { + return "https://www.example.com$arg"; + }); + $template->parse("{{ my_url | absolute_url }}"); + echo $template->render(array( + 'my_url' => '/test' + )); + // expect: https://www.example.com/test + ## Requirements * PHP 5.6+ diff --git a/examples/filters.php b/examples/filters.php new file mode 100644 index 00000000..95c80c24 --- /dev/null +++ b/examples/filters.php @@ -0,0 +1,25 @@ +registerFilter('absolute_url', function ($arg) { + return "https://www.example.com$arg"; +}); +$template->parse("{{ my_url | absolute_url }}"); +echo $template->render(array( + 'my_url' => '/test' +)); +// expect: https://www.example.com/test diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 6587b85c..4df7e3f6 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -64,9 +64,9 @@ public function __construct(array $assigns = array(), array $registers = array() * * @param mixed $filter */ - public function addFilters($filter) + public function addFilters($filter, callable $callback = null) { - $this->filterbank->addFilter($filter); + $this->filterbank->addFilter($filter, $callback); } /** diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index b10adde9..c01bfdfe 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -62,8 +62,14 @@ public function __construct(Context $context) * @throws \Liquid\Exception\WrongArgumentException * @return bool */ - public function addFilter($filter) + public function addFilter($filter, callable $callback = null) { + // If it is a callback, save it as it is + if (is_string($filter) && $callback) { + $this->methodMap[$filter] = $callback; + return true; + } + // If the filter is a class, register all its static methods if (is_string($filter) && class_exists($filter)) { $reflection = new \ReflectionClass($filter); @@ -117,23 +123,28 @@ public function invoke($name, $value, array $args = array()) array_unshift($args, $value); // Consult the mapping - if (isset($this->methodMap[$name])) { - $class = $this->methodMap[$name]; + if (!isset($this->methodMap[$name])) { + return $value; + } - // If we have a registered object for the class, use that instead - if (isset($this->filters[$class])) { - $class = $this->filters[$class]; - } + $class = $this->methodMap[$name]; - // If we're calling a function - if ($class === false) { - return call_user_func_array($name, $args); - } + // If we have a callback + if (is_callable($class)) { + return call_user_func_array($class, $args); + } + + // If we have a registered object for the class, use that instead + if (isset($this->filters[$class])) { + $class = $this->filters[$class]; + } - // Call a class or an instance method - return call_user_func_array(array($class, $name), $args); + // If we're calling a function + if ($class === false) { + return call_user_func_array($name, $args); } - return $value; + // Call a class or an instance method + return call_user_func_array(array($class, $name), $args); } } diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 4d27c7e1..e0036257 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -141,9 +141,14 @@ public static function getTags() * * @param string $filter */ - public function registerFilter($filter) + public function registerFilter($filter, callable $callback = null) { - $this->filters[] = $filter; + // Store callback for later use + if ($callback) { + $this->filters[] = [$filter, $callback]; + } else { + $this->filters[] = $filter; + } } /** @@ -238,7 +243,12 @@ public function render(array $assigns = array(), $filters = null, array $registe } foreach ($this->filters as $filter) { - $context->addFilters($filter); + if (is_array($filter)) { + // Unpack a callback saved as second argument + $context->addFilters(...$filter); + } else { + $context->addFilters($filter); + } } return $this->root->render($context); diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index a7d4259d..d0356475 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -304,6 +304,17 @@ public function testOverrideGlobalFilter() $this->assertEquals('Local test', $template->render(array(), new LocalFilter())); } + public function testCallbackFilter() + { + $template = new Template(); + $template->registerFilter('foo', function ($arg) { + return "Foo $arg"; + }); + + $template->parse("{{'test' | foo }}"); + $this->assertEquals('Foo test', $template->render()); + } + public function testAddItemInOuterScope() { $this->context->set('test', 'test'); diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index f5fae257..c5a108ed 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -51,6 +51,8 @@ public function instance_test_two() namespace Liquid { +use Liquid\Cache\File; + class NamespacedClassFilter { public static function static_test2($var) @@ -75,6 +77,13 @@ protected function setup() $this->filterBank = new FilterBank($this->context); } + protected function tearDown() + { + // have to destroy these else PHP goes nuts + unset($this->context); + unset($this->filterBank); + } + /** * @expectedException \Liquid\Exception\WrongArgumentException */ @@ -158,6 +167,35 @@ public function testObjectFilter() $var = new Variable('var | static_test'); $this->assertEquals('worked', $var->render($this->context)); } + + public function testCallbackFilter() + { + $var = new Variable('var | my_callback'); + $this->context->set('var', 1000); + $this->context->addFilters('my_callback', function ($var) { + return $var * 2; + }); + $this->assertEquals('2000', $var->render($this->context)); + } + + /** + * Closures are not to be serialized. Let's check that. + */ + public function testWithSerializingCache() + { + $template = new Template(); + $template->registerFilter('foo', function ($arg) { + return "Foo $arg"; + }); + $template->setCache(new File(array( + 'cache_dir' => __DIR__.'/cache_dir/', + ))); + $template->parse("{{'test' | foo }}"); + $this->assertEquals('Foo test', $template->render()); + + $template->parse("{{'bar' | foo }}"); + $this->assertEquals('Foo bar', $template->render()); + } } } // Liquid namespace From 3847af0382093c25483723bab2d1eff4fe6b2d77 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 9 Oct 2017 12:46:45 +0900 Subject: [PATCH 162/296] Changelog for 1.4.2 [ci skip] --- CHANGELOG | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 1cf7a15c..bd6f1b06 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,14 @@ * master +* 1.4.2 (2017-10-09) + + * Better caching for non-extending templates + * Simplified 'assign' tag to use rules for variables + * Now supporting PHP 7.2 + * Different types of exception depending on the case + * Filterbank will not call instance methods statically + * Callback-type filters + * 1.4.1 (2017-09-28) * Unquoted template names in 'include' tag, as in Jekyll From 908c0095a74104b592f4ef69a45ebeb7cf6c75de Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 10 Oct 2017 17:55:21 +0900 Subject: [PATCH 163/296] Context: typo --- src/Liquid/Context.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 4df7e3f6..bd063325 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -351,7 +351,7 @@ private function variable($key) // lastly, try to get an embedded value of an object // value could be of any type, not just string, so we have to do this - // conversion here, not laster in AbstractBlock::renderAll + // conversion here, not later in AbstractBlock::renderAll if (method_exists($object, 'toLiquid')) { $object = $object->toLiquid(); } From 07a062e0f9bf7c52ba12bcfff403cb013e4150a0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 10 Oct 2017 17:56:12 +0900 Subject: [PATCH 164/296] string: new standard filter for explicit string conversion --- src/Liquid/StandardFilters.php | 13 ++++++++++++- tests/Liquid/StandardFiltersTest.php | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 59ec2109..b51f3d70 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -535,7 +535,18 @@ public static function sort($input, $property = null) return $input; } - + + /** + * Explicit string conversion. + * + * @param mixed $input + * + * @return string + */ + public static function string($input) + { + return strval($input); + } /** * Split input string into an array of substrings separated by given pattern. diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 05b2f64d..2db2e078 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -45,6 +45,11 @@ public function size() { return self::SIZE; } + + public function __toString() + { + return "forty two"; + } } @@ -748,6 +753,24 @@ public function testLast() } } + public function testString() + { + $data = array( + array( + 1, + '1', + ), + array( + new SizeClass(), + "forty two", + ), + ); + + foreach ($data as $item) { + $this->assertEquals($item[1], StandardFilters::string($item[0])); + } + } + public function testSplit() { $data = array( From ccdba752293a45614bc69fb19ffc19d0efe318de Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 10 Oct 2017 18:06:23 +0900 Subject: [PATCH 165/296] `escape` and `escape_once` should do their job at all costs by casting objects to strings --- src/Liquid/StandardFilters.php | 14 ++++++++++++-- tests/Liquid/StandardFiltersTest.php | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index b51f3d70..4d85f43b 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -145,7 +145,12 @@ public static function raw($input) */ public static function escape($input) { - return is_string($input) ? htmlentities($input, ENT_QUOTES) : $input; + // Arrays are taken care down the stack with an error + if (is_array($input)) { + return $input; + } + + return htmlentities($input, ENT_QUOTES); } @@ -158,7 +163,12 @@ public static function escape($input) */ public static function escape_once($input) { - return is_string($input) ? htmlentities($input, ENT_QUOTES, null, false) : $input; + // Arrays are taken care down the stack with an error + if (is_array($input)) { + return $input; + } + + return htmlentities($input, ENT_QUOTES, null, false); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 2db2e078..48a2ed29 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -177,6 +177,8 @@ public function testEscape() foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::escape($element)); } + + $this->assertSame(array(1), StandardFilters::escape(array(1))); } public function testEscapeOnce() @@ -191,6 +193,8 @@ public function testEscapeOnce() foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::escape_once($element)); } + + $this->assertSame(array(1), StandardFilters::escape_once(array(1))); } public function testStripNewLines() From b2d1d8414671b03d70c527dbbe65be952920cbd8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 10 Oct 2017 17:31:19 +0900 Subject: [PATCH 166/296] EscapeByDefaultTest: verify that object-to-string conversion does not avoid filters --- tests/Liquid/EscapeByDefaultTest.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index 47ce0c28..0b443c35 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -11,6 +11,21 @@ namespace Liquid; +class ObjectWithToString +{ + private $string = ''; + + public function __construct($string) + { + $this->string = $string; + } + + public function __toString() + { + return $this->string; + } +} + class EscapeByDefaultTest extends TestCase { const XSS = ""; @@ -84,6 +99,17 @@ public function testNlToBr() $this->assertTemplateResult($expected, $text, array('xss' => self::XSS."\n".self::XSS)); } + public function testToStringEscape() + { + $this->assertTemplateResult(self::XSS_FAILED, "{{ xss | escape }}", array('xss' => new ObjectWithToString(self::XSS))); + } + + public function testToStringEscapeDefault() + { + Liquid::set('ESCAPE_BY_DEFAULT', true); + $this->assertTemplateResult(self::XSS_FAILED, "{{ xss }}", array('xss' => new ObjectWithToString(self::XSS))); + } + /** System default value for the escape flag */ private static $escapeDefault; From 1bff3340a3d35e34edc4ac4e263c7556e6baf557 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 10 Oct 2017 18:13:07 +0900 Subject: [PATCH 167/296] Changelog for 1.4.3 [ci skip] --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index bd6f1b06..4657d0a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ * master +* 1.4.3 (2017-10-10) + + * `escape` and `escape_once` filters now escape everything, but arrays + * New standard filter for explicit string conversion + * 1.4.2 (2017-10-09) * Better caching for non-extending templates From c47e7a0ae136b52cb2c37f49dec6b83b9eb95671 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 16 Oct 2017 14:40:33 +0900 Subject: [PATCH 168/296] TagUnless is an inverted TagIf: simplify implementation to reflect that Fixes #80 --- src/Liquid/Tag/TagIf.php | 9 ++++ src/Liquid/Tag/TagUnless.php | 78 +----------------------------- tests/Liquid/Tag/TagUnlessTest.php | 7 +++ 3 files changed, 18 insertions(+), 76 deletions(-) diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index 95f54a85..01904a72 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -144,6 +144,9 @@ public function render(Context $context) $display = $this->interpretCondition($conditions[0]['left'], $conditions[0]['right'], $conditions[0]['operator'], $context); } + // hook for unless tag + $display = $this->negateIfUnless($display); + if ($display) { $result = $this->renderAll($block[2], $context); @@ -156,4 +159,10 @@ public function render(Context $context) return $result; } + + protected function negateIfUnless($display) + { + // no need to negate a condition in a regular `if` tag (will do that in `unless` tag) + return $display; + } } diff --git a/src/Liquid/Tag/TagUnless.php b/src/Liquid/Tag/TagUnless.php index bbbebdd1..7d1f94dd 100644 --- a/src/Liquid/Tag/TagUnless.php +++ b/src/Liquid/Tag/TagUnless.php @@ -11,8 +11,6 @@ namespace Liquid\Tag; -use Liquid\Context; - /** * An if statement * @@ -26,80 +24,8 @@ class TagUnless extends TagIf { - - /** - * Replace first found key in $subject to value - * - * @param array $replacer (key => value array) - * @param string $subject - * @return string - */ - protected function strReplaceOne($replacer, $subject) - { - $res = $subject; - foreach ($replacer as $from => $to) { - $res = str_ireplace($from, $to, $subject, $count); - if ($count > 0) { - break; - } - } - return $res; - } - - /** - * Method revert operators in string - * before - * a == 1 and b == 2 - * after - * a != 1 or b != 2 - */ - protected function revertOperators() - { - - // replace - $replacerOperators = array( - '==' => '!=', - '<=' => '>', - '>=' => '<', - '>' => '<=', - '<' => '>=', - '!=' => '==' - ); - - $replacerLogicalOperators = array( - 'or' => 'and', - 'and' => 'or' - ); - - if (count($this->blocks) > 0) { - if (count($this->blocks[0]) > 1) { - $condition = $this->blocks[0][1]; - - $condition = $this->strReplaceOne($replacerOperators, $condition); - $condition = $this->strReplaceOne($replacerLogicalOperators, $condition); - - // if no operators was changed, then it means there is no operators - // soo make condition ==false - if ($this->blocks[0][1] === $condition) { - $condition .= '== false'; - } - $this->blocks[0][1] = $condition; - } - } - } - - /** - * Render the tag - * - * @param Context $context - * - * @throws \Liquid\LiquidException - * @return string - */ - public function render(Context $context) + protected function negateIfUnless($display) { - $this->revertOperators(); - $res = parent::render($context); - return $res; + return !$display; } } diff --git a/tests/Liquid/Tag/TagUnlessTest.php b/tests/Liquid/Tag/TagUnlessTest.php index 95aa8aa2..1f034d93 100644 --- a/tests/Liquid/Tag/TagUnlessTest.php +++ b/tests/Liquid/Tag/TagUnlessTest.php @@ -35,4 +35,11 @@ public function testWithVariable() $expected = " false "; $this->assertTemplateResult($expected, $text, array('variable' => true)); } + + public function testForAndUnless() + { + $this->assertTemplateResult('0=>yay 0=>yay 1=> ', '{% for item in array %}{{ forloop.last }}=>{% unless forloop.last %}yay{% endunless %} {% endfor %}', array('array' => array(1, 2, 3))); + $this->assertTemplateResult('1=> 0=>yay 0=>yay ', '{% for item in array %}{{ forloop.first }}=>{% unless forloop.first %}yay{% endunless %} {% endfor %}', array('array' => array(1, 2, 3))); + $this->assertTemplateResult('0=> 0=> 1=>yay ', '{% for item in array %}{{ forloop.last }}=>{% if forloop.last %}yay{% endif %} {% endfor %}', array('array' => array(1, 2, 3))); + } } From 0f5ff835d4cb9a161e36ae4fe1b69c361feebf33 Mon Sep 17 00:00:00 2001 From: Joshua Angnoe Date: Tue, 17 Oct 2017 21:24:42 +0200 Subject: [PATCH 169/296] Allow dashes in filenames (LocalFileSystem) --- src/Liquid/FileSystem/Local.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/FileSystem/Local.php b/src/Liquid/FileSystem/Local.php index 2571ab17..d1d07073 100644 --- a/src/Liquid/FileSystem/Local.php +++ b/src/Liquid/FileSystem/Local.php @@ -80,8 +80,8 @@ public function fullPath($templatePath) } $nameRegex = Liquid::get('INCLUDE_ALLOW_EXT') - ? new Regexp('/^[^.\/][a-zA-Z0-9_\.\/]+$/') - : new Regexp('/^[^.\/][a-zA-Z0-9_\/]+$/'); + ? new Regexp('/^[^.\/][a-zA-Z0-9_\.\/-]+$/') + : new Regexp('/^[^.\/][a-zA-Z0-9_\/-]+$/'); if (!$nameRegex->match($templatePath)) { throw new ParseException("Illegal template name '$templatePath'"); From e21671089b66047a346100b63510ed4d7fdc02cf Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 3 Nov 2017 09:58:45 +0900 Subject: [PATCH 170/296] Changelog for 1.4.4 Fixes #85 --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4657d0a1..5e76a8b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ * master +* 1.4.4 (2017-11-03) + + * TagUnless is an inverted TagIf: simplified implementation + * Allow dashes in filenames + * 1.4.3 (2017-10-10) * `escape` and `escape_once` filters now escape everything, but arrays From 7f491382e2cc558be26436bfdb272d4d17984b2b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 12 Dec 2017 18:37:16 +0900 Subject: [PATCH 171/296] Test case for issue #90 --- tests/Liquid/fixtures/assign-capture.html | 20 ++++++++++++++++++ tests/Liquid/fixtures/assign-capture.liquid | 23 +++++++++++++++++++++ tests/Liquid/fixtures/assign-capture.php | 12 +++++++++++ 3 files changed, 55 insertions(+) create mode 100644 tests/Liquid/fixtures/assign-capture.html create mode 100644 tests/Liquid/fixtures/assign-capture.liquid create mode 100644 tests/Liquid/fixtures/assign-capture.php diff --git a/tests/Liquid/fixtures/assign-capture.html b/tests/Liquid/fixtures/assign-capture.html new file mode 100644 index 00000000..654c8977 --- /dev/null +++ b/tests/Liquid/fixtures/assign-capture.html @@ -0,0 +1,20 @@ + + +test 0 == test 0 + + + +test 1 == test 1 + + + +test 2 == test 2 + + + +true + + + + +test 3 == test 3 \ No newline at end of file diff --git a/tests/Liquid/fixtures/assign-capture.liquid b/tests/Liquid/fixtures/assign-capture.liquid new file mode 100644 index 00000000..b3821c03 --- /dev/null +++ b/tests/Liquid/fixtures/assign-capture.liquid @@ -0,0 +1,23 @@ +{% assign my_variable = 'test 0' %} + +{{ my_variable }} == test 0 + +{% capture my_variable %}test 1{% endcapture %} + +{{ my_variable }} == test 1 + +{% capture my_variable %}test 2{% endcapture %} + +{{ my_variable }} == test 2 + + +{% if true %} +true +{% assign my_variable = 'test 0' %} +{% capture my_variable %}test 3{% endcapture %} +{% else %} +false +{% capture my_variable%}test 4{% endcapture %} +{% endif %} + +{{ my_variable }} == test 3 \ No newline at end of file diff --git a/tests/Liquid/fixtures/assign-capture.php b/tests/Liquid/fixtures/assign-capture.php new file mode 100644 index 00000000..9890e4eb --- /dev/null +++ b/tests/Liquid/fixtures/assign-capture.php @@ -0,0 +1,12 @@ + Date: Tue, 12 Dec 2017 18:51:48 +0900 Subject: [PATCH 172/296] assign-capture.liquid - clarified cases --- tests/Liquid/fixtures/assign-capture.html | 4 ++-- tests/Liquid/fixtures/assign-capture.liquid | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/Liquid/fixtures/assign-capture.html b/tests/Liquid/fixtures/assign-capture.html index 654c8977..bc8b4132 100644 --- a/tests/Liquid/fixtures/assign-capture.html +++ b/tests/Liquid/fixtures/assign-capture.html @@ -12,9 +12,9 @@ -true +test 3 == test 3 (inside an if) -test 3 == test 3 \ No newline at end of file +test 3 == test 3 (outside of an if) \ No newline at end of file diff --git a/tests/Liquid/fixtures/assign-capture.liquid b/tests/Liquid/fixtures/assign-capture.liquid index b3821c03..7d2bd24a 100644 --- a/tests/Liquid/fixtures/assign-capture.liquid +++ b/tests/Liquid/fixtures/assign-capture.liquid @@ -12,12 +12,13 @@ {% if true %} -true {% assign my_variable = 'test 0' %} {% capture my_variable %}test 3{% endcapture %} +{{ my_variable }} == test 3 (inside an if) {% else %} -false -{% capture my_variable%}test 4{% endcapture %} +{% capture my_variable %}test 4{% endcapture %} +{{ my_variable }} + {% endif %} -{{ my_variable }} == test 3 \ No newline at end of file +{{ my_variable }} == test 3 (outside of an if) \ No newline at end of file From 5cd4b76a648a2f3e9af122a7f05db3679ba1ad64 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 12 Dec 2017 18:52:31 +0900 Subject: [PATCH 173/296] TagCapture: assign variables in the global context; Liquid from Jekyll does that Closes #90 --- src/Liquid/Tag/TagCapture.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index b9232b49..1995d667 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -65,7 +65,7 @@ public function render(Context $context) { $output = parent::render($context); - $context->set($this->to, $output); + $context->set($this->to, $output, true); return ''; } } From 8b08a4634bd9bc7ad5b135f3d6a23821d2eed499 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 12 Dec 2017 23:08:08 +0900 Subject: [PATCH 174/296] Update CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5e76a8b9..a96ed179 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ * master +* 1.4.5 (2017-12-12) + + * Capture tag shall save a variable in the global context. + * 1.4.4 (2017-11-03) * TagUnless is an inverted TagIf: simplified implementation From 2a0fa6070fb3664a7d3b4944231cb804bbda53e5 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 10:47:10 +0900 Subject: [PATCH 175/296] TagPaginate must work in own scope Fixes #93 --- src/Liquid/Tag/TagPaginate.php | 9 ++++++++- tests/Liquid/Tag/TagPaginateTest.php | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 718850bd..8f19007d 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -115,6 +115,9 @@ public function render(Context $context) $this->totalPages = ceil($this->collectionSize / $this->numberItems); $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); + // We must work in a new scope so we won't pollute a global scope + $context->push(); + // Sets the collection if it's a key of another collection (ie search.results, collection.products, blog.articles) $segments = explode('.', $this->collectionName); if (count($segments) == 2) { @@ -143,7 +146,11 @@ public function render(Context $context) $context->set('paginate', $paginate); - return parent::render($context); + $result = parent::render($context); + + $context->pop(); + + return $result; } /** diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index fe72ac36..6926224c 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -43,4 +43,19 @@ public function testSyntaxErrorCase() { $this->assertTemplateResult('', '{% paginate products %}{% endpaginate %}'); } + + public function testPaginationForRepeatedCalls() + { + $assigns = array( + 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)), + ); + + $text = '{% for article in articles %}{{ article.title }},{% endfor %}'; + $expected = '1,2,3,'; + $this->assertTemplateResult($expected, $text, $assigns); + + $text = '{% paginate articles by 2 %}{% for article in articles %}{{ article.title }},{% endfor %}{% endpaginate %} '.$text; + $expected = '1,2, 1,2,3,'; + $this->assertTemplateResult($expected, $text, $assigns); + } } From 33cc34dc24c8262954fba14fba6f7f440f6a25bc Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:13:22 +0900 Subject: [PATCH 176/296] TagFor: refactored different types of cycles in separate functions --- src/Liquid/Tag/TagFor.php | 222 ++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 107 deletions(-) diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index ba18df29..a2e228a5 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -104,120 +104,128 @@ public function render(Context $context) } switch ($this->type) { - case 'collection': - - $collection = $context->get($this->collectionName); - - if ($collection instanceof \Traversable) { - $collection = iterator_to_array($collection); - } - - if (is_null($collection) || !is_array($collection) || count($collection) == 0) { - return ''; - } - - $range = array(0, count($collection)); - - if (isset($this->attributes['limit']) || isset($this->attributes['offset'])) { - $offset = 0; - - if (isset($this->attributes['offset'])) { - $offset = ($this->attributes['offset'] == 'continue') ? $context->registers['for'][$this->name] : $context->get($this->attributes['offset']); - } - - $limit = (isset($this->attributes['limit'])) ? $context->get($this->attributes['limit']) : null; - $rangeEnd = $limit ? $limit : count($collection) - $offset; - $range = array($offset, $rangeEnd); - - $context->registers['for'][$this->name] = $rangeEnd + $offset; - } - - $result = ''; - $segment = array_slice($collection, $range[0], $range[1]); - if (!count($segment)) { - return null; - } - - $context->push(); - $length = count($segment); - - $index = 0; - foreach ($segment as $key => $item) { - $value = is_numeric($key) ? $item : array($key, $item); - $context->set($this->variableName, $value); - $context->set('forloop', array( - 'name' => $this->name, - 'length' => $length, - 'index' => $index + 1, - 'index0' => $index, - 'rindex' => $length - $index, - 'rindex0' => $length - $index - 1, - 'first' => (int)($index == 0), - 'last' => (int)($index == $length - 1) - )); - - $result .= $this->renderAll($this->nodelist, $context); - - $index++; - - if (isset($context->registers['break'])) { - unset($context->registers['break']); - break; - } - if (isset($context->registers['continue'])) { - unset($context->registers['continue']); - } - } - + return $this->renderCollection($context); break; case 'digit': + return $this->renderDigit($context); + break; + } + } - $start = $this->start; - if (!is_integer($this->start)) { - $start = $context->get($this->start); - } - - $end = $this->collectionName; - if (!is_integer($this->collectionName)) { - $end = $context->get($this->collectionName); - } - - $range = array($start, $end); - - $context->push(); - $result = ''; - $index = 0; - $length = $range[1] - $range[0]; - for ($i=$range[0]; $i<=$range[1]; $i++) { - $context->set($this->variableName, $i); - $context->set('forloop', array( - 'name' => $this->name, - 'length' => $length, - 'index' => $index + 1, - 'index0' => $index, - 'rindex' => $length - $index, - 'rindex0' => $length - $index - 1, - 'first' => (int)($index == 0), - 'last' => (int)($index == $length - 1) - )); - - $result .= $this->renderAll($this->nodelist, $context); - - $index++; - - if (isset($context->registers['break'])) { - unset($context->registers['break']); - break; - } - if (isset($context->registers['continue'])) { - unset($context->registers['continue']); - } - } + private function renderCollection(Context $context) + { + $collection = $context->get($this->collectionName); - break; + if ($collection instanceof \Traversable) { + $collection = iterator_to_array($collection); + } + + if (is_null($collection) || !is_array($collection) || count($collection) == 0) { + return ''; + } + + $range = array(0, count($collection)); + + if (isset($this->attributes['limit']) || isset($this->attributes['offset'])) { + $offset = 0; + + if (isset($this->attributes['offset'])) { + $offset = ($this->attributes['offset'] == 'continue') ? $context->registers['for'][$this->name] : $context->get($this->attributes['offset']); + } + + $limit = (isset($this->attributes['limit'])) ? $context->get($this->attributes['limit']) : null; + $rangeEnd = $limit ? $limit : count($collection) - $offset; + $range = array($offset, $rangeEnd); + + $context->registers['for'][$this->name] = $rangeEnd + $offset; + } + $result = ''; + $segment = array_slice($collection, $range[0], $range[1]); + if (!count($segment)) { + return null; + } + + $context->push(); + $length = count($segment); + + $index = 0; + foreach ($segment as $key => $item) { + $value = is_numeric($key) ? $item : array($key, $item); + $context->set($this->variableName, $value); + $context->set('forloop', array( + 'name' => $this->name, + 'length' => $length, + 'index' => $index + 1, + 'index0' => $index, + 'rindex' => $length - $index, + 'rindex0' => $length - $index - 1, + 'first' => (int)($index == 0), + 'last' => (int)($index == $length - 1) + )); + + $result .= $this->renderAll($this->nodelist, $context); + + $index++; + + if (isset($context->registers['break'])) { + unset($context->registers['break']); + break; + } + if (isset($context->registers['continue'])) { + unset($context->registers['continue']); + } + } + + $context->pop(); + + return $result; + } + + private function renderDigit(Context $context) + { + $start = $this->start; + if (!is_integer($this->start)) { + $start = $context->get($this->start); + } + + $end = $this->collectionName; + if (!is_integer($this->collectionName)) { + $end = $context->get($this->collectionName); + } + + $range = array($start, $end); + + $context->push(); + $result = ''; + $index = 0; + $length = $range[1] - $range[0]; + for ($i = $range[0]; $i <= $range[1]; $i++) { + $context->set($this->variableName, $i); + $context->set('forloop', array( + 'name' => $this->name, + 'length' => $length, + 'index' => $index + 1, + 'index0' => $index, + 'rindex' => $length - $index, + 'rindex0' => $length - $index - 1, + 'first' => (int)($index == 0), + 'last' => (int)($index == $length - 1) + )); + + $result .= $this->renderAll($this->nodelist, $context); + + $index++; + + if (isset($context->registers['break'])) { + unset($context->registers['break']); + break; + } + if (isset($context->registers['continue'])) { + unset($context->registers['continue']); + } } $context->pop(); From 99823c545456ed16bb895fc91fe53c30ce669b76 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:13:53 +0900 Subject: [PATCH 177/296] TagPaginate: throw up if no collection present instead of vague "array_slice() expects parameter 1 to be array, null given" --- src/Liquid/Tag/TagPaginate.php | 7 +++++++ tests/Liquid/Tag/TagPaginateTest.php | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 8f19007d..fd48a610 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -17,6 +17,7 @@ use Liquid\Context; use Liquid\FileSystem; use Liquid\Regexp; +use Liquid\Exception\RenderException; /** * The paginate tag works in conjunction with the for tag to split content into numerous pages. @@ -113,6 +114,12 @@ public function render(Context $context) } $this->collectionSize = count($this->collection); $this->totalPages = ceil($this->collectionSize / $this->numberItems); + + if (!is_array($this->collection)) { + // TODO do not throw up if error mode allows, see #83 + throw new RenderException("Missing collection with name '{$this->collectionName}'"); + } + $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); // We must work in a new scope so we won't pollute a global scope diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 6926224c..5054209b 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -44,6 +44,15 @@ public function testSyntaxErrorCase() $this->assertTemplateResult('', '{% paginate products %}{% endpaginate %}'); } + /** + * @expectedException \Liquid\Exception\RenderException + * @expectedExceptionMessage Missing collection + */ + public function testNoCollection() + { + $this->assertTemplateResult('', '{% paginate products by 1 %}{% for product in products %}{{ product.id }}{% endfor %}{% endpaginate %}'); + } + public function testPaginationForRepeatedCalls() { $assigns = array( From 9c99b0e7636e592774b579799b55e564d0cad47e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:14:48 +0900 Subject: [PATCH 178/296] Fixtures for #93 --- tests/Liquid/fixtures/for.html | 24 ++++++++++++++++++++++++ tests/Liquid/fixtures/for.liquid | 15 +++++++++++++++ tests/Liquid/fixtures/for.php | 5 +++++ 3 files changed, 44 insertions(+) diff --git a/tests/Liquid/fixtures/for.html b/tests/Liquid/fixtures/for.html index 951b6232..1852f6c5 100644 --- a/tests/Liquid/fixtures/for.html +++ b/tests/Liquid/fixtures/for.html @@ -78,3 +78,27 @@ 5 + +Regular loop: + + 1 + + 2 + + 3 + + +Within a pagination: + + 1 + + 2 + + +Should not be affected by a pagination: + + 1 + + 2 + + 3 diff --git a/tests/Liquid/fixtures/for.liquid b/tests/Liquid/fixtures/for.liquid index e1e6834b..487b7e08 100644 --- a/tests/Liquid/fixtures/for.liquid +++ b/tests/Liquid/fixtures/for.liquid @@ -24,3 +24,18 @@ Range loop: {% for i in (1..item.quantity) %} {{ i }} {% endfor %} + +Regular loop: +{% for article in articles %} + {{ article.title }} +{% endfor %} + +Within a pagination: +{% paginate articles by 2 %}{% for article in articles %} + {{ article.title }} +{% endfor %}{% endpaginate %} + +Should not be affected by a pagination: +{% for article in articles %} + {{ article.title }} +{% endfor %} \ No newline at end of file diff --git a/tests/Liquid/fixtures/for.php b/tests/Liquid/fixtures/for.php index 0b75cc66..0f2246ef 100644 --- a/tests/Liquid/fixtures/for.php +++ b/tests/Liquid/fixtures/for.php @@ -14,4 +14,9 @@ 'item' => array( 'quantity' => 5, ), + 'articles' => array( + array('title' => 1), + array('title' => 2), + array('title' => 3), + ), ); From 9467bb5a97b12158a0ea876715aa94d9a30a2910 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:20:24 +0900 Subject: [PATCH 179/296] TagFor: by default render a collection, which is the default anyways --- src/Liquid/Tag/TagFor.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index a2e228a5..b3912805 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -103,15 +103,12 @@ public function render(Context $context) $context->registers['for'] = array(); } - switch ($this->type) { - case 'collection': - return $this->renderCollection($context); - break; - - case 'digit': - return $this->renderDigit($context); - break; + if ($this->type == 'digit') { + return $this->renderDigit($context); } + + // that's the default + return $this->renderCollection($context); } private function renderCollection(Context $context) From 7719f1905773c65086a9455d9b8672bff0e8db1f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:23:00 +0900 Subject: [PATCH 180/296] TagPaginate: count() won't work with non-array in PHP 7.2 Errors with: count(): Parameter must be an array or an object that implements Countable --- src/Liquid/Tag/TagPaginate.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index fd48a610..8bf1caeb 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -109,17 +109,18 @@ public function render(Context $context) $this->currentPage = (is_numeric($context->get('page'))) ? $context->get('page') : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); + if ($this->collection instanceof \Traversable) { $this->collection = iterator_to_array($this->collection); } - $this->collectionSize = count($this->collection); - $this->totalPages = ceil($this->collectionSize / $this->numberItems); if (!is_array($this->collection)) { // TODO do not throw up if error mode allows, see #83 throw new RenderException("Missing collection with name '{$this->collectionName}'"); } + $this->collectionSize = count($this->collection); + $this->totalPages = ceil($this->collectionSize / $this->numberItems); $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); // We must work in a new scope so we won't pollute a global scope From 34a240e328ba4969c2e96ee3e1fb21ee3a305443 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 7 Feb 2018 11:27:50 +0900 Subject: [PATCH 181/296] Changelog for 1.4.6 [skip ci] --- CHANGELOG | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a96ed179..80cb6757 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ * master +* 1.4.6 (2018-02-07) + + * TagPaginate shall not pullute the global scope, but work in own scope. + * TagPaginate errors if no collection present instead of vague warning. + * 1.4.5 (2017-12-12) * Capture tag shall save a variable in the global context. From f692ed30c9cd060c9c10465af8b2c9e7f2c2b6c2 Mon Sep 17 00:00:00 2001 From: edwardoka <1197105+edwardoka@users.noreply.github.com> Date: Thu, 8 Feb 2018 01:15:29 +0000 Subject: [PATCH 182/296] TagPaginate: Replace hardcoded references to 'page' with lookups against the Liquid configuration object --- src/Liquid/Tag/TagPaginate.php | 14 +++++-- tests/Liquid/Tag/TagPaginateTest.php | 56 ++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 8bf1caeb..4bd074fb 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -106,7 +106,11 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu */ public function render(Context $context) { - $this->currentPage = (is_numeric($context->get('page'))) ? $context->get('page') : 1; + // Check for a setting in the Liquid config for the context key to use to refer to the current page + $pageContextKey = Liquid::get('PAGINATION_CONTEXT_KEY'); + $pageContextKey = ($pageContextKey) ? $pageContextKey : 'page'; + + $this->currentPage = (is_numeric($context->get($pageContextKey))) ? $context->get($pageContextKey) : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); @@ -142,14 +146,18 @@ public function render(Context $context) 'items' => $this->collectionSize ); + // look to see if there's a key in the Liquid config for the request field to use in URLs + $pageRequestKey = Liquid::get('PAGINATION_REQUEST_KEY'); + $pageRequestKey = ($pageRequestKey) ? $pageRequestKey : 'page'; + if ($this->currentPage != 1) { $paginate['previous']['title'] = 'Previous'; - $paginate['previous']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage - 1); + $paginate['previous']['url'] = $this->currentUrl($context) . '?' . urlencode($pageRequestKey) . '=' . ($this->currentPage - 1); } if ($this->currentPage != $this->totalPages) { $paginate['next']['title'] = 'Next'; - $paginate['next']['url'] = $this->currentUrl($context) . '?page=' . ($this->currentPage + 1); + $paginate['next']['url'] = $this->currentUrl($context) . '?' . urlencode($pageRequestKey) . '=' . ($this->currentPage + 1); } $context->set('paginate', $paginate); diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 5054209b..97b790a2 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -67,4 +67,60 @@ public function testPaginationForRepeatedCalls() $expected = '1,2, 1,2,3,'; $this->assertTemplateResult($expected, $text, $assigns); } + + public function testPaginationDoesntIncludePreviousIfFirst() + { + $assigns = array( + 'HTTP_HOST' => 'example.com', 'page' => 1, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + ); + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + + $expected = '1 , Next,http://example.com?page=2'; + + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateDoesntIncludeNextIfLast() + { + $assigns = array( + 'HTTP_HOST' => 'example.com', 'page' => 3, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + ); + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + + $expected = '3 Previous,http://example.com?page=2 ,'; + + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateUsingDifferentRequestParameterName() + { + $assigns = array( + 'HTTP_HOST' => 'example.com', 'page' => 2, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + ); + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + + $expected = '2 Previous,http://example.com?pagina=1 Next,http://example.com?pagina=3'; + + \Liquid\Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); + $this->assertTemplateResult($expected, $text, $assigns); + \Liquid\Liquid::set('PAGINATION_REQUEST_KEY', null); + } + + public function testPaginateUsingDifferentContextParameter() + { + $assigns = array( + 'HTTP_HOST' => 'example.com', 'the_current_page' => 2, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + ); + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + + $expected = '2 Previous,http://example.com?page=1 Next,http://example.com?page=3'; + + \Liquid\Liquid::set('PAGINATION_CONTEXT_KEY', 'the_current_page'); + $this->assertTemplateResult($expected, $text, $assigns); + \Liquid\Liquid::set('PAGINATION_CONTEXT_KEY', null); + } } From 6e7691d15bd90ebae66ae415ad9814ef3f78ffc0 Mon Sep 17 00:00:00 2001 From: edwardoka <1197105+edwardoka@users.noreply.github.com> Date: Thu, 8 Feb 2018 11:44:26 +0000 Subject: [PATCH 183/296] TagPaginate: Partial changes requested in PR #96 --- src/Liquid/Liquid.php | 6 +++++ src/Liquid/Tag/TagPaginate.php | 7 ++--- tests/Liquid/Tag/TagPaginateTest.php | 38 ++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index c2cc8da2..250903e3 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -72,6 +72,12 @@ class Liquid // Automatically escape any variables unless told otherwise by a "raw" filter 'ESCAPE_BY_DEFAULT' => false, + + // The name of the key to use when building pagination query strings e.g. ?page=1 + 'PAGINATION_REQUEST_KEY' => 'page', + + // The name of the context key used to denote the current page number + 'PAGINATION_CONTEXT_KEY' => 'page' ); /** diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 4bd074fb..aa59c89e 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -45,7 +45,6 @@ class TagPaginate extends AbstractBlock private $collection; /** - * * @var int The size of the collection */ private $collectionSize; @@ -106,9 +105,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu */ public function render(Context $context) { - // Check for a setting in the Liquid config for the context key to use to refer to the current page + // Get the context key to use to refer to the current page $pageContextKey = Liquid::get('PAGINATION_CONTEXT_KEY'); - $pageContextKey = ($pageContextKey) ? $pageContextKey : 'page'; $this->currentPage = (is_numeric($context->get($pageContextKey))) ? $context->get($pageContextKey) : 1; $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; @@ -146,9 +144,8 @@ public function render(Context $context) 'items' => $this->collectionSize ); - // look to see if there's a key in the Liquid config for the request field to use in URLs + // Get the name of the request field to use in URLs $pageRequestKey = Liquid::get('PAGINATION_REQUEST_KEY'); - $pageRequestKey = ($pageRequestKey) ? $pageRequestKey : 'page'; if ($this->currentPage != 1) { $paginate['previous']['title'] = 'Previous'; diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 97b790a2..3b492d02 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -12,9 +12,28 @@ namespace Liquid\Tag; use Liquid\TestCase; +use Liquid\Liquid; class TagPaginateTest extends TestCase { + /** System default values for the request and context page key */ + private static $requestKeyDefault; + private static $contextKeyDefault; + + public static function setUpBeforeClass() + { + // save system default value for the escape flag before all tests + self::$requestKeyDefault = Liquid::get('PAGINATION_REQUEST_KEY'); + self::$contextKeyDefault = Liquid::get('PAGINATION_CONTEXT_KEY'); + } + + public function tearDown() + { + // reset to the defaults after each test + Liquid::set('PAGINATION_REQUEST_KEY', self::$requestKeyDefault); + Liquid::set('PAGINATION_CONTEXT_KEY', self::$contextKeyDefault); + } + public function testWorks() { $text = "{% paginate products by 3 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; @@ -71,7 +90,7 @@ public function testPaginationForRepeatedCalls() public function testPaginationDoesntIncludePreviousIfFirst() { $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 1, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + 'HTTP_HOST' => 'example.com', 'page' => 1, 'articles' => $this->provideArticleFixture() ); $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; @@ -84,7 +103,7 @@ public function testPaginationDoesntIncludePreviousIfFirst() public function testPaginateDoesntIncludeNextIfLast() { $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 3, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + 'HTTP_HOST' => 'example.com', 'page' => 3, 'articles' => $this->provideArticleFixture() ); $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; @@ -97,30 +116,33 @@ public function testPaginateDoesntIncludeNextIfLast() public function testPaginateUsingDifferentRequestParameterName() { $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 2, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + 'HTTP_HOST' => 'example.com', 'page' => 2, 'articles' => $this->provideArticleFixture() ); $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; $expected = '2 Previous,http://example.com?pagina=1 Next,http://example.com?pagina=3'; - \Liquid\Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); + Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); $this->assertTemplateResult($expected, $text, $assigns); - \Liquid\Liquid::set('PAGINATION_REQUEST_KEY', null); } public function testPaginateUsingDifferentContextParameter() { $assigns = array( - 'HTTP_HOST' => 'example.com', 'the_current_page' => 2, 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)) + 'HTTP_HOST' => 'example.com', 'the_current_page' => 2, 'articles' => $this->provideArticleFixture() ); $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; $expected = '2 Previous,http://example.com?page=1 Next,http://example.com?page=3'; - \Liquid\Liquid::set('PAGINATION_CONTEXT_KEY', 'the_current_page'); + Liquid::set('PAGINATION_CONTEXT_KEY', 'the_current_page'); $this->assertTemplateResult($expected, $text, $assigns); - \Liquid\Liquid::set('PAGINATION_CONTEXT_KEY', null); + } + + private function provideArticleFixture() + { + return array(array('title' => 1), array('title' => 2), array('title' => 3)); } } From d645b7b8d5a503ba9b662e9ec09fd0bac26fc5df Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 9 Feb 2018 10:46:22 +0900 Subject: [PATCH 184/296] TagPaginateTest: a constant with default assigns for most tests --- tests/Liquid/Tag/TagPaginateTest.php | 58 ++++++++++++---------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 3b492d02..eab5fc88 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -72,72 +72,64 @@ public function testNoCollection() $this->assertTemplateResult('', '{% paginate products by 1 %}{% for product in products %}{{ product.id }}{% endfor %}{% endpaginate %}'); } + const PAGINATION_ASSIGNS = array( + 'HTTP_HOST' => 'example.com', + 'HTTPS' => 'on', + 'page' => 1, + 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)), + ); + public function testPaginationForRepeatedCalls() { - $assigns = array( - 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)), - ); - $text = '{% for article in articles %}{{ article.title }},{% endfor %}'; $expected = '1,2,3,'; - $this->assertTemplateResult($expected, $text, $assigns); + $this->assertTemplateResult($expected, $text, self::PAGINATION_ASSIGNS); $text = '{% paginate articles by 2 %}{% for article in articles %}{{ article.title }},{% endfor %}{% endpaginate %} '.$text; $expected = '1,2, 1,2,3,'; - $this->assertTemplateResult($expected, $text, $assigns); + $this->assertTemplateResult($expected, $text, self::PAGINATION_ASSIGNS); } public function testPaginationDoesntIncludePreviousIfFirst() { - $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 1, 'articles' => $this->provideArticleFixture() - ); + $assigns = self::PAGINATION_ASSIGNS; $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; - - $expected = '1 , Next,http://example.com?page=2'; - + $expected = '1 , Next,https://example.com?page=2'; $this->assertTemplateResult($expected, $text, $assigns); } public function testPaginateDoesntIncludeNextIfLast() { - $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 3, 'articles' => $this->provideArticleFixture() - ); + $assigns = self::PAGINATION_ASSIGNS; + $assigns['page'] = 3; $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; - - $expected = '3 Previous,http://example.com?page=2 ,'; - + $expected = '3 Previous,https://example.com?page=2 ,'; $this->assertTemplateResult($expected, $text, $assigns); } public function testPaginateUsingDifferentRequestParameterName() { - $assigns = array( - 'HTTP_HOST' => 'example.com', 'page' => 2, 'articles' => $this->provideArticleFixture() - ); - - $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); - $expected = '2 Previous,http://example.com?pagina=1 Next,http://example.com?pagina=3'; + $assigns = self::PAGINATION_ASSIGNS; + $assigns['page'] = 2; - Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + $expected = '2 Previous,https://example.com?pagina=1 Next,https://example.com?pagina=3'; $this->assertTemplateResult($expected, $text, $assigns); } - + public function testPaginateUsingDifferentContextParameter() { - $assigns = array( - 'HTTP_HOST' => 'example.com', 'the_current_page' => 2, 'articles' => $this->provideArticleFixture() - ); - - $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + Liquid::set('PAGINATION_CONTEXT_KEY', 'the_current_page'); - $expected = '2 Previous,http://example.com?page=1 Next,http://example.com?page=3'; + $assigns = self::PAGINATION_ASSIGNS; + $assigns['the_current_page'] = 2; - Liquid::set('PAGINATION_CONTEXT_KEY', 'the_current_page'); + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + $expected = '2 Previous,https://example.com?page=1 Next,https://example.com?page=3'; $this->assertTemplateResult($expected, $text, $assigns); } From 32edab8c02cbdd608a7df8d0879bd62151f884ad Mon Sep 17 00:00:00 2001 From: edwardoka <1197105+edwardoka@users.noreply.github.com> Date: Fri, 9 Feb 2018 10:47:25 +0900 Subject: [PATCH 185/296] TagPaginateTest: URL generation must preserve params --- tests/Liquid/Tag/TagPaginateTest.php | 31 ++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index eab5fc88..b02736ab 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -133,8 +133,35 @@ public function testPaginateUsingDifferentContextParameter() $this->assertTemplateResult($expected, $text, $assigns); } - private function provideArticleFixture() + public function testPaginateUrlGenerationPreservesParams() { - return array(array('title' => 1), array('title' => 2), array('title' => 3)); + $assigns = self::PAGINATION_ASSIGNS; + $assigns['REQUEST_URI'] = '/testfile.php?someparam=1'; + + $text = '{% paginate articles by 1 %}{{ paginate.next.url }}{% endpaginate %}'; + $expected = 'https://example.com/testfile.php?someparam=1&page=2'; + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateUrlGenerationReplacesPageKey() + { + $assigns = self::PAGINATION_ASSIGNS; + $assigns['REQUEST_URI'] = '/testfile.php?someparam=1&page=1'; + + $text = '{% paginate articles by 1 %}{{ paginate.next.url }}{% endpaginate %}'; + $expected = 'https://example.com/testfile.php?someparam=1&page=2'; + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateUrlGenerationRespectsPageParameterKey() + { + Liquid::set('PAGINATION_REQUEST_KEY', 'pagina'); + + $assigns = self::PAGINATION_ASSIGNS; + $assigns['REQUEST_URI'] = '/testfile.php?someparam=1&page=hello&pagina=1'; + + $text = '{% paginate articles by 1 %}{{ paginate.next.url }}{% endpaginate %}'; + $expected = 'https://example.com/testfile.php?someparam=1&page=hello&pagina=2'; + $this->assertTemplateResult($expected, $text, $assigns); } } From d58e2ce876c4a601be3e237b447282fdf11a1e76 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 9 Feb 2018 10:50:59 +0900 Subject: [PATCH 186/296] TagPaginateTest: a case without https --- tests/Liquid/Tag/TagPaginateTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index b02736ab..62b82c83 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -164,4 +164,15 @@ public function testPaginateUrlGenerationRespectsPageParameterKey() $expected = 'https://example.com/testfile.php?someparam=1&page=hello&pagina=2'; $this->assertTemplateResult($expected, $text, $assigns); } + + public function testPaginateUrlGenerationWithoutHTTPS() + { + $assigns = self::PAGINATION_ASSIGNS; + $assigns['REQUEST_URI'] = '/'; + $assigns['HTTPS'] = ''; + + $text = '{% paginate articles by 1 %}{{ paginate.next.url }}{% endpaginate %}'; + $expected = 'http://example.com/?page=2'; + $this->assertTemplateResult($expected, $text, $assigns); + } } From 7f1caa0053a35e02e81eff79e2a8156f970bd3be Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 9 Feb 2018 10:58:43 +0900 Subject: [PATCH 187/296] TagPaginate: keep request parameters Fixes #97 --- src/Liquid/Tag/TagPaginate.php | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index aa59c89e..c027d03b 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -147,14 +147,18 @@ public function render(Context $context) // Get the name of the request field to use in URLs $pageRequestKey = Liquid::get('PAGINATION_REQUEST_KEY'); - if ($this->currentPage != 1) { + if ($this->currentPage > 1) { $paginate['previous']['title'] = 'Previous'; - $paginate['previous']['url'] = $this->currentUrl($context) . '?' . urlencode($pageRequestKey) . '=' . ($this->currentPage - 1); + $paginate['previous']['url'] = $this->currentUrl($context, [ + $pageRequestKey => $this->currentPage - 1, + ]); } - if ($this->currentPage != $this->totalPages) { + if ($this->currentPage < $this->totalPages) { $paginate['next']['title'] = 'Next'; - $paginate['next']['url'] = $this->currentUrl($context) . '?' . urlencode($pageRequestKey) . '=' . ($this->currentPage + 1); + $paginate['next']['url'] = $this->currentUrl($context, [ + $pageRequestKey => $this->currentPage + 1, + ]); } $context->set('paginate', $paginate); @@ -170,20 +174,28 @@ public function render(Context $context) * Returns the current page URL * * @param Context $context + * @param array $queryPart * * @return string * */ - public function currentUrl($context) + public function currentUrl($context, $queryPart = []) { - $uri = explode('?', $context->get('REQUEST_URI')); + // From here we have $url->path and $url->query + $url = (object) parse_url($context->get('REQUEST_URI')); - $url = 'http'; - if ($context->get('HTTPS') == 'on') { - $url .= 's'; + // Let's merge the query part + if (isset($url->query)) { + parse_str($url->query, $url->query); + $url->query = array_merge($url->query, $queryPart); + } else { + $url->query = $queryPart; } - $url .= '://' . $context->get('HTTP_HOST') . reset($uri); - return $url; + $url->query = http_build_query($url->query); + + $scheme = $context->get('HTTPS') == 'on' ? 'https' : 'http'; + + return "$scheme://{$context->get('HTTP_HOST')}{$url->path}?{$url->query}"; } } From 09a3582ea9062408763f2eeda83f1d4820a1e7d5 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 9 Feb 2018 11:12:02 +0900 Subject: [PATCH 188/296] TagPaginate: page number can only be between 1 and a number of pages Fixes #94 --- src/Liquid/Tag/TagPaginate.php | 15 +++++++++----- tests/Liquid/Tag/TagPaginateTest.php | 30 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index c027d03b..afafaef3 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -105,11 +105,6 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu */ public function render(Context $context) { - // Get the context key to use to refer to the current page - $pageContextKey = Liquid::get('PAGINATION_CONTEXT_KEY'); - - $this->currentPage = (is_numeric($context->get($pageContextKey))) ? $context->get($pageContextKey) : 1; - $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $this->collection = $context->get($this->collectionName); if ($this->collection instanceof \Traversable) { @@ -121,8 +116,18 @@ public function render(Context $context) throw new RenderException("Missing collection with name '{$this->collectionName}'"); } + // How many pages are there? $this->collectionSize = count($this->collection); $this->totalPages = ceil($this->collectionSize / $this->numberItems); + + // Whatever there is in the context, we need a number + $this->currentPage = intval($context->get(Liquid::get('PAGINATION_CONTEXT_KEY'))); + + // Page number can only be between 1 and a number of pages + $this->currentPage = max(1, min($this->currentPage, $this->totalPages)); + + // Find the offset and select that part + $this->currentOffset = ($this->currentPage - 1) * $this->numberItems; $paginatedCollection = array_slice($this->collection, $this->currentOffset, $this->numberItems); // We must work in a new scope so we won't pollute a global scope diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 62b82c83..1ce8b046 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -175,4 +175,34 @@ public function testPaginateUrlGenerationWithoutHTTPS() $expected = 'http://example.com/?page=2'; $this->assertTemplateResult($expected, $text, $assigns); } + + public function testPaginateDoesntIncludeNextIfAfterLast() + { + $assigns = self::PAGINATION_ASSIGNS; + $assigns['page'] = 42; + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + $expected = '3 Previous,https://example.com?page=2 ,'; + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateDoesntIncludePreviousIfBeforeFirst() + { + $assigns = self::PAGINATION_ASSIGNS; + $assigns['page'] = 0; + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + $expected = '1 , Next,https://example.com?page=2'; + $this->assertTemplateResult($expected, $text, $assigns); + } + + public function testPaginateIgnoresNonNumbers() + { + $assigns = self::PAGINATION_ASSIGNS; + $assigns['page'] = 'foo'; + + $text = '{% paginate articles by 1 %}{% for article in articles %}{{article.title}}{% endfor %} {{paginate.previous.title}},{{paginate.previous.url}} {{paginate.next.title}},{{paginate.next.url}}{% endpaginate %}'; + $expected = '1 , Next,https://example.com?page=2'; + $this->assertTemplateResult($expected, $text, $assigns); + } } From 2de612522d77005b1922d20c2ae4e088074278de Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 9 Feb 2018 11:20:42 +0900 Subject: [PATCH 189/296] Changelog for 1.4.7 [skip ci] --- CHANGELOG | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 80cb6757..a9f3b025 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,8 +1,14 @@ * master +* 1.4.7 (2018-02-09) + + * Paginate tag shall now respect request parameters. + * It is now possible to set a custom query param for the paginate tag. + * Page number will now never go overboard. + * 1.4.6 (2018-02-07) - * TagPaginate shall not pullute the global scope, but work in own scope. + * TagPaginate shall not pollute the global scope, but work in own scope. * TagPaginate errors if no collection present instead of vague warning. * 1.4.5 (2017-12-12) From 162a8a9c07b2e75d63a98b5c2e086e1714a529d9 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 16 Mar 2018 04:40:58 +0900 Subject: [PATCH 190/296] CI with Infection PHP --- .travis.yml | 2 +- composer.json | 5 +++-- infection.json.dist | 11 +++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 infection.json.dist diff --git a/.travis.yml b/.travis.yml index fbdb0109..61c8240b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ sudo: false language: php php: - - 5.6 - 7.0 - 7.1 - 7.2 @@ -17,6 +16,7 @@ install: script: - vendor/bin/phpunit --verbose || travis_terminate 1 + - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=4 - mkdir -p build/cache && vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix after_success: diff --git a/composer.json b/composer.json index 127eebaf..a3273831 100644 --- a/composer.json +++ b/composer.json @@ -27,12 +27,13 @@ } ], "require": { - "php": ">= 5.6" + "php": ">= 7" }, "require-dev": { "phpunit/phpunit": "<6", "satooshi/php-coveralls": "^1.0", - "friendsofphp/php-cs-fixer": "^2.6" + "friendsofphp/php-cs-fixer": "^2.6", + "infection/infection": "^0.8.1" }, "autoload": { "psr-4": { diff --git a/infection.json.dist b/infection.json.dist new file mode 100644 index 00000000..b883a216 --- /dev/null +++ b/infection.json.dist @@ -0,0 +1,11 @@ +{ + "timeout": 10, + "source": { + "directories": [ + "src" + ] + }, + "logs": { + "text": "infection-log.txt" + } +} \ No newline at end of file From 5fcd1e3d72163f232f56492753587bc9c0c9a603 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 22 Mar 2018 11:57:11 +0900 Subject: [PATCH 191/296] Context: return null for missing properties, like we do for arrays. --- src/Liquid/Context.php | 5 +++++ tests/Liquid/ContextTest.php | 1 + 2 files changed, 6 insertions(+) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index bd063325..ae143e94 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -340,6 +340,11 @@ private function variable($key) continue; } + // Inexistent property is a null, PHP-speak + if (!property_exists($object, $nextPartName)) { + return null; + } + // then try a property (independent of accessibility) if (property_exists($object, $nextPartName)) { $object = $object->$nextPartName; diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index d0356475..12ddd9c2 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -192,6 +192,7 @@ public function testVariableIsObjectWithNoToLiquid() $this->context->set('test', new NoToLiquid()); $this->assertEquals(42, $this->context->get('test.answer')); $this->assertEquals(1, $this->context->get('test.count')); + $this->assertEquals(null, $this->context->get('test.invalid')); $this->assertEquals("forty two", $this->context->get('test')); $this->assertEquals("example", $this->context->get('test.name')); } From cc14ece8322cb25091b4b04b35c4d29aa9df83b7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 23 Mar 2018 11:26:13 +0900 Subject: [PATCH 192/296] Update CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a9f3b025..68fad285 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ * master +* 1.4.8 (2018-03-22) + + * Now we return null for missing properties, like we do for missing keys for arrays. + * 1.4.7 (2018-02-09) * Paginate tag shall now respect request parameters. From 49de9401b1d8360fe1ad87c9b92b51f671350575 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 23 Mar 2018 11:27:44 +0900 Subject: [PATCH 193/296] Update and rename CHANGELOG to CHANGELOG.md Pretty! --- CHANGELOG => CHANGELOG.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) rename CHANGELOG => CHANGELOG.md (87%) diff --git a/CHANGELOG b/CHANGELOG.md similarity index 87% rename from CHANGELOG rename to CHANGELOG.md index 68fad285..96d82707 100644 --- a/CHANGELOG +++ b/CHANGELOG.md @@ -1,35 +1,35 @@ -* master +# master -* 1.4.8 (2018-03-22) +## 1.4.8 (2018-03-22) * Now we return null for missing properties, like we do for missing keys for arrays. -* 1.4.7 (2018-02-09) +## 1.4.7 (2018-02-09) * Paginate tag shall now respect request parameters. * It is now possible to set a custom query param for the paginate tag. * Page number will now never go overboard. -* 1.4.6 (2018-02-07) +## 1.4.6 (2018-02-07) * TagPaginate shall not pollute the global scope, but work in own scope. * TagPaginate errors if no collection present instead of vague warning. -* 1.4.5 (2017-12-12) +## 1.4.5 (2017-12-12) * Capture tag shall save a variable in the global context. -* 1.4.4 (2017-11-03) +## 1.4.4 (2017-11-03) * TagUnless is an inverted TagIf: simplified implementation * Allow dashes in filenames -* 1.4.3 (2017-10-10) +## 1.4.3 (2017-10-10) * `escape` and `escape_once` filters now escape everything, but arrays * New standard filter for explicit string conversion -* 1.4.2 (2017-10-09) +## 1.4.2 (2017-10-09) * Better caching for non-extending templates * Simplified 'assign' tag to use rules for variables @@ -38,19 +38,19 @@ * Filterbank will not call instance methods statically * Callback-type filters -* 1.4.1 (2017-09-28) +## 1.4.1 (2017-09-28) * Unquoted template names in 'include' tag, as in Jekyll * Caching now works correctly with 'extends' tag -* 1.4.0 (2017-09-25) +## 1.4.0 (2017-09-25) * Dropped support for EOL'ed versions of PHP (< 5.6) * Arrays won't be silently cast to string as 'Array' anymore * Complex objects could now be passed between templates and to filters * Additional test coverage -* 1.3.1 (2017-09-23) +## 1.3.1 (2017-09-23) * Support for numeric and variable array indicies * Support loop break and continue @@ -62,47 +62,46 @@ * Lots of tests with the coverage upped to 97% * Small bug fixes and various enhancements -* 1.3.0 (2017-07-17) +## 1.3.0 (2017-07-17) * Support Traversable loops and filters * Fix date filter for format with colon * Various minor improvements and bugs fixes -* 1.2.1 (2016-12-12) +## 1.2.1 (2016-12-12) * Remove content injection from $_GET. * Add PHP 5.6, 7.0, 7.1 to Travis file. -* 1.2 (2016-06-11) +## 1.2 (2016-06-11) * Added "ESCAPE_BY_DEFAULT" setting for context-aware auto-escaping. * Made "Context" work with plain objects. * "escape" now uses "htmlentities". * Fixed "escape_now". -* 1.1 (2015-06-01) +## 1.1 (2015-06-01) * New tags: "paginate", "unless", "ifchanged" were added * Added support for "for in (range)" syntax * Added support for multiple conditions in if statements * Added support for hashes/objects in for loops -* 1.0 (2014-09-07) +## 1.0 (2014-09-07) * Add namespaces * Add composer support * Implement new standard filters * Add 'raw' tag -* 0.9.2 (2012-08-15) +## 0.9.2 (2012-08-15) * context->set allows now global vars * Allow Templatenames with Fileextension * Tag 'extends' supports now multiple inheritance * Clean up code, change all variables and methods to camelCase - -* 0.9.1 (2012-05-12) +## 0.9.1 (2012-05-12) * added the extends and block filter * Initial release From e76a88b5c731673ebaa21e0f8098e66eb42066c2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 23 Mar 2018 11:28:01 +0900 Subject: [PATCH 194/296] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96d82707..c2143dd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# master +## master ## 1.4.8 (2018-03-22) From 9541f09df7b6756aff872c57d024bd70466ce73c Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 11:23:33 +0900 Subject: [PATCH 195/296] FixturesTest: use human-readable dataset names --- tests/Liquid/FixturesTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Liquid/FixturesTest.php b/tests/Liquid/FixturesTest.php index d3d4ecda..2924be5d 100644 --- a/tests/Liquid/FixturesTest.php +++ b/tests/Liquid/FixturesTest.php @@ -38,6 +38,8 @@ public function testFixture($liquid, $data, $expected) public function fixtures() { - return array_map(null, glob(__DIR__.'/fixtures/*.liquid'), glob(__DIR__.'/fixtures/*.php'), glob(__DIR__.'/fixtures/*.html')); + foreach (array_map(null, glob(__DIR__.'/fixtures/*.liquid'), glob(__DIR__.'/fixtures/*.php'), glob(__DIR__.'/fixtures/*.html')) as $files) { + yield basename($files[0], '.liquid') => $files; + }; } } From db888601afd13ebbcfefeb9c8014cb77173d959d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 11:53:43 +0900 Subject: [PATCH 196/296] Strings now have a 'size' property, as in the upstream --- src/Liquid/Context.php | 12 +++++++++++- tests/Liquid/ContextTest.php | 9 +++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index bd063325..0346432e 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -272,7 +272,7 @@ private function variable($key) // since we still have a part to consider // and since we can't dig deeper into plain values // it can be thought as if it has a property with a null value - if (!is_object($object) && !is_array($object)) { + if (!is_object($object) && !is_array($object) && !is_string($object)) { return null; } @@ -293,6 +293,16 @@ private function variable($key) $nextPartName = array_shift($parts); + if (is_string($object)) { + if ($nextPartName == 'size') { + // if the last part of the context variable is .size we return the string length + return mb_strlen($object); + } + + // no other special properties for strings, yet + return null; + } + if (is_array($object)) { // if the last part of the context variable is .size we just return the count if ($nextPartName == 'size' && count($parts) == 0 && !array_key_exists('size', $object)) { diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index d0356475..e0857c23 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -263,6 +263,15 @@ public function testLengthQuery() $this->assertEquals(4, $this->context->get('numbers.size')); } + public function testStringLength() + { + $this->context->set('name', 'Foo Bar'); + $this->assertEquals(7, $this->context->get('name.size')); + + $this->context->set('name', 'テスト'); + $this->assertEquals(3, $this->context->get('name.size')); + } + public function testOverrideSize() { $this->context->set('hash', array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'size' => '5000')); From 61776049ae70cecdb3ae7997cd20800f87c6ab1f Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 11:56:12 +0900 Subject: [PATCH 197/296] Fixture with an example with no whitespace control --- tests/Liquid/fixtures/whitespace-control.html | 3 +++ tests/Liquid/fixtures/whitespace-control.liquid | 6 ++++++ tests/Liquid/fixtures/whitespace-control.php | 12 ++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 tests/Liquid/fixtures/whitespace-control.html create mode 100644 tests/Liquid/fixtures/whitespace-control.liquid create mode 100644 tests/Liquid/fixtures/whitespace-control.php diff --git a/tests/Liquid/fixtures/whitespace-control.html b/tests/Liquid/fixtures/whitespace-control.html new file mode 100644 index 00000000..4c3768df --- /dev/null +++ b/tests/Liquid/fixtures/whitespace-control.html @@ -0,0 +1,3 @@ + + + Wow, John G. Chalmers-Smith, you have a long name! diff --git a/tests/Liquid/fixtures/whitespace-control.liquid b/tests/Liquid/fixtures/whitespace-control.liquid new file mode 100644 index 00000000..b43a93e2 --- /dev/null +++ b/tests/Liquid/fixtures/whitespace-control.liquid @@ -0,0 +1,6 @@ +{% assign username = "John G. Chalmers-Smith" %} +{% if username and username.size > 10 %} + Wow, {{ username }}, you have a long name! +{% else %} + Hello there! +{% endif %} \ No newline at end of file diff --git a/tests/Liquid/fixtures/whitespace-control.php b/tests/Liquid/fixtures/whitespace-control.php new file mode 100644 index 00000000..a1ea6892 --- /dev/null +++ b/tests/Liquid/fixtures/whitespace-control.php @@ -0,0 +1,12 @@ + Date: Sat, 29 Dec 2018 12:11:36 +0900 Subject: [PATCH 198/296] TestCase shall use stock TAG_START/_END --- tests/Liquid/TestCase.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index b47dea9d..7b7c587b 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -34,8 +34,6 @@ protected function setUp() 'INCLUDE_ALLOW_EXT' => false, 'INCLUDE_SUFFIX' => 'liquid', 'INCLUDE_PREFIX' => '_', - 'TAG_START' => '{%', - 'TAG_END' => '%}', 'VARIABLE_START' => '{{', 'VARIABLE_END' => '}}', 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z0-9_.-]*', From 722478f2c930762e1e3338d1d50562e192f5943a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 12:12:24 +0900 Subject: [PATCH 199/296] Implement tags with whitespace control (swallowing all whitespace around them) --- src/Liquid/Liquid.php | 4 ++-- tests/Liquid/fixtures/whitespace-control.html | 3 +++ tests/Liquid/fixtures/whitespace-control.liquid | 11 ++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 250903e3..ad22bf8e 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -53,10 +53,10 @@ class Liquid 'INCLUDE_PREFIX' => '_', // Tag start. - 'TAG_START' => '{%', + 'TAG_START' => '(?:{%|\s*{%-)', // Tag end. - 'TAG_END' => '%}', + 'TAG_END' => '(?:%}|-%}\s*)', // Variable start. 'VARIABLE_START' => '{{', diff --git a/tests/Liquid/fixtures/whitespace-control.html b/tests/Liquid/fixtures/whitespace-control.html index 4c3768df..3e796b51 100644 --- a/tests/Liquid/fixtures/whitespace-control.html +++ b/tests/Liquid/fixtures/whitespace-control.html @@ -1,3 +1,6 @@ +-- Wow, John G. Chalmers-Smith, you have a long name! + +--Wow, John G. Chalmers-Smith, you have a long name!-- \ No newline at end of file diff --git a/tests/Liquid/fixtures/whitespace-control.liquid b/tests/Liquid/fixtures/whitespace-control.liquid index b43a93e2..f9a6f66f 100644 --- a/tests/Liquid/fixtures/whitespace-control.liquid +++ b/tests/Liquid/fixtures/whitespace-control.liquid @@ -1,6 +1,15 @@ +-- {% assign username = "John G. Chalmers-Smith" %} {% if username and username.size > 10 %} Wow, {{ username }}, you have a long name! {% else %} Hello there! -{% endif %} \ No newline at end of file +{% endif %} +-- +{%- assign username = "John G. Chalmers-Smith" -%} +{%- if username and username.size > 10 -%} + Wow, {{ username }}, you have a long name! +{%- else -%} + Hello there! +{%- endif -%} +-- \ No newline at end of file From 9c6b5afae1e4a8e08b115267f8213be565763dd6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 12:13:51 +0900 Subject: [PATCH 200/296] Add basic Regexp debugging to AbstractBlock --- src/Liquid/AbstractBlock.php | 2 +- src/Liquid/Regexp.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 68ef51e6..99ea33fc 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -80,7 +80,7 @@ public function parse(array &$tokens) $this->unknownTag($tagRegexp->matches[1], $tagRegexp->matches[2], $tokens); } } else { - throw new ParseException("Tag $token was not properly terminated"); // harry + throw new ParseException("Tag $token was not properly terminated (won't match $tagRegexp)"); } } elseif ($variableStartRegexp->match($token)) { $this->nodelist[] = $this->createVariable($token); diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index 9bab84e9..bfbdd2a5 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -121,4 +121,14 @@ public function split($string, $limit = null) { return preg_split($this->pattern, $string, $limit); } + + /** + * Returns the original pattern primarily for debugging purposes + * + * @return string + */ + public function __toString() + { + return $this->pattern; + } } From d4f0f16a588c7c9442216598273626b1049545d5 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 12:17:09 +0900 Subject: [PATCH 201/296] Add branch-alias to composer.json to simplify installation of a dev version --- composer.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/composer.json b/composer.json index 127eebaf..dd43021a 100644 --- a/composer.json +++ b/composer.json @@ -43,5 +43,13 @@ "psr-4": { "Liquid\\": "tests/Liquid" } + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "config": { + "sort-packages": true } } From 96e25676ebd7219d5207ef059161a0b20134fb75 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 12:19:22 +0900 Subject: [PATCH 202/296] Also test on PHP 7.3 on Travis CI --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 61c8240b..ceb5baea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 cache: directories: From 9896c0cb75a64596db8917e34c7cc894de6e20ea Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 13:49:03 +0900 Subject: [PATCH 203/296] Fix "Element 'testsuite': The attribute 'name' is required but missing." --- phpunit.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a24f730a..45819138 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ - + tests/ From 56f47fb1cc501c395b5fd4391640b33295d82b56 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 13:52:03 +0900 Subject: [PATCH 204/296] Use a more recent version of PHPUnit, related fixes --- composer.json | 6 +++--- tests/Liquid/ContextTest.php | 2 +- tests/Liquid/Tag/TagAssignTest.php | 2 +- tests/Liquid/TestCase.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 28efb453..4ac4ad5a 100644 --- a/composer.json +++ b/composer.json @@ -27,11 +27,11 @@ } ], "require": { - "php": ">= 7" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "<6", - "satooshi/php-coveralls": "^1.0", + "phpunit/phpunit": ">=6", + "php-coveralls/php-coveralls": "^1.0", "friendsofphp/php-cs-fixer": "^2.6", "infection/infection": "^0.8.1" }, diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 8c0c5cdb..703fe7e9 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -288,7 +288,7 @@ public function testHierchalData() public function testHierchalDataNoKey() { $this->context->set('hash', array('name' => 'tobi')); - $this->assertNotNull('tobi', $this->context->get('hash.no_key')); + $this->assertNull($this->context->get('hash.no_key')); } public function testAddFilter() diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index 79214317..2604325f 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -91,7 +91,7 @@ public function testNumbersAssign() $this->assertTemplateResult('42', '{% assign i = 42 %}{{ i }}'); $this->assertTemplateResult('3.14', '{% assign i = 3.14 %}{{ i }}'); $this->assertTemplateResult('-100', '{% assign i = -100 %}{{ i }}'); - $this->assertTemplateResult('-10', '{% assign i = -10.0 %}{{ i }}'); + $this->assertTemplateResult('-10.0', '{% assign i = -10.0 %}{{ i }}'); $this->assertTemplateResult('-10.5', '{% assign i = -10.5 %}{{ i }}'); } } diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 7b7c587b..a97862cf 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -11,7 +11,7 @@ namespace Liquid; -class TestCase extends \PHPUnit_Framework_TestCase +class TestCase extends \PHPUnit\Framework\TestCase { const TEMPLATES_DIR = 'templates'; From 71968619ea4c163247515db21c029ff26cbf4727 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Dec 2018 13:54:03 +0900 Subject: [PATCH 205/296] Update PULL_REQUEST_TEMPLATE.md We gonna be using git merge --squash in these cases, no need to bother. --- .github/PULL_REQUEST_TEMPLATE.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d5da21d1..499b1123 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,5 +3,3 @@ - [ ] I've seen the coverage report at `build/coverage/index.html` - [ ] Not a single line left uncovered by tests - [ ] Any coding standards issues were fixed with `vendor/bin/php-cs-fixer fix` -- [ ] Hotfix-type commits were squashed with `git rebase -i` or `git commit --amend` -- [ ] All my work wasn't smushed into one large commit without necessity From 2516e13a989ade2860f4696b5d9ebd72d8fb6ebb Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Wed, 2 Jan 2019 08:42:14 +0900 Subject: [PATCH 206/296] A workaround for php-cs-fixer on PHP 7.3 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index ceb5baea..6a3466f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,10 @@ php: - 7.2 - 7.3 +env: + global: + - PHP_CS_FIXER_IGNORE_ENV=1 + cache: directories: - $HOME/.composer/cache From 8f692d6fbb4be1fccc2b9dbac68ca2a5f8953f39 Mon Sep 17 00:00:00 2001 From: Patrick Romowicz Date: Mon, 28 Jan 2019 09:35:30 +0100 Subject: [PATCH 207/296] Don't add '__construct' as filter! (#112) * Don't add '__construct' as filter! If `addFilter()` was given an object than `__construct()' method would be added if exists and something like {{ var | __construct }} would be possible. Test / verify with ReflectionClass that __construct was not registered in the Filterbank as a possible filter. --- src/Liquid/Filterbank.php | 3 +++ tests/Liquid/FilterbankTest.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index c01bfdfe..53775c60 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -98,6 +98,9 @@ public function addFilter($filter, callable $callback = null) // Then register all public static and not methods as filters foreach (get_class_methods($filter) as $method) { + if (strtolower($method) === '__construct') { + continue; + } $this->methodMap[$method] = $className; } diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index c5a108ed..172688e3 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -30,6 +30,10 @@ class ClassFilter { private $variable = 'not set'; + public function __construct() + { + } + public static function static_test() { return "worked"; @@ -166,6 +170,30 @@ public function testObjectFilter() $var = new Variable('var | static_test'); $this->assertEquals('worked', $var->render($this->context)); + + $var = new Variable('var | __construct'); + $this->assertEquals('1000', $var->render($this->context)); + } + + public function testObjectFilterDontCallConstruct() + { + $this->context->set('var', 1000); + $this->context->addFilters(new \ClassFilter()); + + $filterbankReflectionClass = new \ReflectionClass(Context::class); + $methodMapProperty = $filterbankReflectionClass->getProperty('filterbank'); + $methodMapProperty->setAccessible(true); + $filterbank = $methodMapProperty->getValue($this->context); + + $filterbankReflectionClass = new \ReflectionClass(Filterbank::class); + $methodMapProperty = $filterbankReflectionClass->getProperty('methodMap'); + $methodMapProperty->setAccessible(true); + $methodMap = $methodMapProperty->getValue($filterbank); + + $this->assertArrayNotHasKey('__construct', $methodMap); + + $var = new Variable('var | __construct'); + $this->assertEquals('1000', $var->render($this->context)); } public function testCallbackFilter() From 107d4832111f488a05ad1f83adf79e40f6dfe4ae Mon Sep 17 00:00:00 2001 From: Tim Glabisch Date: Tue, 29 Jan 2019 10:13:07 +0100 Subject: [PATCH 208/296] add support for content ticks (#113) One problem we encountered is that an untrusted template could render for a very long time. For example someone could harm by running `for i in (1..[VERY_LARGE])` When Liquid starts to render, there is no way to stop it. This introduces something similar like the php tick function for Liquid. This would allow us track the rendering cost at runtime, abort it or do something else while the rendering started. Co-Authored-By: timglabisch --- src/Liquid/AbstractBlock.php | 2 ++ src/Liquid/Context.php | 27 ++++++++++++++++++++ src/Liquid/Template.php | 14 +++++++++++ tests/Liquid/TickTest.php | 49 ++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 tests/Liquid/TickTest.php diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 99ea33fc..d98ab290 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -135,6 +135,8 @@ protected function renderAll(array $list, Context $context) if (isset($context->registers['continue'])) { break; } + + $context->tick(); } return $result; diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index b96dbb1e..de0c48a0 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -44,6 +44,13 @@ class Context */ public $environments = array(); + /** + * Called "sometimes" while rendering. For example to abort the execution of a rendering. + * + * @var null|callable + */ + private $tickFunction = null; + /** * Constructor * @@ -59,6 +66,16 @@ public function __construct(array $assigns = array(), array $registers = array() $this->environments = array(array(), $_SERVER); } + /** + * Sets a tick function, this function is called sometimes while liquid is rendering a template. + * + * @param callable $tickFunction + */ + public function setTickFunction(callable $tickFunction) + { + $this->tickFunction = $tickFunction; + } + /** * Add a filter to the context * @@ -383,4 +400,14 @@ private function variable($key) return $object; } + + public function tick() + { + if ($this->tickFunction === null) { + return; + } + + $tickFunction = $this->tickFunction; + $tickFunction($this); + } } diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index e0036257..3d837822 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -42,6 +42,11 @@ class Template */ private $filters = array(); + /** + * @var callable|null Called "sometimes" while rendering. For example to abort the execution of a rendering. + */ + private $tickFunction = null; + /** * @var array Custom tags */ @@ -151,6 +156,11 @@ public function registerFilter($filter, callable $callback = null) } } + public function setTickFunction(callable $tickFunction) + { + $this->tickFunction = $tickFunction; + } + /** * Tokenizes the given source string * @@ -234,6 +244,10 @@ public function render(array $assigns = array(), $filters = null, array $registe { $context = new Context($assigns, $registers); + if ($this->tickFunction) { + $context->setTickFunction($this->tickFunction); + } + if (!is_null($filters)) { if (is_array($filters)) { $this->filters = array_merge($this->filters, $filters); diff --git a/tests/Liquid/TickTest.php b/tests/Liquid/TickTest.php new file mode 100644 index 00000000..0633a39c --- /dev/null +++ b/tests/Liquid/TickTest.php @@ -0,0 +1,49 @@ +parse($source); + $template->setTickFunction(function (Context $context) use (&$ticks) { + $ticks++; + }); + + $template->render(); + + $this->assertGreaterThanOrEqual($min, $ticks); + $this->assertLessThanOrEqual($max, $ticks); + } +} From ce53ad8318dae9b5acab8b849659a240a4b98dca Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 11 Feb 2019 16:53:25 +0900 Subject: [PATCH 209/296] Do not expose $_SERVER in templates by default (#116) This is important primarily because $_SERVER may contain sensitive data, like AWS access keys, which then can be accessed from user- provided templates. Fixes #114 --- src/Liquid/Context.php | 7 ++++++- src/Liquid/Liquid.php | 5 ++++- tests/Liquid/ContextTest.php | 24 ++++++++++++++++++++++++ tests/Liquid/TestCase.php | 1 + 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index de0c48a0..1912bc4f 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -62,8 +62,13 @@ public function __construct(array $assigns = array(), array $registers = array() $this->assigns = array($assigns); $this->registers = $registers; $this->filterbank = new Filterbank($this); + // first empty array serves as source for overrides, e.g. as in TagDecrement - $this->environments = array(array(), $_SERVER); + $this->environments = array(array(), array()); + + if (Liquid::get('EXPOSE_SERVER')) { + $this->environments[1] = $_SERVER; + } } /** diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index ad22bf8e..9407364a 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -77,7 +77,10 @@ class Liquid 'PAGINATION_REQUEST_KEY' => 'page', // The name of the context key used to denote the current page number - 'PAGINATION_CONTEXT_KEY' => 'page' + 'PAGINATION_CONTEXT_KEY' => 'page', + + // Whenever variables from $_SERVER should be directly available to templates + 'EXPOSE_SERVER' => false, ); /** diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 8c0c5cdb..2ce31510 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -392,4 +392,28 @@ public function testGetNoOverride() $context->set('test', 'test'); $this->assertEquals('test', $context->get('test')); } + + public function testServerNotExposedByDefault() + { + $_SERVER['AWS_SECRET_ACCESS_KEY'] = 'super_secret'; + + $context = new Context(); + $this->assertNull($context->get('AWS_SECRET_ACCESS_KEY')); + + $context->set('AWS_SECRET_ACCESS_KEY', 'test'); + $this->assertEquals('test', $context->get('AWS_SECRET_ACCESS_KEY')); + } + + public function testServerExposedWhenRequested() + { + Liquid::set('EXPOSE_SERVER', true); + + $_SERVER['AWS_SECRET_ACCESS_KEY'] = 'super_secret'; + + $context = new Context(); + $this->assertEquals('super_secret', $context->get('AWS_SECRET_ACCESS_KEY')); + + $context->set('AWS_SECRET_ACCESS_KEY', 'test'); + $this->assertEquals('super_secret', $context->get('AWS_SECRET_ACCESS_KEY'), '$_SERVER should take precedence in this case'); + } } diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 7b7c587b..57ba6595 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -37,6 +37,7 @@ protected function setUp() 'VARIABLE_START' => '{{', 'VARIABLE_END' => '}}', 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z0-9_.-]*', + 'EXPOSE_SERVER' => false, ); foreach ($defaultConfig as $configKey => $configValue) { From 0085fe21aa76a28169eb242a4745f935f7e3ff9e Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 03:20:14 -0500 Subject: [PATCH 210/296] Implement whitespace control for variables --- src/Liquid/AbstractBlock.php | 35 ++++++++++++++++++++++++++++++++--- src/Liquid/Liquid.php | 7 +++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index d98ab290..58feee9a 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -26,6 +26,11 @@ class AbstractBlock extends AbstractTag */ protected $nodelist = array(); + /** + * @var bool + */ + protected static $trimWhitespace = false; + /** * @return array */ @@ -45,7 +50,7 @@ public function getNodelist() public function parse(array &$tokens) { $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); - $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); + $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*)?' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); $this->nodelist = array(); @@ -56,6 +61,7 @@ public function parse(array &$tokens) $token = array_shift($tokens); if ($startRegexp->match($token)) { + $this->whitespaceHandler($token); if ($tagRegexp->match($token)) { // If we found the proper block delimitor just end parsing here and let the outer block proceed if ($tagRegexp->matches[1] == $this->blockDelimiter()) { @@ -83,8 +89,14 @@ public function parse(array &$tokens) throw new ParseException("Tag $token was not properly terminated (won't match $tagRegexp)"); } } elseif ($variableStartRegexp->match($token)) { + $this->whitespaceHandler($token); $this->nodelist[] = $this->createVariable($token); - } elseif ($token != '') { + } else { + if (self::$trimWhitespace) { + $token = ltrim($token); + } + + self::$trimWhitespace = false; $this->nodelist[] = $token; } } @@ -92,6 +104,23 @@ public function parse(array &$tokens) $this->assertMissingDelimitation(); } + /** + * Handle the whitespace. + * + * @param string $token + */ + protected function whitespaceHandler(&$token) + { + if (mb_strlen($token) > 2 && $token[2] === Liquid::get('WHITESPACE_CONTROL')) { + $previousToken = end($this->nodelist); + if (is_string($previousToken)) { + $this->nodelist[key($this->nodelist)] = rtrim($previousToken); + } + } + + self::$trimWhitespace = (mb_strlen($token) > 2 && $token[-3] === Liquid::get('WHITESPACE_CONTROL')); + } + /** * Render the block. * @@ -214,7 +243,7 @@ private function blockName() */ private function createVariable($token) { - $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '(.*)' . Liquid::get('VARIABLE_END') . '$/'); + $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/'); if ($variableRegexp->match($token)) { return new Variable($variableRegexp->matches[1]); } diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 9407364a..5a23ede1 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -52,11 +52,14 @@ class Liquid // Prefix for include files. 'INCLUDE_PREFIX' => '_', + // Whitespace control. + 'WHITESPACE_CONTROL' => '-', + // Tag start. - 'TAG_START' => '(?:{%|\s*{%-)', + 'TAG_START' => '{%', // Tag end. - 'TAG_END' => '(?:%}|-%}\s*)', + 'TAG_END' => '%}', // Variable start. 'VARIABLE_START' => '{{', From 26af642751d04923f1cb1f29e4cfbb47f8d45e8d Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 04:00:32 -0500 Subject: [PATCH 211/296] Remove negative string offset for PHP 7.0 sake --- src/Liquid/AbstractBlock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 58feee9a..bd852a4e 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -118,7 +118,7 @@ protected function whitespaceHandler(&$token) } } - self::$trimWhitespace = (mb_strlen($token) > 2 && $token[-3] === Liquid::get('WHITESPACE_CONTROL')); + self::$trimWhitespace = (mb_strlen($token) > 2 && substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); } /** From 60dbd0c85eb98ce1b164adc2bccbef8db3edce78 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 04:19:15 -0500 Subject: [PATCH 212/296] Added variable whitespace control test --- tests/Liquid/fixtures/whitespace-control.html | 5 +++-- tests/Liquid/fixtures/whitespace-control.liquid | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/Liquid/fixtures/whitespace-control.html b/tests/Liquid/fixtures/whitespace-control.html index 3e796b51..8629bdf7 100644 --- a/tests/Liquid/fixtures/whitespace-control.html +++ b/tests/Liquid/fixtures/whitespace-control.html @@ -1,6 +1,7 @@ -- - Wow, John G. Chalmers-Smith, you have a long name! + Wow, + John G. Chalmers-Smith, you have a long name! ---Wow, John G. Chalmers-Smith, you have a long name!-- \ No newline at end of file +--Wow,John G. Chalmers-Smith, you have a long name!-- \ No newline at end of file diff --git a/tests/Liquid/fixtures/whitespace-control.liquid b/tests/Liquid/fixtures/whitespace-control.liquid index f9a6f66f..f53ae1e2 100644 --- a/tests/Liquid/fixtures/whitespace-control.liquid +++ b/tests/Liquid/fixtures/whitespace-control.liquid @@ -1,14 +1,16 @@ -- {% assign username = "John G. Chalmers-Smith" %} {% if username and username.size > 10 %} - Wow, {{ username }}, you have a long name! + Wow, + {{ username }}, you have a long name! {% else %} Hello there! {% endif %} -- {%- assign username = "John G. Chalmers-Smith" -%} {%- if username and username.size > 10 -%} - Wow, {{ username }}, you have a long name! + Wow, + {{- username -}}, you have a long name! {%- else -%} Hello there! {%- endif -%} From 15d3e7ea4ee0361db5444b37ed58159bf4a28965 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 05:04:29 -0500 Subject: [PATCH 213/296] Use mb_substr inplace of array access --- src/Liquid/AbstractBlock.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index bd852a4e..66bf3307 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -111,14 +111,14 @@ public function parse(array &$tokens) */ protected function whitespaceHandler(&$token) { - if (mb_strlen($token) > 2 && $token[2] === Liquid::get('WHITESPACE_CONTROL')) { + if (mb_strlen($token) > 2 && mb_substr($token, 2, 1) === Liquid::get('WHITESPACE_CONTROL')) { $previousToken = end($this->nodelist); if (is_string($previousToken)) { $this->nodelist[key($this->nodelist)] = rtrim($previousToken); } } - self::$trimWhitespace = (mb_strlen($token) > 2 && substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); + self::$trimWhitespace = (mb_strlen($token) > 2 && mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); } /** From ff15a51302c5d5e55fdff98bd148a8dba04674de Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 05:09:39 -0500 Subject: [PATCH 214/296] Remove needless mb_strlen calls --- src/Liquid/AbstractBlock.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 66bf3307..30840d04 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -111,14 +111,14 @@ public function parse(array &$tokens) */ protected function whitespaceHandler(&$token) { - if (mb_strlen($token) > 2 && mb_substr($token, 2, 1) === Liquid::get('WHITESPACE_CONTROL')) { + if (mb_substr($token, 2, 1) === Liquid::get('WHITESPACE_CONTROL')) { $previousToken = end($this->nodelist); if (is_string($previousToken)) { $this->nodelist[key($this->nodelist)] = rtrim($previousToken); } } - self::$trimWhitespace = (mb_strlen($token) > 2 && mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); + self::$trimWhitespace = (mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); } /** From cd847b35da5ef8e3abafd855eb90fa684b2d05b2 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 06:06:23 -0500 Subject: [PATCH 215/296] Fix greediness of tag and variable contents --- src/Liquid/AbstractBlock.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 30840d04..d9833749 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -50,7 +50,7 @@ public function getNodelist() public function parse(array &$tokens) { $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); - $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*)?' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/'); + $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); $this->nodelist = array(); @@ -243,7 +243,7 @@ private function blockName() */ private function createVariable($token) { - $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/'); + $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/'); if ($variableRegexp->match($token)) { return new Variable($variableRegexp->matches[1]); } From 36640c80f789a1a8ea0acdaf2438792a936ebc56 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 13:22:04 -0500 Subject: [PATCH 216/296] Adding test for whitespace ctrl/if tag edge case --- tests/Liquid/Tag/TagIfTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index a49bb29c..59d9ccfc 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -158,6 +158,12 @@ public function testNotNil() $this->assertTemplateResult($expected, $text, array('var' => 1)); } + public function testNotNilWhitespaceControlEdgeCase() + { + $this->assertTemplateResult("true", "{% if 1 -%}true{% endif %}"); + $this->assertTemplateResult("true", "{% if 1 -%} true{% endif %}"); + } + public function testIfFromVariable() { $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => false)); From 2c22f62abfa446ad45755ded6c61667394855c69 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 8 Mar 2019 13:26:14 -0500 Subject: [PATCH 217/296] Fix for whitespace ctrl/if tag edge case --- src/Liquid/AbstractBlock.php | 2 +- tests/Liquid/Tag/TagIfTest.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index d98ab290..84798097 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -45,7 +45,7 @@ public function getNodelist() public function parse(array &$tokens) { $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); - $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); + $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*?)' . Liquid::get('TAG_END') . '$/'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); $this->nodelist = array(); diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index a49bb29c..59d9ccfc 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -158,6 +158,12 @@ public function testNotNil() $this->assertTemplateResult($expected, $text, array('var' => 1)); } + public function testNotNilWhitespaceControlEdgeCase() + { + $this->assertTemplateResult("true", "{% if 1 -%}true{% endif %}"); + $this->assertTemplateResult("true", "{% if 1 -%} true{% endif %}"); + } + public function testIfFromVariable() { $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => false)); From f7890dfe3a92fc2f4f989fe7f37dbd65101a70b6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 22 Mar 2019 03:02:52 +0900 Subject: [PATCH 218/296] AbstractBlock: document changes, add an extra test --- src/Liquid/AbstractBlock.php | 19 +++++++++++++++---- tests/Liquid/AbstractBlockTest.php | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index d9833749..2b90f18a 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -22,11 +22,13 @@ class AbstractBlock extends AbstractTag const TAG_PREFIX = '\Liquid\Tag\Tag'; /** - * @var AbstractTag[] + * @var AbstractTag[]|Variable[]|string[] */ protected $nodelist = array(); /** + * Whenever next token should be ltrim'med. + * * @var bool */ protected static $trimWhitespace = false; @@ -92,6 +94,7 @@ public function parse(array &$tokens) $this->whitespaceHandler($token); $this->nodelist[] = $this->createVariable($token); } else { + // This is neither a tag or a variable, proceed with an ltrim if (self::$trimWhitespace) { $token = ltrim($token); } @@ -109,16 +112,24 @@ public function parse(array &$tokens) * * @param string $token */ - protected function whitespaceHandler(&$token) + protected function whitespaceHandler($token) { + /* + * This assumes that TAG_START is always '{%', and a whitespace control indicator + * is exactly one character long, on a third position. + */ if (mb_substr($token, 2, 1) === Liquid::get('WHITESPACE_CONTROL')) { $previousToken = end($this->nodelist); - if (is_string($previousToken)) { + if (is_string($previousToken)) { // this can also be a tag or a variable $this->nodelist[key($this->nodelist)] = rtrim($previousToken); } } - self::$trimWhitespace = (mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL')); + /* + * This assumes that TAG_END is always '%}', and a whitespace control indicator + * is exactly one character long, on a third position from the end. + */ + self::$trimWhitespace = mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL'); } /** diff --git a/tests/Liquid/AbstractBlockTest.php b/tests/Liquid/AbstractBlockTest.php index bd12a358..066c9449 100644 --- a/tests/Liquid/AbstractBlockTest.php +++ b/tests/Liquid/AbstractBlockTest.php @@ -22,4 +22,18 @@ public function testUnterminatedBlockError() { $this->assertTemplateResult('', '{% block }'); } + + public function testWhitespaceHandler() + { + $this->assertTemplateResult('foo', '{% if true %}foo{% endif %}'); + $this->assertTemplateResult(' foo ', '{% if true %} foo {% endif %}'); + $this->assertTemplateResult(' foo ', ' {% if true %} foo {% endif %} '); + $this->assertTemplateResult('foo ', '{% if true -%} foo {% endif %}'); + $this->assertTemplateResult('foo', '{% if true -%} foo {%- endif %}'); + $this->assertTemplateResult('foo', ' {%- if true -%} foo {%- endif %}'); + $this->assertTemplateResult('foo', ' {%- if true -%} foo {%- endif -%} '); + $this->assertTemplateResult('foo', ' {%- if true -%} foo {%- endif -%} {%- if false -%} bar {%- endif -%} '); + $this->assertTemplateResult('foobar', ' {%- if true -%} foo {%- endif -%} {%- if true -%} bar {%- endif -%} '); + $this->assertTemplateResult('-> foo', '{% if true %}-> {% endif %} {%- if true -%} foo {%- endif -%}'); + } } From e8cbf7b47a803bc394f053a04781847510b5a896 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 30 May 2019 05:14:42 +0900 Subject: [PATCH 219/296] PHPUnit 8 requires more advanced changes --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4ac4ad5a..c9341ffb 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": ">=6", + "phpunit/phpunit": "^6.5 || ^7.4", "php-coveralls/php-coveralls": "^1.0", "friendsofphp/php-cs-fixer": "^2.6", "infection/infection": "^0.8.1" From 72ca54397c17080afc26a3b2813d394bc3dd97e0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 30 May 2019 05:21:35 +0900 Subject: [PATCH 220/296] Do not generate a coverage report by default to speed up tests --- .travis.yml | 2 +- phpunit.xml.dist | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a3466f8..6f48e80d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ install: - composer install --prefer-dist script: - - vendor/bin/phpunit --verbose || travis_terminate 1 + - vendor/bin/phpunit --verbose --coverage-clover=build/logs/clover.xml || travis_terminate 1 - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=4 - mkdir -p build/cache && vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 45819138..b918c794 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,10 +11,4 @@ src/ - - - - - - From 034d499f249be21c24bf43a2a435d16fb3dfb5e0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 31 May 2019 11:50:59 +0900 Subject: [PATCH 221/296] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c61d6d1e..ce5fde4b 100644 --- a/README.md +++ b/README.md @@ -115,9 +115,9 @@ Adding filters has never been easier. ## Requirements - * PHP 5.6+ + * PHP 7.0+ -Package versions below 1.4 could be used with PHP 5.3/5.4/5.5. +Some earlier versions could be used with PHP 5.3/5.4/5.5/5.6, though they're not supported anymore. ## Issues From aa26c4802e8a4ae87395e25326a7faa36b2546c0 Mon Sep 17 00:00:00 2001 From: Patrick Romowicz Date: Fri, 14 Jun 2019 10:55:57 +0200 Subject: [PATCH 222/296] Add wrapper for call_user_func_array() with try/catch block. Catch TypeError and rethrow LiquidException because Filter is called with too few arguments. A LiquidException is more meaningful as TypeError and developer can handle this like liquid template error. --- src/Liquid/Filterbank.php | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 53775c60..4fb51aea 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -134,7 +134,7 @@ public function invoke($name, $value, array $args = array()) // If we have a callback if (is_callable($class)) { - return call_user_func_array($class, $args); + return $this->callUserFuncArrayInTryCatch($class, $args); } // If we have a registered object for the class, use that instead @@ -144,10 +144,29 @@ public function invoke($name, $value, array $args = array()) // If we're calling a function if ($class === false) { - return call_user_func_array($name, $args); + return $this->callUserFuncArrayInTryCatch($name, $args); } // Call a class or an instance method - return call_user_func_array(array($class, $name), $args); + return $this->callUserFuncArrayInTryCatch(array($class, $name), $args); + } + + /** + * This is a wrapper for call_user_func_array() with try/catch + * to cast TypeError in LiquidException. + * + * @param callback $function + * @param array $param_arr + * + * @throws \Liquid\LiquidException + * @return mixed + */ + private function callUserFuncArrayInTryCatch($function, array $param_arr) + { + try { + return call_user_func_array($function, $param_arr); + } catch (\TypeError $typeError) { + throw new LiquidException($typeError->getMessage(), 0, $typeError); + } } } From eed1cea146a85c29a34876ef3eaeffafe49b45c5 Mon Sep 17 00:00:00 2001 From: Patrick Romowicz Date: Mon, 17 Jun 2019 08:02:54 +0200 Subject: [PATCH 223/296] Add test case to confirm that LiquidException is throw. When filter are called with too few arguments. --- tests/Liquid/FilterbankTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 172688e3..6b0243f2 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -104,6 +104,17 @@ public function testAddFilterNoFunctionOrClass() $this->filterBank->addFilter('no_such_function_or_class'); } + + /** + * @expectedException \Liquid\LiquidException + */ + public function testTypeErrorExceptionAndCallDateFilterWithoutArguments() + { + $var = new Variable('var | date'); + $this->context->set('var', 1000); + $this->assertEquals('worked', $var->render($this->context)); + } + public function testInvokeNoFilter() { $value = 'value'; From a19537035dbb18d68e72dae9b0134b27fbf0901c Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 17 Jun 2019 04:27:48 +0900 Subject: [PATCH 224/296] Take care of TypeError from within the Context. This reverts commit aa26c4802e8a4ae87395e25326a7faa36b2546c0. --- src/Liquid/Context.php | 6 +++++- src/Liquid/Filterbank.php | 25 +++---------------------- tests/Liquid/FilterbankTest.php | 12 +++++++----- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 1912bc4f..13132d69 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -102,7 +102,11 @@ public function addFilters($filter, callable $callback = null) */ public function invoke($name, $value, array $args = array()) { - return $this->filterbank->invoke($name, $value, $args); + try { + return $this->filterbank->invoke($name, $value, $args); + } catch (\TypeError $typeError) { + throw new LiquidException($typeError->getMessage(), 0, $typeError); + } } /** diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 4fb51aea..53775c60 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -134,7 +134,7 @@ public function invoke($name, $value, array $args = array()) // If we have a callback if (is_callable($class)) { - return $this->callUserFuncArrayInTryCatch($class, $args); + return call_user_func_array($class, $args); } // If we have a registered object for the class, use that instead @@ -144,29 +144,10 @@ public function invoke($name, $value, array $args = array()) // If we're calling a function if ($class === false) { - return $this->callUserFuncArrayInTryCatch($name, $args); + return call_user_func_array($name, $args); } // Call a class or an instance method - return $this->callUserFuncArrayInTryCatch(array($class, $name), $args); - } - - /** - * This is a wrapper for call_user_func_array() with try/catch - * to cast TypeError in LiquidException. - * - * @param callback $function - * @param array $param_arr - * - * @throws \Liquid\LiquidException - * @return mixed - */ - private function callUserFuncArrayInTryCatch($function, array $param_arr) - { - try { - return call_user_func_array($function, $param_arr); - } catch (\TypeError $typeError) { - throw new LiquidException($typeError->getMessage(), 0, $typeError); - } + return call_user_func_array(array($class, $name), $args); } } diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 6b0243f2..04976aae 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -104,15 +104,17 @@ public function testAddFilterNoFunctionOrClass() $this->filterBank->addFilter('no_such_function_or_class'); } - - /** - * @expectedException \Liquid\LiquidException - */ public function testTypeErrorExceptionAndCallDateFilterWithoutArguments() { + if (\PHP_VERSION_ID < 70100) { + $this->markTestSkipped('TypeError is not thrown in PHP 7.0'); + } + $var = new Variable('var | date'); $this->context->set('var', 1000); - $this->assertEquals('worked', $var->render($this->context)); + + $this->expectException(\Liquid\LiquidException::class); + $var->render($this->context); } public function testInvokeNoFilter() From 1d283af418fbd8093bd3a8e9316d108e3d78384c Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 11 Jul 2019 05:51:24 +0900 Subject: [PATCH 225/296] Allow later versions of php-coveralls --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c9341ffb..0ee05273 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "require-dev": { "phpunit/phpunit": "^6.5 || ^7.4", - "php-coveralls/php-coveralls": "^1.0", + "php-coveralls/php-coveralls": ">=1.0", "friendsofphp/php-cs-fixer": "^2.6", "infection/infection": "^0.8.1" }, From 6630f6b876e8e08b9104d5841ee307a9a8fcb361 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 11 Jul 2019 05:53:17 +0900 Subject: [PATCH 226/296] Normalize composer.json --- composer.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 0ee05273..26c4132b 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,6 @@ { "name": "liquid/liquid", + "type": "library", "description": "Liquid template engine for PHP", "keywords": [ "liquid", @@ -7,7 +8,6 @@ ], "homepage": "https://github.com/kalimatas/php-liquid", "license": "MIT", - "type": "library", "authors": [ { "name": "Guz Alexander", @@ -30,10 +30,18 @@ "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^6.5 || ^7.4", - "php-coveralls/php-coveralls": ">=1.0", "friendsofphp/php-cs-fixer": "^2.6", - "infection/infection": "^0.8.1" + "infection/infection": "^0.8.1", + "php-coveralls/php-coveralls": ">=1.0", + "phpunit/phpunit": "^6.5 || ^7.4" + }, + "config": { + "sort-packages": true + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } }, "autoload": { "psr-4": { @@ -44,13 +52,5 @@ "psr-4": { "Liquid\\": "tests/Liquid" } - }, - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "config": { - "sort-packages": true } } From 179fd312d49d6fcc49ba35468f939d3ae01c7af8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 11 Jul 2019 06:23:03 +0900 Subject: [PATCH 227/296] Work nicely with virtual properties Fixes #130 --- src/Liquid/Context.php | 6 ++++++ tests/Liquid/ContextTest.php | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 1912bc4f..2f088172 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -372,6 +372,12 @@ private function variable($key) continue; } + // if a magic accessor method present... + if (method_exists($object, '__get')) { + $object = $object->$nextPartName; + continue; + } + // Inexistent property is a null, PHP-speak if (!property_exists($object, $nextPartName)) { return null; diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 765f848e..87398a1e 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -106,6 +106,17 @@ public function get($prop) } } +class GetSetMagic +{ + public function __get($prop) + { + if ($prop == 'prime') { + return 2; + } + } +} + + class HiFilter { public function hi($value) @@ -240,6 +251,13 @@ public function testGetSetObject() $this->assertNull($this->context->get('object.invalid')); } + public function testGetSetMagic() + { + $this->context->set('object', new GetSetMagic()); + $this->assertEquals(2, $this->context->get('object.prime')); + $this->assertNull($this->context->get('object.invalid')); + } + public function testFinalVariableCanBeObject() { $this->context->set('test', (object) array('value' => (object) array())); From a9f0d8fac88d20aff06d4d586d903164ea2968a5 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 11 Jul 2019 06:23:55 +0900 Subject: [PATCH 228/296] Improve test coverage --- tests/Liquid/ContextTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 87398a1e..10945621 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -19,6 +19,14 @@ public function toLiquid() } } +class ToLiquidNotObject +{ + public function toLiquid() + { + return STDIN; + } +} + class CentsDrop extends Drop { public function amount() @@ -297,6 +305,12 @@ public function testOverrideSize() $this->assertEquals(5000, $this->context->get('hash.size')); } + public function testDeepValueNotObject() + { + $this->context->set('example', array('foo' => new ToLiquidNotObject())); + $this->assertNull($this->context->get('example.foo.bar')); + } + public function testHierchalData() { $this->context->set('hash', array('name' => 'tobi')); From 6c0657a388fc3cfaaf1df11e4c5c1dc2d8c2bad6 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Tue, 30 Jul 2019 19:17:11 -0400 Subject: [PATCH 229/296] Add support for Countables --- src/Liquid/Context.php | 7 +++++++ tests/Liquid/ContextTest.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 31eaa708..07cdf390 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -350,6 +350,13 @@ private function variable($key) return null; } + if ($object instanceof \Countable) { + // if the last part of the context variable is .size we just return the count + if ($nextPartName == 'size' && count($parts) == 0) { + return count($object); + } + } + if ($object instanceof Drop) { // if the object is a drop, make sure it supports the given method if (!$object->hasKey($nextPartName)) { diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 10945621..19456abc 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -83,6 +83,14 @@ public function toLiquid() } } +class CountableObject implements \Countable +{ + public function count() + { + return 2; + } +} + class ToArrayObject { public $property; @@ -299,6 +307,12 @@ public function testStringLength() $this->assertEquals(3, $this->context->get('name.size')); } + public function testCountableLength() + { + $this->context->set('countable', new CountableObject()); + $this->assertEquals(2, $this->context->get('countable.size')); + } + public function testOverrideSize() { $this->context->set('hash', array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'size' => '5000')); From 87ec8686ed222ab0177283458a0b6306e1e98e5e Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 13 Sep 2019 19:11:57 -0400 Subject: [PATCH 230/296] Add support for array first/last dot notation --- src/Liquid/Context.php | 10 ++++++++++ src/Liquid/Liquid.php | 14 ++++++++++++++ tests/Liquid/ContextTest.php | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 07cdf390..5ed1b2aa 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -330,6 +330,16 @@ private function variable($key) } if (is_array($object)) { + // if the last part of the context variable is .first we return the first array element + if ($nextPartName == 'first' && count($parts) == 0 && !Liquid::arrayIsAssoc($object)) { + return StandardFilters::first($object); + } + + // if the last part of the context variable is .first we return the last array element + if ($nextPartName == 'last' && count($parts) == 0 && !Liquid::arrayIsAssoc($object)) { + return StandardFilters::last($object); + } + // if the last part of the context variable is .size we just return the count if ($nextPartName == 'size' && count($parts) == 0 && !array_key_exists('size', $object)) { return count($object); diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 5a23ede1..4e2b4ba0 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -151,4 +151,18 @@ public static function arrayFlatten($array) } return $return; } + + /** + * Check if an array is associative or not. + * + * @param array $array + * + * @return bool + */ + public static function arrayIsAssoc($array) + { + $keys = array_keys($array); + + return array_keys($keys) !== $keys; + } } diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 19456abc..f5749b7b 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -319,6 +319,18 @@ public function testOverrideSize() $this->assertEquals(5000, $this->context->get('hash.size')); } + public function testArrayFirst() + { + $this->context->set('array', array(11, 'jack', 43, 74, 5, 'tom')); + $this->assertEquals(11, $this->context->get('array.first')); + } + + public function testArrayLast() + { + $this->context->set('array', array(11, 'jack', 43, 74, 5, 'tom')); + $this->assertEquals('tom', $this->context->get('array.last')); + } + public function testDeepValueNotObject() { $this->context->set('example', array('foo' => new ToLiquidNotObject())); From c5b725342e547ac3bf49180c7c01461eb35dc8e9 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 13 Sep 2019 21:33:57 -0400 Subject: [PATCH 231/296] Update src/Liquid/Context.php Co-Authored-By: Alexey Kopytko --- src/Liquid/Context.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 5ed1b2aa..6ecab95a 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -335,7 +335,7 @@ private function variable($key) return StandardFilters::first($object); } - // if the last part of the context variable is .first we return the last array element + // if the last part of the context variable is .last we return the last array element if ($nextPartName == 'last' && count($parts) == 0 && !Liquid::arrayIsAssoc($object)) { return StandardFilters::last($object); } From dea55bcab1aab091f0cc9726256b1d78fa975353 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 13 Sep 2019 21:34:09 -0400 Subject: [PATCH 232/296] Update src/Liquid/Liquid.php Co-Authored-By: Alexey Kopytko --- src/Liquid/Liquid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 4e2b4ba0..67d81279 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -159,7 +159,7 @@ public static function arrayFlatten($array) * * @return bool */ - public static function arrayIsAssoc($array) + public static function arrayIsAssoc(array $array) { $keys = array_keys($array); From c358ce76b648599df58316dfcc105b54286072e7 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 13 Sep 2019 22:45:22 -0400 Subject: [PATCH 233/296] Update usage to work for both associative arrays --- src/Liquid/Context.php | 4 ++-- src/Liquid/Liquid.php | 14 -------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 6ecab95a..79aec8b1 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -331,12 +331,12 @@ private function variable($key) if (is_array($object)) { // if the last part of the context variable is .first we return the first array element - if ($nextPartName == 'first' && count($parts) == 0 && !Liquid::arrayIsAssoc($object)) { + if ($nextPartName == 'first' && count($parts) == 0 && !array_key_exists('first', $object)) { return StandardFilters::first($object); } // if the last part of the context variable is .last we return the last array element - if ($nextPartName == 'last' && count($parts) == 0 && !Liquid::arrayIsAssoc($object)) { + if ($nextPartName == 'last' && count($parts) == 0 && !array_key_exists('last', $object)) { return StandardFilters::last($object); } diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 67d81279..5a23ede1 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -151,18 +151,4 @@ public static function arrayFlatten($array) } return $return; } - - /** - * Check if an array is associative or not. - * - * @param array $array - * - * @return bool - */ - public static function arrayIsAssoc(array $array) - { - $keys = array_keys($array); - - return array_keys($keys) !== $keys; - } } From 9534e908e668b2ca438472aa94416e89fac62bcf Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Fri, 13 Sep 2019 23:01:30 -0400 Subject: [PATCH 234/296] Adding additional tests for overrides --- tests/Liquid/ContextTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index f5749b7b..f56813ba 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -325,12 +325,24 @@ public function testArrayFirst() $this->assertEquals(11, $this->context->get('array.first')); } + public function testOverrideFirst() + { + $this->context->set('array', array(11, 'jack', 43, 'first' => 74, 5, 'tom')); + $this->assertEquals(74, $this->context->get('array.first')); + } + public function testArrayLast() { $this->context->set('array', array(11, 'jack', 43, 74, 5, 'tom')); $this->assertEquals('tom', $this->context->get('array.last')); } + public function testOverrideLast() + { + $this->context->set('array', array(11, 'jack', 43, 'last' => 74, 5, 'tom')); + $this->assertEquals(74, $this->context->get('array.last')); + } + public function testDeepValueNotObject() { $this->context->set('example', array('foo' => new ToLiquidNotObject())); From 4e939ce9fa7072c05bb261c1cdfadc81850fe5bc Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 30 Jan 2020 17:01:22 +0900 Subject: [PATCH 235/296] Update .travis.yml --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6f48e80d..5b79a10a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4 env: global: @@ -18,11 +19,12 @@ cache: install: - composer install --prefer-dist + - mkdir -p build/cache script: - vendor/bin/phpunit --verbose --coverage-clover=build/logs/clover.xml || travis_terminate 1 - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=4 - - mkdir -p build/cache && vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix + - vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix after_success: - travis_retry php vendor/bin/coveralls From 9c9149918d6b5e50ed9c5215c66ea99efae6c462 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 30 Jan 2020 17:01:32 +0900 Subject: [PATCH 236/296] Update .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5b79a10a..df0af9f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ -sudo: false - language: php php: - 7.0 From 2bf1685147e8e5e2ced8e72808666cd6ecd22434 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Wed, 18 Mar 2020 05:11:14 -0400 Subject: [PATCH 237/296] Fix bug preventing keyword args from being used with filters (#137) * Fix bug with keyword args for filters * Update src/Liquid/Variable.php Co-authored-by: Alexey Kopytko --- src/Liquid/Liquid.php | 4 ++-- src/Liquid/Variable.php | 39 +++++++++++++++++++++++++++++++++-- tests/Liquid/OutputTest.php | 36 ++++++++++++++++++++++++++++++++ tests/Liquid/VariableTest.php | 4 ++++ 4 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 5a23ede1..d6fb0af0 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -70,7 +70,7 @@ class Liquid // Variable name. 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z_0-9.-]*', - 'QUOTED_STRING' => '"[^"]*"|\'[^\']*\'', + 'QUOTED_STRING' => '(?:"[^"]*"|\'[^\']*\')', 'QUOTED_STRING_FILTER_ARGUMENT' => '"[^"]*"|\'[^\']*\'', // Automatically escape any variables unless told otherwise by a "raw" filter @@ -105,7 +105,7 @@ public static function get($key) // This case is needed for compound settings switch ($key) { case 'QUOTED_FRAGMENT': - return self::$config['QUOTED_STRING'] . '|(?:[^\s,\|\'"]|' . self::$config['QUOTED_STRING'] . ')+'; + return '(?:' . self::get('QUOTED_STRING') . '|(?:[^\s,\|\'"]|' . self::get('QUOTED_STRING') . ')+)'; case 'TAG_ATTRIBUTES': return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; case 'TOKENIZATION_REGEXP': diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index 2ac3d89b..868738a6 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -60,7 +60,7 @@ public function __construct($markup) $filterName = $matches[0]; $filterArgsRegex->matchAll($filter); $matches = Liquid::arrayFlatten($filterArgsRegex->matches[1]); - $this->filters[] = array($filterName, $matches); + $this->filters[] = $this->parseFilterExpressions($filterName, $matches); } } } @@ -91,6 +91,32 @@ public function __construct($markup) } } + /** + * @param string $filterName + * @param array $unparsedArgs + * @return array + */ + private static function parseFilterExpressions($filterName, array $unparsedArgs) + { + $filterArgs = array(); + $keywordArgs = array(); + + $justTagAttributes = new Regexp('/\A' . trim(Liquid::get('TAG_ATTRIBUTES'), '/') . '\z/'); + + foreach ($unparsedArgs as $a) { + if ($justTagAttributes->match($a)) { + $keywordArgs[$justTagAttributes->matches[1]] = $justTagAttributes->matches[2]; + } else { + $filterArgs[] = $a; + } + } + + if (count($keywordArgs)) { + $filterArgs[] = $keywordArgs; + } + + return array($filterName, $filterArgs); + } /** * Gets the variable name @@ -126,9 +152,18 @@ public function render(Context $context) list($filtername, $filterArgKeys) = $filter; $filterArgValues = array(); + $keywordArgValues = array(); foreach ($filterArgKeys as $arg_key) { - $filterArgValues[] = $context->get($arg_key); + if (is_array($arg_key)) { + foreach ($arg_key as $keywordArgName => $keywordArgKey) { + $keywordArgValues[$keywordArgName] = $context->get($keywordArgKey); + } + + $filterArgValues[] = $keywordArgValues; + } else { + $filterArgValues[] = $context->get($arg_key); + } } $output = $context->invoke($filtername, $output, $filterArgValues); diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index feda47bf..5acfbf31 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -42,6 +42,26 @@ public function link_to($name, $url, $protocol) { return "" . $name . ""; } + + public function str_replace($input, $data) + { + foreach ($data as $k => $v) { + $input = str_replace("[" . $k . "]", $v, $input); + } + return $input; + } + + public function img_url($input, $size, $opts = null) + { + $output = "image_" . $size; + if (isset($opts['crop'])) { + $output .= "_cropped_" . $opts['crop']; + } + if (isset($opts['scale'])) { + $output .= "@" . $opts['scale'] . 'x'; + } + return $output . ".png"; + } } class OutputTest extends TestCase @@ -132,6 +152,22 @@ public function testVariablePipingWithVariableArgs() $this->assertTemplateResult($expected, $text, $this->assigns); } + public function testVariablePipingWithKeywordArg() + { + $text = " {{ 'Welcome, [name]' | str_replace: name: 'Santa' }} "; + $expected = " Welcome, Santa "; + + $this->assertTemplateResult($expected, $text, $this->assigns); + } + + public function testVariablePipingWithArgsAndKeywordArgs() + { + $text = " {{ car.gm | img_url: '450x450', crop: 'center', scale: 2 }} "; + $expected = " image_450x450_cropped_center@2x.png "; + + $this->assertTemplateResult($expected, $text, $this->assigns); + } + public function testMultiplePipings() { $text = " {{ best_cars | cite_funny | paragraph }} "; diff --git a/tests/Liquid/VariableTest.php b/tests/Liquid/VariableTest.php index 669bee52..697f3996 100644 --- a/tests/Liquid/VariableTest.php +++ b/tests/Liquid/VariableTest.php @@ -60,6 +60,10 @@ public function testFilters() $var = new Variable(" hello | things: \"%Y, okay?\", 'the other one'"); $this->assertEquals('hello', $var->getName()); $this->assertEquals(array(array('things', array('"%Y, okay?"', "'the other one'"))), $var->getFilters()); + + $var = new Variable(" product.featured_image | img_url: '450x450', crop: 'center', scale: 2 "); + $this->assertEquals("product.featured_image", $var->getName()); + $this->assertEquals(array(array('img_url', array("'450x450'", array("crop" => "'center'", "scale" => "2")))), $var->getFilters()); } public function testFiltersWithoutWhitespace() From 6c87f31e6da4c10d34f8fc4ac39497121edbd642 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 18 Sep 2020 16:25:12 +0900 Subject: [PATCH 238/296] Fix issues with Generator types (#139) * Fix issues with Generator types * Add testing workflow * Work around generators --- .github/workflows/tests.yaml | 45 +++++++++++++++++++++++++++ src/Liquid/Decision.php | 14 ++++++--- src/Liquid/Tag/TagFor.php | 4 +++ tests/Liquid/FixturesTest.php | 5 +++ tests/Liquid/fixtures/iterable.html | 12 +++++++ tests/Liquid/fixtures/iterable.liquid | 15 +++++++++ tests/Liquid/fixtures/iterable.php | 18 +++++++++++ 7 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/tests.yaml create mode 100644 tests/Liquid/fixtures/iterable.html create mode 100644 tests/Liquid/fixtures/iterable.liquid create mode 100644 tests/Liquid/fixtures/iterable.php diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 00000000..9cd60388 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,45 @@ +name: Tests + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: ['7.0', '7.1', '7.2.', '7.3', '7.4'] + dependencies: [''] + include: + - { php-version: '7.0', dependencies: '--prefer-lowest' } + + name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} + + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: + coverage: pcov + tools: composer:v2 + + - name: Install dependencies + run: | + composer update --no-interaction ${{ matrix.dependencies }} + + - name: Run tests + run: | + php vendor/bin/phpunit + + - name: Run mutation testing + run: | + php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=$(nproc) + diff --git a/src/Liquid/Decision.php b/src/Liquid/Decision.php index 8713d5fd..c2a9477d 100644 --- a/src/Liquid/Decision.php +++ b/src/Liquid/Decision.php @@ -45,12 +45,16 @@ private function stringValue($value) // Objects should have a __toString method to get a value to compare to if (is_object($value)) { if (method_exists($value, '__toString')) { - $value = (string) $value; - } else { - // toLiquid is handled in Context::variable - $class = get_class($value); - throw new RenderException("Value of type $class has no `toLiquid` nor `__toString` methods"); + return (string) $value; } + + if ($value instanceof \Generator) { + return (string) $value->valid(); + } + + // toLiquid is handled in Context::variable + $class = get_class($value); + throw new RenderException("Value of type $class has no `toLiquid` nor `__toString` methods"); } // Arrays simply return true diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index b3912805..e1468877 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -115,6 +115,10 @@ private function renderCollection(Context $context) { $collection = $context->get($this->collectionName); + if ($collection instanceof \Generator && !$collection->valid()) { + return ''; + } + if ($collection instanceof \Traversable) { $collection = iterator_to_array($collection); } diff --git a/tests/Liquid/FixturesTest.php b/tests/Liquid/FixturesTest.php index 2924be5d..07e112b1 100644 --- a/tests/Liquid/FixturesTest.php +++ b/tests/Liquid/FixturesTest.php @@ -33,6 +33,11 @@ public function testFixture($liquid, $data, $expected) $template->parse(file_get_contents($liquid)); $result = $template->render(include $data); + if (getenv('GOLDEN') !== false) { + file_put_contents($expected, $result); + $this->markTestIncomplete("Saved golden fixture"); + } + $this->assertEquals(file_get_contents($expected), $result); } diff --git a/tests/Liquid/fixtures/iterable.html b/tests/Liquid/fixtures/iterable.html new file mode 100644 index 00000000..c257035c --- /dev/null +++ b/tests/Liquid/fixtures/iterable.html @@ -0,0 +1,12 @@ + + + - a + + - b + + - c + + + + + diff --git a/tests/Liquid/fixtures/iterable.liquid b/tests/Liquid/fixtures/iterable.liquid new file mode 100644 index 00000000..d0926853 --- /dev/null +++ b/tests/Liquid/fixtures/iterable.liquid @@ -0,0 +1,15 @@ +{% if generator %} + {% for number in generator %} + - {{ number }} + {% endfor %} +{% endif %} + +{% if generator %} + {% for number in generator %} + - {{ number }} + {% endfor %} +{% endif %} + +{% for number in generator %} + - {{ number }} +{% endfor %} \ No newline at end of file diff --git a/tests/Liquid/fixtures/iterable.php b/tests/Liquid/fixtures/iterable.php new file mode 100644 index 00000000..6265127a --- /dev/null +++ b/tests/Liquid/fixtures/iterable.php @@ -0,0 +1,18 @@ + call_user_func(function () { + yield 'a'; + yield 'b'; + yield 'c'; + }), +); From 9d28b5255413336a69af45cff7d6b7a2a6ce8f5b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 21 Sep 2020 13:42:13 +0900 Subject: [PATCH 239/296] Add GitHub workflows, update and composer.json to use newer PHPUnit (#140) --- .github/workflows/cs.yaml | 37 ++++++++++++++++++++++++ .github/workflows/tests.yaml | 8 +++--- .php_cs.dist | 11 +++++++ .travis.yml | 5 +--- composer.json | 9 +++--- src/Liquid/Template.php | 2 +- tests/Liquid/AbstractBlockTest.php | 5 ++-- tests/Liquid/Cache/ApcTest.php | 2 +- tests/Liquid/Cache/FileTest.php | 22 +++++++------- tests/Liquid/Cache/LocalTest.php | 2 +- tests/Liquid/ContextTest.php | 12 ++++---- tests/Liquid/CustomFiltersTest.php | 2 +- tests/Liquid/CustomTagTest.php | 16 ++++++++--- tests/Liquid/DropTest.php | 5 ++-- tests/Liquid/EscapeByDefaultTest.php | 6 ++-- tests/Liquid/FilterbankTest.php | 10 ++++--- tests/Liquid/LocalFileSystemTest.php | 35 +++++++++++++--------- tests/Liquid/OutputTest.php | 7 +++-- tests/Liquid/ParsingQuirksTest.php | 2 +- tests/Liquid/RegexpTest.php | 2 +- tests/Liquid/StandardFiltersTest.php | 23 ++++++++------- tests/Liquid/Tag/TagAssignTest.php | 3 +- tests/Liquid/Tag/TagBlockTest.php | 3 +- tests/Liquid/Tag/TagCaptureTest.php | 3 +- tests/Liquid/Tag/TagCaseTest.php | 12 +++++--- tests/Liquid/Tag/TagCycleTest.php | 3 +- tests/Liquid/Tag/TagDecrementTest.php | 3 +- tests/Liquid/Tag/TagExtendsTest.php | 20 +++++++------ tests/Liquid/Tag/TagForTest.php | 3 +- tests/Liquid/Tag/TagIfTest.php | 24 ++++++++++------ tests/Liquid/Tag/TagIncludeTest.php | 19 ++++++------ tests/Liquid/Tag/TagIncrementTest.php | 3 +- tests/Liquid/Tag/TagPaginateTest.php | 12 ++++---- tests/Liquid/Tag/TagTablerowTest.php | 6 ++-- tests/Liquid/TemplateTest.php | 40 ++++++++++++++------------ tests/Liquid/TestCase.php | 2 +- tests/Liquid/VirtualFileSystemTest.php | 10 ++++--- 37 files changed, 246 insertions(+), 143 deletions(-) create mode 100644 .github/workflows/cs.yaml diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml new file mode 100644 index 00000000..e20c7bfe --- /dev/null +++ b/.github/workflows/cs.yaml @@ -0,0 +1,37 @@ +name: Code Style + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: ['7.3'] + + name: PHP ${{ matrix.php-version }} + + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: + coverage: pcov + tools: composer:v1 + + - name: Install dependencies + run: | + composer update --no-interaction ${{ matrix.dependencies }} + + - name: Check code style + run: | + php vendor/bin/php-cs-fixer --using-cache=no --diff --dry-run --stop-on-violation --verbose fix + diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9cd60388..3663d214 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -13,10 +13,10 @@ jobs: strategy: matrix: - php-version: ['7.0', '7.1', '7.2.', '7.3', '7.4'] + php-version: ['7.3', '7.4'] dependencies: [''] include: - - { php-version: '7.0', dependencies: '--prefer-lowest' } + - { php-version: '7.3', dependencies: '--prefer-lowest' } name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} @@ -29,7 +29,7 @@ jobs: php-version: ${{ matrix.php-version }} extensions: coverage: pcov - tools: composer:v2 + tools: composer:v1 - name: Install dependencies run: | @@ -41,5 +41,5 @@ jobs: - name: Run mutation testing run: | - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=$(nproc) + php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --show-mutations --threads=$(nproc) diff --git a/.php_cs.dist b/.php_cs.dist index 6f600034..713a8be5 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -22,6 +22,17 @@ return PhpCsFixer\Config::create() 'semicolon_after_instruction' => true, 'whitespace_after_comma_in_array' => true, 'header_comment' => ['header' => $header], + 'php_unit_construct' => true, + 'php_unit_dedicate_assert' => true, + 'php_unit_dedicate_assert_internal_type' => true, + 'php_unit_expectation' => true, + 'php_unit_mock_short_will_return' => true, + 'php_unit_mock' => true, + 'php_unit_namespaced' => true, + 'php_unit_no_expectation_annotation' => true, + 'php_unit_ordered_covers' => true, + 'php_unit_set_up_tear_down_visibility' => true, + 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], ]) ->setIndent("\t") ->setFinder( diff --git a/.travis.yml b/.travis.yml index df0af9f5..12959f85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,5 @@ language: php php: - - 7.0 - - 7.1 - - 7.2 - 7.3 - 7.4 @@ -21,7 +18,7 @@ install: script: - vendor/bin/phpunit --verbose --coverage-clover=build/logs/clover.xml || travis_terminate 1 - - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --log-verbosity=2 --threads=4 + - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --threads=4 - vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix after_success: diff --git a/composer.json b/composer.json index 26c4132b..99519ce0 100644 --- a/composer.json +++ b/composer.json @@ -27,13 +27,14 @@ } ], "require": { - "php": ">=7.0" + "php": "^7.3" }, "require-dev": { + "ergebnis/composer-normalize": "^2.8", "friendsofphp/php-cs-fixer": "^2.6", - "infection/infection": "^0.8.1", - "php-coveralls/php-coveralls": ">=1.0", - "phpunit/phpunit": "^6.5 || ^7.4" + "infection/infection": "^0.17.5", + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^9.2.6" }, "config": { "sort-packages": true diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 3d837822..bae79ec3 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -128,7 +128,7 @@ public function getRoot() * @param string $name * @param string $class */ - public function registerTag($name, $class) + public static function registerTag($name, $class) { self::$tags[$name] = $class; } diff --git a/tests/Liquid/AbstractBlockTest.php b/tests/Liquid/AbstractBlockTest.php index 066c9449..fef3ac66 100644 --- a/tests/Liquid/AbstractBlockTest.php +++ b/tests/Liquid/AbstractBlockTest.php @@ -15,11 +15,10 @@ class AbstractBlockTest extends TestCase { - /** - * @expectedException \Liquid\Exception\ParseException - */ public function testUnterminatedBlockError() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% block }'); } diff --git a/tests/Liquid/Cache/ApcTest.php b/tests/Liquid/Cache/ApcTest.php index 3e2b1be0..2b66116d 100644 --- a/tests/Liquid/Cache/ApcTest.php +++ b/tests/Liquid/Cache/ApcTest.php @@ -18,7 +18,7 @@ class ApcTest extends TestCase /** @var \Liquid\Cache\Apc */ protected $cache; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index 2fbe92d7..9080976d 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -19,7 +19,7 @@ class FileTest extends TestCase protected $cache; protected $cacheDir; - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -31,7 +31,7 @@ protected function setUp() )); } - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); @@ -39,19 +39,17 @@ protected function tearDown() array_map('unlink', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); } - /** - * @expectedException \Liquid\Exception\FilesystemException - */ public function testConstructInvalidOptions() { + $this->expectException(\Liquid\Exception\FilesystemException::class); + new File(); } - /** - * @expectedException \Liquid\Exception\FilesystemException - */ public function testConstructNoSuchDirOrNotWritable() { + $this->expectException(\Liquid\Exception\FilesystemException::class); + new File(array('cache_dir' => '/no/such/dir/liquid/cache')); } @@ -81,7 +79,9 @@ public function testFlushAll() touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test'); touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test_two'); - $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); + $files = join(', ', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); + + $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*'), "Found more than two files: $files"); $this->cache->flush(); @@ -93,7 +93,9 @@ public function testFlushExpired() touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test'); touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test_two', time() - 1000000); - $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); + $files = join(', ', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); + + $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*'), "Found more than two files: $files"); $this->cache->flush(true); diff --git a/tests/Liquid/Cache/LocalTest.php b/tests/Liquid/Cache/LocalTest.php index fd996c47..a72cbf90 100644 --- a/tests/Liquid/Cache/LocalTest.php +++ b/tests/Liquid/Cache/LocalTest.php @@ -18,7 +18,7 @@ class LocalTest extends TestCase /** @var \Liquid\Cache\Local */ protected $cache; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index f56813ba..67e0b11e 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -162,7 +162,7 @@ class ContextTest extends TestCase /** @var Context */ public $context; - public function setup() + protected function setUp(): void { parent::setUp(); @@ -176,18 +176,20 @@ public function testScoping() } /** - * @expectedException \Liquid\LiquidException */ public function testNoScopeToPop() { + $this->expectException(\Liquid\LiquidException::class); + $this->context->pop(); } /** - * @expectedException \Liquid\LiquidException */ public function testGetArray() { + $this->expectException(\Liquid\LiquidException::class); + $this->context->get(array()); } @@ -219,7 +221,7 @@ public function testVariableIsObjectWithNoToLiquid() $this->context->set('test', new NoToLiquid()); $this->assertEquals(42, $this->context->get('test.answer')); $this->assertEquals(1, $this->context->get('test.count')); - $this->assertEquals(null, $this->context->get('test.invalid')); + $this->assertNull($this->context->get('test.invalid')); $this->assertEquals("forty two", $this->context->get('test')); $this->assertEquals("example", $this->context->get('test.name')); } @@ -410,7 +412,7 @@ public function testAddItemInInnerScope() $this->context->set('test', 'test'); $this->assertEquals('test', $this->context->get('test')); $this->context->pop(); - $this->assertEquals(null, $this->context->get('test')); + $this->assertNull($this->context->get('test')); } public function testMerge() diff --git a/tests/Liquid/CustomFiltersTest.php b/tests/Liquid/CustomFiltersTest.php index 8378d216..597bdf4c 100644 --- a/tests/Liquid/CustomFiltersTest.php +++ b/tests/Liquid/CustomFiltersTest.php @@ -20,7 +20,7 @@ class CustomFiltersTest extends TestCase */ public $context; - protected function setup() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Liquid/CustomTagTest.php b/tests/Liquid/CustomTagTest.php index 90d150b7..ceb255a2 100644 --- a/tests/Liquid/CustomTagTest.php +++ b/tests/Liquid/CustomTagTest.php @@ -19,20 +19,28 @@ class TagFoo extends TagComment class CustomTagTest extends TestCase { - /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage Unknown tag foo - */ public function testUnknownTag() { $template = new Template(); + + if (array_key_exists('foo', $template->getTags())) { + $this->markTestIncomplete("Test tag already registered. Are you missing @depends?"); + } + + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('Unknown tag foo'); + $template->parse('[ba{% foo %} Comment {% endfoo %}r]'); } + /** + * @depends testUnknownTag + */ public function testCustomTag() { $template = new Template(); $template->registerTag('foo', TagFoo::class); + $template->parse('[ba{% foo %} Comment {% endfoo %}r]'); $this->assertEquals('[bar]', $template->render()); } diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index 3022c362..56997553 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -76,11 +76,12 @@ public function hasKey($name) class DropTest extends TestCase { /** - * @expectedException \Exception - * @expectedExceptionMessage worked */ public function testProductDrop() { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('worked'); + $template = new Template(); $template->parse(' {{ product.top_sales }} '); $template->render(array('product' => new ProductDrop)); diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index 0b443c35..54eed9bf 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -33,7 +33,7 @@ class EscapeByDefaultTest extends TestCase protected $assigns = array(); - protected function setup() + protected function setUp(): void { parent::setUp(); @@ -113,13 +113,13 @@ public function testToStringEscapeDefault() /** System default value for the escape flag */ private static $escapeDefault; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { // save system default value for the escape flag before all tests self::$escapeDefault = Liquid::get('ESCAPE_BY_DEFAULT'); } - public function tearDown() + protected function tearDown(): void { // reset to the default after each test Liquid::set('ESCAPE_BY_DEFAULT', self::$escapeDefault); diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 04976aae..97865830 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -73,7 +73,7 @@ class FilterbankTest extends TestCase /** @var Context */ private $context; - protected function setup() + protected function setUp(): void { parent::setUp(); @@ -81,7 +81,7 @@ protected function setup() $this->filterBank = new FilterBank($this->context); } - protected function tearDown() + protected function tearDown(): void { // have to destroy these else PHP goes nuts unset($this->context); @@ -89,18 +89,20 @@ protected function tearDown() } /** - * @expectedException \Liquid\Exception\WrongArgumentException */ public function testAddFilterNotObjectAndString() { + $this->expectException(\Liquid\Exception\WrongArgumentException::class); + $this->filterBank->addFilter(array()); } /** - * @expectedException \Liquid\Exception\WrongArgumentException */ public function testAddFilterNoFunctionOrClass() { + $this->expectException(\Liquid\Exception\WrongArgumentException::class); + $this->filterBank->addFilter('no_such_function_or_class'); } diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index d38d8721..4e38e7d7 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -17,7 +17,7 @@ class LocalFileSystemTest extends TestCase { protected $root; - protected function setUp() + protected function setUp(): void { $this->root = __DIR__ . DIRECTORY_SEPARATOR . self::TEMPLATES_DIR . DIRECTORY_SEPARATOR; // reset to defaults @@ -25,28 +25,31 @@ protected function setUp() } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalTemplateNameEmpty() { + $this->expectException(\Liquid\LiquidException::class); + $fileSystem = new Local(''); $fileSystem->fullPath(''); } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalRootPath() { + $this->expectException(\Liquid\LiquidException::class); + $fileSystem = new Local('invalid/not/found'); $fileSystem->fullPath(''); } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalTemplateNameIncludeExtension() { + $this->expectException(\Liquid\LiquidException::class); + Liquid::set('INCLUDE_ALLOW_EXT', false); $fileSystem = new Local(''); @@ -54,10 +57,11 @@ public function testIllegalTemplateNameIncludeExtension() } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalTemplateNameNotIncludeExtension() { + $this->expectException(\Liquid\LiquidException::class); + Liquid::set('INCLUDE_ALLOW_EXT', true); $fileSystem = new Local(''); @@ -65,29 +69,32 @@ public function testIllegalTemplateNameNotIncludeExtension() } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalTemplatePathNoRoot() { + $this->expectException(\Liquid\LiquidException::class); + $fileSystem = new Local(''); $fileSystem->fullPath('mypartial'); } /** - * @expectedException \Liquid\LiquidException */ public function testIllegalTemplatePathNoFileExists() { + $this->expectException(\Liquid\LiquidException::class); + $fileSystem = new Local(dirname(__DIR__)); $fileSystem->fullPath('no_such_file_exists'); } /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage not under */ public function testIllegalTemplatePathNotUnderTemplateRoot() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('not under'); + Liquid::set('INCLUDE_ALLOW_EXT', true); $fileSystem = new Local(dirname($this->root)); // find any fail under deeper under the root, so all other checks would pass @@ -116,11 +123,12 @@ public function testValidPathWithCustomExtension() } /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage File not found */ public function testReadIllegalTemplatePathNoFileExists() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('File not found'); + $fileSystem = new Local(dirname(__DIR__)); $fileSystem->readTemplateFile('no_such_file_exists'); } @@ -149,11 +157,12 @@ public function testParseTemplateFile() } /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage Could not load a template */ public function testParseTemplateFileError() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('Could not load a template'); + $template = new Template(); $template->parseFile('mypartial'); } diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 5acfbf31..4eac2e91 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -68,7 +68,7 @@ class OutputTest extends TestCase { protected $assigns = array(); - protected function setup() + protected function setUp(): void { parent::setUp(); @@ -185,11 +185,12 @@ public function testLinkTo() } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage was not properly terminated */ public function testVariableWithANewLine() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('was not properly terminated'); + $text = "{{ aaa\n }}"; $this->assertTemplateResult('', $text, $this->assigns); } diff --git a/tests/Liquid/ParsingQuirksTest.php b/tests/Liquid/ParsingQuirksTest.php index 2249eb2b..ce0db792 100644 --- a/tests/Liquid/ParsingQuirksTest.php +++ b/tests/Liquid/ParsingQuirksTest.php @@ -22,6 +22,6 @@ public function testErrorWithCss() $nodelist = $template->getRoot()->getNodelist(); $this->assertEquals($text, $template->render()); - $this->assertInternalType('string', $nodelist[0]); + $this->assertIsString($nodelist[0]); } } diff --git a/tests/Liquid/RegexpTest.php b/tests/Liquid/RegexpTest.php index 40ed8af5..b7e6f458 100644 --- a/tests/Liquid/RegexpTest.php +++ b/tests/Liquid/RegexpTest.php @@ -16,7 +16,7 @@ class RegexpTest extends TestCase /** @var Regexp */ protected $regexp; - protected function setup() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 48a2ed29..4bcbf48f 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -62,7 +62,7 @@ class StandardFiltersTest extends TestCase */ public $context; - protected function setup() + protected function setUp(): void { parent::setUp(); @@ -85,11 +85,12 @@ public function testSize() } /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage cannot be estimated */ public function testSizeObject() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('cannot be estimated'); + StandardFilters::size((object) array()); } @@ -527,26 +528,26 @@ public function testSort() ), ); - foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::sort($item[0]), '', 0, 10, true); + foreach ($data as $key => $item) { + $this->assertEquals(array_values($item[1]), array_values(StandardFilters::sort($item[0])), "Sort failed for case #{$key}"); } // Sort by inner key $original = array( array('a' => 20, 'b' => 10), array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 5), + array('a' => 40, 'b' => 6), array('a' => 30, 'b' => 48), ); $expected = array( array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 5), + array('a' => 40, 'b' => 6), array('a' => 20, 'b' => 10), array('a' => 30, 'b' => 48), ); - $this->assertEquals($expected, StandardFilters::sort($original, 'b'), '', 0, 10, true); - $this->assertEquals($expected, StandardFilters::sort(new \ArrayIterator($original), 'b'), '', 0, 10, true); + $this->assertEquals($expected, array_values(StandardFilters::sort($original, 'b'))); + $this->assertEquals($expected, array_values(StandardFilters::sort(new \ArrayIterator($original), 'b'))); } /* @@ -578,7 +579,7 @@ public function testDefault() // check that our workaround for 'default' works as it should $this->assertTemplateResult('something', '{{ nothing | default: "something" }}'); } - + public function testUnique() { $data = array( @@ -601,7 +602,7 @@ public function testUnique() ); foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::uniq($item[0]), '', 0, 10, true); + $this->assertEquals($item[1], array_values(StandardFilters::uniq($item[0]))); } } diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index 2604325f..74c83b63 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -23,10 +23,11 @@ class TagAssignTest extends TestCase /** * Tests the normal behavior of throwing an exception when the assignment is incorrect * - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidAssign() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->parse('{% assign test %}'); diff --git a/tests/Liquid/Tag/TagBlockTest.php b/tests/Liquid/Tag/TagBlockTest.php index 25c0e3c5..70aba906 100644 --- a/tests/Liquid/Tag/TagBlockTest.php +++ b/tests/Liquid/Tag/TagBlockTest.php @@ -16,10 +16,11 @@ class TagBlockTest extends TestCase { /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxError() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% block %}'); } diff --git a/tests/Liquid/Tag/TagCaptureTest.php b/tests/Liquid/Tag/TagCaptureTest.php index 250790a4..9752265b 100644 --- a/tests/Liquid/Tag/TagCaptureTest.php +++ b/tests/Liquid/Tag/TagCaptureTest.php @@ -17,10 +17,11 @@ class TagCaptureTest extends TestCase { /** - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->parse("{% capture %} hello"); } diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index 3dabd2a9..8e99ec9b 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -59,34 +59,38 @@ public function testCaseWithElse() } /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorCase() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% case %}{% when 5 %}{% endcase %}'); } /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorWhen() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% case condition %}{% when %}{% endcase %}'); } /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorEnd() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% case condition %}{% end %}'); } /** - * @expectedException \Liquid\Exception\RenderException */ public function testObject() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->assertTemplateResult('', '{% case variable %}{% when 5 %}{% endcase %}', array('variable' => (object) array())); } diff --git a/tests/Liquid/Tag/TagCycleTest.php b/tests/Liquid/Tag/TagCycleTest.php index a4160f94..857a59a6 100644 --- a/tests/Liquid/Tag/TagCycleTest.php +++ b/tests/Liquid/Tag/TagCycleTest.php @@ -17,10 +17,11 @@ class TagCycleTest extends TestCase { /** - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->parse("{% cycle %}"); } diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index 62bf950f..6d2def4b 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -16,10 +16,11 @@ class TagDecrementTest extends TestCase { /** - * @expectedException \Liquid\LiquidException */ public function testSyntaxError() { + $this->expectException(\Liquid\LiquidException::class); + $this->assertTemplateResult('', '{% decrement %}'); } diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index 08ffb785..fe1252a9 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -23,7 +23,7 @@ class TagExtendsTest extends TestCase { private $fs; - protected function setUp() + protected function setUp(): void { $this->fs = TestFileSystem::fromArray(array( 'base' => "{% block content %}{% endblock %}{% block footer %}{% endblock %}", @@ -31,7 +31,7 @@ protected function setUp() )); } - protected function tearDown() + protected function tearDown(): void { // PHP goes nuts unless we unset it unset($this->fs); @@ -162,39 +162,43 @@ public function testCacheDiscardedIfFileChanges() } /** - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxNoTemplateName() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->parse("{% extends %}"); } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage Error in tag */ public function testInvalidSyntaxNotQuotedTemplateName() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('Error in tag'); + $template = new Template(); $template->parse("{% extends base %}"); } /** - * @expectedException \Liquid\Exception\MissingFilesystemException - * @expectedExceptionMessage No file system */ public function testMissingFilesystem() { + $this->expectException(\Liquid\Exception\MissingFilesystemException::class); + $this->expectExceptionMessage('No file system'); + $template = new Template(); $template->parse("{% extends 'base' %}"); } /** - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntaxEmptyTemplateName() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% extends '' %}"); diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 435aa48a..d1e14047 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -17,10 +17,11 @@ class TagForTest extends TestCase { /** - * @expectedException \Liquid\Exception\ParseException */ public function testForInvalidSyntax() { + $this->expectException(\Liquid\Exception\ParseException::class); + $template = new Template(); $template->parse("{% for elem %}{% endfor %}"); } diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 59d9ccfc..9a8ef329 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -223,53 +223,59 @@ public function testContains() } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage if tag was never closed */ public function testSyntaxErrorNotClosed() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('if tag was never closed'); + $this->assertTemplateResult('', '{% if jerry == 1 %}'); } /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorEnd() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% if jerry == 1 %}{% end %}'); } /** - * @expectedException \Liquid\Exception\RenderException */ public function testInvalidOperator() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->assertTemplateResult('', '{% if foo === y %}true{% else %}false{% endif %}', array('foo' => true, 'y' => true)); } /** - * @expectedException \Liquid\Exception\RenderException */ public function testIncomparable() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', array('foo' => (object) array())); } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage does not expect else tag */ public function testSyntaxErrorElse() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('does not expect else tag'); + $this->assertTemplateResult('', '{% if foo == 1 %}{% endif %}{% else %}'); } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage Unknown tag */ public function testSyntaxErrorUnknown() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('Unknown tag'); + $this->assertTemplateResult('', '{% unknown-tag %}'); } } diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 72645708..12a1506e 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -21,7 +21,7 @@ class TagIncludeTest extends TestCase { private $fs; - protected function setUp() + protected function setUp(): void { $this->fs = TestFileSystem::fromArray(array( 'a' => "{% include 'b' %}", @@ -33,29 +33,31 @@ protected function setUp() )); } - protected function tearDown() + protected function tearDown(): void { // PHP goes nuts unless we unset it unset($this->fs); } /** - * @expectedException \Liquid\Exception\ParseException - * @expectedExceptionMessage Error in tag */ public function testInvalidSyntaxNoTemplateName() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('Error in tag'); + $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% include %}"); } /** - * @expectedException \Liquid\Exception\MissingFilesystemException - * @expectedExceptionMessage No file system */ public function testMissingFilesystem() { + $this->expectException(\Liquid\Exception\MissingFilesystemException::class); + $this->expectExceptionMessage('No file system'); + $template = new Template(); $template->parse("{% include 'hello' %}"); } @@ -143,11 +145,12 @@ public function testIncludePassPlainValue() } /** - * @expectedException \Liquid\Exception\RenderException - * @expectedExceptionMessage Use index operator */ public function testIncludePassArrayWithoutIndex() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->expectExceptionMessage('Use index operator'); + $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other }}]", diff --git a/tests/Liquid/Tag/TagIncrementTest.php b/tests/Liquid/Tag/TagIncrementTest.php index 7208f170..4a49bdea 100644 --- a/tests/Liquid/Tag/TagIncrementTest.php +++ b/tests/Liquid/Tag/TagIncrementTest.php @@ -16,10 +16,11 @@ class TagIncrementTest extends TestCase { /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxError() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% increment %}'); } diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 1ce8b046..30c03113 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -20,14 +20,14 @@ class TagPaginateTest extends TestCase private static $requestKeyDefault; private static $contextKeyDefault; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { // save system default value for the escape flag before all tests self::$requestKeyDefault = Liquid::get('PAGINATION_REQUEST_KEY'); self::$contextKeyDefault = Liquid::get('PAGINATION_CONTEXT_KEY'); } - public function tearDown() + protected function tearDown(): void { // reset to the defaults after each test Liquid::set('PAGINATION_REQUEST_KEY', self::$requestKeyDefault); @@ -56,19 +56,21 @@ public function testNextPage() } /** - * @expectedException \Liquid\Exception\ParseException */ public function testSyntaxErrorCase() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{% paginate products %}{% endpaginate %}'); } /** - * @expectedException \Liquid\Exception\RenderException - * @expectedExceptionMessage Missing collection */ public function testNoCollection() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->expectExceptionMessage('Missing collection'); + $this->assertTemplateResult('', '{% paginate products by 1 %}{% for product in products %}{{ product.id }}{% endfor %}{% endpaginate %}'); } diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index 2b46a140..c5e2b18b 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -47,18 +47,20 @@ public function testTablerow() } /** - * @expectedException \Liquid\Exception\ParseException */ public function testInvalidSyntax() { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); } /** - * @expectedException \Liquid\Exception\RenderException */ public function testNotArray() { + $this->expectException(\Liquid\Exception\RenderException::class); + $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); } } diff --git a/tests/Liquid/TemplateTest.php b/tests/Liquid/TemplateTest.php index 88923d31..2f372cac 100644 --- a/tests/Liquid/TemplateTest.php +++ b/tests/Liquid/TemplateTest.php @@ -18,14 +18,14 @@ class TemplateTest extends TestCase /** @var string full path to cache dir */ protected $cacheDir; - protected function setUp() + protected function setUp(): void { parent::setUp(); $this->cacheDir = __DIR__ . DIRECTORY_SEPARATOR . self::CACHE_DIR; } - protected function tearDown() + protected function tearDown(): void { parent::tearDown(); @@ -34,19 +34,21 @@ protected function tearDown() } /** - * @expectedException \Liquid\LiquidException */ public function testSetCacheInvalidKey() { + $this->expectException(\Liquid\LiquidException::class); + $template = new Template(); $template->setCache(array()); } /** - * @expectedException \Liquid\LiquidException */ public function testSetCacheInvalidClass() { + $this->expectException(\Liquid\LiquidException::class); + $template = new Template(); $template->setCache(array('cache' => 'no_such_class')); } @@ -105,9 +107,9 @@ public function testVariableBeginning() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(2, count($nodelist)); + $this->assertCount(2, $nodelist); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[0]); - $this->assertInternalType('string', $nodelist[1]); + $this->assertIsString($nodelist[1]); } public function testVariableEnd() @@ -117,8 +119,8 @@ public function testVariableEnd() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(2, count($nodelist)); - $this->assertInternalType('string', $nodelist[0]); + $this->assertCount(2, $nodelist); + $this->assertIsString($nodelist[0]); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); } @@ -129,10 +131,10 @@ public function testVariableMiddle() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(3, count($nodelist)); - $this->assertInternalType('string', $nodelist[0]); + $this->assertCount(3, $nodelist); + $this->assertIsString($nodelist[0]); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); - $this->assertInternalType('string', $nodelist[2]); + $this->assertIsString($nodelist[2]); } public function testVariableManyEmbeddedFragments() @@ -142,14 +144,14 @@ public function testVariableManyEmbeddedFragments() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(7, count($nodelist)); - $this->assertInternalType('string', $nodelist[0]); + $this->assertCount(7, $nodelist); + $this->assertIsString($nodelist[0]); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[1]); - $this->assertInternalType('string', $nodelist[2]); + $this->assertIsString($nodelist[2]); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[3]); - $this->assertInternalType('string', $nodelist[4]); + $this->assertIsString($nodelist[4]); $this->assertInstanceOf(\Liquid\Variable::class, $nodelist[5]); - $this->assertInternalType('string', $nodelist[6]); + $this->assertIsString($nodelist[6]); } public function testWithBlock() @@ -159,9 +161,9 @@ public function testWithBlock() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(3, count($nodelist)); - $this->assertInternalType('string', $nodelist[0]); + $this->assertCount(3, $nodelist); + $this->assertIsString($nodelist[0]); $this->assertInstanceOf(\Liquid\Tag\TagComment::class, $nodelist[1]); - $this->assertInternalType('string', $nodelist[2]); + $this->assertIsString($nodelist[2]); } } diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 04856058..4cbb1a98 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -20,7 +20,7 @@ class TestCase extends \PHPUnit\Framework\TestCase */ public $filters; - protected function setUp() + protected function setUp(): void { parent::setUp(); diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 269ce622..5b096abd 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -17,11 +17,12 @@ class VirtualFileSystemTest extends TestCase { /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage Not a callback */ public function testInvalidCallback() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('Not a callback'); + new Virtual(''); } @@ -45,11 +46,12 @@ public function testReadTemplateFile() } /** - * @expectedException \Liquid\LiquidException - * @expectedExceptionMessage cannot be used with a serializing cache */ public function testWithFileCache() { + $this->expectException(\Liquid\LiquidException::class); + $this->expectExceptionMessage('cannot be used with a serializing cache'); + $template = new Template(); $template->setFileSystem(new Virtual(function ($templatePath) { return ''; From fcdae2cff626ac1dbbedba61c5dc5f4688386434 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 21 Sep 2020 14:31:27 +0900 Subject: [PATCH 240/296] Fix build failures (#141) --- composer.json | 2 +- infection.json.dist | 4 ++-- phpunit.xml.dist | 11 ++++++++++- tests/Liquid/Cache/FileTest.php | 23 +++++++++++++++++------ tests/Liquid/Tag/TagIncludeTest.php | 3 +++ 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 99519ce0..a418d514 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "require-dev": { "ergebnis/composer-normalize": "^2.8", - "friendsofphp/php-cs-fixer": "^2.6", + "friendsofphp/php-cs-fixer": "^2.16.4", "infection/infection": "^0.17.5", "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^9.2.6" diff --git a/infection.json.dist b/infection.json.dist index b883a216..dde01cb6 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -1,5 +1,5 @@ { - "timeout": 10, + "timeout": 2, "source": { "directories": [ "src" @@ -8,4 +8,4 @@ "logs": { "text": "infection-log.txt" } -} \ No newline at end of file +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b918c794..84562a64 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,14 @@ - + + tests/ diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index 9080976d..bcee1a61 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -24,6 +24,10 @@ protected function setUp(): void parent::setUp(); $this->cacheDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache_dir'; + + // Remove tmp cache files because they may remain after a failed test run + $this->removeOldCachedFiles(); + $this->cache = new File(array( 'cache_dir' => $this->cacheDir, 'cache_expire' => 3600, @@ -35,8 +39,14 @@ protected function tearDown(): void { parent::tearDown(); - // Remove tmp cache files - array_map('unlink', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); + $this->removeOldCachedFiles(); + } + + private function removeOldCachedFiles(): void + { + if ($files = glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')) { + array_map('unlink', $files); + } } public function testConstructInvalidOptions() @@ -79,9 +89,7 @@ public function testFlushAll() touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test'); touch($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_test_two'); - $files = join(', ', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); - - $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*'), "Found more than two files: $files"); + $this->assertGreaterThanOrEqual(2, count(glob($this->cacheDir . DIRECTORY_SEPARATOR . '*'))); $this->cache->flush(); @@ -95,7 +103,7 @@ public function testFlushExpired() $files = join(', ', glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')); - $this->assertCount(2, glob($this->cacheDir . DIRECTORY_SEPARATOR . '*'), "Found more than two files: $files"); + $this->assertGreaterThanOrEqual(2, count(glob($this->cacheDir . DIRECTORY_SEPARATOR . '*')), "Found more than two files: $files"); $this->cache->flush(true); @@ -122,6 +130,9 @@ public function testWriteSerialized() $this->assertEquals(serialize($value), file_get_contents($this->cacheDir . DIRECTORY_SEPARATOR . 'liquid_' . $key)); } + /** + * @depends testWriteSerialized + */ public function testWriteGc() { $key = 'test'; diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 12a1506e..db37640d 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -104,6 +104,9 @@ public function testIncludeTagNoWith() $this->assertEquals("Outer-Inner: orig-Outer-Inner: orig23", $output); } + /** + * @depends testInvalidSyntaxNoObjectCollection + */ public function testWithCache() { $template = new Template(); From 7f51a8a6ff6ffc7ba0d2e40cb59fd6afc90cb35c Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 1 Jan 2021 20:31:25 +0900 Subject: [PATCH 241/296] Update workflow to test under PHP 8 (#142) * Update workflow to test under PHP 8 * Fix PHP 8 issues --- .github/workflows/cs.yaml | 11 ++++++++- .github/workflows/mt.yaml | 48 ++++++++++++++++++++++++++++++++++++ .github/workflows/tests.yaml | 20 +++++++++------ composer.json | 4 +-- src/Liquid/Context.php | 14 ++++++----- 5 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/mt.yaml diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml index e20c7bfe..123909f3 100644 --- a/.github/workflows/cs.yaml +++ b/.github/workflows/cs.yaml @@ -27,9 +27,18 @@ jobs: coverage: pcov tools: composer:v1 + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/composer + key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + composer-${{ matrix.php-version }}- + composer- + - name: Install dependencies run: | - composer update --no-interaction ${{ matrix.dependencies }} + composer update --prefer-dist --no-interaction --no-progress ${{ matrix.dependencies }} - name: Check code style run: | diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml new file mode 100644 index 00000000..0cc10c41 --- /dev/null +++ b/.github/workflows/mt.yaml @@ -0,0 +1,48 @@ +name: Mutation Testing + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-version: ['7.4'] + dependencies: [''] + + name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} + + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: + coverage: pcov + tools: composer:v2 + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/composer + key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + composer-${{ matrix.php-version }}- + composer- + + - name: Install dependencies + run: | + composer update --prefer-dist --no-interaction --no-progress ${{ matrix.dependencies }} + + - name: Run mutation testing + run: | + php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --show-mutations --threads=$(nproc) + diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 3663d214..bdde5990 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -17,7 +17,9 @@ jobs: dependencies: [''] include: - { php-version: '7.3', dependencies: '--prefer-lowest' } + - { php-version: '8.0', dependencies: '--ignore-platform-req=php' } + continue-on-error: ${{ matrix.php-version == '8.0' }} name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} steps: @@ -29,17 +31,21 @@ jobs: php-version: ${{ matrix.php-version }} extensions: coverage: pcov - tools: composer:v1 + tools: composer:v2 + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/composer + key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + composer-${{ matrix.php-version }}- + composer- - name: Install dependencies run: | - composer update --no-interaction ${{ matrix.dependencies }} + composer update --prefer-dist --no-interaction --no-progress ${{ matrix.dependencies }} - name: Run tests run: | php vendor/bin/phpunit - - - name: Run mutation testing - run: | - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --show-mutations --threads=$(nproc) - diff --git a/composer.json b/composer.json index a418d514..7730e31b 100644 --- a/composer.json +++ b/composer.json @@ -27,12 +27,12 @@ } ], "require": { - "php": "^7.3" + "php": "^7.3 || ^8.0" }, "require-dev": { "ergebnis/composer-normalize": "^2.8", "friendsofphp/php-cs-fixer": "^2.16.4", - "infection/infection": "^0.17.5", + "infection/infection": "^0.17.6", "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^9.2.6" }, diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 79aec8b1..630483d2 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -303,10 +303,12 @@ private function variable($key) } // first try to cast an object to an array or value - if (method_exists($object, 'toLiquid')) { - $object = $object->toLiquid(); - } elseif (method_exists($object, 'toArray')) { - $object = $object->toArray(); + if (is_object($object)) { + if (method_exists($object, 'toLiquid')) { + $object = $object->toLiquid(); + } elseif (method_exists($object, 'toArray')) { + $object = $object->toArray(); + } } if (is_null($object)) { @@ -394,7 +396,7 @@ private function variable($key) } // if a magic accessor method present... - if (method_exists($object, '__get')) { + if (is_object($object) && method_exists($object, '__get')) { $object = $object->$nextPartName; continue; } @@ -416,7 +418,7 @@ private function variable($key) // lastly, try to get an embedded value of an object // value could be of any type, not just string, so we have to do this // conversion here, not later in AbstractBlock::renderAll - if (method_exists($object, 'toLiquid')) { + if (is_object($object) && method_exists($object, 'toLiquid')) { $object = $object->toLiquid(); } From b761303f5bbf160f0d523cebdb269fa6f0f05671 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 1 Jan 2021 20:44:44 +0900 Subject: [PATCH 242/296] Fix current build failures (#145) * Fix current build failures * Disable Travis CI * Update CI workflow * Update job descriptions * Remove unneeded logging for Infection --- .github/workflows/tests.yaml | 35 ++++++++++++++++++++--------------- .travis.yml | 25 ------------------------- composer.json | 2 +- infection.json.dist | 3 --- 4 files changed, 21 insertions(+), 44 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index bdde5990..4b41a197 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,11 +1,14 @@ -name: Tests +# yamllint disable rule:line-length +# yamllint disable rule:braces + +name: CI on: - push: - branches: [ master ] pull_request: - branches: [ master ] - + push: + branches: + - master + - main jobs: build: @@ -13,14 +16,11 @@ jobs: strategy: matrix: - php-version: ['7.3', '7.4'] - dependencies: [''] + php-version: ['7.3', '7.4', '8.0'] include: - - { php-version: '7.3', dependencies: '--prefer-lowest' } - - { php-version: '8.0', dependencies: '--ignore-platform-req=php' } + - { php-version: '7.3', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } - continue-on-error: ${{ matrix.php-version == '8.0' }} - name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} + name: PHP ${{ matrix.php-version }} ${{ matrix.legend }} steps: - uses: actions/checkout@v2 @@ -29,17 +29,22 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} - extensions: coverage: pcov tools: composer:v2 + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies uses: actions/cache@v2 with: - path: ~/.cache/composer - key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}-${{ matrix.composer-flags }} restore-keys: | - composer-${{ matrix.php-version }}- + composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}- + composer-${{ runner.os }}-${{ matrix.php-version }}- + composer-${{ runner.os }}- composer- - name: Install dependencies diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 12959f85..00000000 --- a/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: php -php: - - 7.3 - - 7.4 - -env: - global: - - PHP_CS_FIXER_IGNORE_ENV=1 - -cache: - directories: - - $HOME/.composer/cache - - build/cache - -install: - - composer install --prefer-dist - - mkdir -p build/cache - -script: - - vendor/bin/phpunit --verbose --coverage-clover=build/logs/clover.xml || travis_terminate 1 - - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --threads=4 - - vendor/bin/php-cs-fixer --cache-file=build/cache/.php_cs.cache --diff --dry-run --stop-on-violation --verbose fix - -after_success: - - travis_retry php vendor/bin/coveralls diff --git a/composer.json b/composer.json index 7730e31b..1a2ee6ab 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "require-dev": { "ergebnis/composer-normalize": "^2.8", "friendsofphp/php-cs-fixer": "^2.16.4", - "infection/infection": "^0.17.6", + "infection/infection": ">=0.17.6", "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^9.2.6" }, diff --git a/infection.json.dist b/infection.json.dist index dde01cb6..51839eff 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -4,8 +4,5 @@ "directories": [ "src" ] - }, - "logs": { - "text": "infection-log.txt" } } From 9b73a100850779ea1eddc9bab77f33b416ad3176 Mon Sep 17 00:00:00 2001 From: Eric Schmitt Date: Thu, 7 Jan 2021 06:08:39 -0800 Subject: [PATCH 243/296] If the $object variable is a string php will attempt to load a class with the value of $object and check that class for the method toLiquid. (#144) When using older auto loading code this generates warnings attempting to load classes for every liquid string Co-authored-by: Eric Schmitt From d3e9c3de5b8a17840af2a29ac39cfe3afac55282 Mon Sep 17 00:00:00 2001 From: Eric Schmitt Date: Fri, 22 Jan 2021 06:14:26 -0800 Subject: [PATCH 244/296] If the $token variable is a string php will attempt to load a class with the value of $token and check for the Render method (#147) When using older auto loading code this generates warnings attempting to load classes for a liquid string Co-authored-by: Eric Schmitt --- src/Liquid/AbstractBlock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 2b90f18a..e0d3e4ba 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -157,7 +157,7 @@ protected function renderAll(array $list, Context $context) $result = ''; foreach ($list as $token) { - if (method_exists($token, 'render')) { + if (is_object($token) && method_exists($token, 'render')) { $value = $token->render($context); } else { $value = $token; From 4f5ae8de96031e2985a900427f2d508cf556c100 Mon Sep 17 00:00:00 2001 From: ShawnG Date: Fri, 25 Jun 2021 14:02:16 +0800 Subject: [PATCH 245/296] Add whitelist check and a default whitelist. (#151) Co-authored-by: Shawn Goh --- src/Liquid/Context.php | 11 +++++++++++ src/Liquid/Liquid.php | 16 ++++++++++++++++ tests/Liquid/ContextTest.php | 14 +++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 630483d2..251faa05 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -68,6 +68,17 @@ public function __construct(array $assigns = array(), array $registers = array() if (Liquid::get('EXPOSE_SERVER')) { $this->environments[1] = $_SERVER; + } else { + $this->environments[1] = array_filter( + $_SERVER, + function ($key) { + return in_array( + $key, + (array)Liquid::get('SERVER_SUPERGLOBAL_WHITELIST') + ); + }, + ARRAY_FILTER_USE_KEY + ); } } diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index d6fb0af0..cc78650f 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -84,6 +84,22 @@ class Liquid // Whenever variables from $_SERVER should be directly available to templates 'EXPOSE_SERVER' => false, + + // $_SERVER variables whitelist - exposed even when EXPOSE_SERVER is false + 'SERVER_SUPERGLOBAL_WHITELIST' => [ + 'HTTP_ACCEPT', + 'HTTP_ACCEPT_CHARSET', + 'HTTP_ACCEPT_ENCODING', + 'HTTP_ACCEPT_LANGUAGE', + 'HTTP_CONNECTION', + 'HTTP_HOST', + 'HTTP_REFERER', + 'HTTP_USER_AGENT', + 'HTTPS', + 'REQUEST_METHOD', + 'REQUEST_URI', + 'SERVER_NAME', + ], ); /** diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 67e0b11e..b95abea1 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -465,7 +465,7 @@ public function testGetNoOverride() $this->assertEquals('test', $context->get('test')); } - public function testServerNotExposedByDefault() + public function testServerOnlyExposeWhitelistByDefault() { $_SERVER['AWS_SECRET_ACCESS_KEY'] = 'super_secret'; @@ -474,6 +474,18 @@ public function testServerNotExposedByDefault() $context->set('AWS_SECRET_ACCESS_KEY', 'test'); $this->assertEquals('test', $context->get('AWS_SECRET_ACCESS_KEY')); + + $_SERVER['FOO'] = 'foo'; + $_SERVER['BAR'] = 'bar'; + + Liquid::set('SERVER_SUPERGLOBAL_WHITELIST', ['FOO']); + + $context = new Context(); + $this->assertEquals('foo', $context->get('FOO')); + $this->assertNull($context->get('BAR')); + + $context->set('BAR', 'bar'); + $this->assertEquals('bar', $context->get('BAR')); } public function testServerExposedWhenRequested() From b55e8681fc0167fdc4596ae6d4a5c91af5c43bea Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Sat, 18 Sep 2021 02:01:13 +0300 Subject: [PATCH 246/296] Fix slice method for UTF8 (#150) Co-authored-by: Alexey Kopytko --- src/Liquid/StandardFilters.php | 4 +--- tests/Liquid/StandardFiltersTest.php | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 4d85f43b..954aa56d 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -506,9 +506,7 @@ public static function slice($input, $offset, $length = null) if (is_array($input)) { $input = array_slice($input, $offset, $length); } elseif (is_string($input)) { - $input = $length === null - ? substr($input, $offset) - : substr($input, $offset, $length); + $input = mb_substr($input, $offset, $length); } return $input; diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 4bcbf48f..a37795e4 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -411,6 +411,8 @@ public function testSlice() } $this->assertEquals($item[1], $actual); } + + $this->assertEquals('Владимир', StandardFilters::slice('Владимир Владимирович', 0, 8)); } public function testTruncate() From 763a95a38d98378db2bad53d236a456b1e980c9a Mon Sep 17 00:00:00 2001 From: Ryan Marshall Date: Fri, 5 Nov 2021 02:16:06 +1300 Subject: [PATCH 247/296] Allow arrays to be output to template as string, rather than throwing an exception. (#156) * Output arrays as strings * Update `testIncludePassArrayWithIndex` * Update TagIncludeTest.php * Update TagIncludeTest.php * Wrap output in `htmlspecialchars()` --- src/Liquid/AbstractBlock.php | 2 +- tests/Liquid/Tag/TagIncludeTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index e0d3e4ba..15468d64 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -164,7 +164,7 @@ protected function renderAll(array $list, Context $context) } if (is_array($value)) { - throw new RenderException("Implicit rendering of arrays not supported. Use index operator."); + $value = htmlspecialchars(print_r($value, true)); } $result .= $value; diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index db37640d..3d8a4cfc 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -151,9 +151,6 @@ public function testIncludePassPlainValue() */ public function testIncludePassArrayWithoutIndex() { - $this->expectException(\Liquid\Exception\RenderException::class); - $this->expectExceptionMessage('Use index operator'); - $template = new Template(); $template->setFileSystem(TestFileSystem::fromArray(array( 'inner' => "[{{ other }}]", @@ -161,7 +158,10 @@ public function testIncludePassArrayWithoutIndex() ))); $template->parse("{% include 'example' %}"); - $template->render(array("var" => array("a", "b", "c"))); + + $output = $template->render(array("var" => array("a", "b", "c"))); + $expectedOutput = htmlspecialchars(print_r(array("a", "b", "c"), true)); + $this->assertEquals("([$expectedOutput])", $output); } public function testIncludePassArrayWithIndex() From d81a52634ffbe588c8e9a833b7db3842061ed2e2 Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Thu, 17 Feb 2022 15:19:16 +0300 Subject: [PATCH 248/296] Fix truncate, capitalize, upcase, downcase methods for UTF-8 (#158) --- src/Liquid/StandardFilters.php | 9 +++++---- tests/Liquid/StandardFiltersTest.php | 9 +++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 954aa56d..cc923a33 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -43,7 +43,8 @@ public static function append($input, $string) public static function capitalize($input) { return preg_replace_callback("/(^|[^\p{L}'])([\p{Ll}])/u", function ($matches) { - return $matches[1] . ucfirst($matches[2]); + $first_char = mb_substr($matches[2], 0, 1); + return $matches[1] . mb_strtoupper($first_char) . mb_substr($matches[2], 1); }, ucwords($input)); } @@ -119,7 +120,7 @@ public static function divided_by($input, $operand) */ public static function downcase($input) { - return is_string($input) ? strtolower($input) : $input; + return is_string($input) ? mb_strtolower($input) : $input; } @@ -636,7 +637,7 @@ public static function truncate($input, $characters = 100, $ending = '...') { if (is_string($input) || is_numeric($input)) { if (strlen($input) > $characters) { - return substr($input, 0, $characters) . $ending; + return mb_substr($input, 0, $characters) . $ending; } } @@ -692,7 +693,7 @@ public static function uniq($input) */ public static function upcase($input) { - return is_string($input) ? strtoupper($input) : $input; + return is_string($input) ? mb_strtoupper($input) : $input; } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index a37795e4..7892f36f 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -99,6 +99,8 @@ public function testDowncase() $data = array( 'UpperCaseMiXed' => 'uppercasemixed', 3 => 3, + // UTF-8 + 'Владимир' => 'владимир' ); foreach ($data as $element => $expected) { @@ -111,6 +113,8 @@ public function testUpcase() $data = array( 'UpperCaseMiXed' => 'UPPERCASEMIXED', 3 => 3, + // UTF-8 + 'владимир' => 'ВЛАДИМИР' ); foreach ($data as $element => $expected) { @@ -124,6 +128,8 @@ public function testCapitalize() 'one Word not' => 'One Word Not', '1test' => '1Test', '' => '', + // UTF-8 + 'владимир владимирович' => 'Владимир Владимирович' ); foreach ($data as $element => $expected) { @@ -434,6 +440,9 @@ public function testTruncate() // Custom ending $this->assertEquals('abcend', StandardFilters::truncate('abcdef', 3, 'end')); + + // UTF-8 + $this->assertEquals('Влад...', StandardFilters::truncate('Владимир Владимирович', 4)); } public function testTruncateWords() From 33f649caaa5239756cbfe5dd7c2fe4cad8b512cd Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Tue, 1 Mar 2022 03:57:16 +0300 Subject: [PATCH 249/296] fix parse exception "tag was never closed" with line break (#159) --- src/Liquid/AbstractBlock.php | 2 +- tests/Liquid/Tag/TagIfTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 15468d64..0d29f011 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -52,7 +52,7 @@ public function getNodelist() public function parse(array &$tokens) { $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); - $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/'); + $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/s'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); $this->nodelist = array(); diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 9a8ef329..31482f7b 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -232,6 +232,14 @@ public function testSyntaxErrorNotClosed() $this->assertTemplateResult('', '{% if jerry == 1 %}'); } + public function testSyntaxErrorNotClosedLineBreak() + { + $this->expectException(\Liquid\Exception\ParseException::class); + $this->expectExceptionMessage('if tag was never closed'); + + $this->assertTemplateResult('', "{% if jerry\n == 1 %}"); + } + /** */ public function testSyntaxErrorEnd() From 948327dcbb4f6f7f1fbd9080f92404b629707122 Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Tue, 22 Mar 2022 03:39:59 +0300 Subject: [PATCH 250/296] fix parse exception "Unknown tag endfor" with line break (#161) --- src/Liquid/Liquid.php | 2 +- tests/Liquid/Tag/TagForTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index cc78650f..6f872ab0 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -125,7 +125,7 @@ public static function get($key) case 'TAG_ATTRIBUTES': return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; case 'TOKENIZATION_REGEXP': - return '/(' . self::$config['TAG_START'] . '.*?' . self::$config['TAG_END'] . '|' . self::$config['VARIABLE_START'] . '.*?' . self::$config['VARIABLE_END'] . ')/'; + return '/(' . self::$config['TAG_START'] . '.*?' . self::$config['TAG_END'] . '|' . self::$config['VARIABLE_START'] . '.*?' . self::$config['VARIABLE_END'] . ')/s'; default: return null; } diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index d1e14047..72ec2c60 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -60,6 +60,7 @@ public function testForWithVariable() $this->assertTemplateResult('abcd', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', 'b', 'c', 'd'))); $this->assertTemplateResult('a b c', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', ' ', 'b', ' ', 'c'))); $this->assertTemplateResult('abc', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', '', 'b', '', 'c'))); + $this->assertTemplateResult(' a ', "{%\nfor item in array%} {{item}} {%endfor%}", array('array' => array('a'))); } public function testForWithHash() From 1dbd10e852b8e06e0c09488acbfaed58521cd9ab Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Tue, 22 Mar 2022 11:53:20 +0300 Subject: [PATCH 251/296] fix parse exception "Variable was not properly terminated" with line break (#162) --- src/Liquid/AbstractBlock.php | 2 +- src/Liquid/Variable.php | 2 +- tests/Liquid/OutputTest.php | 3 --- tests/Liquid/VariableResolutionTest.php | 8 ++++++++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 0d29f011..4ca05b2a 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -254,7 +254,7 @@ private function blockName() */ private function createVariable($token) { - $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/'); + $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/s'); if ($variableRegexp->match($token)) { return new Variable($variableRegexp->matches[1]); } diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index 868738a6..6afeb059 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -41,7 +41,7 @@ public function __construct($markup) $this->markup = $markup; $filterSep = new Regexp('/' . Liquid::get('FILTER_SEPARATOR') . '\s*(.*)/m'); - $syntaxParser = new Regexp('/(' . Liquid::get('QUOTED_FRAGMENT') . ')(.*)/m'); + $syntaxParser = new Regexp('/(' . Liquid::get('QUOTED_FRAGMENT') . ')(.*)/ms'); $filterParser = new Regexp('/(?:\s+|' . Liquid::get('QUOTED_FRAGMENT') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')+/'); $filterArgsRegex = new Regexp('/(?:' . Liquid::get('FILTER_ARGUMENT_SEPARATOR') . '|' . Liquid::get('ARGUMENT_SEPARATOR') . ')\s*((?:\w+\s*\:\s*)?' . Liquid::get('QUOTED_FRAGMENT') . ')/'); diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 4eac2e91..a18b048a 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -188,9 +188,6 @@ public function testLinkTo() */ public function testVariableWithANewLine() { - $this->expectException(\Liquid\Exception\ParseException::class); - $this->expectExceptionMessage('was not properly terminated'); - $text = "{{ aaa\n }}"; $this->assertTemplateResult('', $text, $this->assigns); } diff --git a/tests/Liquid/VariableResolutionTest.php b/tests/Liquid/VariableResolutionTest.php index 3f8a26cc..28a3f072 100644 --- a/tests/Liquid/VariableResolutionTest.php +++ b/tests/Liquid/VariableResolutionTest.php @@ -37,6 +37,14 @@ public function testIgnoreUnknown() $this->assertEquals('', $template->render()); } + public function testLineBreak() + { + $template = new Template(); + + $template->parse("{{ test |\n strip_html }}"); + $this->assertEquals('worked', $template->render(array('test' => 'worked'))); + } + public function testArrayScoping() { $template = new Template(); From 4818847793ceae9bfc9029eb97dc55cf091f6f51 Mon Sep 17 00:00:00 2001 From: Peter Jaap Blaakmeer Date: Fri, 15 Apr 2022 09:02:38 +0200 Subject: [PATCH 252/296] Fix PHP 8.1 error in preg_split by replacing null with default value (#163) This fixes the following deprecation warning: Deprecated Functionality: preg_split(): Passing null to parameter #3 ($limit) of type int is deprecated in vendor/liquid/liquid/src/Liquid/Template.php on line 175 --- src/Liquid/Template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index bae79ec3..14a8c64e 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -172,7 +172,7 @@ public static function tokenize($source) { return empty($source) ? array() - : preg_split(Liquid::get('TOKENIZATION_REGEXP'), $source, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + : preg_split(Liquid::get('TOKENIZATION_REGEXP'), $source, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); } /** From e9e0c1620a95f2ee73c2a1d58b39115617402a88 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 15 Apr 2022 16:10:57 +0900 Subject: [PATCH 253/296] Start testing on PHP 8.1 (#164) --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4b41a197..1ec8e5ac 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - php-version: ['7.3', '7.4', '8.0'] + php-version: ['7.3', '7.4', '8.0', '8.1'] include: - { php-version: '7.3', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } From a7a6f2406790a6c867ca9b4d4dd513df8ba952cb Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Sat, 14 May 2022 17:12:18 +0300 Subject: [PATCH 254/296] Fix PHP 8.1 error in preg_split by replacing null with default value (#165) --- src/Liquid/Regexp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index bfbdd2a5..0cbcd0e6 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -117,7 +117,7 @@ public function matchAll($string) * * @return array */ - public function split($string, $limit = null) + public function split($string, $limit = -1) { return preg_split($this->pattern, $string, $limit); } From 5dcd84ad22052e103e7aa61702c94eeda8f28d99 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sun, 7 Aug 2022 22:41:55 +0900 Subject: [PATCH 255/296] Allow plugins to be loaded (#168) --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1a2ee6ab..a4536432 100644 --- a/composer.json +++ b/composer.json @@ -37,7 +37,8 @@ "phpunit/phpunit": "^9.2.6" }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": true }, "extra": { "branch-alias": { From 2b6a48a422deda49f963e0d910d3a922876025bf Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sun, 7 Aug 2022 06:42:47 -0700 Subject: [PATCH 256/296] use build statuus badge from github actions (#166) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce5fde4b..3f29aad6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Liquid template engine for PHP [![Build Status](https://travis-ci.org/kalimatas/php-liquid.svg?branch=master)](https://travis-ci.org/kalimatas/php-liquid) [![Coverage Status](https://coveralls.io/repos/github/kalimatas/php-liquid/badge.svg?branch=master)](https://coveralls.io/github/kalimatas/php-liquid?branch=master) [![Total Downloads](https://poser.pugx.org/liquid/liquid/downloads.svg)](https://packagist.org/packages/liquid/liquid) +# Liquid template engine for PHP [![CI](https://github.com/kalimatas/php-liquid/actions/workflows/tests.yaml/badge.svg)](https://github.com/kalimatas/php-liquid/actions/workflows/tests.yaml) [![Coverage Status](https://coveralls.io/repos/github/kalimatas/php-liquid/badge.svg?branch=master)](https://coveralls.io/github/kalimatas/php-liquid?branch=master) [![Total Downloads](https://poser.pugx.org/liquid/liquid/downloads.svg)](https://packagist.org/packages/liquid/liquid) Liquid is a PHP port of the [Liquid template engine for Ruby](https://github.com/Shopify/liquid), which was written by Tobias Lutke. Although there are many other templating engines for PHP, including Smarty (from which Liquid was partially inspired), Liquid had some advantages that made porting worthwhile: From f0be8a3e0e0fcee99c0091748dcb21675b3caf46 Mon Sep 17 00:00:00 2001 From: Tim Robertson Date: Sun, 7 Aug 2022 21:55:20 -0400 Subject: [PATCH 257/296] Align split filter behaviour with Ruby liquid (#167) This aligns the behaviour of the split filter with that of Shopify/Ruby Liquid. This allows for the creation of empty arrays that variables/etc can then be pushed onto. For example, {% assign posts = "" | split: "," %} {% assign posts = posts | push: featured_post %} {% assign posts = posts | push: post %} --- src/Liquid/StandardFilters.php | 4 ++++ tests/Liquid/StandardFiltersTest.php | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index cc923a33..fa022478 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -567,6 +567,10 @@ public static function string($input) */ public static function split($input, $pattern) { + if ($input === '' || $input === null) { + return []; + } + return explode($pattern, $input); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 7892f36f..e4d725e8 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -792,7 +792,11 @@ public function testSplit() $data = array( array( '', - array(0 => ''), + array(), + ), + array( + null, + array(), ), array( 'two-one-three', From ff1bb2bcbbd0b2609e4a6adee14a22a71bd7d015 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sun, 30 Oct 2022 12:55:54 +0900 Subject: [PATCH 258/296] Test on PHP 8.2 (#172) * Update StandardFiltersTest.php --- .github/workflows/tests.yaml | 6 +++--- tests/Liquid/StandardFiltersTest.php | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1ec8e5ac..2f280008 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,14 +16,14 @@ jobs: strategy: matrix: - php-version: ['7.3', '7.4', '8.0', '8.1'] + php-version: ['7.3', '7.4', '8.0', '8.1', '8.2'] include: - { php-version: '7.3', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } name: PHP ${{ matrix.php-version }} ${{ matrix.legend }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -37,7 +37,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}-${{ matrix.composer-flags }} diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index e4d725e8..20162883 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -896,7 +896,7 @@ public function testPlus() ); foreach ($data as $item) { - $this->assertEquals($item[2], StandardFilters::plus($item[0], $item[1]), '', 0.00001); + $this->assertEqualsWithDelta($item[2], StandardFilters::plus($item[0], $item[1]), 0.00001); } } @@ -926,7 +926,7 @@ public function testMinus() ); foreach ($data as $item) { - $this->assertEquals($item[2], StandardFilters::minus($item[0], $item[1]), '', 0.00001); + $this->assertEqualsWithDelta($item[2], StandardFilters::minus($item[0], $item[1]), 0.00001); } } @@ -956,7 +956,7 @@ public function testTimes() ); foreach ($data as $item) { - $this->assertEquals($item[2], StandardFilters::times($item[0], $item[1]), '', 0.00001); + $this->assertEqualsWithDelta($item[2], StandardFilters::times($item[0], $item[1]), 0.00001); } } @@ -986,7 +986,7 @@ public function testDivideBy() ); foreach ($data as $item) { - $this->assertEquals($item[2], StandardFilters::divided_by($item[0], $item[1]), '', 0.00001); + $this->assertEqualsWithDelta($item[2], StandardFilters::divided_by($item[0], $item[1]), 0.00001); } } @@ -1021,7 +1021,7 @@ public function testModulo() ); foreach ($data as $item) { - $this->assertEquals($item[2], StandardFilters::modulo($item[0], $item[1]), '', 0.00001); + $this->assertEqualsWithDelta($item[2], StandardFilters::modulo($item[0], $item[1]), 0.00001); } } From c8356295b9ddaafabcbea8d1e8d39658842b5758 Mon Sep 17 00:00:00 2001 From: Ryan Marshall Date: Wed, 4 Jan 2023 22:08:41 +1300 Subject: [PATCH 259/296] Replace strftime (#175) * Replace deprecated strftime() * Default date string should match Ruby implementation `{{ 'now' | date }}` => `Wednesday, January 4, 2023 at 10:22 am +1300` * Update testDate() * Update FilterbankTest.php * Use `\DateTime` * `%l` should not return leading whitespace * PHP CS Fixer formatting * Test should match original Ruby implementation Passing an empty string as the `format` argument should simply render the input string, as per the original Ruby implementation. --- src/Liquid/StandardFilters.php | 29 ++++++++++++++++++++-------- tests/Liquid/FilterbankTest.php | 2 +- tests/Liquid/StandardFiltersTest.php | 18 +++++++++-------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index fa022478..84aaf500 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -61,24 +61,37 @@ public static function ceil($input) /** - * Formats a date using strftime + * Formats a date * * @param mixed $input - * @param string $format + * @param string $strftimeFormat (see http://strftime.net) * * @return string */ - public static function date($input, $format) + public static function date($input, $strftimeFormat = '%A, %B %e, %Y at %l:%S %P %z') { - if (!is_numeric($input)) { - $input = strtotime($input); + if (!$strftimeFormat) { + return $input; + } + + if (is_numeric($input)) { + $input = date('Y-m-d H:i:s', $input); } - if ($format == 'r') { - return date($format, $input); + $dateTime = new \DateTime($input); + if (!$dateTime) { + return ""; } - return strftime($format, $input); + $dateFormat = str_replace( + ['at', '%a', '%A', '%d', '%e', '%u', '%w', '%W', '%b', '%h', '%B', '%m', '%y', '%Y', '%D', '%F', '%x', '%n', '%t', '%H', '%k', '%I', '%l', '%M', '%p', '%P', '%r', '%R', '%S', '%T', '%X', '%z', '%Z', '%c', '%s', '%%'], + ['\a\t', 'D', 'l', 'd', 'j', 'N', 'w', 'W', 'M', 'M', 'F', 'm', 'y', 'Y', 'm/d/y', 'Y-m-d', 'm/d/y', "\n", "\t", 'H', 'G', 'h', 'g', 'i', 'A', 'a', 'h:i:s A', 'H:i', 's', 'H:i:s', 'H:i:s', 'O', 'T', 'D M j H:i:s Y', 'U', '%'], + $strftimeFormat + ); + + $formatted = $dateTime->format($dateFormat); + + return $formatted; } diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index 97865830..dd490af0 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -113,7 +113,7 @@ public function testTypeErrorExceptionAndCallDateFilterWithoutArguments() } $var = new Variable('var | date'); - $this->context->set('var', 1000); + $this->context->set('var', []); $this->expectException(\Liquid\LiquidException::class); $var->render($this->context); diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 20162883..899336fe 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -1125,20 +1125,22 @@ public function testSecondFilterOverwritesFirst() public function testDate() { + $dateVar = '2017-07-01 21:00:00'; + $var = new Variable('var | date, "%Y"'); - $this->context->set('var', '2017-07-01 21:00:00'); + $this->context->set('var', $dateVar); $this->assertEquals('2017', $var->render($this->context)); $var = new Variable("var | date: '%d/%m/%Y %l:%M %p'"); - $this->context->set('var', '2017-07-01 21:00:00'); - $this->assertEquals('01/07/2017 9:00 PM', $var->render($this->context)); + $this->context->set('var', $dateVar); + $this->assertEquals('01/07/2017 9:00 PM', $var->render($this->context)); $var = new Variable('var | date, ""'); - $this->context->set('var', '2017-07-01 21:00:00'); - $this->assertEquals('', $var->render($this->context)); + $this->context->set('var', $dateVar); + $this->assertEquals($dateVar, $var->render($this->context)); - $var = new Variable('var | date, "r"'); - $this->context->set('var', 1000000000); - $this->assertEquals(date('r', 1000000000), $var->render($this->context)); + $var = new Variable('var | date, "%Y-%m-%d %H:%M:%S"'); + $this->context->set('var', 1498942800); + $this->assertEquals($dateVar, $var->render($this->context)); } } From 0088a17289fe489fef436d20214d6f90175ca2df Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sat, 11 Feb 2023 03:34:05 -0700 Subject: [PATCH 260/296] Ignore non-essential files for the composer package (#181) --- .gitattributes | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b0cfea28 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +/.gitattributes export-ignore +/.github export-ignore +/.gitignore export-ignore +/.php_cs.dist export-ignore +/.infection.json.dist export-ignore +/.phpunit.xml.dist export-ignore +/examples export-ignore +/tests export-ignore From befadb54dff136c7278dc5c4e36896d6a20f5c08 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sun, 12 Feb 2023 17:03:20 +0900 Subject: [PATCH 261/296] Migrate PHPUnit configuration on the fly (#184) --- .github/workflows/tests.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 2f280008..525903d3 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -53,4 +53,5 @@ jobs: - name: Run tests run: | + php vendor/bin/phpunit --migrate-configuration || true php vendor/bin/phpunit From d9c16298089686e09fad954ec6319e55eaaa6cd3 Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sun, 12 Feb 2023 01:04:25 -0700 Subject: [PATCH 262/296] Remove superfluous alternation from the QUOTED_FRAGMENT regex (#182) --- src/Liquid/Liquid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 6f872ab0..24974dab 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -121,7 +121,7 @@ public static function get($key) // This case is needed for compound settings switch ($key) { case 'QUOTED_FRAGMENT': - return '(?:' . self::get('QUOTED_STRING') . '|(?:[^\s,\|\'"]|' . self::get('QUOTED_STRING') . ')+)'; + return '(?:' . self::get('QUOTED_STRING') . '|[^\s,\|\'"]+)'; case 'TAG_ATTRIBUTES': return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; case 'TOKENIZATION_REGEXP': From 345ff549fbc0d1d19ec76a18c4fdcf322c061581 Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sat, 11 Mar 2023 02:38:50 -0700 Subject: [PATCH 263/296] Improve compatibility for array operands (#190) Fix #189 --- src/Liquid/AbstractBlock.php | 2 +- tests/Liquid/Tag/TagIncludeTest.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 4ca05b2a..6e0820b2 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -164,7 +164,7 @@ protected function renderAll(array $list, Context $context) } if (is_array($value)) { - $value = htmlspecialchars(print_r($value, true)); + $value = htmlspecialchars(implode($value)); } $result .= $value; diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 3d8a4cfc..1fdaa2b8 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -160,8 +160,7 @@ public function testIncludePassArrayWithoutIndex() $template->parse("{% include 'example' %}"); $output = $template->render(array("var" => array("a", "b", "c"))); - $expectedOutput = htmlspecialchars(print_r(array("a", "b", "c"), true)); - $this->assertEquals("([$expectedOutput])", $output); + $this->assertEquals("([abc])", $output); } public function testIncludePassArrayWithIndex() From fbfbbcff97de5e717ab2338c9c634d841a4327c0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 11 Mar 2023 20:05:09 +0900 Subject: [PATCH 264/296] Test improvements (#191) Co-authored-by: John Rayes --- phpunit.xml.dist | 4 ++++ tests/Liquid/Tag/TagCaseTest.php | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 84562a64..29b38ac0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -20,4 +20,8 @@ src/ + + + + diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index 8e99ec9b..e87e11f1 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -49,6 +49,26 @@ public function testCase() $this->assertTemplateResult('', '{% case condition %}{% when "string here" %} hit {% endcase %}', $assigns); } + public function multipleConditionsProvider() + { + yield [[], '{% assign handle = "apple" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie", "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is not a cake nor a cookie']; + yield [[], '{% assign handle = "cake" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie", "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cake']; + yield [[], '{% assign handle = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie", "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + yield [[], '{% assign handle = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie" ,"biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + yield [[], '{% assign handle = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie" or "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + yield [[], '{% assign handle = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when "cookie"or"biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + yield [['condition' => 'cookie'], '{% assign handle = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when condition, "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + yield [[], '{% assign handle = "cookie" %}{% assign condition = "cookie" %}{% case handle %}{% when "cake" %}This is a cake{% when condition, "biscuit" %}This is a cookie{% else %}This is not a cake nor a cookie{% endcase %}', 'This is a cookie']; + } + + /** + * @dataProvider multipleConditionsProvider + */ + public function testMultipleConditions(array $assigns, string $test, string $expected) + { + $this->assertTemplateResult($expected, $test, $assigns); + } + public function testCaseWithElse() { $assigns = array('condition' => 5); From 4c20f564e890ee5cfb8433924750c52f876a2a9a Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sun, 12 Mar 2023 05:12:07 -0700 Subject: [PATCH 265/296] these tests should pass on Windows (#192) --- tests/Liquid/LocalFileSystemTest.php | 2 +- tests/Liquid/Tag/TagIncludeTest.php | 2 +- tests/Liquid/Tag/TagTablerowTest.php | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/Liquid/LocalFileSystemTest.php b/tests/Liquid/LocalFileSystemTest.php index 4e38e7d7..c6165cbb 100644 --- a/tests/Liquid/LocalFileSystemTest.php +++ b/tests/Liquid/LocalFileSystemTest.php @@ -153,7 +153,7 @@ public function testParseTemplateFile() Liquid::set('INCLUDE_SUFFIX', 'tpl'); $template = new Template($this->root); - $this->assertEquals("test content\n", $template->parseFile('mypartial')->render()); + $this->assertEquals("test content" . PHP_EOL, $template->parseFile('mypartial')->render()); } /** diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 1fdaa2b8..07335dac 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -130,7 +130,7 @@ public function testIncludeTemplateFile() $template = new Template(dirname(__DIR__).DIRECTORY_SEPARATOR.self::TEMPLATES_DIR); $template->parse("{% include 'mypartial' %}"); // template include inserts a new line - $this->assertEquals("test content\n", $template->render()); + $this->assertEquals("test content" . PHP_EOL, $template->render()); } public function testIncludePassPlainValue() diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index c5e2b18b..58bd7942 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -24,11 +24,7 @@ public function testTablerow() ); $this->assertTemplateResult( - ' - item 1 - - item 2 -', + '' . "\n" . ' item 1 ' . "\n" . '' . "\n" . ' item 2 ' . "\n", '{% tablerow item in array cols:1 %} item {{ item }} {% endtablerow %}', array('array' => array(1, 2)) ); From efb285b2da18daef6d43f52d58cbdb59cd13be04 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 16 Mar 2023 19:40:11 +0900 Subject: [PATCH 266/296] Add a test for case tag with compound conditions in when clauses (#196) See #124 --- tests/Liquid/fixtures/case.html | 9 +++++++++ tests/Liquid/fixtures/case.liquid | 27 +++++++++++++++++++++++++++ tests/Liquid/fixtures/case.php | 1 + 3 files changed, 37 insertions(+) diff --git a/tests/Liquid/fixtures/case.html b/tests/Liquid/fixtures/case.html index 5f23814c..3540bf48 100644 --- a/tests/Liquid/fixtures/case.html +++ b/tests/Liquid/fixtures/case.html @@ -20,3 +20,12 @@ + +Spring + +2019 + + +May. + +2019 diff --git a/tests/Liquid/fixtures/case.liquid b/tests/Liquid/fixtures/case.liquid index 1fcbcd44..f366765d 100644 --- a/tests/Liquid/fixtures/case.liquid +++ b/tests/Liquid/fixtures/case.liquid @@ -9,3 +9,30 @@ {% endcase %} {% endfor %} +{% assign m = post.date | date: "%b" %} +{% case m %} + {% when 'April' %}Spring + {% when 'May' %}Spring + {% when 'June' %}Spring + {% when 'July' %}Summer + {% when 'August' %}Summer + {% when 'September' %}Summer + {% when 'October' %}Autumn + {% when 'November' %}Autumn + {% when 'December' %}Autumn + {% when 'January' %}Winter + {% when 'February' %}Winter + {% when 'March' %}Winter + {% else %}{{ post.date | date: "%b" }}. +{% endcase %} +{{ post.date | date: "%Y" }} + +{% assign m = post.date | date: "%b" %} +{% case m %} + {% when 'April' or 'May' or 'June' %}Spring + {% when 'July' or 'August' or 'September' %}Summer + {% when 'October' or 'November' or 'December' %}Autumn + {% when 'January' or 'February' or 'March' %}Winter + {% else %}{{ post.date | date: "%b" }}. +{% endcase %} +{{ post.date | date: "%Y" }} diff --git a/tests/Liquid/fixtures/case.php b/tests/Liquid/fixtures/case.php index c0ffa720..2e3fb4ae 100644 --- a/tests/Liquid/fixtures/case.php +++ b/tests/Liquid/fixtures/case.php @@ -11,4 +11,5 @@ return array( 'max' => 5, + 'post' => ['date' => 'May 28, 2019'], ); From d8fd54a8fa76b1f17421e853a0abe9878b3c61b1 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 16 Mar 2023 19:47:16 +0900 Subject: [PATCH 267/296] Support compound conditions in when clauses (#197) See #187 Fix #124 Co-authored-by: John Rayes --- src/Liquid/Tag/TagCase.php | 21 ++++++++++++--------- tests/Liquid/fixtures/case.html | 8 ++++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 9ed29a34..1563042a 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -99,14 +99,13 @@ public function endTag() */ public function unknownTag($tag, $params, array $tokens) { - $whenSyntaxRegexp = new Regexp('/' . Liquid::get('QUOTED_FRAGMENT') . '/'); - switch ($tag) { case 'when': + $whenSyntax = preg_match_all('/(?<=,|or|^)\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')/', $params, $matches); // push the current nodelist onto the stack and prepare for a new one - if ($whenSyntaxRegexp->match($params)) { + if ($whenSyntax) { $this->pushNodelist(); - $this->right = $whenSyntaxRegexp->matches[0]; + $this->right = $matches[1]; $this->nodelist = array(); } else { throw new ParseException("Syntax Error in tag 'case' - Valid when condition: when [condition]"); // harry @@ -151,12 +150,16 @@ public function render(Context $context) foreach ($this->nodelists as $data) { list($right, $nodelist) = $data; - if ($this->equalVariables($this->left, $right, $context)) { - $runElseBlock = false; + foreach ($right as $var) { + if ($this->equalVariables($this->left, $var, $context)) { + $runElseBlock = false; + + $context->push(); + $output .= $this->renderAll($nodelist, $context); + $context->pop(); - $context->push(); - $output .= $this->renderAll($nodelist, $context); - $context->pop(); + break; + } } } diff --git a/tests/Liquid/fixtures/case.html b/tests/Liquid/fixtures/case.html index 3540bf48..27ecaad0 100644 --- a/tests/Liquid/fixtures/case.html +++ b/tests/Liquid/fixtures/case.html @@ -8,8 +8,8 @@ - ... else ... - + hit 2 or 3 + ... else ... @@ -26,6 +26,6 @@ 2019 -May. - +Spring + 2019 From 8000aedfa0ee3ea83425c4a3b612505a0e777cb2 Mon Sep 17 00:00:00 2001 From: Julian Krenge Date: Sun, 14 May 2023 01:22:02 +0200 Subject: [PATCH 268/296] add support for filter (#201) --- src/Liquid/StandardFilters.php | 13 ++++++++++++ tests/Liquid/StandardFiltersTest.php | 30 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 84aaf500..cc219d29 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -150,6 +150,19 @@ public static function raw($input) } + /** + * Converts into JSON string + * + * @param mixed $input + * + * @return string + */ + public static function json($input) + { + return json_encode($input); + } + + /** * Escape a string * diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 899336fe..36b157d3 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -174,6 +174,36 @@ public function testRaw() } } + public function testJson() + { + $data = array( + array( + "before" => "Anything", + "after" => "\"Anything\"", + ), + array( + "before" => 3, + "after" => 3, + ), + array( + "before" => array(1, 2, 3), + "after" => "[1,2,3]", + ), + array( + "before" => array("one" => 1, "two" => 2, "three" => 3), + "after" => "{\"one\":1,\"two\":2,\"three\":3}", + ), + array( + "before" => array("one" => 1, "two" => array(1, 2, 3), "three" => 3), + "after" => "{\"one\":1,\"two\":[1,2,3],\"three\":3}", + ), + ); + + foreach ($data as $testCase) { + $this->assertEquals($testCase['after'], StandardFilters::json($testCase['before'])); + } + } + public function testEscape() { $data = array( From 2c67bbbefce8dcdc062cf7c24a65b704d6d4255e Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 11:28:43 +0900 Subject: [PATCH 269/296] Update PHP Coding Standards Fixer --- .php_cs.dist => .php-cs-fixer.dist.php | 14 +++++++++----- composer.json | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) rename .php_cs.dist => .php-cs-fixer.dist.php (83%) diff --git a/.php_cs.dist b/.php-cs-fixer.dist.php similarity index 83% rename from .php_cs.dist rename to .php-cs-fixer.dist.php index 713a8be5..1919f4fc 100644 --- a/.php_cs.dist +++ b/.php-cs-fixer.dist.php @@ -9,11 +9,12 @@ @package Liquid EOF; -return PhpCsFixer\Config::create() - ->setRiskyAllowed(true) - ->setRules([ +$config = new PhpCsFixer\Config(); +$config + ->setRiskyAllowed(true) + ->setRules([ '@PSR2' => true, - 'psr4' => true, + 'psr_autoloading' => true, 'no_unreachable_default_argument_value' => true, 'no_useless_else' => true, 'no_useless_return' => true, @@ -30,7 +31,7 @@ 'php_unit_mock' => true, 'php_unit_namespaced' => true, 'php_unit_no_expectation_annotation' => true, - 'php_unit_ordered_covers' => true, + "phpdoc_order_by_value" => ['annotations' => ['covers']], 'php_unit_set_up_tear_down_visibility' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], ]) @@ -40,3 +41,6 @@ ->in(__DIR__) ) ; + + +return $config; diff --git a/composer.json b/composer.json index a4536432..c25a6b7e 100644 --- a/composer.json +++ b/composer.json @@ -27,11 +27,11 @@ } ], "require": { - "php": "^7.3 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { - "ergebnis/composer-normalize": "^2.8", - "friendsofphp/php-cs-fixer": "^2.16.4", + "ergebnis/composer-normalize": ">=2.8", + "friendsofphp/php-cs-fixer": "^3.22", "infection/infection": ">=0.17.6", "php-coveralls/php-coveralls": "^2.2", "phpunit/phpunit": "^9.2.6" From e80bc5682e6684921ff4d90411f1dbf0d499e50b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 11:29:43 +0900 Subject: [PATCH 270/296] Bump PHP version support --- .github/workflows/cs.yaml | 2 +- .github/workflows/mt.yaml | 2 +- .github/workflows/tests.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml index 123909f3..57cab33f 100644 --- a/.github/workflows/cs.yaml +++ b/.github/workflows/cs.yaml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - php-version: ['7.3'] + php-version: ['7.4'] name: PHP ${{ matrix.php-version }} diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml index 0cc10c41..f4b360ff 100644 --- a/.github/workflows/mt.yaml +++ b/.github/workflows/mt.yaml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - php-version: ['7.4'] + php-version: ['8.2'] dependencies: [''] name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 525903d3..94dbc939 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,9 +16,9 @@ jobs: strategy: matrix: - php-version: ['7.3', '7.4', '8.0', '8.1', '8.2'] + php-version: ['7.4', '8.0', '8.1', '8.2'] include: - - { php-version: '7.3', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } + - { php-version: '7.4', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } name: PHP ${{ matrix.php-version }} ${{ matrix.legend }} From fcf2e3c7c0efd629949214bb0626460874bec4aa Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 11:56:51 +0900 Subject: [PATCH 271/296] Add another rule --- .php-cs-fixer.dist.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 1919f4fc..a3dfaa3c 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -34,6 +34,7 @@ "phpdoc_order_by_value" => ['annotations' => ['covers']], 'php_unit_set_up_tear_down_visibility' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], + 'no_whitespace_in_blank_line' => true, ]) ->setIndent("\t") ->setFinder( From 72c7e3f4e34d2ed474b1399f2a7ab427fb6f3b14 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 11:58:20 +0900 Subject: [PATCH 272/296] Apply code style changes --- .php-cs-fixer.dist.php | 8 +- src/Liquid/CustomFilters.php | 2 +- src/Liquid/Liquid.php | 18 +- src/Liquid/StandardFilters.php | 90 +++---- tests/Liquid/FilterbankTest.php | 372 +++++++++++++-------------- tests/Liquid/StandardFiltersTest.php | 2 +- tests/Liquid/Tag/TagForTest.php | 2 +- tests/Liquid/Tag/TagIncludeTest.php | 2 +- 8 files changed, 248 insertions(+), 248 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index a3dfaa3c..935d6f1b 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -11,8 +11,8 @@ $config = new PhpCsFixer\Config(); $config - ->setRiskyAllowed(true) - ->setRules([ + ->setRiskyAllowed(true) + ->setRules([ '@PSR2' => true, 'psr_autoloading' => true, 'no_unreachable_default_argument_value' => true, @@ -31,10 +31,10 @@ 'php_unit_mock' => true, 'php_unit_namespaced' => true, 'php_unit_no_expectation_annotation' => true, - "phpdoc_order_by_value" => ['annotations' => ['covers']], + "phpdoc_order_by_value" => ['annotations' => ['covers']], 'php_unit_set_up_tear_down_visibility' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], - 'no_whitespace_in_blank_line' => true, + 'no_whitespace_in_blank_line' => true, ]) ->setIndent("\t") ->setFinder( diff --git a/src/Liquid/CustomFilters.php b/src/Liquid/CustomFilters.php index de524a04..ce028fcf 100644 --- a/src/Liquid/CustomFilters.php +++ b/src/Liquid/CustomFilters.php @@ -16,7 +16,7 @@ */ class CustomFilters { - + /** * Sort an array by key. * diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 24974dab..93f6bd01 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -120,15 +120,15 @@ public static function get($key) } // This case is needed for compound settings switch ($key) { - case 'QUOTED_FRAGMENT': - return '(?:' . self::get('QUOTED_STRING') . '|[^\s,\|\'"]+)'; - case 'TAG_ATTRIBUTES': - return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; - case 'TOKENIZATION_REGEXP': - return '/(' . self::$config['TAG_START'] . '.*?' . self::$config['TAG_END'] . '|' . self::$config['VARIABLE_START'] . '.*?' . self::$config['VARIABLE_END'] . ')/s'; - default: - return null; - } + case 'QUOTED_FRAGMENT': + return '(?:' . self::get('QUOTED_STRING') . '|[^\s,\|\'"]+)'; + case 'TAG_ATTRIBUTES': + return '/(\w+)\s*\:\s*(' . self::get('QUOTED_FRAGMENT') . ')/'; + case 'TOKENIZATION_REGEXP': + return '/(' . self::$config['TAG_START'] . '.*?' . self::$config['TAG_END'] . '|' . self::$config['VARIABLE_START'] . '.*?' . self::$config['VARIABLE_END'] . ')/s'; + default: + return null; + } } /** diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 84aaf500..76400ee4 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -18,7 +18,7 @@ */ class StandardFilters { - + /** * Add one string to another * @@ -31,7 +31,7 @@ public static function append($input, $string) { return $input . $string; } - + /** * Capitalize words in the input sentence @@ -47,7 +47,7 @@ public static function capitalize($input) return $matches[1] . mb_strtoupper($first_char) . mb_substr($matches[2], 1); }, ucwords($input)); } - + /** * @param mixed $input number @@ -58,7 +58,7 @@ public static function ceil($input) { return (int) ceil((float)$input); } - + /** * Formats a date @@ -93,8 +93,8 @@ public static function date($input, $strftimeFormat = '%A, %B %e, %Y at %l:%S %P return $formatted; } - - + + /** * Default * @@ -108,8 +108,8 @@ public static function _default($input, $default_value) $isBlank = $input == '' || $input === false || $input === null; return $isBlank ? $default_value : $input; } - - + + /** * division * @@ -123,7 +123,7 @@ public static function divided_by($input, $operand) return (float)$input / (float)$operand; } - + /** * Convert an input to lowercase * @@ -135,8 +135,8 @@ public static function downcase($input) { return is_string($input) ? mb_strtolower($input) : $input; } - - + + /** * Pseudo-filter: negates auto-added escape filter * @@ -201,8 +201,8 @@ public static function first($input) } return is_array($input) ? reset($input) : $input; } - - + + /** * @param mixed $input number * @@ -212,8 +212,8 @@ public static function floor($input) { return (int) floor((float)$input); } - - + + /** * Joins elements of an array with a given character between them * @@ -236,8 +236,8 @@ public static function join($input, $glue = ' ') } return is_array($input) ? implode($glue, $input) : $input; } - - + + /** * Returns the last element of an array * @@ -256,7 +256,7 @@ public static function last($input) } return is_array($input) ? end($input) : $input; } - + /** * @param string $input @@ -267,8 +267,8 @@ public static function lstrip($input) { return ltrim($input); } - - + + /** * Map/collect on a given property * @@ -294,7 +294,7 @@ public static function map($input, $property) return null; }, $input); } - + /** * subtraction @@ -308,8 +308,8 @@ public static function minus($input, $operand) { return (float)$input - (float)$operand; } - - + + /** * modulo * @@ -322,8 +322,8 @@ public static function modulo($input, $operand) { return fmod((float)$input, (float)$operand); } - - + + /** * Replace each newline (\n) with html break * @@ -335,7 +335,7 @@ public static function newline_to_br($input) { return is_string($input) ? str_replace("\n", "
\n", $input) : $input; } - + /** * addition @@ -349,7 +349,7 @@ public static function plus($input, $operand) { return (float)$input + (float)$operand; } - + /** * Prepend a string to another @@ -363,7 +363,7 @@ public static function prepend($input, $string) { return $string . $input; } - + /** * Remove a substring @@ -395,7 +395,7 @@ public static function remove_first($input, $string) return $input; } - + /** * Replace occurrences of a string with another @@ -429,8 +429,8 @@ public static function replace_first($input, $string, $replacement = '') return $input; } - - + + /** * Reverse the elements of an array * @@ -445,8 +445,8 @@ public static function reverse($input) } return array_reverse($input); } - - + + /** * Round a number * @@ -459,8 +459,8 @@ public static function round($input, $n = 0) { return round((float)$input, (int)$n); } - - + + /** * @param string $input * @@ -471,7 +471,7 @@ public static function rstrip($input) return rtrim($input); } - + /** * Return the size of an array or of an string * @@ -503,7 +503,7 @@ public static function size($input) // only plain values and stringable objects left at this point return strlen($input); } - + /** * @param array|\Iterator|string $input @@ -525,8 +525,8 @@ public static function slice($input, $offset, $length = null) return $input; } - - + + /** * Sort the elements of an array * @@ -597,8 +597,8 @@ public static function strip($input) { return trim($input); } - - + + /** * Removes html tags from text * @@ -610,7 +610,7 @@ public static function strip_html($input) { return is_string($input) ? strip_tags($input) : $input; } - + /** * Strip all newlines (\n, \r) from string @@ -625,7 +625,7 @@ public static function strip_newlines($input) "\n", "\r" ), '', $input) : $input; } - + /** * multiplication @@ -639,7 +639,7 @@ public static function times($input, $operand) { return (float)$input * (float)$operand; } - + /** * Truncate a string down to x characters @@ -683,7 +683,7 @@ public static function truncatewords($input, $words = 3, $ending = '...') return $input; } - + /** * Remove duplicate elements from an array diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index dd490af0..ed7cd8cf 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -11,234 +11,234 @@ namespace { -/** - * Global function acts as a filter. - * - * @param $value - * - * @return string - */ -function functionFilter($value) -{ - return 'worked'; -} - -/** - * Global filter class - */ -class ClassFilter -{ - private $variable = 'not set'; - - public function __construct() + /** + * Global function acts as a filter. + * + * @param $value + * + * @return string + */ + function functionFilter($value) { + return 'worked'; } - public static function static_test() + /** + * Global filter class + */ + class ClassFilter { - return "worked"; - } + private $variable = 'not set'; - public function instance_test_one() - { - $this->variable = 'set'; - return 'set'; - } + public function __construct() + { + } - public function instance_test_two() - { - return $this->variable; + public static function static_test() + { + return "worked"; + } + + public function instance_test_one() + { + $this->variable = 'set'; + return 'set'; + } + + public function instance_test_two() + { + return $this->variable; + } } -} } // global namespace namespace Liquid { -use Liquid\Cache\File; + use Liquid\Cache\File; -class NamespacedClassFilter -{ - public static function static_test2($var) + class NamespacedClassFilter { - return "good {$var}"; + public static function static_test2($var) + { + return "good {$var}"; + } } -} - -class FilterbankTest extends TestCase -{ - /** @var FilterBank */ - private $filterBank; - - /** @var Context */ - private $context; - protected function setUp(): void + class FilterbankTest extends TestCase { - parent::setUp(); - - $this->context = new Context(); - $this->filterBank = new FilterBank($this->context); - } + /** @var FilterBank */ + private $filterBank; - protected function tearDown(): void - { - // have to destroy these else PHP goes nuts - unset($this->context); - unset($this->filterBank); - } + /** @var Context */ + private $context; - /** - */ - public function testAddFilterNotObjectAndString() - { - $this->expectException(\Liquid\Exception\WrongArgumentException::class); + protected function setUp(): void + { + parent::setUp(); - $this->filterBank->addFilter(array()); - } + $this->context = new Context(); + $this->filterBank = new FilterBank($this->context); + } - /** - */ - public function testAddFilterNoFunctionOrClass() - { - $this->expectException(\Liquid\Exception\WrongArgumentException::class); + protected function tearDown(): void + { + // have to destroy these else PHP goes nuts + unset($this->context); + unset($this->filterBank); + } - $this->filterBank->addFilter('no_such_function_or_class'); - } + /** + */ + public function testAddFilterNotObjectAndString() + { + $this->expectException(\Liquid\Exception\WrongArgumentException::class); - public function testTypeErrorExceptionAndCallDateFilterWithoutArguments() - { - if (\PHP_VERSION_ID < 70100) { - $this->markTestSkipped('TypeError is not thrown in PHP 7.0'); + $this->filterBank->addFilter(array()); } - $var = new Variable('var | date'); - $this->context->set('var', []); + /** + */ + public function testAddFilterNoFunctionOrClass() + { + $this->expectException(\Liquid\Exception\WrongArgumentException::class); - $this->expectException(\Liquid\LiquidException::class); - $var->render($this->context); - } + $this->filterBank->addFilter('no_such_function_or_class'); + } - public function testInvokeNoFilter() - { - $value = 'value'; - $this->assertEquals($value, $this->filterBank->invoke('non_existing_filter', $value)); - } + public function testTypeErrorExceptionAndCallDateFilterWithoutArguments() + { + if (\PHP_VERSION_ID < 70100) { + $this->markTestSkipped('TypeError is not thrown in PHP 7.0'); + } - /** - * Test using a simple function - */ - public function testFunctionFilter() - { - $var = new Variable('var | functionFilter'); - $this->context->set('var', 1000); - $this->context->addFilters('functionFilter'); - $this->assertEquals('worked', $var->render($this->context)); - } + $var = new Variable('var | date'); + $this->context->set('var', []); - /** - * Test using a namespaced static class - */ - public function testNamespacedStaticClassFilter() - { - $var = new Variable('var | static_test2'); - $this->context->set('var', 1000); - $this->context->addFilters(NamespacedClassFilter::class); - $this->assertEquals('good 1000', $var->render($this->context)); - } + $this->expectException(\Liquid\LiquidException::class); + $var->render($this->context); + } - /** - * Test using a static class - */ - public function testStaticClassFilter() - { - $var = new Variable('var | static_test'); - $this->context->set('var', 1000); - $this->context->addFilters(\ClassFilter::class); - $this->assertEquals('worked', $var->render($this->context)); - } + public function testInvokeNoFilter() + { + $value = 'value'; + $this->assertEquals($value, $this->filterBank->invoke('non_existing_filter', $value)); + } - /** - * Test with instance method on a static class - */ - public function testStaticMixedClassFilter() - { - $var = new Variable('var | instance_test_one'); - $this->context->set('var', 'foo'); - $this->context->addFilters(\ClassFilter::class); - $this->assertEquals('foo', $var->render($this->context)); - } + /** + * Test using a simple function + */ + public function testFunctionFilter() + { + $var = new Variable('var | functionFilter'); + $this->context->set('var', 1000); + $this->context->addFilters('functionFilter'); + $this->assertEquals('worked', $var->render($this->context)); + } - /** - * Test using an object as a filter; an object fiter will retain its state - * between calls to its filters. - */ - public function testObjectFilter() - { - $var = new Variable('var | instance_test_one'); - $this->context->set('var', 1000); - $this->context->addFilters(new \ClassFilter()); - $this->assertEquals('set', $var->render($this->context)); + /** + * Test using a namespaced static class + */ + public function testNamespacedStaticClassFilter() + { + $var = new Variable('var | static_test2'); + $this->context->set('var', 1000); + $this->context->addFilters(NamespacedClassFilter::class); + $this->assertEquals('good 1000', $var->render($this->context)); + } - $var = new Variable('var | instance_test_two'); - $this->assertEquals('set', $var->render($this->context)); + /** + * Test using a static class + */ + public function testStaticClassFilter() + { + $var = new Variable('var | static_test'); + $this->context->set('var', 1000); + $this->context->addFilters(\ClassFilter::class); + $this->assertEquals('worked', $var->render($this->context)); + } - $var = new Variable('var | static_test'); - $this->assertEquals('worked', $var->render($this->context)); + /** + * Test with instance method on a static class + */ + public function testStaticMixedClassFilter() + { + $var = new Variable('var | instance_test_one'); + $this->context->set('var', 'foo'); + $this->context->addFilters(\ClassFilter::class); + $this->assertEquals('foo', $var->render($this->context)); + } - $var = new Variable('var | __construct'); - $this->assertEquals('1000', $var->render($this->context)); - } + /** + * Test using an object as a filter; an object fiter will retain its state + * between calls to its filters. + */ + public function testObjectFilter() + { + $var = new Variable('var | instance_test_one'); + $this->context->set('var', 1000); + $this->context->addFilters(new \ClassFilter()); + $this->assertEquals('set', $var->render($this->context)); + + $var = new Variable('var | instance_test_two'); + $this->assertEquals('set', $var->render($this->context)); + + $var = new Variable('var | static_test'); + $this->assertEquals('worked', $var->render($this->context)); + + $var = new Variable('var | __construct'); + $this->assertEquals('1000', $var->render($this->context)); + } - public function testObjectFilterDontCallConstruct() - { - $this->context->set('var', 1000); - $this->context->addFilters(new \ClassFilter()); + public function testObjectFilterDontCallConstruct() + { + $this->context->set('var', 1000); + $this->context->addFilters(new \ClassFilter()); - $filterbankReflectionClass = new \ReflectionClass(Context::class); - $methodMapProperty = $filterbankReflectionClass->getProperty('filterbank'); - $methodMapProperty->setAccessible(true); - $filterbank = $methodMapProperty->getValue($this->context); + $filterbankReflectionClass = new \ReflectionClass(Context::class); + $methodMapProperty = $filterbankReflectionClass->getProperty('filterbank'); + $methodMapProperty->setAccessible(true); + $filterbank = $methodMapProperty->getValue($this->context); - $filterbankReflectionClass = new \ReflectionClass(Filterbank::class); - $methodMapProperty = $filterbankReflectionClass->getProperty('methodMap'); - $methodMapProperty->setAccessible(true); - $methodMap = $methodMapProperty->getValue($filterbank); + $filterbankReflectionClass = new \ReflectionClass(Filterbank::class); + $methodMapProperty = $filterbankReflectionClass->getProperty('methodMap'); + $methodMapProperty->setAccessible(true); + $methodMap = $methodMapProperty->getValue($filterbank); - $this->assertArrayNotHasKey('__construct', $methodMap); + $this->assertArrayNotHasKey('__construct', $methodMap); - $var = new Variable('var | __construct'); - $this->assertEquals('1000', $var->render($this->context)); - } + $var = new Variable('var | __construct'); + $this->assertEquals('1000', $var->render($this->context)); + } - public function testCallbackFilter() - { - $var = new Variable('var | my_callback'); - $this->context->set('var', 1000); - $this->context->addFilters('my_callback', function ($var) { - return $var * 2; - }); - $this->assertEquals('2000', $var->render($this->context)); - } + public function testCallbackFilter() + { + $var = new Variable('var | my_callback'); + $this->context->set('var', 1000); + $this->context->addFilters('my_callback', function ($var) { + return $var * 2; + }); + $this->assertEquals('2000', $var->render($this->context)); + } - /** - * Closures are not to be serialized. Let's check that. - */ - public function testWithSerializingCache() - { - $template = new Template(); - $template->registerFilter('foo', function ($arg) { - return "Foo $arg"; - }); - $template->setCache(new File(array( - 'cache_dir' => __DIR__.'/cache_dir/', - ))); - $template->parse("{{'test' | foo }}"); - $this->assertEquals('Foo test', $template->render()); - - $template->parse("{{'bar' | foo }}"); - $this->assertEquals('Foo bar', $template->render()); + /** + * Closures are not to be serialized. Let's check that. + */ + public function testWithSerializingCache() + { + $template = new Template(); + $template->registerFilter('foo', function ($arg) { + return "Foo $arg"; + }); + $template->setCache(new File(array( + 'cache_dir' => __DIR__.'/cache_dir/', + ))); + $template->parse("{{'test' | foo }}"); + $this->assertEquals('Foo test', $template->render()); + + $template->parse("{{'bar' | foo }}"); + $this->assertEquals('Foo bar', $template->render()); + } } -} } // Liquid namespace diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 899336fe..79516c51 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -1126,7 +1126,7 @@ public function testSecondFilterOverwritesFirst() public function testDate() { $dateVar = '2017-07-01 21:00:00'; - + $var = new Variable('var | date, "%Y"'); $this->context->set('var', $dateVar); $this->assertEquals('2017', $var->render($this->context)); diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index 72ec2c60..ebea7fd4 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -62,7 +62,7 @@ public function testForWithVariable() $this->assertTemplateResult('abc', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', '', 'b', '', 'c'))); $this->assertTemplateResult(' a ', "{%\nfor item in array%} {{item}} {%endfor%}", array('array' => array('a'))); } - + public function testForWithHash() { $this->assertTemplateResult('a=b c=d e=f ', '{%for item in array%}{{item[0]}}={{item[1]}} {%endfor%}', array('array' => array('a' => 'b', 'c' => 'd', 'e' => 'f'))); diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 07335dac..234dfe0d 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -158,7 +158,7 @@ public function testIncludePassArrayWithoutIndex() ))); $template->parse("{% include 'example' %}"); - + $output = $template->render(array("var" => array("a", "b", "c"))); $this->assertEquals("([abc])", $output); } From 321174645129c0d1a35dde8fa6f888190a6b0245 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 11:59:18 +0900 Subject: [PATCH 273/296] Ignore CS changes on git blame --- .git-blame-ignore-revs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000..42492d25 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view +# https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt + +72c7e3f4e34d2ed474b1399f2a7ab427fb6f3b14 From d3703d8207de365df054a0fec958ade25c0a1f19 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 12:03:11 +0900 Subject: [PATCH 274/296] Skip test on PHP 8 --- tests/Liquid/VirtualFileSystemTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index 5b096abd..e78287a9 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -75,7 +75,12 @@ public function testWithRegularCallback() 'cache_dir' => __DIR__.'/cache_dir/', ))); - $template->parse("Test: {% include 'hello' %}"); + try { + $template->parse("Test: {% include 'hello' %}"); + } catch (\Throwable $e) { + $this->assertStringContainsString("Serialization of 'DOMDocument' is not allowed", $e->getMessage()); + $this->markTestIncomplete(); + } $this->assertEquals('Test: OK', $template->render()); } } From 80eda0205b788358fc5badf344b01342fb89dcba Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Aug 2023 12:05:21 +0900 Subject: [PATCH 275/296] Bump Composer version --- .github/workflows/cs.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml index 57cab33f..aa07a8fe 100644 --- a/.github/workflows/cs.yaml +++ b/.github/workflows/cs.yaml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - php-version: ['7.4'] + php-version: ['8.2'] name: PHP ${{ matrix.php-version }} @@ -23,9 +23,9 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} - extensions: + extensions: coverage: pcov - tools: composer:v1 + tools: composer:v2 - name: Cache dependencies uses: actions/cache@v2 From c76f0b81e5d170e180875b745952755cbe9dd4e1 Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Wed, 9 Aug 2023 10:31:33 +0300 Subject: [PATCH 276/296] Fix sort different array keys (#202) --- src/Liquid/StandardFilters.php | 4 ++-- tests/Liquid/StandardFiltersTest.php | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 20c20d93..da670472 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -559,11 +559,11 @@ public static function sort($input, $property = null) $first = reset($input); if ($first !== false && is_array($first) && array_key_exists($property, $first)) { uasort($input, function ($a, $b) use ($property) { - if ($a[$property] == $b[$property]) { + if (($a[$property] ?? 0) == ($b[$property] ?? 0)) { return 0; } - return $a[$property] < $b[$property] ? -1 : 1; + return ($a[$property] ?? 0) < ($b[$property] ?? 0) ? -1 : 1; }); } } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 2f059587..bc6c0be4 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -591,6 +591,28 @@ public function testSort() $this->assertEquals($expected, array_values(StandardFilters::sort(new \ArrayIterator($original), 'b'))); } + public function testSortWithoutKey() + { + // Sort by inner key + $original = array( + array('a' => 20, 'b' => 10), + array('a' => 45, 'b' => 5), + array('a' => 40, 'b' => 6), + array('a' => 30, 'b' => 48), + array('a' => 50), + ); + $expected = array( + array('a' => 50), + array('a' => 45, 'b' => 5), + array('a' => 40, 'b' => 6), + array('a' => 20, 'b' => 10), + array('a' => 30, 'b' => 48), + ); + + $this->assertEquals($expected, array_values(StandardFilters::sort($original, 'b'))); + $this->assertEquals($expected, array_values(StandardFilters::sort(new \ArrayIterator($original), 'b'))); + } + /* I've commented this out as its not one of the Ruby Standard Filters From 71b1d11805aad546292823846b9b7ac04686f43a Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Thu, 28 Dec 2023 02:35:48 +0300 Subject: [PATCH 277/296] Add where filter for array (#209) --- src/Liquid/StandardFilters.php | 21 +++++++++++++++++++++ src/Liquid/Tag/TagFor.php | 5 +++++ src/Liquid/Tag/TagPaginate.php | 2 +- tests/Liquid/ContextTest.php | 8 +++++++- tests/Liquid/FilterbankTest.php | 6 ++++++ tests/Liquid/OutputTest.php | 24 ++++++++++++++++++++++++ tests/Liquid/StandardFiltersTest.php | 22 ++++++++++++++++++++++ 7 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index da670472..d3a8bf66 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -162,6 +162,27 @@ public static function json($input) return json_encode($input); } + /** + * Creates an array including only the objects with a given property value + * @link https://shopify.github.io/liquid/filters/where/ + * + * @param array $input + * @param string ...$args + * + * @throws LiquidException + * @return array + */ + public static function where(array $input, string ...$args): array + { + switch (count($args)) { + case 1: + return array_filter($input, fn ($v) => ($v[$args[0]] ?? null) !== null); + case 2: + return array_filter($input, fn ($v) => ($v[$args[0]] ?? '') == $args[1]); + default: + throw new LiquidException('Wrong number of arguments to function `where`, given ' . count($args) . ', expected 1 or 2'); + } + } /** * Escape a string diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index e1468877..edf732ca 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -50,6 +50,11 @@ class TagFor extends AbstractBlock */ private $name; + /** + * @var string + */ + private $start; + /** * @var string The type of the loop (collection or digit) */ diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index afafaef3..35726c5e 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -187,7 +187,7 @@ public function render(Context $context) public function currentUrl($context, $queryPart = []) { // From here we have $url->path and $url->query - $url = (object) parse_url($context->get('REQUEST_URI')); + $url = (object) parse_url($context->get('REQUEST_URI') ?: ''); // Let's merge the query part if (isset($url->query)) { diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index b95abea1..1321f784 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -85,7 +85,7 @@ public function toLiquid() class CountableObject implements \Countable { - public function count() + public function count(): int { return 2; } @@ -135,6 +135,8 @@ public function __get($prop) class HiFilter { + public Context $context; + public function hi($value) { return $value . ' hi!'; @@ -143,6 +145,8 @@ public function hi($value) class GlobalFilter { + public Context $context; + public function notice($value) { return "Global $value"; @@ -151,6 +155,8 @@ public function notice($value) class LocalFilter { + public Context $context; + public function notice($value) { return "Local $value"; diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index ed7cd8cf..a52855ec 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -11,6 +11,8 @@ namespace { + use Liquid\Context; + /** * Global function acts as a filter. * @@ -28,6 +30,8 @@ function functionFilter($value) */ class ClassFilter { + public Context $context; + private $variable = 'not set'; public function __construct() @@ -59,6 +63,8 @@ public function instance_test_two() class NamespacedClassFilter { + public Context $context; + public static function static_test2($var) { return "good {$var}"; diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index a18b048a..1b2fdf50 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -13,6 +13,8 @@ class FunnyFilter { + public Context $context; + public function make_funny($input) { return 'LOL'; @@ -191,4 +193,26 @@ public function testVariableWithANewLine() $text = "{{ aaa\n }}"; $this->assertTemplateResult('', $text, $this->assigns); } + + public function testFilterArray() + { + $text = ' {{ cars | where: "model", "bmw" | json }} '; + $expected = ' [{"model":"bmw"}] '; + + $this->assertTemplateResult($expected, $text, ['cars' => [ + ['model' => 'bmw'], + ['model' => 'audi'], + ]]); + } + + public function testFilterArrayTruthy() + { + $text = ' {{ cars | where: "available" | json }} '; + $expected = ' [{"model":"bmw","available":1}] '; + + $this->assertTemplateResult($expected, $text, ['cars' => [ + ['model' => 'bmw', 'available' => 1], + ['model' => 'audi'], + ]]); + } } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index bc6c0be4..729266b2 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -13,6 +13,8 @@ class MoneyFilter { + public Context $context; + public function money($value) { return sprintf(' %d$ ', $value); @@ -26,6 +28,8 @@ public function money_with_underscore($value) class CanadianMoneyFilter { + public Context $context; + public function money($value) { return sprintf(' %d$ CAD ', $value); @@ -204,6 +208,24 @@ public function testJson() } } + public function testWhere() + { + $data = [ + [ + 'before' => [['model' => 'bmw'], ['model' => 'audi']], + 'after' => [['model' => 'bmw']], + ], + [ + 'before' => ['model' => 'bmw'], + 'after' => [], + ], + ]; + + foreach ($data as $testCase) { + $this->assertEquals($testCase['after'], StandardFilters::where($testCase['before'], 'model', 'bmw')); + } + } + public function testEscape() { $data = array( From 36b1289f6962829edf70003801295e08c657544d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 28 Dec 2023 09:31:04 +0900 Subject: [PATCH 278/296] Test on PHP 8.3 (#210) --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 94dbc939..f24398c8 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,7 +16,7 @@ jobs: strategy: matrix: - php-version: ['7.4', '8.0', '8.1', '8.2'] + php-version: ['7.4', '8.0', '8.1', '8.2', '8.3'] include: - { php-version: '7.4', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } From c503efd5a0e5c1cd5542047c560391232851b41e Mon Sep 17 00:00:00 2001 From: Sergey Odintsov Date: Tue, 9 Jan 2024 16:20:01 +0300 Subject: [PATCH 279/296] Fix array where method with multiple input types (#211) --- src/Liquid/StandardFilters.php | 23 +++++++++++++---------- tests/Liquid/OutputTest.php | 9 +++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index d3a8bf66..433bd416 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -166,22 +166,25 @@ public static function json($input) * Creates an array including only the objects with a given property value * @link https://shopify.github.io/liquid/filters/where/ * - * @param array $input + * @param mixed $input * @param string ...$args * * @throws LiquidException - * @return array + * @return mixed */ - public static function where(array $input, string ...$args): array + public static function where($input, string ...$args) { - switch (count($args)) { - case 1: - return array_filter($input, fn ($v) => ($v[$args[0]] ?? null) !== null); - case 2: - return array_filter($input, fn ($v) => ($v[$args[0]] ?? '') == $args[1]); - default: - throw new LiquidException('Wrong number of arguments to function `where`, given ' . count($args) . ', expected 1 or 2'); + if (is_array($input)) { + switch (count($args)) { + case 1: + return array_values(array_filter($input, fn ($v) => !in_array($v[$args[0]] ?? null, [null, false], true))); + case 2: + return array_values(array_filter($input, fn ($v) => ($v[$args[0]] ?? '') == $args[1])); + default: + throw new LiquidException('Wrong number of arguments to function `where`, given ' . count($args) . ', expected 1 or 2'); + } } + return $input; } /** diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index 1b2fdf50..c9e300b3 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -213,6 +213,15 @@ public function testFilterArrayTruthy() $this->assertTemplateResult($expected, $text, ['cars' => [ ['model' => 'bmw', 'available' => 1], ['model' => 'audi'], + ['model' => 'toyota', 'available' => false], ]]); } + + public function testFilterArrayNull() + { + $text = ' {{ cars | where: "available" | json }} '; + $expected = ' null '; + + $this->assertTemplateResult($expected, $text, []); + } } From 1f4477cb62e6bbe9147bff9b7742cfe494aa41b8 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 19 Mar 2024 15:42:28 +0900 Subject: [PATCH 280/296] Improve StandardFiltersTest (#214) --- tests/Liquid/StandardFiltersTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 729266b2..b8efb7a2 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -876,10 +876,15 @@ public function testSplit() 'two-one-three', array('two', 'one', 'three'), ), + array( + '12301230123', + array('123', '123', '123'), + '0' + ), ); foreach ($data as $item) { - $this->assertEquals($item[1], StandardFilters::split($item[0], '-')); + $this->assertEquals($item[1], StandardFilters::split($item[0], $item[2] ?? '-')); } } From de705d5629f037ce078ae068fd98c6cd2ef6ba51 Mon Sep 17 00:00:00 2001 From: oleksii-pavlikovskii-eleks-com <118443397+oleksii-pavlikovskii-eleks-com@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:22:06 +0200 Subject: [PATCH 281/296] Fix split filter for php >=8.0 in case of empty separator (#213) Co-authored-by: pavlikovsky --- src/Liquid/StandardFilters.php | 4 ++++ tests/Liquid/StandardFiltersTest.php | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 433bd416..76a9f7d1 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -621,6 +621,10 @@ public static function split($input, $pattern) return []; } + if ($pattern === '') { + return mb_str_split($input); + } + return explode($pattern, $input); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index b8efb7a2..8bafd465 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -881,6 +881,21 @@ public function testSplit() array('123', '123', '123'), '0' ), + array( + 'phrase', + array('p', 'h', 'r', 'a', 's', 'e'), + '' + ), + array( + 'phrase', + array('phrase'), + null + ), + array( + '123 123 123', + array('123', '123', '123'), + ' ' + ), ); foreach ($data as $item) { From f6befea68ae19c68524ac23cd327e0c2ec400889 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 4 Oct 2024 15:14:17 +0900 Subject: [PATCH 282/296] Mutation testing on PHP 8.3 (#219) --- .github/workflows/mt.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml index f4b360ff..c99f7255 100644 --- a/.github/workflows/mt.yaml +++ b/.github/workflows/mt.yaml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - php-version: ['8.2'] + php-version: ['8.3'] dependencies: [''] name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} @@ -44,5 +44,5 @@ jobs: - name: Run mutation testing run: | - php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --show-mutations --threads=$(nproc) + php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --threads=$(nproc) --no-progress From 3a472d5a87fd40c075eea2c4afec5028564e00c1 Mon Sep 17 00:00:00 2001 From: Fede Isas Date: Fri, 4 Oct 2024 03:14:41 -0300 Subject: [PATCH 283/296] Fix: htmlentities() shouldn't be called with null (#218) * Fix: htmlentities(): Passing null to parameter 1 ($string) of type string is deprecated --- src/Liquid/StandardFilters.php | 4 ++++ tests/Liquid/StandardFiltersTest.php | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index 76a9f7d1..c3e274d6 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -201,6 +201,10 @@ public static function escape($input) return $input; } + if (is_null($input)) { + return ''; + } + return htmlentities($input, ENT_QUOTES); } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 8bafd465..701e9996 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -231,6 +231,7 @@ public function testEscape() $data = array( "one Word's not" => "one Word's not", "&><\"'" => "&><"'", + null => '', ); foreach ($data as $element => $expected) { From 502820cb2faac6e57a6b9a6def4449e56710aed6 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Oct 2024 08:07:46 +0900 Subject: [PATCH 284/296] AbstractTag: add cached instance of the config, to improve performance (#220) --- src/Liquid/AbstractTag.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index 6b382672..af20bcba 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -37,6 +37,13 @@ abstract class AbstractTag */ protected $attributes = array(); + /** + * A cached instance of the config array, for performance reasons. + * + * @var array + */ + protected $config = array(); + /** * Constructor. * @@ -48,6 +55,8 @@ public function __construct($markup, array &$tokens, FileSystem $fileSystem = nu { $this->markup = $markup; $this->fileSystem = $fileSystem; + $this->config = &Liquid::$config; + $this->parse($tokens); } From 906686c274e3c7faf145c6cb11b40a417ef13cae Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Mon, 7 Oct 2024 08:09:54 +0900 Subject: [PATCH 285/296] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f29aad6..2a66e466 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Adding filters has never been easier. ## Requirements - * PHP 7.0+ + * PHP 7.4+ Some earlier versions could be used with PHP 5.3/5.4/5.5/5.6, though they're not supported anymore. From ac914b7ebaa6e9144d21de24693c9a0ea40d4be2 Mon Sep 17 00:00:00 2001 From: John Rayes Date: Fri, 28 Mar 2025 17:23:04 -0700 Subject: [PATCH 286/296] Create dependabot.yml (#221) * Create dependabot.yml This file is used to automate the process of keeping the GitHub Actions dependencies up to date by configuring Dependabot to check for updates on a weekly basis and apply them as needed. * Update .github/dependabot.yml --------- Co-authored-by: Alexey Kopytko --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..57661264 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" From 66e7e29d3b179ff0c6acbeb2019247f01a6260a7 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 29 Mar 2025 09:40:12 +0900 Subject: [PATCH 287/296] Fix GH Actions config (#222) --- .github/dependabot.yml | 9 +++++++-- .github/workflows/cs.yaml | 4 ++-- .github/workflows/mt.yaml | 4 ++-- .github/workflows/tests.yaml | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 57661264..97ddf0db 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,12 @@ version: 2 updates: - - package-ecosystem: "github-actions" # See documentation for possible values - directory: "/" # Location of package manifests + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + + - package-ecosystem: "composer" + directory: "/" schedule: interval: "monthly" diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml index aa07a8fe..8d920181 100644 --- a/.github/workflows/cs.yaml +++ b/.github/workflows/cs.yaml @@ -17,7 +17,7 @@ jobs: name: PHP ${{ matrix.php-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -28,7 +28,7 @@ jobs: tools: composer:v2 - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/composer key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml index c99f7255..70070bdc 100644 --- a/.github/workflows/mt.yaml +++ b/.github/workflows/mt.yaml @@ -19,7 +19,7 @@ jobs: name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -30,7 +30,7 @@ jobs: tools: composer:v2 - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.cache/composer key: composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.*') }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f24398c8..fb423725 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -23,7 +23,7 @@ jobs: name: PHP ${{ matrix.php-version }} ${{ matrix.legend }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -37,7 +37,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: composer-${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('composer.*') }}-${{ matrix.composer-flags }} From a3eb2188e7bd6fff958645b07bd6d5e9413d74e3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 11:26:23 +0900 Subject: [PATCH 288/296] Improve PHP-CS-Fixer configuration (#225) --- .php-cs-fixer.dist.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 935d6f1b..54575916 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -1,5 +1,14 @@ setParallelConfig(PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()) ->setRiskyAllowed(true) ->setRules([ '@PSR2' => true, @@ -40,6 +50,7 @@ ->setFinder( PhpCsFixer\Finder::create() ->in(__DIR__) + ->append([__FILE__]) ) ; From 772eb3997e624f077607553a3dc2a10447d04882 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 18:37:10 +0900 Subject: [PATCH 289/296] Ignore all .dot files (#226) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 072705cd..cfa1a18f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -.idea/ +.?* vendor/ composer.lock From a07411c0f7e3de085a621a1807c1998f6cc24d73 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 19:11:17 +0900 Subject: [PATCH 290/296] PHP 8.4 compatibility (implicit nullable types) (#228) Co-authored-by: Graham Campbell Co-authored-by: Graham Campbell --- .github/workflows/cs.yaml | 5 +++-- .github/workflows/mt.yaml | 7 ++++--- .github/workflows/tests.yaml | 8 +++++++- .php-cs-fixer.dist.php | 5 +++-- composer.json | 8 ++++---- src/Liquid/AbstractTag.php | 4 ++-- src/Liquid/Context.php | 2 +- src/Liquid/Document.php | 4 ++-- src/Liquid/Filterbank.php | 2 +- src/Liquid/Tag/TagAssign.php | 4 ++-- src/Liquid/Tag/TagBlock.php | 4 ++-- src/Liquid/Tag/TagCapture.php | 4 ++-- src/Liquid/Tag/TagCase.php | 4 ++-- src/Liquid/Tag/TagCycle.php | 4 ++-- src/Liquid/Tag/TagDecrement.php | 4 ++-- src/Liquid/Tag/TagExtends.php | 4 ++-- src/Liquid/Tag/TagFor.php | 4 ++-- src/Liquid/Tag/TagIf.php | 4 ++-- src/Liquid/Tag/TagIfchanged.php | 4 ++-- src/Liquid/Tag/TagInclude.php | 4 ++-- src/Liquid/Tag/TagIncrement.php | 4 ++-- src/Liquid/Tag/TagPaginate.php | 4 ++-- src/Liquid/Tag/TagTablerow.php | 4 ++-- src/Liquid/Template.php | 2 +- 24 files changed, 56 insertions(+), 47 deletions(-) diff --git a/.github/workflows/cs.yaml b/.github/workflows/cs.yaml index 8d920181..2d136cbb 100644 --- a/.github/workflows/cs.yaml +++ b/.github/workflows/cs.yaml @@ -12,7 +12,8 @@ jobs: strategy: matrix: - php-version: ['8.2'] + php-version: + - '8.3' name: PHP ${{ matrix.php-version }} @@ -43,4 +44,4 @@ jobs: - name: Check code style run: | php vendor/bin/php-cs-fixer --using-cache=no --diff --dry-run --stop-on-violation --verbose fix - + diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml index 70070bdc..ddab4efb 100644 --- a/.github/workflows/mt.yaml +++ b/.github/workflows/mt.yaml @@ -13,7 +13,8 @@ jobs: strategy: matrix: - php-version: ['8.3'] + php-version: + - '8.4' dependencies: [''] name: PHP ${{ matrix.php-version }} ${{ matrix.dependencies }} @@ -25,7 +26,7 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} - extensions: + extensions: coverage: pcov tools: composer:v2 @@ -45,4 +46,4 @@ jobs: - name: Run mutation testing run: | php vendor/bin/infection --min-msi=80 --min-covered-msi=80 --threads=$(nproc) --no-progress - + diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index fb423725..09b3ea9f 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -16,7 +16,13 @@ jobs: strategy: matrix: - php-version: ['7.4', '8.0', '8.1', '8.2', '8.3'] + php-version: + - '7.4' + - '8.0' + - '8.1' + - '8.2' + - '8.3' + - '8.4' include: - { php-version: '7.4', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 54575916..f549e542 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -41,10 +41,11 @@ 'php_unit_mock' => true, 'php_unit_namespaced' => true, 'php_unit_no_expectation_annotation' => true, - "phpdoc_order_by_value" => ['annotations' => ['covers']], + "phpdoc_order_by_value" => ['annotations' => ['covers']], 'php_unit_set_up_tear_down_visibility' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], - 'no_whitespace_in_blank_line' => true, + 'no_whitespace_in_blank_line' => true, + 'nullable_type_declaration_for_default_null_value' => true, ]) ->setIndent("\t") ->setFinder( diff --git a/composer.json b/composer.json index c25a6b7e..3fdc946f 100644 --- a/composer.json +++ b/composer.json @@ -30,11 +30,11 @@ "php": "^7.4 || ^8.0" }, "require-dev": { - "ergebnis/composer-normalize": ">=2.8", - "friendsofphp/php-cs-fixer": "^3.22", + "ergebnis/composer-normalize": ">=2.47", + "friendsofphp/php-cs-fixer": "^3.75", "infection/infection": ">=0.17.6", - "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^9.2.6" + "php-coveralls/php-coveralls": "^2.8", + "phpunit/phpunit": "^9.6.23" }, "config": { "sort-packages": true, diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index af20bcba..36a21938 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -49,9 +49,9 @@ abstract class AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $this->markup = $markup; $this->fileSystem = $fileSystem; diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 251faa05..3a50e747 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -97,7 +97,7 @@ public function setTickFunction(callable $tickFunction) * * @param mixed $filter */ - public function addFilters($filter, callable $callback = null) + public function addFilters($filter, ?callable $callback = null) { $this->filterbank->addFilter($filter, $callback); } diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index ec7e3508..e2398d99 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -24,9 +24,9 @@ class Document extends AbstractBlock * Constructor. * * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem */ - public function __construct(array &$tokens, FileSystem $fileSystem = null) + public function __construct(array &$tokens, ?FileSystem $fileSystem = null) { $this->fileSystem = $fileSystem; $this->parse($tokens); diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index 53775c60..ca16c43d 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -62,7 +62,7 @@ public function __construct(Context $context) * @throws \Liquid\Exception\WrongArgumentException * @return bool */ - public function addFilter($filter, callable $callback = null) + public function addFilter($filter, ?callable $callback = null) { // If it is a callback, save it as it is if (is_string($filter) && $callback) { diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index 76dabda2..d47710f6 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -44,11 +44,11 @@ class TagAssign extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $syntaxRegexp = new Regexp('/(\w+)\s*=\s*(.*)\s*/'); diff --git a/src/Liquid/Tag/TagBlock.php b/src/Liquid/Tag/TagBlock.php index c1f63cbf..188e13b2 100644 --- a/src/Liquid/Tag/TagBlock.php +++ b/src/Liquid/Tag/TagBlock.php @@ -37,12 +37,12 @@ class TagBlock extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException * @return \Liquid\Tag\TagBlock */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $syntaxRegexp = new Regexp('/(\w+)/'); diff --git a/src/Liquid/Tag/TagCapture.php b/src/Liquid/Tag/TagCapture.php index 1995d667..afcd1a02 100644 --- a/src/Liquid/Tag/TagCapture.php +++ b/src/Liquid/Tag/TagCapture.php @@ -38,11 +38,11 @@ class TagCapture extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $syntaxRegexp = new Regexp('/(\w+)/'); diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 1563042a..0b17b207 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -60,11 +60,11 @@ class TagCase extends Decision * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $this->nodelists = array(); $this->elseNodelist = array(); diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index 21408474..509b56c9 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -51,11 +51,11 @@ class TagCycle extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $simpleSyntax = new Regexp("/" . Liquid::get('QUOTED_FRAGMENT') . "/"); $namedSyntax = new Regexp("/(" . Liquid::get('QUOTED_FRAGMENT') . ")\s*\:\s*(.*)/"); diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index 2a768872..dde684eb 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -41,11 +41,11 @@ class TagDecrement extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 8c88a297..0c27d55c 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -50,11 +50,11 @@ class TagExtends extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $regex = new Regexp('/("[^"]+"|\'[^\']+\')?/'); diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index edf732ca..cd6ae116 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -65,11 +65,11 @@ class TagFor extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index 01904a72..67495d4d 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -49,9 +49,9 @@ class TagIf extends Decision * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $this->nodelist = & $this->nodelistHolders[count($this->blocks)]; diff --git a/src/Liquid/Tag/TagIfchanged.php b/src/Liquid/Tag/TagIfchanged.php index ae4cec1f..42eb371d 100644 --- a/src/Liquid/Tag/TagIfchanged.php +++ b/src/Liquid/Tag/TagIfchanged.php @@ -32,11 +32,11 @@ class TagIfchanged extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\LiquidException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); } diff --git a/src/Liquid/Tag/TagInclude.php b/src/Liquid/Tag/TagInclude.php index 481cdbab..fe03d9b6 100644 --- a/src/Liquid/Tag/TagInclude.php +++ b/src/Liquid/Tag/TagInclude.php @@ -72,11 +72,11 @@ class TagInclude extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $regex = new Regexp('/("[^"]+"|\'[^\']+\'|[^\'"\s]+)(\s+(with|for)\s+(' . Liquid::get('QUOTED_FRAGMENT') . '+))?/'); diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index ed428c88..91fe0f85 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -41,11 +41,11 @@ class TagIncrement extends AbstractTag * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 35726c5e..75916beb 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -75,12 +75,12 @@ class TagPaginate extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException * */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 13cf6e3d..6632857a 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -50,11 +50,11 @@ class TagTablerow extends AbstractBlock * * @param string $markup * @param array $tokens - * @param FileSystem $fileSystem + * @param FileSystem|null $fileSystem * * @throws \Liquid\Exception\ParseException */ - public function __construct($markup, array &$tokens, FileSystem $fileSystem = null) + public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { parent::__construct($markup, $tokens, $fileSystem); diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index 14a8c64e..eb2953fd 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -146,7 +146,7 @@ public static function getTags() * * @param string $filter */ - public function registerFilter($filter, callable $callback = null) + public function registerFilter($filter, ?callable $callback = null) { // Store callback for later use if ($callback) { From 2a9d2d741a4887920b7c0dccadc43abd4ace800b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 19:17:28 +0900 Subject: [PATCH 291/296] Bring array syntax up to speed --- .php-cs-fixer.dist.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f549e542..77312786 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -46,6 +46,9 @@ 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'], 'no_whitespace_in_blank_line' => true, 'nullable_type_declaration_for_default_null_value' => true, + 'array_syntax' => ['syntax' => 'short'], + 'trailing_comma_in_multiline' => ['elements' => ['arrays']], + 'binary_operator_spaces' => ['default' => 'at_least_single_space'], ]) ->setIndent("\t") ->setFinder( From d837112369c0193def1c27636da1b9a8df5c98f3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 19:20:04 +0900 Subject: [PATCH 292/296] Apply the PHP-CS-Fixer ruleset --- examples/block.php | 8 +- examples/filters.php | 6 +- examples/index.php | 46 +- examples/simple.php | 2 +- src/Liquid/AbstractBlock.php | 4 +- src/Liquid/AbstractTag.php | 6 +- src/Liquid/Cache.php | 2 +- src/Liquid/Cache/Apc.php | 2 +- src/Liquid/Cache/File.php | 2 +- src/Liquid/Cache/Local.php | 4 +- src/Liquid/Context.php | 22 +- src/Liquid/Drop.php | 2 +- src/Liquid/FileSystem/Local.php | 2 +- src/Liquid/Filterbank.php | 4 +- src/Liquid/Liquid.php | 6 +- src/Liquid/Regexp.php | 2 +- src/Liquid/StandardFilters.php | 6 +- src/Liquid/Tag/TagCase.php | 10 +- src/Liquid/Tag/TagCycle.php | 4 +- src/Liquid/Tag/TagExtends.php | 6 +- src/Liquid/Tag/TagFor.php | 22 +- src/Liquid/Tag/TagIf.php | 18 +- src/Liquid/Tag/TagPaginate.php | 8 +- src/Liquid/Tag/TagRaw.php | 2 +- src/Liquid/Tag/TagTablerow.php | 6 +- src/Liquid/Template.php | 8 +- src/Liquid/Variable.php | 14 +- tests/Liquid/Cache/FileTest.php | 6 +- tests/Liquid/ContextTest.php | 52 +- tests/Liquid/CustomFiltersTest.php | 20 +- tests/Liquid/DropTest.php | 16 +- tests/Liquid/EscapeByDefaultTest.php | 12 +- tests/Liquid/FilterbankTest.php | 6 +- tests/Liquid/LiquidTest.php | 32 +- tests/Liquid/OutputTest.php | 8 +- tests/Liquid/RegexpTest.php | 16 +- tests/Liquid/StandardFiltersTest.php | 866 +++++++++---------- tests/Liquid/Tag/TagAssignTest.php | 8 +- tests/Liquid/Tag/TagBreakTest.php | 12 +- tests/Liquid/Tag/TagCaptureTest.php | 2 +- tests/Liquid/Tag/TagCaseTest.php | 20 +- tests/Liquid/Tag/TagContinueTest.php | 12 +- tests/Liquid/Tag/TagCycleTest.php | 2 +- tests/Liquid/Tag/TagDecrementTest.php | 6 +- tests/Liquid/Tag/TagExtendsTest.php | 38 +- tests/Liquid/Tag/TagForTest.php | 52 +- tests/Liquid/Tag/TagIfTest.php | 84 +- tests/Liquid/Tag/TagIfchangedTest.php | 4 +- tests/Liquid/Tag/TagIncludeTest.php | 66 +- tests/Liquid/Tag/TagIncrementTest.php | 4 +- tests/Liquid/Tag/TagPaginateTest.php | 12 +- tests/Liquid/Tag/TagRawTest.php | 2 +- tests/Liquid/Tag/TagTablerowTest.php | 12 +- tests/Liquid/Tag/TagUnlessTest.php | 8 +- tests/Liquid/TemplateTest.php | 30 +- tests/Liquid/TestCase.php | 6 +- tests/Liquid/TickTest.php | 2 +- tests/Liquid/VariableResolutionTest.php | 10 +- tests/Liquid/VariableTest.php | 28 +- tests/Liquid/VirtualFileSystemTest.php | 10 +- tests/Liquid/fixtures/assign.php | 8 +- tests/Liquid/fixtures/case.php | 4 +- tests/Liquid/fixtures/comment.php | 2 +- tests/Liquid/fixtures/cycle.php | 2 +- tests/Liquid/fixtures/filters.php | 14 +- tests/Liquid/fixtures/for.php | 18 +- tests/Liquid/fixtures/include.php | 2 +- tests/Liquid/fixtures/iterable.php | 4 +- tests/Liquid/fixtures/output.php | 10 +- tests/Liquid/fixtures/whitespace-control.php | 2 +- 70 files changed, 877 insertions(+), 877 deletions(-) diff --git a/examples/block.php b/examples/block.php index b7832d0e..dfb11286 100644 --- a/examples/block.php +++ b/examples/block.php @@ -28,12 +28,12 @@ $liquid->parse(file_get_contents($protectedPath . 'templates' . DIRECTORY_SEPARATOR . 'child.tpl')); -$assigns = array( - 'document' => array( +$assigns = [ + 'document' => [ 'title' => 'This is php-liquid', 'content' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.', 'copyright' => '© Copyright 2014 Guz Alexander - All rights reserved.', - ), -); + ], +]; echo $liquid->render($assigns); diff --git a/examples/filters.php b/examples/filters.php index 95c80c24..0aa2872b 100644 --- a/examples/filters.php +++ b/examples/filters.php @@ -19,7 +19,7 @@ return "https://www.example.com$arg"; }); $template->parse("{{ my_url | absolute_url }}"); -echo $template->render(array( - 'my_url' => '/test' -)); +echo $template->render([ + 'my_url' => '/test', +]); // expect: https://www.example.com/test diff --git a/examples/index.php b/examples/index.php index 850fe42c..2cd14b3a 100644 --- a/examples/index.php +++ b/examples/index.php @@ -29,42 +29,42 @@ $liquid->parse(file_get_contents($protectedPath . 'templates' . DIRECTORY_SEPARATOR . 'index.tpl')); -$assigns = array( - 'document' => array( +$assigns = [ + 'document' => [ 'title' => 'This is php-liquid', 'content' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.', 'copyright' => 'Guz Alexander - All rights reserved.', - ), - 'blog' => array( - array( + ], + 'blog' => [ + [ 'title' => 'Blog Title 1', 'content' => 'Nunc putamus parum claram', - 'tags' => array('claram', 'parum'), - 'comments' => array( - array( + 'tags' => ['claram', 'parum'], + 'comments' => [ + [ 'title' => 'First Comment', 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', - ), - ), - ), - array( + ], + ], + ], + [ 'title' => 'Blog Title 2', 'content' => 'Nunc putamus parum claram', - 'tags' => array('claram', 'parum', 'freestyle'), - 'comments' => array( - array( + 'tags' => ['claram', 'parum', 'freestyle'], + 'comments' => [ + [ 'title' => 'First Comment', 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', - ), - array( + ], + [ 'title' => 'Second Comment', 'message' => 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr', - ), - ), - ), + ], + ], + ], - ), - 'array' => array('one', 'two', 'three', 'four'), -); + ], + 'array' => ['one', 'two', 'three', 'four'], +]; echo $liquid->render($assigns); diff --git a/examples/simple.php b/examples/simple.php index 7cea203b..4381a080 100644 --- a/examples/simple.php +++ b/examples/simple.php @@ -20,4 +20,4 @@ $liquid = new Template(); $liquid->parse('{{ hello }} {{ goback }}'); -echo $liquid->render(array('hello' => 'hello world', 'goback' => 'index')); +echo $liquid->render(['hello' => 'hello world', 'goback' => 'index']); diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 6e0820b2..62a19fc6 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -24,7 +24,7 @@ class AbstractBlock extends AbstractTag /** * @var AbstractTag[]|Variable[]|string[] */ - protected $nodelist = array(); + protected $nodelist = []; /** * Whenever next token should be ltrim'med. @@ -55,7 +55,7 @@ public function parse(array &$tokens) $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/s'); $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); - $this->nodelist = array(); + $this->nodelist = []; $tags = Template::getTags(); diff --git a/src/Liquid/AbstractTag.php b/src/Liquid/AbstractTag.php index 36a21938..0b47418f 100644 --- a/src/Liquid/AbstractTag.php +++ b/src/Liquid/AbstractTag.php @@ -35,14 +35,14 @@ abstract class AbstractTag * * @var array */ - protected $attributes = array(); + protected $attributes = []; /** * A cached instance of the config array, for performance reasons. * * @var array */ - protected $config = array(); + protected $config = []; /** * Constructor. @@ -86,7 +86,7 @@ abstract public function render(Context $context); */ protected function extractAttributes($markup) { - $this->attributes = array(); + $this->attributes = []; $attributeRegexp = new Regexp(Liquid::get('TAG_ATTRIBUTES')); diff --git a/src/Liquid/Cache.php b/src/Liquid/Cache.php index 28749a3d..3bfb6ac7 100644 --- a/src/Liquid/Cache.php +++ b/src/Liquid/Cache.php @@ -26,7 +26,7 @@ abstract class Cache /** * @param array $options */ - public function __construct(array $options = array()) + public function __construct(array $options = []) { if (isset($options['cache_expire'])) { $this->expire = $options['cache_expire']; diff --git a/src/Liquid/Cache/Apc.php b/src/Liquid/Cache/Apc.php index b52d909c..0256ad66 100644 --- a/src/Liquid/Cache/Apc.php +++ b/src/Liquid/Cache/Apc.php @@ -30,7 +30,7 @@ class Apc extends Cache * * @throws LiquidException if APC cache extension is not loaded or is disabled. */ - public function __construct(array $options = array()) + public function __construct(array $options = []) { parent::__construct($options); diff --git a/src/Liquid/Cache/File.php b/src/Liquid/Cache/File.php index ac0358ee..1ece9e3d 100644 --- a/src/Liquid/Cache/File.php +++ b/src/Liquid/Cache/File.php @@ -28,7 +28,7 @@ class File extends Cache * * @throws NotFoundException if Cachedir not exists. */ - public function __construct(array $options = array()) + public function __construct(array $options = []) { parent::__construct($options); diff --git a/src/Liquid/Cache/Local.php b/src/Liquid/Cache/Local.php index f48415eb..933da518 100644 --- a/src/Liquid/Cache/Local.php +++ b/src/Liquid/Cache/Local.php @@ -18,7 +18,7 @@ */ class Local extends Cache { - private $cache = array(); + private $cache = []; /** * {@inheritdoc} @@ -54,7 +54,7 @@ public function write($key, $value, $serialize = true) */ public function flush($expiredOnly = false) { - $this->cache = array(); + $this->cache = []; return true; } } diff --git a/src/Liquid/Context.php b/src/Liquid/Context.php index 3a50e747..066427b7 100644 --- a/src/Liquid/Context.php +++ b/src/Liquid/Context.php @@ -42,7 +42,7 @@ class Context * * @var array */ - public $environments = array(); + public $environments = []; /** * Called "sometimes" while rendering. For example to abort the execution of a rendering. @@ -57,14 +57,14 @@ class Context * @param array $assigns * @param array $registers */ - public function __construct(array $assigns = array(), array $registers = array()) + public function __construct(array $assigns = [], array $registers = []) { - $this->assigns = array($assigns); + $this->assigns = [$assigns]; $this->registers = $registers; $this->filterbank = new Filterbank($this); // first empty array serves as source for overrides, e.g. as in TagDecrement - $this->environments = array(array(), array()); + $this->environments = [[], []]; if (Liquid::get('EXPOSE_SERVER')) { $this->environments[1] = $_SERVER; @@ -111,7 +111,7 @@ public function addFilters($filter, ?callable $callback = null) * * @return string */ - public function invoke($name, $value, array $args = array()) + public function invoke($name, $value, array $args = []) { try { return $this->filterbank->invoke($name, $value, $args); @@ -137,7 +137,7 @@ public function merge($newAssigns) */ public function push() { - array_unshift($this->assigns, array()); + array_unshift($this->assigns, []); return true; } @@ -295,7 +295,7 @@ private function variable($key) if (preg_match("|\[[0-9]+\]|", $key)) { $key = preg_replace("|\[([0-9]+)\]|", ".$1", $key); } elseif (preg_match("|\[[0-9a-z._]+\]|", $key, $matches)) { - $index = $this->get(str_replace(array("[", "]"), "", $matches[0])); + $index = $this->get(str_replace(["[", "]"], "", $matches[0])); if (strlen($index)) { $key = preg_replace("|\[([0-9a-z._]+)\]|", ".$index", $key); } @@ -392,17 +392,17 @@ private function variable($key) // if it has `get` or `field_exists` methods if (method_exists($object, Liquid::get('HAS_PROPERTY_METHOD'))) { - if (!call_user_func(array($object, Liquid::get('HAS_PROPERTY_METHOD')), $nextPartName)) { + if (!call_user_func([$object, Liquid::get('HAS_PROPERTY_METHOD')], $nextPartName)) { return null; } - $object = call_user_func(array($object, Liquid::get('GET_PROPERTY_METHOD')), $nextPartName); + $object = call_user_func([$object, Liquid::get('GET_PROPERTY_METHOD')], $nextPartName); continue; } // if it's just a regular object, attempt to access a public method - if (is_callable(array($object, $nextPartName))) { - $object = call_user_func(array($object, $nextPartName)); + if (is_callable([$object, $nextPartName])) { + $object = call_user_func([$object, $nextPartName]); continue; } diff --git a/src/Liquid/Drop.php b/src/Liquid/Drop.php index 7adbf624..48e71f5e 100644 --- a/src/Liquid/Drop.php +++ b/src/Liquid/Drop.php @@ -70,7 +70,7 @@ public function invokeDrop($method) { $result = $this->beforeMethod($method); - if (is_null($result) && is_callable(array($this, $method))) { + if (is_null($result) && is_callable([$this, $method])) { $result = $this->$method(); } diff --git a/src/Liquid/FileSystem/Local.php b/src/Liquid/FileSystem/Local.php index d1d07073..533eb5f8 100644 --- a/src/Liquid/FileSystem/Local.php +++ b/src/Liquid/FileSystem/Local.php @@ -94,7 +94,7 @@ public function fullPath($templatePath) $templateFile = Liquid::get('INCLUDE_PREFIX') . $templateFile . '.' . Liquid::get('INCLUDE_SUFFIX'); } - $fullPath = join(DIRECTORY_SEPARATOR, array($this->root, $templateDir, $templateFile)); + $fullPath = join(DIRECTORY_SEPARATOR, [$this->root, $templateDir, $templateFile]); $realFullPath = realpath($fullPath); if ($realFullPath === false) { diff --git a/src/Liquid/Filterbank.php b/src/Liquid/Filterbank.php index ca16c43d..17c305d5 100644 --- a/src/Liquid/Filterbank.php +++ b/src/Liquid/Filterbank.php @@ -116,7 +116,7 @@ public function addFilter($filter, ?callable $callback = null) * * @return string */ - public function invoke($name, $value, array $args = array()) + public function invoke($name, $value, array $args = []) { // workaround for a single standard filter being a reserved keyword - we can't use overloading for static calls if ($name == 'default') { @@ -148,6 +148,6 @@ public function invoke($name, $value, array $args = array()) } // Call a class or an instance method - return call_user_func_array(array($class, $name), $args); + return call_user_func_array([$class, $name], $args); } } diff --git a/src/Liquid/Liquid.php b/src/Liquid/Liquid.php index 93f6bd01..6a02d04e 100644 --- a/src/Liquid/Liquid.php +++ b/src/Liquid/Liquid.php @@ -22,7 +22,7 @@ class Liquid * * @var array configuration array */ - public static $config = array( + public static $config = [ // The method is called on objects when resolving variables to see // if a given property exists. 'HAS_PROPERTY_METHOD' => 'field_exists', @@ -100,7 +100,7 @@ class Liquid 'REQUEST_URI', 'SERVER_NAME', ], - ); + ]; /** * Get a configuration setting. @@ -156,7 +156,7 @@ public static function set($key, $value) */ public static function arrayFlatten($array) { - $return = array(); + $return = []; foreach ($array as $element) { if (is_array($element)) { diff --git a/src/Liquid/Regexp.php b/src/Liquid/Regexp.php index 0cbcd0e6..70a499ae 100644 --- a/src/Liquid/Regexp.php +++ b/src/Liquid/Regexp.php @@ -74,7 +74,7 @@ public function scan($string) array_shift($matches); - $result = array(); + $result = []; foreach ($matches as $matchKey => $subMatches) { foreach ($subMatches as $subMatchKey => $subMatch) { diff --git a/src/Liquid/StandardFilters.php b/src/Liquid/StandardFilters.php index c3e274d6..086b517f 100644 --- a/src/Liquid/StandardFilters.php +++ b/src/Liquid/StandardFilters.php @@ -666,9 +666,9 @@ public static function strip_html($input) */ public static function strip_newlines($input) { - return is_string($input) ? str_replace(array( - "\n", "\r" - ), '', $input) : $input; + return is_string($input) ? str_replace([ + "\n", "\r", + ], '', $input) : $input; } diff --git a/src/Liquid/Tag/TagCase.php b/src/Liquid/Tag/TagCase.php index 0b17b207..b2f4d2a4 100644 --- a/src/Liquid/Tag/TagCase.php +++ b/src/Liquid/Tag/TagCase.php @@ -66,8 +66,8 @@ class TagCase extends Decision */ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { - $this->nodelists = array(); - $this->elseNodelist = array(); + $this->nodelists = []; + $this->elseNodelist = []; parent::__construct($markup, $tokens, $fileSystem); @@ -106,7 +106,7 @@ public function unknownTag($tag, $params, array $tokens) if ($whenSyntax) { $this->pushNodelist(); $this->right = $matches[1]; - $this->nodelist = array(); + $this->nodelist = []; } else { throw new ParseException("Syntax Error in tag 'case' - Valid when condition: when [condition]"); // harry } @@ -117,7 +117,7 @@ public function unknownTag($tag, $params, array $tokens) $this->pushNodelist(); $this->right = null; $this->elseNodelist = &$this->nodelist; - $this->nodelist = array(); + $this->nodelist = []; break; default: @@ -131,7 +131,7 @@ public function unknownTag($tag, $params, array $tokens) public function pushNodelist() { if (!is_null($this->right)) { - $this->nodelists[] = array($this->right, $this->nodelist); + $this->nodelists[] = [$this->right, $this->nodelist]; } } diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index 509b56c9..dd7e88dd 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -44,7 +44,7 @@ class TagCycle extends AbstractTag /** * @var Variable[] The variables to cycle between */ - private $variables = array(); + private $variables = []; /** * Constructor @@ -115,7 +115,7 @@ private function variablesFromString($markup) { $regexp = new Regexp('/\s*(' . Liquid::get('QUOTED_FRAGMENT') . ')\s*/'); $parts = explode(',', $markup); - $result = array(); + $result = []; foreach ($parts as $part) { $regexp->match($part); diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 0c27d55c..0a3ab2fb 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -77,13 +77,13 @@ private function findBlocks(array $tokens) $blockstartRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*block (\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); $blockendRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*endblock\s*?' . Liquid::get('TAG_END') . '$/'); - $b = array(); + $b = []; $name = null; foreach ($tokens as $token) { if ($blockstartRegexp->match($token)) { $name = $blockstartRegexp->matches[1]; - $b[$name] = array(); + $b[$name] = []; } elseif ($blockendRegexp->match($token)) { $name = null; } else { @@ -133,7 +133,7 @@ public function parse(array &$tokens) $name = null; - $rest = array(); + $rest = []; $keep = false; for ($i = 0; $i < count($maintokens); $i++) { diff --git a/src/Liquid/Tag/TagFor.php b/src/Liquid/Tag/TagFor.php index cd6ae116..9b616acb 100644 --- a/src/Liquid/Tag/TagFor.php +++ b/src/Liquid/Tag/TagFor.php @@ -105,7 +105,7 @@ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = n public function render(Context $context) { if (!isset($context->registers['for'])) { - $context->registers['for'] = array(); + $context->registers['for'] = []; } if ($this->type == 'digit') { @@ -132,7 +132,7 @@ private function renderCollection(Context $context) return ''; } - $range = array(0, count($collection)); + $range = [0, count($collection)]; if (isset($this->attributes['limit']) || isset($this->attributes['offset'])) { $offset = 0; @@ -143,7 +143,7 @@ private function renderCollection(Context $context) $limit = (isset($this->attributes['limit'])) ? $context->get($this->attributes['limit']) : null; $rangeEnd = $limit ? $limit : count($collection) - $offset; - $range = array($offset, $rangeEnd); + $range = [$offset, $rangeEnd]; $context->registers['for'][$this->name] = $rangeEnd + $offset; } @@ -159,9 +159,9 @@ private function renderCollection(Context $context) $index = 0; foreach ($segment as $key => $item) { - $value = is_numeric($key) ? $item : array($key, $item); + $value = is_numeric($key) ? $item : [$key, $item]; $context->set($this->variableName, $value); - $context->set('forloop', array( + $context->set('forloop', [ 'name' => $this->name, 'length' => $length, 'index' => $index + 1, @@ -169,8 +169,8 @@ private function renderCollection(Context $context) 'rindex' => $length - $index, 'rindex0' => $length - $index - 1, 'first' => (int)($index == 0), - 'last' => (int)($index == $length - 1) - )); + 'last' => (int)($index == $length - 1), + ]); $result .= $this->renderAll($this->nodelist, $context); @@ -202,7 +202,7 @@ private function renderDigit(Context $context) $end = $context->get($this->collectionName); } - $range = array($start, $end); + $range = [$start, $end]; $context->push(); $result = ''; @@ -210,7 +210,7 @@ private function renderDigit(Context $context) $length = $range[1] - $range[0]; for ($i = $range[0]; $i <= $range[1]; $i++) { $context->set($this->variableName, $i); - $context->set('forloop', array( + $context->set('forloop', [ 'name' => $this->name, 'length' => $length, 'index' => $index + 1, @@ -218,8 +218,8 @@ private function renderDigit(Context $context) 'rindex' => $length - $index, 'rindex0' => $length - $index - 1, 'first' => (int)($index == 0), - 'last' => (int)($index == $length - 1) - )); + 'last' => (int)($index == $length - 1), + ]); $result .= $this->renderAll($this->nodelist, $context); diff --git a/src/Liquid/Tag/TagIf.php b/src/Liquid/Tag/TagIf.php index 67495d4d..4624ae43 100644 --- a/src/Liquid/Tag/TagIf.php +++ b/src/Liquid/Tag/TagIf.php @@ -35,14 +35,14 @@ class TagIf extends Decision * * @var array */ - private $nodelistHolders = array(); + private $nodelistHolders = []; /** * Array holding the block type, block markup (conditions) and block nodelist * * @var array */ - protected $blocks = array(); + protected $blocks = []; /** * Constructor @@ -55,7 +55,7 @@ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = n { $this->nodelist = & $this->nodelistHolders[count($this->blocks)]; - array_push($this->blocks, array('if', $markup, &$this->nodelist)); + array_push($this->blocks, ['if', $markup, &$this->nodelist]); parent::__construct($markup, $tokens, $fileSystem); } @@ -72,9 +72,9 @@ public function unknownTag($tag, $params, array $tokens) if ($tag == 'else' || $tag == 'elsif') { // Update reference to nodelistHolder for this block $this->nodelist = & $this->nodelistHolders[count($this->blocks) + 1]; - $this->nodelistHolders[count($this->blocks) + 1] = array(); + $this->nodelistHolders[count($this->blocks) + 1] = []; - array_push($this->blocks, array($tag, $params, &$this->nodelist)); + array_push($this->blocks, [$tag, $params, &$this->nodelist]); } else { parent::unknownTag($tag, $params, $tokens); } @@ -112,7 +112,7 @@ public function render(Context $context) // Extract individual conditions $temp = $logicalRegex->split($block[1]); - $conditions = array(); + $conditions = []; foreach ($temp as $condition) { if ($conditionalRegex->match($condition)) { @@ -120,11 +120,11 @@ public function render(Context $context) $operator = (isset($conditionalRegex->matches[2])) ? $conditionalRegex->matches[2] : null; $right = (isset($conditionalRegex->matches[3])) ? $conditionalRegex->matches[3] : null; - array_push($conditions, array( + array_push($conditions, [ 'left' => $left, 'operator' => $operator, - 'right' => $right - )); + 'right' => $right, + ]); } else { throw new ParseException("Syntax Error in tag 'if' - Valid syntax: if [condition]"); } diff --git a/src/Liquid/Tag/TagPaginate.php b/src/Liquid/Tag/TagPaginate.php index 75916beb..3d1fc3cf 100644 --- a/src/Liquid/Tag/TagPaginate.php +++ b/src/Liquid/Tag/TagPaginate.php @@ -136,18 +136,18 @@ public function render(Context $context) // Sets the collection if it's a key of another collection (ie search.results, collection.products, blog.articles) $segments = explode('.', $this->collectionName); if (count($segments) == 2) { - $context->set($segments[0], array($segments[1] => $paginatedCollection)); + $context->set($segments[0], [$segments[1] => $paginatedCollection]); } else { $context->set($this->collectionName, $paginatedCollection); } - $paginate = array( + $paginate = [ 'page_size' => $this->numberItems, 'current_page' => $this->currentPage, 'current_offset' => $this->currentOffset, 'pages' => $this->totalPages, - 'items' => $this->collectionSize - ); + 'items' => $this->collectionSize, + ]; // Get the name of the request field to use in URLs $pageRequestKey = Liquid::get('PAGINATION_REQUEST_KEY'); diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index 36310d73..b7c67ce1 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -34,7 +34,7 @@ public function parse(array &$tokens) { $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '\s*(\w+)\s*(.*)?' . Liquid::get('TAG_END') . '$/'); - $this->nodelist = array(); + $this->nodelist = []; while (count($tokens)) { $token = array_shift($tokens); diff --git a/src/Liquid/Tag/TagTablerow.php b/src/Liquid/Tag/TagTablerow.php index 6632857a..ca9dfc0d 100644 --- a/src/Liquid/Tag/TagTablerow.php +++ b/src/Liquid/Tag/TagTablerow.php @@ -111,15 +111,15 @@ public function render(Context $context) foreach ($collection as $index => $item) { $context->set($this->variableName, $item); - $context->set('tablerowloop', array( + $context->set('tablerowloop', [ 'length' => $length, 'index' => $index + 1, 'index0' => $index, 'rindex' => $length - $index, 'rindex0' => $length - $index - 1, 'first' => (int)($index == 0), - 'last' => (int)($index == $length - 1) - )); + 'last' => (int)($index == $length - 1), + ]); $text = $this->renderAll($this->nodelist, $context); $break = isset($context->registers['break']); diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index eb2953fd..b5f2245f 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -40,7 +40,7 @@ class Template /** * @var array Globally included filters */ - private $filters = array(); + private $filters = []; /** * @var callable|null Called "sometimes" while rendering. For example to abort the execution of a rendering. @@ -50,7 +50,7 @@ class Template /** * @var array Custom tags */ - private static $tags = array(); + private static $tags = []; /** * @var Cache @@ -171,7 +171,7 @@ public function setTickFunction(callable $tickFunction) public static function tokenize($source) { return empty($source) - ? array() + ? [] : preg_split(Liquid::get('TOKENIZATION_REGEXP'), $source, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); } @@ -240,7 +240,7 @@ public function parseFile($templatePath) * * @return string */ - public function render(array $assigns = array(), $filters = null, array $registers = array()) + public function render(array $assigns = [], $filters = null, array $registers = []) { $context = new Context($assigns, $registers); diff --git a/src/Liquid/Variable.php b/src/Liquid/Variable.php index 6afeb059..c168fde2 100644 --- a/src/Liquid/Variable.php +++ b/src/Liquid/Variable.php @@ -78,7 +78,7 @@ public function __construct($markup) foreach ($this->filters as $filter) { // with empty filters set we would just move along - if (in_array($filter[0], array('escape', 'escape_once', 'raw', 'newline_to_br'))) { + if (in_array($filter[0], ['escape', 'escape_once', 'raw', 'newline_to_br'])) { // if we have any raw-like filter, stop $addEscapeFilter = false; break; @@ -86,7 +86,7 @@ public function __construct($markup) } if ($addEscapeFilter) { - $this->filters[] = array('escape', array()); + $this->filters[] = ['escape', []]; } } } @@ -98,8 +98,8 @@ public function __construct($markup) */ private static function parseFilterExpressions($filterName, array $unparsedArgs) { - $filterArgs = array(); - $keywordArgs = array(); + $filterArgs = []; + $keywordArgs = []; $justTagAttributes = new Regexp('/\A' . trim(Liquid::get('TAG_ATTRIBUTES'), '/') . '\z/'); @@ -115,7 +115,7 @@ private static function parseFilterExpressions($filterName, array $unparsedArgs) $filterArgs[] = $keywordArgs; } - return array($filterName, $filterArgs); + return [$filterName, $filterArgs]; } /** @@ -151,8 +151,8 @@ public function render(Context $context) foreach ($this->filters as $filter) { list($filtername, $filterArgKeys) = $filter; - $filterArgValues = array(); - $keywordArgValues = array(); + $filterArgValues = []; + $keywordArgValues = []; foreach ($filterArgKeys as $arg_key) { if (is_array($arg_key)) { diff --git a/tests/Liquid/Cache/FileTest.php b/tests/Liquid/Cache/FileTest.php index bcee1a61..88f55d85 100644 --- a/tests/Liquid/Cache/FileTest.php +++ b/tests/Liquid/Cache/FileTest.php @@ -28,11 +28,11 @@ protected function setUp(): void // Remove tmp cache files because they may remain after a failed test run $this->removeOldCachedFiles(); - $this->cache = new File(array( + $this->cache = new File([ 'cache_dir' => $this->cacheDir, 'cache_expire' => 3600, 'cache_prefix' => 'liquid_', - )); + ]); } protected function tearDown(): void @@ -60,7 +60,7 @@ public function testConstructNoSuchDirOrNotWritable() { $this->expectException(\Liquid\Exception\FilesystemException::class); - new File(array('cache_dir' => '/no/such/dir/liquid/cache')); + new File(['cache_dir' => '/no/such/dir/liquid/cache']); } public function testGetExistsNoFile() diff --git a/tests/Liquid/ContextTest.php b/tests/Liquid/ContextTest.php index 1321f784..a9d7137f 100644 --- a/tests/Liquid/ContextTest.php +++ b/tests/Liquid/ContextTest.php @@ -76,10 +76,10 @@ public function toLiquid() { // we intentionally made the value different so // that we could see where it is coming from - return array( + return [ 'property' => $this->property, 'value' => 42, - ); + ]; } } @@ -100,10 +100,10 @@ public function toArray() { // we intentionally made the value different so // that we could see where it is coming from - return array( + return [ 'property' => $this->property, 'value' => 42, - ); + ]; } } @@ -196,19 +196,19 @@ public function testGetArray() { $this->expectException(\Liquid\LiquidException::class); - $this->context->get(array()); + $this->context->get([]); } public function testGetNotVariable() { - $data = array( + $data = [ null => null, 'null' => null, 'true' => true, 'false' => false, "'quoted_string'" => 'quoted_string', '"double_quoted_string"' => "double_quoted_string", - ); + ]; foreach ($data as $key => $expected) { $this->assertEquals($expected, $this->context->get($key)); @@ -284,7 +284,7 @@ public function testGetSetMagic() public function testFinalVariableCanBeObject() { - $this->context->set('test', (object) array('value' => (object) array())); + $this->context->set('test', (object) ['value' => (object) []]); $this->assertInstanceOf(\stdClass::class, $this->context->get('test.value')); } @@ -302,7 +302,7 @@ public function testVariables() public function testLengthQuery() { - $this->context->set('numbers', array(1, 2, 3, 4)); + $this->context->set('numbers', [1, 2, 3, 4]); $this->assertEquals(4, $this->context->get('numbers.size')); } @@ -323,49 +323,49 @@ public function testCountableLength() public function testOverrideSize() { - $this->context->set('hash', array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'size' => '5000')); + $this->context->set('hash', ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'size' => '5000']); $this->assertEquals(5000, $this->context->get('hash.size')); } public function testArrayFirst() { - $this->context->set('array', array(11, 'jack', 43, 74, 5, 'tom')); + $this->context->set('array', [11, 'jack', 43, 74, 5, 'tom']); $this->assertEquals(11, $this->context->get('array.first')); } public function testOverrideFirst() { - $this->context->set('array', array(11, 'jack', 43, 'first' => 74, 5, 'tom')); + $this->context->set('array', [11, 'jack', 43, 'first' => 74, 5, 'tom']); $this->assertEquals(74, $this->context->get('array.first')); } public function testArrayLast() { - $this->context->set('array', array(11, 'jack', 43, 74, 5, 'tom')); + $this->context->set('array', [11, 'jack', 43, 74, 5, 'tom']); $this->assertEquals('tom', $this->context->get('array.last')); } public function testOverrideLast() { - $this->context->set('array', array(11, 'jack', 43, 'last' => 74, 5, 'tom')); + $this->context->set('array', [11, 'jack', 43, 'last' => 74, 5, 'tom']); $this->assertEquals(74, $this->context->get('array.last')); } public function testDeepValueNotObject() { - $this->context->set('example', array('foo' => new ToLiquidNotObject())); + $this->context->set('example', ['foo' => new ToLiquidNotObject()]); $this->assertNull($this->context->get('example.foo.bar')); } public function testHierchalData() { - $this->context->set('hash', array('name' => 'tobi')); + $this->context->set('hash', ['name' => 'tobi']); $this->assertEquals('tobi', $this->context->get('hash.name')); } public function testHierchalDataNoKey() { - $this->context->set('hash', array('name' => 'tobi')); + $this->context->set('hash', ['name' => 'tobi']); $this->assertNull($this->context->get('hash.no_key')); } @@ -389,7 +389,7 @@ public function testOverrideGlobalFilter() $template->parse("{{'test' | notice }}"); $this->assertEquals('Global test', $template->render()); - $this->assertEquals('Local test', $template->render(array(), new LocalFilter())); + $this->assertEquals('Local test', $template->render([], new LocalFilter())); } public function testCallbackFilter() @@ -423,41 +423,41 @@ public function testAddItemInInnerScope() public function testMerge() { - $this->context->merge(array('test' => 'test')); + $this->context->merge(['test' => 'test']); $this->assertEquals('test', $this->context->get('test')); - $this->context->merge(array('test' => 'newvalue', 'foo' => 'bar')); + $this->context->merge(['test' => 'newvalue', 'foo' => 'bar']); $this->assertEquals('newvalue', $this->context->get('test')); $this->assertEquals('bar', $this->context->get('foo')); } public function testCents() { - $this->context->merge(array('cents' => new HundredCentes())); + $this->context->merge(['cents' => new HundredCentes()]); $this->assertEquals(100, $this->context->get('cents')); } public function testNestedCents() { - $this->context->merge(array('cents' => array('amount' => new HundredCentes()))); + $this->context->merge(['cents' => ['amount' => new HundredCentes()]]); $this->assertEquals(100, $this->context->get('cents.amount')); - $this->context->merge(array('cents' => array('cents' => array('amount' => new HundredCentes())))); + $this->context->merge(['cents' => ['cents' => ['amount' => new HundredCentes()]]]); $this->assertEquals(100, $this->context->get('cents.cents.amount')); } public function testCentsThroughDrop() { - $this->context->merge(array('cents' => new CentsDrop())); + $this->context->merge(['cents' => new CentsDrop()]); $this->assertEquals(100, $this->context->get('cents.amount')); } public function testCentsThroughDropNestedly() { - $this->context->merge(array('cents' => array('cents' => new CentsDrop()))); + $this->context->merge(['cents' => ['cents' => new CentsDrop()]]); $this->assertEquals(100, $this->context->get('cents.cents.amount')); - $this->context->merge(array('cents' => array('cents' => array('cents' => new CentsDrop())))); + $this->context->merge(['cents' => ['cents' => ['cents' => new CentsDrop()]]]); $this->assertEquals(100, $this->context->get('cents.cents.cents.amount')); } diff --git a/tests/Liquid/CustomFiltersTest.php b/tests/Liquid/CustomFiltersTest.php index 597bdf4c..4867de66 100644 --- a/tests/Liquid/CustomFiltersTest.php +++ b/tests/Liquid/CustomFiltersTest.php @@ -29,16 +29,16 @@ protected function setUp(): void public function testSortKey() { - $data = array( - array( - array(), - array(), - ), - array( - array('b' => 1, 'c' => 5, 'a' => 3, 'z' => 4, 'h' => 2), - array('a' => 3, 'b' => 1, 'c' => 5, 'h' => 2, 'z' => 4), - ), - ); + $data = [ + [ + [], + [], + ], + [ + ['b' => 1, 'c' => 5, 'a' => 3, 'z' => 4, 'h' => 2], + ['a' => 3, 'b' => 1, 'c' => 5, 'h' => 2, 'z' => 4], + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], CustomFilters::sort_key($item[0])); diff --git a/tests/Liquid/DropTest.php b/tests/Liquid/DropTest.php index 56997553..060c6b41 100644 --- a/tests/Liquid/DropTest.php +++ b/tests/Liquid/DropTest.php @@ -23,7 +23,7 @@ class TextDrop extends Drop { public function get_array() { - return array('text1', 'text2'); + return ['text1', 'text2']; } public function text() @@ -84,14 +84,14 @@ public function testProductDrop() $template = new Template(); $template->parse(' {{ product.top_sales }} '); - $template->render(array('product' => new ProductDrop)); + $template->render(['product' => new ProductDrop]); } public function testNoKeyDrop() { $template = new Template(); $template->parse(' {{ product.invalid.unknown }}{{ product.false }} '); - $output = $template->render(array('product' => new ProductDrop)); + $output = $template->render(['product' => new ProductDrop]); $this->assertEquals(' ', $output); } @@ -99,12 +99,12 @@ public function testTextDrop() { $template = new Template(); $template->parse(' {{ product.texts.text }} '); - $output = $template->render(array('product' => new ProductDrop())); + $output = $template->render(['product' => new ProductDrop()]); $this->assertEquals(' text1 ', $output); $template = new Template(); $template->parse(' {{ product.catchall.unknown }} '); - $output = $template->render(array('product' => new ProductDrop())); + $output = $template->render(['product' => new ProductDrop()]); $this->assertEquals(' method: unknown ', $output); } @@ -112,7 +112,7 @@ public function testTextArrayDrop() { $template = new Template(); $template->parse('{% for text in product.texts.get_array %} {{text}} {% endfor %}'); - $output = $template->render(array('product' => new ProductDrop())); + $output = $template->render(['product' => new ProductDrop()]); $this->assertEquals(' text1 text2 ', $output); } @@ -121,7 +121,7 @@ public function testContextDrop() { $template = new Template(); $template->parse(' {{ context.bar }} '); - $output = $template->render(array('context' => new ContextDrop(), 'bar' => 'carrot')); + $output = $template->render(['context' => new ContextDrop(), 'bar' => 'carrot']); $this->assertEquals(' carrot ', $output); } @@ -129,7 +129,7 @@ public function testNestedContextDrop() { $template = new Template(); $template->parse(' {{ product.context.foo }} '); - $output = $template->render(array('product' => new ProductDrop(), 'foo' => 'monkey')); + $output = $template->render(['product' => new ProductDrop(), 'foo' => 'monkey']); $this->assertEquals(' monkey ', $output); } diff --git a/tests/Liquid/EscapeByDefaultTest.php b/tests/Liquid/EscapeByDefaultTest.php index 54eed9bf..aa8c70f0 100644 --- a/tests/Liquid/EscapeByDefaultTest.php +++ b/tests/Liquid/EscapeByDefaultTest.php @@ -31,15 +31,15 @@ class EscapeByDefaultTest extends TestCase const XSS = ""; const XSS_FAILED = "<script>alert()</script>"; - protected $assigns = array(); + protected $assigns = []; protected function setUp(): void { parent::setUp(); - $this->assigns = array( + $this->assigns = [ 'xss' => self::XSS, - ); + ]; } public function testUnescaped() @@ -96,18 +96,18 @@ public function testNlToBr() Liquid::set('ESCAPE_BY_DEFAULT', true); $text = "{{ xss | newline_to_br }}"; $expected = self::XSS."
\n".self::XSS; - $this->assertTemplateResult($expected, $text, array('xss' => self::XSS."\n".self::XSS)); + $this->assertTemplateResult($expected, $text, ['xss' => self::XSS."\n".self::XSS]); } public function testToStringEscape() { - $this->assertTemplateResult(self::XSS_FAILED, "{{ xss | escape }}", array('xss' => new ObjectWithToString(self::XSS))); + $this->assertTemplateResult(self::XSS_FAILED, "{{ xss | escape }}", ['xss' => new ObjectWithToString(self::XSS)]); } public function testToStringEscapeDefault() { Liquid::set('ESCAPE_BY_DEFAULT', true); - $this->assertTemplateResult(self::XSS_FAILED, "{{ xss }}", array('xss' => new ObjectWithToString(self::XSS))); + $this->assertTemplateResult(self::XSS_FAILED, "{{ xss }}", ['xss' => new ObjectWithToString(self::XSS)]); } /** System default value for the escape flag */ diff --git a/tests/Liquid/FilterbankTest.php b/tests/Liquid/FilterbankTest.php index a52855ec..09eaf026 100644 --- a/tests/Liquid/FilterbankTest.php +++ b/tests/Liquid/FilterbankTest.php @@ -100,7 +100,7 @@ public function testAddFilterNotObjectAndString() { $this->expectException(\Liquid\Exception\WrongArgumentException::class); - $this->filterBank->addFilter(array()); + $this->filterBank->addFilter([]); } /** @@ -236,9 +236,9 @@ public function testWithSerializingCache() $template->registerFilter('foo', function ($arg) { return "Foo $arg"; }); - $template->setCache(new File(array( + $template->setCache(new File([ 'cache_dir' => __DIR__.'/cache_dir/', - ))); + ])); $template->parse("{{'test' | foo }}"); $this->assertEquals('Foo test', $template->render()); diff --git a/tests/Liquid/LiquidTest.php b/tests/Liquid/LiquidTest.php index 3934e511..f90ba536 100644 --- a/tests/Liquid/LiquidTest.php +++ b/tests/Liquid/LiquidTest.php @@ -35,7 +35,7 @@ public function testGetSetAllowedChars() public function testArrayFlattenEmptyArray() { - $this->assertSame(array(), Liquid::arrayFlatten(array())); + $this->assertSame([], Liquid::arrayFlatten([])); } public function testArrayFlattenFlatArray() @@ -43,17 +43,17 @@ public function testArrayFlattenFlatArray() $object = new \stdClass(); // Method does not maintain keys. - $original = array( + $original = [ 'one' => 'one_value', 42, $object, - ); + ]; - $expected = array( + $expected = [ 'one_value', 42, - $object - ); + $object, + ]; $this->assertEquals($expected, Liquid::arrayFlatten($original)); } @@ -63,25 +63,25 @@ public function testArrayFlattenNestedArray() $object = new \stdClass(); // Method does not maintain keys. - $original = array( + $original = [ 'one' => 'one_value', - 42 => array( + 42 => [ 'one_value', - array( + [ 'two_value', - 10 - ), - ), + 10, + ], + ], $object, - ); + ]; - $expected = array( + $expected = [ 'one_value', 'one_value', 'two_value', 10, - $object - ); + $object, + ]; $this->assertEquals($expected, Liquid::arrayFlatten($original)); } diff --git a/tests/Liquid/OutputTest.php b/tests/Liquid/OutputTest.php index c9e300b3..de035b73 100644 --- a/tests/Liquid/OutputTest.php +++ b/tests/Liquid/OutputTest.php @@ -68,16 +68,16 @@ public function img_url($input, $size, $opts = null) class OutputTest extends TestCase { - protected $assigns = array(); + protected $assigns = []; protected function setUp(): void { parent::setUp(); - $this->assigns = array( + $this->assigns = [ 'best_cars' => 'bmw', - 'car' => array('bmw' => 'good', 'gm' => 'bad') - ); + 'car' => ['bmw' => 'good', 'gm' => 'bad'], + ]; $this->filters = new FunnyFilter(); } diff --git a/tests/Liquid/RegexpTest.php b/tests/Liquid/RegexpTest.php index b7e6f458..30b7f1d2 100644 --- a/tests/Liquid/RegexpTest.php +++ b/tests/Liquid/RegexpTest.php @@ -25,32 +25,32 @@ protected function setUp(): void public function testEmpty() { - $this->assertEquals(array(), $this->regexp->scan('')); + $this->assertEquals([], $this->regexp->scan('')); } public function testQuote() { - $this->assertEquals(array('"arg 1"'), $this->regexp->scan('"arg 1"')); + $this->assertEquals(['"arg 1"'], $this->regexp->scan('"arg 1"')); } public function testWords() { - $this->assertEquals(array('arg1', 'arg2'), $this->regexp->scan('arg1 arg2')); + $this->assertEquals(['arg1', 'arg2'], $this->regexp->scan('arg1 arg2')); } public function testQuotedWords() { - $this->assertEquals(array('arg1', 'arg2', '"arg 3"'), $this->regexp->scan('arg1 arg2 "arg 3"')); + $this->assertEquals(['arg1', 'arg2', '"arg 3"'], $this->regexp->scan('arg1 arg2 "arg 3"')); } public function testQuotedWords2() { - $this->assertEquals(array('arg1', 'arg2', "'arg 3'"), $this->regexp->scan('arg1 arg2 \'arg 3\'')); + $this->assertEquals(['arg1', 'arg2', "'arg 3'"], $this->regexp->scan('arg1 arg2 \'arg 3\'')); } public function testQuotedWordsInTheMiddle() { - $this->assertEquals(array('arg1', 'arg2', '"arg 3"', 'arg4'), $this->regexp->scan('arg1 arg2 "arg 3" arg4 ')); + $this->assertEquals(['arg1', 'arg2', '"arg 3"', 'arg4'], $this->regexp->scan('arg1 arg2 "arg 3" arg4 ')); } public function testPregQuote() @@ -63,7 +63,7 @@ public function testPregQuote() public function testNoDelimiter() { $regexp = new Regexp('(example)'); - $this->assertEquals(array('(example)'), $regexp->scan('(example)')); - $this->assertEquals(array(), $regexp->scan('nothing')); + $this->assertEquals(['(example)'], $regexp->scan('(example)')); + $this->assertEquals([], $regexp->scan('nothing')); } } diff --git a/tests/Liquid/StandardFiltersTest.php b/tests/Liquid/StandardFiltersTest.php index 701e9996..c7b04f1e 100644 --- a/tests/Liquid/StandardFiltersTest.php +++ b/tests/Liquid/StandardFiltersTest.php @@ -75,13 +75,13 @@ protected function setUp(): void public function testSize() { - $data = array( + $data = [ 4 => 1000, 3 => 100, - 2 => array('one', 'two'), - 1 => new \ArrayIterator(array('one')), + 2 => ['one', 'two'], + 1 => new \ArrayIterator(['one']), SizeClass::SIZE => new SizeClass(), - ); + ]; foreach ($data as $expected => $element) { $this->assertEquals($expected, StandardFilters::size($element)); @@ -95,17 +95,17 @@ public function testSizeObject() $this->expectException(\Liquid\LiquidException::class); $this->expectExceptionMessage('cannot be estimated'); - StandardFilters::size((object) array()); + StandardFilters::size((object) []); } public function testDowncase() { - $data = array( + $data = [ 'UpperCaseMiXed' => 'uppercasemixed', 3 => 3, // UTF-8 - 'Владимир' => 'владимир' - ); + 'Владимир' => 'владимир', + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::downcase($element)); @@ -114,12 +114,12 @@ public function testDowncase() public function testUpcase() { - $data = array( + $data = [ 'UpperCaseMiXed' => 'UPPERCASEMIXED', 3 => 3, // UTF-8 - 'владимир' => 'ВЛАДИМИР' - ); + 'владимир' => 'ВЛАДИМИР', + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::upcase($element)); @@ -128,13 +128,13 @@ public function testUpcase() public function testCapitalize() { - $data = array( + $data = [ 'one Word not' => 'One Word Not', '1test' => '1Test', '' => '', // UTF-8 - 'владимир владимирович' => 'Владимир Владимирович' - ); + 'владимир владимирович' => 'Владимир Владимирович', + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::capitalize($element)); @@ -143,10 +143,10 @@ public function testCapitalize() public function testUrlEncode() { - $data = array( + $data = [ 'nothing' => 'nothing', '%#&^' => '%25%23%26%5E', - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::url_encode($element)); @@ -156,9 +156,9 @@ public function testUrlEncode() public function testUrlDecode() { - $data = array( + $data = [ '%25%23%26%5E' => '%#&^', - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::url_decode($element)); @@ -168,10 +168,10 @@ public function testUrlDecode() public function testRaw() { - $data = array( + $data = [ "Anything" => "Anything", 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::raw($element)); @@ -180,28 +180,28 @@ public function testRaw() public function testJson() { - $data = array( - array( + $data = [ + [ "before" => "Anything", "after" => "\"Anything\"", - ), - array( + ], + [ "before" => 3, "after" => 3, - ), - array( - "before" => array(1, 2, 3), + ], + [ + "before" => [1, 2, 3], "after" => "[1,2,3]", - ), - array( - "before" => array("one" => 1, "two" => 2, "three" => 3), + ], + [ + "before" => ["one" => 1, "two" => 2, "three" => 3], "after" => "{\"one\":1,\"two\":2,\"three\":3}", - ), - array( - "before" => array("one" => 1, "two" => array(1, 2, 3), "three" => 3), + ], + [ + "before" => ["one" => 1, "two" => [1, 2, 3], "three" => 3], "after" => "{\"one\":1,\"two\":[1,2,3],\"three\":3}", - ), - ); + ], + ]; foreach ($data as $testCase) { $this->assertEquals($testCase['after'], StandardFilters::json($testCase['before'])); @@ -228,42 +228,42 @@ public function testWhere() public function testEscape() { - $data = array( + $data = [ "one Word's not" => "one Word's not", "&><\"'" => "&><"'", null => '', - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::escape($element)); } - $this->assertSame(array(1), StandardFilters::escape(array(1))); + $this->assertSame([1], StandardFilters::escape([1])); } public function testEscapeOnce() { - $data = array( + $data = [ "" => "<b><script>alert()</script>", "a < b & c" => "a < b & c", "a < b & c" => "a < b & c", "<\">" => "<">", - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::escape_once($element)); } - $this->assertSame(array(1), StandardFilters::escape_once(array(1))); + $this->assertSame([1], StandardFilters::escape_once([1])); } public function testStripNewLines() { - $data = array( + $data = [ "one Word\r\n not\r\n\r\n" => "one Word not", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::strip_newlines($element)); @@ -272,11 +272,11 @@ public function testStripNewLines() public function testNewLineToBr() { - $data = array( + $data = [ "one Word\n not\n" => "one Word
\n not
\n", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::newline_to_br($element)); @@ -286,22 +286,22 @@ public function testNewLineToBr() public function testReplace() { // Replace for empty string - $data = array( + $data = [ "one Word not Word" => "one not ", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::replace($element, 'Word')); } // Replace for "Hello" string - $data = array( + $data = [ "one Word not Word" => "one Hello not Hello", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::replace($element, 'Word', 'Hello')); @@ -311,22 +311,22 @@ public function testReplace() public function testReplaceFirst() { // Replace for empty string - $data = array( + $data = [ "one Word not Word" => "one not Word", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::replace_first($element, 'Word')); } // Replace for "Hello" string - $data = array( + $data = [ "one Word not Word" => "one Hello not Word", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::replace_first($element, 'Word', 'Hello')); @@ -335,11 +335,11 @@ public function testReplaceFirst() public function testRemove() { - $data = array( + $data = [ "one Word not Word" => "one not ", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::remove($element, 'Word')); @@ -348,11 +348,11 @@ public function testRemove() public function testRemoveFirst() { - $data = array( + $data = [ "one Word not Word" => "one not Word", 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::remove_first($element, 'Word')); @@ -361,11 +361,11 @@ public function testRemoveFirst() public function testAppend() { - $data = array( + $data = [ "one Word not Word" => "one Word not Word appended", '' => ' appended', 3 => '3 appended', - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::append($element, ' appended')); @@ -374,11 +374,11 @@ public function testAppend() public function testPrepend() { - $data = array( + $data = [ "one Word not Word" => "prepended one Word not Word", '' => 'prepended ', 3 => 'prepended 3', - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::prepend($element, 'prepended ')); @@ -388,36 +388,36 @@ public function testPrepend() public function testSlice() { // Slice up to the end - $data = array( - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( + $data = [ + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ '', '', - ), - array( - array(1, 2, 3, 4, 5), - array(3, 4, 5), - ), - array( - new \ArrayIterator(array(1, 2, 3, 4, 5)), - array(3, 4, 5), - ), - array( + ], + [ + [1, 2, 3, 4, 5], + [3, 4, 5], + ], + [ + new \ArrayIterator([1, 2, 3, 4, 5]), + [3, 4, 5], + ], + [ '12345', - '345' - ), - array( + '345', + ], + [ 100, - 100 - ), - ); + 100, + ], + ]; foreach ($data as $item) { $actual = StandardFilters::slice($item[0], 2); @@ -428,40 +428,40 @@ public function testSlice() } // Slice a few elements - $data = array( - array( + $data = [ + [ null, null, - ), - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( + ], + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ '', '', - ), - array( - array(1, 2, 3, 4, 5), - array(3, 4), - ), - array( - new \ArrayIterator(array(1, 2, 3, 4, 5)), - array(3, 4), - ), - array( + ], + [ + [1, 2, 3, 4, 5], + [3, 4], + ], + [ + new \ArrayIterator([1, 2, 3, 4, 5]), + [3, 4], + ], + [ '12345', - '34' - ), - array( + '34', + ], + [ 100, - 100 - ), - ); + 100, + ], + ]; foreach ($data as $item) { $actual = StandardFilters::slice($item[0], 2, 2); @@ -477,12 +477,12 @@ public function testSlice() public function testTruncate() { // Truncate with default ending - $data = array( + $data = [ '' => '', str_repeat('a', 150) => str_repeat('a', 100) . '...', 'test' => 'test', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::truncate($element)); @@ -501,12 +501,12 @@ public function testTruncate() public function testTruncateWords() { // Truncate with default ending - $data = array( + $data = [ '' => '', str_repeat('abc ', 10) => rtrim(str_repeat('abc ', 3)) . '...', 'test two' => 'test two', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::truncatewords($element)); @@ -521,12 +521,12 @@ public function testTruncateWords() public function testStripHtml() { - $data = array( + $data = [ '' => '', 'test no html tags' => 'test no html tags', 'test

paragraph

hello' => 'test paragraph hello', 3 => 3, - ); + ]; foreach ($data as $element => $expected) { $this->assertEquals($expected, StandardFilters::strip_html($element)); @@ -535,80 +535,80 @@ public function testStripHtml() public function testJoin() { - $data = array( - array( - array(), + $data = [ + [ + [], '', - ), - array( - new \ArrayIterator(array()), - '' - ), - array( + ], + [ + new \ArrayIterator([]), '', + ], + [ '', - ), - array( - array(1, 2, 3, 4, 5), - '1 2 3 4 5' - ), - array( - new \ArrayIterator(array(1, 2, 3, 4, 5)), - '1 2 3 4 5' - ), - array( + '', + ], + [ + [1, 2, 3, 4, 5], + '1 2 3 4 5', + ], + [ + new \ArrayIterator([1, 2, 3, 4, 5]), + '1 2 3 4 5', + ], + [ + 100, 100, - 100 - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::join($item[0])); } // Custom glue - $this->assertEquals('1-2-3', StandardFilters::join(array(1, 2, 3), '-')); - $this->assertEquals('1-2-3', StandardFilters::join(new \ArrayIterator(array(1, 2, 3)), '-')); + $this->assertEquals('1-2-3', StandardFilters::join([1, 2, 3], '-')); + $this->assertEquals('1-2-3', StandardFilters::join(new \ArrayIterator([1, 2, 3]), '-')); } public function testSort() { - $data = array( - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( - array(1, 5, 3, 4, 2), - array(1, 2, 3, 4, 5), - ), - array( - new \ArrayIterator(array(1, 5, 3, 4, 2)), - array(1, 2, 3, 4, 5), - ), - ); + $data = [ + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ + [1, 5, 3, 4, 2], + [1, 2, 3, 4, 5], + ], + [ + new \ArrayIterator([1, 5, 3, 4, 2]), + [1, 2, 3, 4, 5], + ], + ]; foreach ($data as $key => $item) { $this->assertEquals(array_values($item[1]), array_values(StandardFilters::sort($item[0])), "Sort failed for case #{$key}"); } // Sort by inner key - $original = array( - array('a' => 20, 'b' => 10), - array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 6), - array('a' => 30, 'b' => 48), - ); - $expected = array( - array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 6), - array('a' => 20, 'b' => 10), - array('a' => 30, 'b' => 48), - ); + $original = [ + ['a' => 20, 'b' => 10], + ['a' => 45, 'b' => 5], + ['a' => 40, 'b' => 6], + ['a' => 30, 'b' => 48], + ]; + $expected = [ + ['a' => 45, 'b' => 5], + ['a' => 40, 'b' => 6], + ['a' => 20, 'b' => 10], + ['a' => 30, 'b' => 48], + ]; $this->assertEquals($expected, array_values(StandardFilters::sort($original, 'b'))); $this->assertEquals($expected, array_values(StandardFilters::sort(new \ArrayIterator($original), 'b'))); @@ -617,20 +617,20 @@ public function testSort() public function testSortWithoutKey() { // Sort by inner key - $original = array( - array('a' => 20, 'b' => 10), - array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 6), - array('a' => 30, 'b' => 48), - array('a' => 50), - ); - $expected = array( - array('a' => 50), - array('a' => 45, 'b' => 5), - array('a' => 40, 'b' => 6), - array('a' => 20, 'b' => 10), - array('a' => 30, 'b' => 48), - ); + $original = [ + ['a' => 20, 'b' => 10], + ['a' => 45, 'b' => 5], + ['a' => 40, 'b' => 6], + ['a' => 30, 'b' => 48], + ['a' => 50], + ]; + $expected = [ + ['a' => 50], + ['a' => 45, 'b' => 5], + ['a' => 40, 'b' => 6], + ['a' => 20, 'b' => 10], + ['a' => 30, 'b' => 48], + ]; $this->assertEquals($expected, array_values(StandardFilters::sort($original, 'b'))); $this->assertEquals($expected, array_values(StandardFilters::sort(new \ArrayIterator($original), 'b'))); @@ -668,24 +668,24 @@ public function testDefault() public function testUnique() { - $data = array( - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( - array(1, 1, 5, 3, 4, 2, 5, 2), - array(1, 5, 3, 4, 2), - ), - array( - new \ArrayIterator(array(1, 1, 5, 3, 4, 2, 5, 2)), - array(1, 5, 3, 4, 2), - ), - ); + $data = [ + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ + [1, 1, 5, 3, 4, 2, 5, 2], + [1, 5, 3, 4, 2], + ], + [ + new \ArrayIterator([1, 1, 5, 3, 4, 2, 5, 2]), + [1, 5, 3, 4, 2], + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], array_values(StandardFilters::uniq($item[0]))); @@ -694,24 +694,24 @@ public function testUnique() public function testReverse() { - $data = array( - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( - array(1, 1, 5, 3, 4, 2, 5, 2), - array(2, 5, 2, 4, 3, 5, 1, 1), - ), - array( - new \ArrayIterator(array(1, 1, 5, 3, 4, 2, 5, 2)), - array(2, 5, 2, 4, 3, 5, 1, 1), - ), - ); + $data = [ + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ + [1, 1, 5, 3, 4, 2, 5, 2], + [2, 5, 2, 4, 3, 5, 1, 1], + ], + [ + new \ArrayIterator([1, 1, 5, 3, 4, 2, 5, 2]), + [2, 5, 2, 4, 3, 5, 1, 1], + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::reverse($item[0]), '', 0, 10, true); @@ -720,52 +720,52 @@ public function testReverse() public function testMap() { - $data = array( - array( - array(), - array(), - ), - array( - new \ArrayIterator(array()), - array(), - ), - array( - array( + $data = [ + [ + [], + [], + ], + [ + new \ArrayIterator([]), + [], + ], + [ + [ function () { return 'from function '; }, - array( + [ 'b' => 10, 'attr' => 'value ', - ), - array( + ], + [ 'a' => 20, - 'no_attr' => 'another value ' - ), - ), - array('from function ', 'value ', null), - ), - array( - new \ArrayIterator(array( + 'no_attr' => 'another value ', + ], + ], + ['from function ', 'value ', null], + ], + [ + new \ArrayIterator([ function () { return 'from function '; }, - array( + [ 'b' => 10, 'attr' => 'value ', - ), - array( + ], + [ 'a' => 20, - 'no_attr' => 'another value ' - ), - )), - array('from function ', 'value ', null), - ), - array( + 'no_attr' => 'another value ', + ], + ]), + ['from function ', 'value ', null], + ], + [ 0, - 0 - ) - ); + 0, + ], + ]; foreach ($data as $item) { $actual = StandardFilters::map($item[0], 'attr'); @@ -778,32 +778,32 @@ function () { public function testFirst() { - $data = array( - array( - array(), + $data = [ + [ + [], false, - ), - array( - new \ArrayIterator(array()), + ], + [ + new \ArrayIterator([]), false, - ), - array( - array('two', 'one', 'three'), + ], + [ + ['two', 'one', 'three'], 'two', - ), - array( - new \ArrayIterator(array('two', 'one', 'three')), + ], + [ + new \ArrayIterator(['two', 'one', 'three']), 'two', - ), - array( - array(100, 400, 200), + ], + [ + [100, 400, 200], 100, - ), - array( - new \ArrayIterator(array(100, 400, 200)), + ], + [ + new \ArrayIterator([100, 400, 200]), 100, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::first($item[0])); @@ -812,32 +812,32 @@ public function testFirst() public function testLast() { - $data = array( - array( - array(), + $data = [ + [ + [], false, - ), - array( - new \ArrayIterator(array()), + ], + [ + new \ArrayIterator([]), false, - ), - array( - array('two', 'one', 'three'), + ], + [ + ['two', 'one', 'three'], 'three', - ), - array( - new \ArrayIterator(array('two', 'one', 'three')), + ], + [ + new \ArrayIterator(['two', 'one', 'three']), 'three', - ), - array( - array(100, 400, 200), + ], + [ + [100, 400, 200], 200, - ), - array( - new \ArrayIterator(array(100, 400, 200)), + ], + [ + new \ArrayIterator([100, 400, 200]), 200, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::last($item[0])); @@ -846,16 +846,16 @@ public function testLast() public function testString() { - $data = array( - array( + $data = [ + [ 1, '1', - ), - array( + ], + [ new SizeClass(), "forty two", - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::string($item[0])); @@ -864,40 +864,40 @@ public function testString() public function testSplit() { - $data = array( - array( + $data = [ + [ '', - array(), - ), - array( + [], + ], + [ null, - array(), - ), - array( + [], + ], + [ 'two-one-three', - array('two', 'one', 'three'), - ), - array( + ['two', 'one', 'three'], + ], + [ '12301230123', - array('123', '123', '123'), - '0' - ), - array( + ['123', '123', '123'], + '0', + ], + [ 'phrase', - array('p', 'h', 'r', 'a', 's', 'e'), - '' - ), - array( + ['p', 'h', 'r', 'a', 's', 'e'], + '', + ], + [ 'phrase', - array('phrase'), - null - ), - array( + ['phrase'], + null, + ], + [ '123 123 123', - array('123', '123', '123'), - ' ' - ), - ); + ['123', '123', '123'], + ' ', + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::split($item[0], $item[2] ?? '-')); @@ -906,20 +906,20 @@ public function testSplit() public function testStrip() { - $data = array( - array( + $data = [ + [ '', '', - ), - array( + ], + [ ' hello ', 'hello', - ), - array( + ], + [ 1, 1, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::strip($item[0])); @@ -928,20 +928,20 @@ public function testStrip() public function testLStrip() { - $data = array( - array( + $data = [ + [ '', '', - ), - array( + ], + [ ' hello ', 'hello ', - ), - array( + ], + [ 1, 1, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::lstrip($item[0])); @@ -950,20 +950,20 @@ public function testLStrip() public function testRStrip() { - $data = array( - array( + $data = [ + [ '', '', - ), - array( + ], + [ ' hello ', ' hello', - ), - array( + ], + [ 1, 1, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEquals($item[1], StandardFilters::rstrip($item[0])); @@ -972,23 +972,23 @@ public function testRStrip() public function testPlus() { - $data = array( - array( + $data = [ + [ '', '', 0, - ), - array( + ], + [ 10, 20, 30, - ), - array( + ], + [ 1.5, 2.7, 4.2, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEqualsWithDelta($item[2], StandardFilters::plus($item[0], $item[1]), 0.00001); @@ -997,28 +997,28 @@ public function testPlus() public function testMinus() { - $data = array( - array( + $data = [ + [ '', '', 0, - ), - array( + ], + [ 10, 20, -10, - ), - array( + ], + [ 1.5, 2.7, -1.2, - ), - array( + ], + [ 3.1, 3.1, - 0 - ) - ); + 0, + ], + ]; foreach ($data as $item) { $this->assertEqualsWithDelta($item[2], StandardFilters::minus($item[0], $item[1]), 0.00001); @@ -1027,28 +1027,28 @@ public function testMinus() public function testTimes() { - $data = array( - array( + $data = [ + [ '', '', 0, - ), - array( + ], + [ 10, 20, 200, - ), - array( + ], + [ 1.5, 2.7, 4.05, - ), - array( + ], + [ 7.5, 0, - 0 - ) - ); + 0, + ], + ]; foreach ($data as $item) { $this->assertEqualsWithDelta($item[2], StandardFilters::times($item[0], $item[1]), 0.00001); @@ -1057,28 +1057,28 @@ public function testTimes() public function testDivideBy() { - $data = array( - array( + $data = [ + [ '20', 10, 2, - ), - array( + ], + [ 10, 20, 0.5, - ), - array( + ], + [ 0, 200, 0, - ), - array( + ], + [ 10, 0.5, 20, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEqualsWithDelta($item[2], StandardFilters::divided_by($item[0], $item[1]), 0.00001); @@ -1087,33 +1087,33 @@ public function testDivideBy() public function testModulo() { - $data = array( - array( + $data = [ + [ '20', 10, 0, - ), - array( + ], + [ 10, 20, 10, - ), - array( + ], + [ 8, 3, 2, - ), - array( + ], + [ 8.9, 3.5, 1.9, - ), - array( + ], + [ 183.357, 12, 3.357, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertEqualsWithDelta($item[2], StandardFilters::modulo($item[0], $item[1]), 0.00001); @@ -1122,23 +1122,23 @@ public function testModulo() public function testRound() { - $data = array( - array( + $data = [ + [ '20.003', 2, 20.00, - ), - array( + ], + [ 10, 3, 10.000, - ), - array( + ], + [ 8, 0, 8.0, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertSame($item[2], StandardFilters::round($item[0], $item[1])); @@ -1147,20 +1147,20 @@ public function testRound() public function testCeil() { - $data = array( - array( + $data = [ + [ '20.003', 21, - ), - array( + ], + [ 10, 10, - ), - array( + ], + [ 0.42, 1, - ), - ); + ], + ]; foreach ($data as $item) { $this->assertSame($item[1], StandardFilters::ceil($item[0])); @@ -1169,24 +1169,24 @@ public function testCeil() public function testFloor() { - $data = array( - array( + $data = [ + [ '20.003', 20, - ), - array( + ], + [ 10, 10, - ), - array( + ], + [ 0.42, 0, - ), - array( + ], + [ 2.5, 2, - ) - ); + ], + ]; foreach ($data as $item) { $this->assertSame($item[1], StandardFilters::floor($item[0])); diff --git a/tests/Liquid/Tag/TagAssignTest.php b/tests/Liquid/Tag/TagAssignTest.php index 74c83b63..49c53ede 100644 --- a/tests/Liquid/Tag/TagAssignTest.php +++ b/tests/Liquid/Tag/TagAssignTest.php @@ -58,16 +58,16 @@ public function testAssignWithFilters() $this->assertTrue($template->render() === 'Hello'); $template->parse('{% assign test = var1 | first | upcase %}{{ test }}'); - $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'A'); + $this->assertTrue($template->render(['var1' => ['a', 'b', 'c']]) === 'A'); $template->parse('{% assign test = var1 | last | upcase %}{{ test }}'); - $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'C'); + $this->assertTrue($template->render(['var1' => ['a', 'b', 'c']]) === 'C'); $template->parse('{% assign test = var1 | join %}{{ test }}'); - $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'a b c'); + $this->assertTrue($template->render(['var1' => ['a', 'b', 'c']]) === 'a b c'); $template->parse('{% assign test = var1 | join : "." %}{{ test }}'); - $this->assertTrue($template->render(array('var1' => array('a', 'b', 'c'))) === 'a.b.c'); + $this->assertTrue($template->render(['var1' => ['a', 'b', 'c']]) === 'a.b.c'); } /** diff --git a/tests/Liquid/Tag/TagBreakTest.php b/tests/Liquid/Tag/TagBreakTest.php index d31b8825..721a9c0f 100644 --- a/tests/Liquid/Tag/TagBreakTest.php +++ b/tests/Liquid/Tag/TagBreakTest.php @@ -17,9 +17,9 @@ class TagBreakTest extends TestCase { public function testFor() { - $this->assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' ', '{%for item in array%} {%break%} yo {%endfor%}', ['array' => [1, 2, 3, 4]]); + $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%break%} {%endfor%}', ['array' => [1, 2, 3, 4]]); + $this->assertTemplateResult(' 1 2 ', '{%for item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endfor%}', ['array' => [1, 2, 3, 4]]); } public function testRange() @@ -34,17 +34,17 @@ public function testTablerow() $this->assertTemplateResult( "\n\n", '{%tablerow item in array%} {%break%} yo {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( "\n yo \n", '{%tablerow item in array%} yo {%break%} {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( "\n 1 2 \n", '{%tablerow item in array%} {%if item == 3%} {%break%} {%endif%} {{ item }} {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); } } diff --git a/tests/Liquid/Tag/TagCaptureTest.php b/tests/Liquid/Tag/TagCaptureTest.php index 9752265b..296777e5 100644 --- a/tests/Liquid/Tag/TagCaptureTest.php +++ b/tests/Liquid/Tag/TagCaptureTest.php @@ -28,7 +28,7 @@ public function testInvalidSyntax() public function testCapture() { - $assigns = array('var' => 'content'); + $assigns = ['var' => 'content']; $this->assertTemplateResult('content foo content foo ', '{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', $assigns); } } diff --git a/tests/Liquid/Tag/TagCaseTest.php b/tests/Liquid/Tag/TagCaseTest.php index e87e11f1..cb2e50d8 100644 --- a/tests/Liquid/Tag/TagCaseTest.php +++ b/tests/Liquid/Tag/TagCaseTest.php @@ -33,19 +33,19 @@ class TagCaseTest extends TestCase { public function testCase() { - $assigns = array('condition' => 2); + $assigns = ['condition' => 2]; $this->assertTemplateResult(' its 2 ', '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', $assigns); - $assigns = array('condition' => 1); + $assigns = ['condition' => 1]; $this->assertTemplateResult(' its 1 ', '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', $assigns); - $assigns = array('condition' => 3); + $assigns = ['condition' => 3]; $this->assertTemplateResult('', '{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', $assigns); - $assigns = array('condition' => "string here"); + $assigns = ['condition' => "string here"]; $this->assertTemplateResult(' hit ', '{% case condition %}{% when "string here" %} hit {% endcase %}', $assigns); - $assigns = array('condition' => "bad string here"); + $assigns = ['condition' => "bad string here"]; $this->assertTemplateResult('', '{% case condition %}{% when "string here" %} hit {% endcase %}', $assigns); } @@ -71,10 +71,10 @@ public function testMultipleConditions(array $assigns, string $test, string $exp public function testCaseWithElse() { - $assigns = array('condition' => 5); + $assigns = ['condition' => 5]; $this->assertTemplateResult(' hit ', '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', $assigns); - $assigns = array('condition' => 6); + $assigns = ['condition' => 6]; $this->assertTemplateResult(' else ', '{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', $assigns); } @@ -111,16 +111,16 @@ public function testObject() { $this->expectException(\Liquid\Exception\RenderException::class); - $this->assertTemplateResult('', '{% case variable %}{% when 5 %}{% endcase %}', array('variable' => (object) array())); + $this->assertTemplateResult('', '{% case variable %}{% when 5 %}{% endcase %}', ['variable' => (object) []]); } public function testStringable() { - $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new Stringable())); + $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', ['variable' => new Stringable()]); } public function testToLiquid() { - $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', array('variable' => new HasToLiquid())); + $this->assertTemplateResult('hit', '{% case variable %}{% when 100 %}hit{% endcase %}', ['variable' => new HasToLiquid()]); } } diff --git a/tests/Liquid/Tag/TagContinueTest.php b/tests/Liquid/Tag/TagContinueTest.php index cd7f8757..87457bcb 100644 --- a/tests/Liquid/Tag/TagContinueTest.php +++ b/tests/Liquid/Tag/TagContinueTest.php @@ -17,9 +17,9 @@ class TagContinueTest extends TestCase { public function testFor() { - $this->assertTemplateResult(' ', '{%for item in array%} {%continue%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%continue%} {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' 1 2 4 ', '{%for item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endfor%}', array('array' => array(1, 2, 3, 4))); + $this->assertTemplateResult(' ', '{%for item in array%} {%continue%} yo {%endfor%}', ['array' => [1, 2, 3, 4]]); + $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%continue%} {%endfor%}', ['array' => [1, 2, 3, 4]]); + $this->assertTemplateResult(' 1 2 4 ', '{%for item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endfor%}', ['array' => [1, 2, 3, 4]]); } public function testRange() @@ -34,17 +34,17 @@ public function testTablerow() $this->assertTemplateResult( "\n\n", '{%tablerow item in array%} {%continue%} yo {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( "\n yo yo yo yo \n", '{%tablerow item in array%} yo {%continue%} {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( "\n 1 2 4 \n", '{%tablerow item in array%} {%if item == 3%} {%continue%} {%endif%} {{ item }} {%endtablerow%}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); } } diff --git a/tests/Liquid/Tag/TagCycleTest.php b/tests/Liquid/Tag/TagCycleTest.php index 857a59a6..64a02859 100644 --- a/tests/Liquid/Tag/TagCycleTest.php +++ b/tests/Liquid/Tag/TagCycleTest.php @@ -45,7 +45,7 @@ public function testMultipleNamedCycles() public function testMultipleNamedCyclesWithNamesFromContext() { - $assigns = array("var1" => 1, "var2" => 2); + $assigns = ["var1" => 1, "var2" => 2]; $this->assertTemplateResult('one one two two one one', '{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', $assigns); } } diff --git a/tests/Liquid/Tag/TagDecrementTest.php b/tests/Liquid/Tag/TagDecrementTest.php index 6d2def4b..dae8c8a7 100644 --- a/tests/Liquid/Tag/TagDecrementTest.php +++ b/tests/Liquid/Tag/TagDecrementTest.php @@ -34,16 +34,16 @@ public function testDecrementNonExistingVariable() public function testDecrementVariable() { - $this->assertTemplateResult(42, '{% decrement var %}{{ var }}', array('var' => 43)); + $this->assertTemplateResult(42, '{% decrement var %}{{ var }}', ['var' => 43]); } public function testDecrementNestedVariable() { - $this->assertTemplateResult(42, '{% for var in vars %}{% decrement var %}{{ var }}{% endfor %}', array('vars' => array(43))); + $this->assertTemplateResult(42, '{% for var in vars %}{% decrement var %}{{ var }}{% endfor %}', ['vars' => [43]]); } public function testVariableNameContainingNumber() { - $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', array('var123' => 43)); + $this->assertTemplateResult(42, '{% decrement var123 %}{{ var123 }}', ['var123' => 43]); } } diff --git a/tests/Liquid/Tag/TagExtendsTest.php b/tests/Liquid/Tag/TagExtendsTest.php index fe1252a9..260b1c28 100644 --- a/tests/Liquid/Tag/TagExtendsTest.php +++ b/tests/Liquid/Tag/TagExtendsTest.php @@ -25,10 +25,10 @@ class TagExtendsTest extends TestCase protected function setUp(): void { - $this->fs = TestFileSystem::fromArray(array( + $this->fs = TestFileSystem::fromArray([ 'base' => "{% block content %}{% endblock %}{% block footer %}{% endblock %}", 'sub-base' => "{% extends 'base' %}{% block content %}{% endblock %}{% block footer %} Boo! {% endblock %}", - )); + ]); } protected function tearDown(): void @@ -42,7 +42,7 @@ public function testBasicExtends() $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); - $output = $template->render(array("hello" => "Hello!")); + $output = $template->render(["hello" => "Hello!"]); $this->assertEquals("Hello!", $output); } @@ -51,7 +51,7 @@ public function testDefaultContentExtends() $template = new Template(); $template->setFileSystem($this->fs); $template->parse("{% block content %}{{ hello }}{% endblock %}\n{% extends 'sub-base' %}"); - $output = $template->render(array("hello" => "Hello!")); + $output = $template->render(["hello" => "Hello!"]); $this->assertEquals("Hello!\n Boo! ", $output); } @@ -61,7 +61,7 @@ public function testDeepExtends() $template->setFileSystem($this->fs); $template->parse('{% extends "sub-base" %}{% block content %}{{ hello }}{% endblock %}{% block footer %} I am a footer.{% endblock %}'); - $output = $template->render(array("hello" => "Hello!")); + $output = $template->render(["hello" => "Hello!"]); $this->assertEquals("Hello! I am a footer.", $output); } @@ -71,9 +71,9 @@ public function testWithCache() $template->setFileSystem($this->fs); $template->setCache(new Local()); - foreach (array("Before cache", "With cache") as $type) { + foreach (["Before cache", "With cache"] as $type) { $template->parse("{% extends 'base' %}{% block content %}{{ hello }}{% endblock %}"); - $output = $template->render(array("hello" => "$type")); + $output = $template->render(["hello" => "$type"]); $this->assertEquals($type, $output); } @@ -86,10 +86,10 @@ public function testWithCache() public function testExtendsReplaceContentWithCache() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'outer' => "{% block content %}Content for outer block{% endblock %} / {% block footer %}Footer for outer block{% endblock %}", 'inner' => "{% extends 'outer' %}{% block content %}Content for inner block{% endblock %}", - ))); + ])); $contentsWithoutCache = $template->parseFile('inner')->render(); @@ -102,11 +102,11 @@ public function testExtendsReplaceContentWithCache() public function testExtendsReplaceContentWithVariables() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'outer' => "{% block content %}Outer{{ a }}{% endblock %}Spacer{{ a }}{% block footer %}Footer{{ a }}{% endblock %}", 'middle' => "{% extends 'outer' %}{% block content %}Middle{{ a }}{% endblock %}", 'inner' => "{% extends 'middle' %}{% block content %}Inner{{ a }}{% endblock %}", - ))); + ])); $template->setCache(new Local()); @@ -120,10 +120,10 @@ public function testExtendsReplaceContentWithVariables() public function testExtendsWithEmptyDefaultContent() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'base' => "
{% block content %}{% endblock %}
", 'extends' => "{% extends 'base' %}{% block content %}{{ test }}{% endblock %}", - ))); + ])); $template->setCache(new Local()); @@ -140,24 +140,24 @@ public function testCacheDiscardedIfFileChanges() $template->setCache(new Local()); $content = "[{{ name }}]"; - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'outer' => &$content, - 'inner' => "{% extends 'outer' %}" - ))); + 'inner' => "{% extends 'outer' %}", + ])); $template->parseFile('inner'); - $output = $template->render(array("name" => "Example")); + $output = $template->render(["name" => "Example"]); $this->assertEquals("[Example]", $output); // this should go from cache $template->parse("{% extends 'outer' %}"); - $output = $template->render(array("name" => "Example")); + $output = $template->render(["name" => "Example"]); $this->assertEquals("[Example]", $output); // content change should trigger re-render $content = "<{{ name }}>"; $template->parseFile('inner'); - $output = $template->render(array("name" => "Example")); + $output = $template->render(["name" => "Example"]); $this->assertEquals("", $output); } diff --git a/tests/Liquid/Tag/TagForTest.php b/tests/Liquid/Tag/TagForTest.php index ebea7fd4..588045f3 100644 --- a/tests/Liquid/Tag/TagForTest.php +++ b/tests/Liquid/Tag/TagForTest.php @@ -28,12 +28,12 @@ public function testForInvalidSyntax() public function testFor() { - $this->assertTemplateResult('', '{%for item in array%} yo {%endfor%}', array('array' => array())); - $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1, 2, 3, 4))); - $this->assertTemplateResult(' boo boo boo boo ', '{%for item in array%} boo {%endfor%}', array('array' => new \ArrayIterator(array(1, 2, 3, 4)))); - $this->assertTemplateResult('yoyo', '{%for item in array%}yo{%endfor%}', array('array' => array(1, 2))); - $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%endfor%}', array('array' => array(1))); - $this->assertTemplateResult('', '{%for item in array%}{%endfor%}', array('array' => array(1, 2))); + $this->assertTemplateResult('', '{%for item in array%} yo {%endfor%}', ['array' => []]); + $this->assertTemplateResult(' yo yo yo yo ', '{%for item in array%} yo {%endfor%}', ['array' => [1, 2, 3, 4]]); + $this->assertTemplateResult(' boo boo boo boo ', '{%for item in array%} boo {%endfor%}', ['array' => new \ArrayIterator([1, 2, 3, 4])]); + $this->assertTemplateResult('yoyo', '{%for item in array%}yo{%endfor%}', ['array' => [1, 2]]); + $this->assertTemplateResult(' yo ', '{%for item in array%} yo {%endfor%}', ['array' => [1]]); + $this->assertTemplateResult('', '{%for item in array%}{%endfor%}', ['array' => [1, 2]]); $expected = <<assertTemplateResult($expected, $template, array('array' => array(1, 2, 3))); + $this->assertTemplateResult($expected, $template, ['array' => [1, 2, 3]]); } public function testForWithVariable() { - $this->assertTemplateResult(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', array('array' => array(1, 2, 3))); - $this->assertTemplateResult('123', '{%for item in array%}{{item}}{%endfor%}', array('array' => array(1, 2, 3))); - $this->assertTemplateResult('123', '{% for item in array %}{{item}}{% endfor %}', array('array' => array(1, 2, 3))); - $this->assertTemplateResult('abcd', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', 'b', 'c', 'd'))); - $this->assertTemplateResult('a b c', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', ' ', 'b', ' ', 'c'))); - $this->assertTemplateResult('abc', '{%for item in array%}{{item}}{%endfor%}', array('array' => array('a', '', 'b', '', 'c'))); - $this->assertTemplateResult(' a ', "{%\nfor item in array%} {{item}} {%endfor%}", array('array' => array('a'))); + $this->assertTemplateResult(' 1 2 3 ', '{%for item in array%} {{item}} {%endfor%}', ['array' => [1, 2, 3]]); + $this->assertTemplateResult('123', '{%for item in array%}{{item}}{%endfor%}', ['array' => [1, 2, 3]]); + $this->assertTemplateResult('123', '{% for item in array %}{{item}}{% endfor %}', ['array' => [1, 2, 3]]); + $this->assertTemplateResult('abcd', '{%for item in array%}{{item}}{%endfor%}', ['array' => ['a', 'b', 'c', 'd']]); + $this->assertTemplateResult('a b c', '{%for item in array%}{{item}}{%endfor%}', ['array' => ['a', ' ', 'b', ' ', 'c']]); + $this->assertTemplateResult('abc', '{%for item in array%}{{item}}{%endfor%}', ['array' => ['a', '', 'b', '', 'c']]); + $this->assertTemplateResult(' a ', "{%\nfor item in array%} {{item}} {%endfor%}", ['array' => ['a']]); } public function testForWithHash() { - $this->assertTemplateResult('a=b c=d e=f ', '{%for item in array%}{{item[0]}}={{item[1]}} {%endfor%}', array('array' => array('a' => 'b', 'c' => 'd', 'e' => 'f'))); + $this->assertTemplateResult('a=b c=d e=f ', '{%for item in array%}{{item[0]}}={{item[1]}} {%endfor%}', ['array' => ['a' => 'b', 'c' => 'd', 'e' => 'f']]); } public function testForHelpers() { - $assigns = array('array' => array(1, 2, 3)); + $assigns = ['array' => [1, 2, 3]]; $this->assertTemplateResult(' 1/3 2/3 3/3 ', '{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}', $assigns); $this->assertTemplateResult(' 1 2 3 ', '{%for item in array%} {{forloop.index}} {%endfor%}', $assigns); @@ -83,7 +83,7 @@ public function testForHelpers() public function testForHelpersWithOffsetAndLimit() { - $assigns = array('array' => array(0, 1, 2, 3, 4)); + $assigns = ['array' => [0, 1, 2, 3, 4]]; $this->assertTemplateResult(' 1/3 2/3 3/3 ', '{%for item in array offset:1 limit:3%} {{forloop.index}}/{{forloop.length}} {%endfor%}', $assigns); $this->assertTemplateResult(' 1 2 3 ', '{%for item in array offset:1 limit:3%} {{forloop.index}} {%endfor%}', $assigns); @@ -96,7 +96,7 @@ public function testForHelpersWithOffsetAndLimit() public function testForAndIf() { - $assigns = array('array' => array(1, 2, 3)); + $assigns = ['array' => [1, 2, 3]]; $this->assertTemplateResult(' yay ', '{%for item in array%} {% if forloop.first %}yay{% endif %} {%endfor%}', $assigns); $this->assertTemplateResult(' yay boo boo ', '{%for item in array%} {% if forloop.first %}yay{% else %}boo{% endif %} {%endfor%}', $assigns); $this->assertTemplateResult(' boo boo ', '{%for item in array%} {% if forloop.first %}{% else %}boo{% endif %} {%endfor%}', $assigns); @@ -104,7 +104,7 @@ public function testForAndIf() public function testLimiting() { - $assigns = array('array' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); + $assigns = ['array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]; $this->assertTemplateResult('12', '{%for i in array limit:2 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('1234567890', '{%for i in array limit:20 %}{{ i }}{%endfor%}', $assigns); $this->assertTemplateResult('1234', '{%for i in array limit:4 %}{{ i }}{%endfor%}', $assigns); @@ -118,19 +118,19 @@ public function testLimiting() public function testNestedFor() { - $assigns = array('array' => array(array(1, 2), array(3, 4), array(5, 6))); + $assigns = ['array' => [[1, 2], [3, 4], [5, 6]]]; $this->assertTemplateResult('123456', '{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}', $assigns); } public function testOffsetOnly() { - $assigns = array('array' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); + $assigns = ['array' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]; $this->assertTemplateResult('890', '{%for i in array offset:7 %}{{ i }}{%endfor%}', $assigns); } public function testPauseResume() { - $assigns = array('array' => array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); + $assigns = ['array' => ['items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]]; $markup = << array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); + $assigns = ['array' => ['items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]]; $markup = << array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); + $assigns = ['array' => ['items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]]; $markup = << array('items' => array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0))); + $assigns = ['array' => ['items' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]]; $markup = <<assertTemplateResult(' 9 10 11', '{%for i in (9..11)%} {{i}}{%endfor%}'); $this->assertTemplateResult('9991000', '{%for i in (999..1000)%}{{i}}{%endfor%}'); - $assigns = array('variable' => 100); + $assigns = ['variable' => 100]; $this->assertTemplateResult('9596979899100', '{%for i in (95..variable)%}{{i}}{%endfor%}', $assigns); } } diff --git a/tests/Liquid/Tag/TagIfTest.php b/tests/Liquid/Tag/TagIfTest.php index 31482f7b..2b6a21fa 100644 --- a/tests/Liquid/Tag/TagIfTest.php +++ b/tests/Liquid/Tag/TagIfTest.php @@ -94,68 +94,68 @@ public function testVarStringsEqual() { $text = " {% if var == \"hello there!\" %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); + $this->assertTemplateResult($expected, $text, ['var' => 'hello there!']); } public function testVarStringsAreNotEqual() { $text = " {% if \"hello there!\" == var %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); + $this->assertTemplateResult($expected, $text, ['var' => 'hello there!']); } public function testVarAndLongStringAreEqual() { $text = " {% if var == 'hello there!' %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); + $this->assertTemplateResult($expected, $text, ['var' => 'hello there!']); } public function testVarAndLongStringAreEqualBackwards() { $text = " {% if 'hello there!' == var %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 'hello there!')); + $this->assertTemplateResult($expected, $text, ['var' => 'hello there!']); } public function testIsCollectionEmpty() { $text = " {% if array == empty %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('array' => array())); + $this->assertTemplateResult($expected, $text, ['array' => []]); $text = " {% if empty == array %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('array' => array())); + $this->assertTemplateResult($expected, $text, ['array' => []]); } public function testIsNotCollectionEmpty() { $text = " {% if array == empty %} true {% else %} false {% endif %} "; $expected = " false "; - $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 3))); + $this->assertTemplateResult($expected, $text, ['array' => [1, 2, 3]]); } public function testNil() { $text = " {% if var == null %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => null)); + $this->assertTemplateResult($expected, $text, ['var' => null]); $text = " {% if var == null %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => null)); + $this->assertTemplateResult($expected, $text, ['var' => null]); } public function testNotNil() { $text = " {% if var != null %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 1)); + $this->assertTemplateResult($expected, $text, ['var' => 1]); $text = " {% if var != null %} true {% else %} false {% endif %} "; $expected = " true "; - $this->assertTemplateResult($expected, $text, array('var' => 1)); + $this->assertTemplateResult($expected, $text, ['var' => 1]); } public function testNotNilWhitespaceControlEdgeCase() @@ -166,31 +166,31 @@ public function testNotNilWhitespaceControlEdgeCase() public function testIfFromVariable() { - $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => false)); - $this->assertTemplateResult('', '{% if var %} NO {% endif %}', array('var' => null)); - $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', array('foo' => array('bar' => false))); - $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', array('foo' => array())); - $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', array('foo' => null)); - - $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', array('var' => "text")); - $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', array('var' => true)); - $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', array('var' => 1)); + $this->assertTemplateResult('', '{% if var %} NO {% endif %}', ['var' => false]); + $this->assertTemplateResult('', '{% if var %} NO {% endif %}', ['var' => null]); + $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', ['foo' => ['bar' => false]]); + $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', ['foo' => []]); + $this->assertTemplateResult('', '{% if foo.bar %} NO {% endif %}', ['foo' => null]); + + $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', ['var' => "text"]); + $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', ['var' => true]); + $this->assertTemplateResult(' YES ', '{% if var %} YES {% endif %}', ['var' => 1]); $this->assertTemplateResult(' YES ', '{% if "foo" %} YES {% endif %}'); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', array('foo' => array('bar' => true))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', array('foo' => array('bar' => "text"))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', array('foo' => array('bar' => 1))); - - $this->assertTemplateResult(' YES ', '{% if var %} NO {% else %} YES {% endif %}', array('var' => false)); - $this->assertTemplateResult(' YES ', '{% if var %} NO {% else %} YES {% endif %}', array('var' => null)); - $this->assertTemplateResult(' YES ', '{% if var %} YES {% else %} NO {% endif %}', array('var' => true)); - $this->assertTemplateResult(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', array('var' => "text")); - - $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', array('foo' => array('bar' => false))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', array('foo' => array('bar' => true))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', array('foo' => array('bar' => "text"))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', array('foo' => array('notbar' => true))); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', array('foo' => array())); - $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', array('notfoo' => array('bar' => true))); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', ['foo' => ['bar' => true]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', ['foo' => ['bar' => "text"]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% endif %}', ['foo' => ['bar' => 1]]); + + $this->assertTemplateResult(' YES ', '{% if var %} NO {% else %} YES {% endif %}', ['var' => false]); + $this->assertTemplateResult(' YES ', '{% if var %} NO {% else %} YES {% endif %}', ['var' => null]); + $this->assertTemplateResult(' YES ', '{% if var %} YES {% else %} NO {% endif %}', ['var' => true]); + $this->assertTemplateResult(' YES ', '{% if "foo" %} YES {% else %} NO {% endif %}', ['var' => "text"]); + + $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', ['foo' => ['bar' => false]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', ['foo' => ['bar' => true]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} YES {% else %} NO {% endif %}', ['foo' => ['bar' => "text"]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', ['foo' => ['notbar' => true]]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', ['foo' => []]); + $this->assertTemplateResult(' YES ', '{% if foo.bar %} NO {% else %} YES {% endif %}', ['notfoo' => ['bar' => true]]); } public function testNestedIf() @@ -215,11 +215,11 @@ public function testComplexConditions() public function testContains() { - $this->assertTemplateResult('true', '{% if foo contains "h" %}true{% else %}false{% endif %}', array('foo' => array('k', 'h', 'z'))); - $this->assertTemplateResult('false', '{% if foo contains "y" %}true{% else %}false{% endif %}', array('foo' => array('k', 'h', 'z'))); - $this->assertTemplateResult('true', '{% if foo contains "e" %}true{% else %}false{% endif %}', array('foo' => 'abcedf')); - $this->assertTemplateResult('true', '{% if foo contains "e" %}true{% else %}false{% endif %}', array('foo' => 'e')); - $this->assertTemplateResult('false', '{% if foo contains "y" %}true{% else %}false{% endif %}', array('foo' => 'abcedf')); + $this->assertTemplateResult('true', '{% if foo contains "h" %}true{% else %}false{% endif %}', ['foo' => ['k', 'h', 'z']]); + $this->assertTemplateResult('false', '{% if foo contains "y" %}true{% else %}false{% endif %}', ['foo' => ['k', 'h', 'z']]); + $this->assertTemplateResult('true', '{% if foo contains "e" %}true{% else %}false{% endif %}', ['foo' => 'abcedf']); + $this->assertTemplateResult('true', '{% if foo contains "e" %}true{% else %}false{% endif %}', ['foo' => 'e']); + $this->assertTemplateResult('false', '{% if foo contains "y" %}true{% else %}false{% endif %}', ['foo' => 'abcedf']); } /** @@ -255,7 +255,7 @@ public function testInvalidOperator() { $this->expectException(\Liquid\Exception\RenderException::class); - $this->assertTemplateResult('', '{% if foo === y %}true{% else %}false{% endif %}', array('foo' => true, 'y' => true)); + $this->assertTemplateResult('', '{% if foo === y %}true{% else %}false{% endif %}', ['foo' => true, 'y' => true]); } /** @@ -264,7 +264,7 @@ public function testIncomparable() { $this->expectException(\Liquid\Exception\RenderException::class); - $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', array('foo' => (object) array())); + $this->assertTemplateResult('', '{% if foo == 1 %}true{% endif %}', ['foo' => (object) []]); } /** diff --git a/tests/Liquid/Tag/TagIfchangedTest.php b/tests/Liquid/Tag/TagIfchangedTest.php index 03587316..5dcad58a 100644 --- a/tests/Liquid/Tag/TagIfchangedTest.php +++ b/tests/Liquid/Tag/TagIfchangedTest.php @@ -19,13 +19,13 @@ public function testWorks() { $text = "{% for i in array %}{% ifchanged %} {{ i }} {% endifchanged %}{% endfor %}"; $expected = " 1 2 3 "; - $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 3))); + $this->assertTemplateResult($expected, $text, ['array' => [1, 2, 3]]); } public function testFails() { $text = "{% for i in array %}{% ifchanged %} {{ i }} {% endifchanged %}{% endfor %}"; $expected = " 1 2 1 "; - $this->assertTemplateResult($expected, $text, array('array' => array(1, 2, 2, 1))); + $this->assertTemplateResult($expected, $text, ['array' => [1, 2, 2, 1]]); } } diff --git a/tests/Liquid/Tag/TagIncludeTest.php b/tests/Liquid/Tag/TagIncludeTest.php index 234dfe0d..bb1d8229 100644 --- a/tests/Liquid/Tag/TagIncludeTest.php +++ b/tests/Liquid/Tag/TagIncludeTest.php @@ -23,14 +23,14 @@ class TagIncludeTest extends TestCase protected function setUp(): void { - $this->fs = TestFileSystem::fromArray(array( + $this->fs = TestFileSystem::fromArray([ 'a' => "{% include 'b' %}", 'b' => "{% include 'c' %}", 'c' => "{% include 'd' %}", 'd' => '({{ inner }})', 'inner' => "Inner: {{ inner }}{{ other }}", 'example' => "Example: {% include 'inner' %}", - )); + ]); } protected function tearDown(): void @@ -87,7 +87,7 @@ public function testIncludeTag() $template->parse("Outer-{% include 'inner' with 'value' other:23 %}-Outer{% include 'inner' for var other:'loop' %}"); - $output = $template->render(array("var" => array(1, 2, 3))); + $output = $template->render(["var" => [1, 2, 3]]); $this->assertEquals("Outer-Inner: value23-OuterInner: 1loopInner: 2loopInner: 3loop", $output); } @@ -99,7 +99,7 @@ public function testIncludeTagNoWith() $template->parse("Outer-{% include 'inner' %}-Outer-{% include 'inner' other:'23' %}"); - $output = $template->render(array("inner" => "orig", "var" => array(1, 2, 3))); + $output = $template->render(["inner" => "orig", "var" => [1, 2, 3]]); $this->assertEquals("Outer-Inner: orig-Outer-Inner: orig23", $output); } @@ -113,10 +113,10 @@ public function testWithCache() $template->setFileSystem($this->fs); $template->setCache(new Local()); - foreach (array("Before cache:", "With cache:") as $type) { + foreach (["Before cache:", "With cache:"] as $type) { $template->parse("{{ type }} {% for item in list %}{% include 'example' inner:item %} {% endfor %}{% include 'a' %}"); - $template->render(array("inner" => "foo", "list" => array(1, 2, 3)), array()); - $this->assertEquals("$type Example: Inner: 1 Example: Inner: 2 (bar)", $template->render(array("type" => $type, "inner" => "bar", "list" => array(1, 2)))); + $template->render(["inner" => "foo", "list" => [1, 2, 3]], []); + $this->assertEquals("$type Example: Inner: 1 Example: Inner: 2 (bar)", $template->render(["type" => $type, "inner" => "bar", "list" => [1, 2]])); } $template->setCache(null); @@ -136,14 +136,14 @@ public function testIncludeTemplateFile() public function testIncludePassPlainValue() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'inner' => "[{{ other }}]", 'example' => "({% include 'inner' other:var %})", - ))); + ])); $template->parse("{% include 'example' %}"); - $output = $template->render(array("var" => "test")); + $output = $template->render(["var" => "test"]); $this->assertEquals("([test])", $output); } @@ -152,61 +152,61 @@ public function testIncludePassPlainValue() public function testIncludePassArrayWithoutIndex() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'inner' => "[{{ other }}]", 'example' => "({% include 'inner' other:var %})", - ))); + ])); $template->parse("{% include 'example' %}"); - $output = $template->render(array("var" => array("a", "b", "c"))); + $output = $template->render(["var" => ["a", "b", "c"]]); $this->assertEquals("([abc])", $output); } public function testIncludePassArrayWithIndex() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'inner' => "[{{ other[0] }}]", 'example' => "({% include 'inner' other:var %})", - ))); + ])); $template->parse("{% include 'example' %}"); - $output = $template->render(array("var" => array("a", "b", "c"))); + $output = $template->render(["var" => ["a", "b", "c"]]); $this->assertEquals("([a])", $output); } public function testIncludePassObjectValue() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'inner' => "[{{ other.a }}]", 'example' => "({% include 'inner' other:var %})", - ))); + ])); $template->parse("{% include 'example' %}"); - $output = $template->render(array("var" => (object) array('a' => 'b'))); + $output = $template->render(["var" => (object) ['a' => 'b']]); $this->assertEquals("([b])", $output); } public function testIncludeWithoutQuotes() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'inner' => "[{{ other }}]", 'example' => "{%include inner other:var %} ({{var}})", - ))); + ])); $template->parse("{% include example other:var %}"); - $output = $template->render(array("var" => "test")); + $output = $template->render(["var" => "test"]); $this->assertEquals("[test] (test)", $output); $template->parse("{% include inner %}"); - $output = $template->render(array("other" => "test")); + $output = $template->render(["other" => "test"]); $this->assertEquals("[test]", $output); } @@ -216,24 +216,24 @@ public function testIncludeWithoutQuotes() public function testIncludeWithExtends() { $template = new Template(); - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'outer' => "{% block content %}Content for outer block{% endblock %} / {% block footer %}Footer for outer block{% endblock %}", 'content' => 'Content for {{ name }} block', 'middle' => "{% extends 'outer' %}{% block content %}{% include 'content' name:'middle' %}{% endblock %}", 'main' => "Main: {% extends 'middle' %}{% block footer %}{% include 'footer-top' hello:message %}{% endblock %}", 'footer-bottom' => "{{ name }} with message: {{ hello }}", 'footer-top' => "Footer top and {% include 'footer-bottom' name:'bottom' %}", - ))); + ])); $template->setCache(new Local()); - foreach (array("Before cache", "With cache") as $type) { - $this->assertEquals("Block with message: $type", $template->parseFile('footer-bottom')->render(array("name" => "Block", "hello" => $type))); + foreach (["Before cache", "With cache"] as $type) { + $this->assertEquals("Block with message: $type", $template->parseFile('footer-bottom')->render(["name" => "Block", "hello" => $type])); $this->assertEquals('Content for middle block / Footer for outer block', $template->parseFile('middle')->render()); - $this->assertEquals("Main: Content for middle block / Footer top and bottom with message: $type", $template->parseFile('main')->render(array("message" => $type))); + $this->assertEquals("Main: Content for middle block / Footer top and bottom with message: $type", $template->parseFile('main')->render(["message" => $type])); $template->parse("{% include 'main' hello:message %}"); - $output = $template->render(array("message" => $type)); + $output = $template->render(["message" => $type]); $this->assertEquals("Main: Content for middle block / Footer top and bottom with message: $type", $output); } @@ -246,17 +246,17 @@ public function testCacheDiscardedIfFileChanges() $template->setCache(new Local()); $content = "[{{ name }}]"; - $template->setFileSystem(TestFileSystem::fromArray(array( + $template->setFileSystem(TestFileSystem::fromArray([ 'example' => &$content, - ))); + ])); $template->parse("{% include 'example' %}"); - $output = $template->render(array("name" => "Example")); + $output = $template->render(["name" => "Example"]); $this->assertEquals("[Example]", $output); $content = "<{{ name }}>"; $template->parse("{% include 'example' %}"); - $output = $template->render(array("name" => "Example")); + $output = $template->render(["name" => "Example"]); $this->assertEquals("", $output); } } diff --git a/tests/Liquid/Tag/TagIncrementTest.php b/tests/Liquid/Tag/TagIncrementTest.php index 4a49bdea..8a90eb7b 100644 --- a/tests/Liquid/Tag/TagIncrementTest.php +++ b/tests/Liquid/Tag/TagIncrementTest.php @@ -34,11 +34,11 @@ public function testIncrementNonExistingVariable() public function testIncrementVariable() { - $this->assertTemplateResult(42, '{% increment var %}{{ var }}', array('var' => 41)); + $this->assertTemplateResult(42, '{% increment var %}{{ var }}', ['var' => 41]); } public function testIncrementNestedVariable() { - $this->assertTemplateResult(42, '{% for var in vars %}{% increment var %}{{ var }}{% endfor %}', array('vars' => array(41))); + $this->assertTemplateResult(42, '{% for var in vars %}{% increment var %}{{ var }}{% endfor %}', ['vars' => [41]]); } } diff --git a/tests/Liquid/Tag/TagPaginateTest.php b/tests/Liquid/Tag/TagPaginateTest.php index 30c03113..af80f39b 100644 --- a/tests/Liquid/Tag/TagPaginateTest.php +++ b/tests/Liquid/Tag/TagPaginateTest.php @@ -38,21 +38,21 @@ public function testWorks() { $text = "{% paginate products by 3 %}{% for product in products %} {{ product.id }} {% endfor %}{% endpaginate %}"; $expected = " 1 2 3 "; - $this->assertTemplateResult($expected, $text, array('products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + $this->assertTemplateResult($expected, $text, ['products' => [['id' => 1], ['id' => 2], ['id' => 3], ['id' => 4], ['id' => 5]]]); } public function testVariables() { $text = " {% paginate search.products by 3 %}{{ paginate.page_size }} {{ paginate.current_page }} {{ paginate.current_offset }} {{ paginate.pages }} {{ paginate.items }} {{ paginate.next.url }}{% endpaginate %}"; $expected = " 3 1 0 2 5 http://?page=2"; - $this->assertTemplateResult($expected, $text, array('search' => array('products' => new \ArrayIterator(array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))))); + $this->assertTemplateResult($expected, $text, ['search' => ['products' => new \ArrayIterator([['id' => 1], ['id' => 2], ['id' => 3], ['id' => 4], ['id' => 5]])]]); } public function testNextPage() { $text = '{% paginate products by 1 %}{% for product in products %} {{ product.id }} {% endfor %}{{ paginate.next.title }}{% endpaginate %}'; $expected = ' 2 Next'; - $this->assertTemplateResult($expected, $text, array('HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2, 'products' => array(array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)))); + $this->assertTemplateResult($expected, $text, ['HTTP_HOST' => 'example.com', 'REQUEST_URI' => '/products', 'HTTPS' => 'on', 'page' => 2, 'products' => [['id' => 1], ['id' => 2], ['id' => 3], ['id' => 4], ['id' => 5]]]); } /** @@ -74,12 +74,12 @@ public function testNoCollection() $this->assertTemplateResult('', '{% paginate products by 1 %}{% for product in products %}{{ product.id }}{% endfor %}{% endpaginate %}'); } - const PAGINATION_ASSIGNS = array( + const PAGINATION_ASSIGNS = [ 'HTTP_HOST' => 'example.com', 'HTTPS' => 'on', 'page' => 1, - 'articles' => array(array('title' => 1), array('title' => 2), array('title' => 3)), - ); + 'articles' => [['title' => 1], ['title' => 2], ['title' => 3]], + ]; public function testPaginationForRepeatedCalls() { diff --git a/tests/Liquid/Tag/TagRawTest.php b/tests/Liquid/Tag/TagRawTest.php index 21a90d95..a79acf2f 100644 --- a/tests/Liquid/Tag/TagRawTest.php +++ b/tests/Liquid/Tag/TagRawTest.php @@ -20,7 +20,7 @@ public function testRaw() $this->assertTemplateResult( '{{ y | plus: x }}{% if %} is equal to 11.', '{% raw %}{{ y | plus: x }}{% if %}{% endraw %} is equal to 11.', - array('x' => 5, 'y' => 6) + ['x' => 5, 'y' => 6] ); $this->assertTemplateResult('', '{% raw %}{% endraw %}'); diff --git a/tests/Liquid/Tag/TagTablerowTest.php b/tests/Liquid/Tag/TagTablerowTest.php index 58bd7942..951e79c7 100644 --- a/tests/Liquid/Tag/TagTablerowTest.php +++ b/tests/Liquid/Tag/TagTablerowTest.php @@ -20,25 +20,25 @@ public function testTablerow() $this->assertTemplateResult( ''."\n".' yo yo yo yo '."\n", '{% tablerow item in array %} yo {% endtablerow %}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( '' . "\n" . ' item 1 ' . "\n" . '' . "\n" . ' item 2 ' . "\n", '{% tablerow item in array cols:1 %} item {{ item }} {% endtablerow %}', - array('array' => array(1, 2)) + ['array' => [1, 2]] ); $this->assertTemplateResult( ''."\n".' 2 3 '."\n", '{% tablerow item in array limit:2 offset:1 %} {{ item }} {% endtablerow %}', - array('array' => array(1, 2, 3, 4)) + ['array' => [1, 2, 3, 4]] ); $this->assertTemplateResult( ''."\n".' yo yo '."\n", '{%tablerow item in array%} yo {%endtablerow%}', - array('array' => new \ArrayIterator(array(1, 2))) + ['array' => new \ArrayIterator([1, 2])] ); } @@ -48,7 +48,7 @@ public function testInvalidSyntax() { $this->expectException(\Liquid\Exception\ParseException::class); - $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', array()); + $this->assertTemplateResult('', '{%tablerow item array%} yo {%endtablerow%}', []); } /** @@ -57,6 +57,6 @@ public function testNotArray() { $this->expectException(\Liquid\Exception\RenderException::class); - $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', array('array' => true)); + $this->assertTemplateResult('', '{%tablerow item in array%} yo {%endtablerow%}', ['array' => true]); } } diff --git a/tests/Liquid/Tag/TagUnlessTest.php b/tests/Liquid/Tag/TagUnlessTest.php index 1f034d93..5f54156a 100644 --- a/tests/Liquid/Tag/TagUnlessTest.php +++ b/tests/Liquid/Tag/TagUnlessTest.php @@ -33,13 +33,13 @@ public function testWithVariable() { $text = " {% unless variable %} true {% else %} false {% endunless %} "; $expected = " false "; - $this->assertTemplateResult($expected, $text, array('variable' => true)); + $this->assertTemplateResult($expected, $text, ['variable' => true]); } public function testForAndUnless() { - $this->assertTemplateResult('0=>yay 0=>yay 1=> ', '{% for item in array %}{{ forloop.last }}=>{% unless forloop.last %}yay{% endunless %} {% endfor %}', array('array' => array(1, 2, 3))); - $this->assertTemplateResult('1=> 0=>yay 0=>yay ', '{% for item in array %}{{ forloop.first }}=>{% unless forloop.first %}yay{% endunless %} {% endfor %}', array('array' => array(1, 2, 3))); - $this->assertTemplateResult('0=> 0=> 1=>yay ', '{% for item in array %}{{ forloop.last }}=>{% if forloop.last %}yay{% endif %} {% endfor %}', array('array' => array(1, 2, 3))); + $this->assertTemplateResult('0=>yay 0=>yay 1=> ', '{% for item in array %}{{ forloop.last }}=>{% unless forloop.last %}yay{% endunless %} {% endfor %}', ['array' => [1, 2, 3]]); + $this->assertTemplateResult('1=> 0=>yay 0=>yay ', '{% for item in array %}{{ forloop.first }}=>{% unless forloop.first %}yay{% endunless %} {% endfor %}', ['array' => [1, 2, 3]]); + $this->assertTemplateResult('0=> 0=> 1=>yay ', '{% for item in array %}{{ forloop.last }}=>{% if forloop.last %}yay{% endif %} {% endfor %}', ['array' => [1, 2, 3]]); } } diff --git a/tests/Liquid/TemplateTest.php b/tests/Liquid/TemplateTest.php index 2f372cac..8a7cad3c 100644 --- a/tests/Liquid/TemplateTest.php +++ b/tests/Liquid/TemplateTest.php @@ -40,7 +40,7 @@ public function testSetCacheInvalidKey() $this->expectException(\Liquid\LiquidException::class); $template = new Template(); - $template->setCache(array()); + $template->setCache([]); } /** @@ -50,44 +50,44 @@ public function testSetCacheInvalidClass() $this->expectException(\Liquid\LiquidException::class); $template = new Template(); - $template->setCache(array('cache' => 'no_such_class')); + $template->setCache(['cache' => 'no_such_class']); } public function testSetCacheThroughArray() { $template = new Template(); - $template->setCache(array('cache' => 'file', 'cache_dir' => $this->cacheDir)); + $template->setCache(['cache' => 'file', 'cache_dir' => $this->cacheDir]); $this->assertInstanceOf(\Liquid\Cache\File::class, $template::getCache()); } public function testSetCacheThroughCacheObject() { $template = new Template(); - $cache = new Cache\File(array('cache_dir' => $this->cacheDir)); + $cache = new Cache\File(['cache_dir' => $this->cacheDir]); $template->setCache($cache); $this->assertEquals($cache, $template::getCache()); } public function testTokenizeStrings() { - $this->assertEquals(array(' '), Template::tokenize(' ')); - $this->assertEquals(array('hello world'), Template::tokenize('hello world')); + $this->assertEquals([' '], Template::tokenize(' ')); + $this->assertEquals(['hello world'], Template::tokenize('hello world')); } public function testTokenizeVariables() { - $this->assertEquals(array('{{funk}}'), Template::tokenize('{{funk}}')); - $this->assertEquals(array(' ', '{{funk}}', ' '), Template::tokenize(' {{funk}} ')); - $this->assertEquals(array(' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '), Template::tokenize(' {{funk}} {{so}} {{brother}} ')); - $this->assertEquals(array(' ', '{{ funk }}', ' '), Template::tokenize(' {{ funk }} ')); + $this->assertEquals(['{{funk}}'], Template::tokenize('{{funk}}')); + $this->assertEquals([' ', '{{funk}}', ' '], Template::tokenize(' {{funk}} ')); + $this->assertEquals([' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], Template::tokenize(' {{funk}} {{so}} {{brother}} ')); + $this->assertEquals([' ', '{{ funk }}', ' '], Template::tokenize(' {{ funk }} ')); } public function testTokenizeBlocks() { - $this->assertEquals(array('{%comment%}'), Template::tokenize('{%comment%}')); - $this->assertEquals(array(' ', '{%comment%}', ' '), Template::tokenize(' {%comment%} ')); - $this->assertEquals(array(' ', '{%comment%}', ' ', '{%endcomment%}', ' '), Template::tokenize(' {%comment%} {%endcomment%} ')); - $this->assertEquals(array(' ', '{% comment %}', ' ', '{% endcomment %}', ' '), Template::tokenize(" {% comment %} {% endcomment %} ")); + $this->assertEquals(['{%comment%}'], Template::tokenize('{%comment%}')); + $this->assertEquals([' ', '{%comment%}', ' '], Template::tokenize(' {%comment%} ')); + $this->assertEquals([' ', '{%comment%}', ' ', '{%endcomment%}', ' '], Template::tokenize(' {%comment%} {%endcomment%} ')); + $this->assertEquals([' ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template::tokenize(" {% comment %} {% endcomment %} ")); } public function testBlackspace() @@ -97,7 +97,7 @@ public function testBlackspace() $nodelist = $template->getRoot()->getNodelist(); - $this->assertEquals(array(' '), $nodelist); + $this->assertEquals([' '], $nodelist); } public function testVariableBeginning() diff --git a/tests/Liquid/TestCase.php b/tests/Liquid/TestCase.php index 4cbb1a98..1b4bf176 100644 --- a/tests/Liquid/TestCase.php +++ b/tests/Liquid/TestCase.php @@ -24,7 +24,7 @@ protected function setUp(): void { parent::setUp(); - $defaultConfig = array( + $defaultConfig = [ 'HAS_PROPERTY_METHOD' => 'field_exists', 'GET_PROPERTY_METHOD' => 'get', 'FILTER_SEPARATOR' => '\|', @@ -38,7 +38,7 @@ protected function setUp(): void 'VARIABLE_END' => '}}', 'VARIABLE_NAME' => '[a-zA-Z_][a-zA-Z0-9_.-]*', 'EXPOSE_SERVER' => false, - ); + ]; foreach ($defaultConfig as $configKey => $configValue) { Liquid::set($configKey, $configValue); @@ -53,7 +53,7 @@ protected function setUp(): void * @param array $assigns * @param string $message */ - public function assertTemplateResult($expected, $templateString, array $assigns = array(), $message = "%s") + public function assertTemplateResult($expected, $templateString, array $assigns = [], $message = "%s") { $template = new Template(); $template->parse($templateString); diff --git a/tests/Liquid/TickTest.php b/tests/Liquid/TickTest.php index 0633a39c..2e2cdadb 100644 --- a/tests/Liquid/TickTest.php +++ b/tests/Liquid/TickTest.php @@ -20,7 +20,7 @@ public function tickDataProvider() [20, 40, '{% for i in (1..10) %}{% for ii in (1..2) %}x{% endfor %}{% endfor %}'], [1, 2, '{% if true %} {% endif %}'], [7, 8, '{% assign a = 0 %} {% increment a %} {% increment a %} {% increment a %}'], - [1, 1, ' '] + [1, 1, ' '], ]; } diff --git a/tests/Liquid/VariableResolutionTest.php b/tests/Liquid/VariableResolutionTest.php index 28a3f072..064f7b14 100644 --- a/tests/Liquid/VariableResolutionTest.php +++ b/tests/Liquid/VariableResolutionTest.php @@ -17,7 +17,7 @@ public function testSimpleVariable() { $template = new Template(); $template->parse("{{test}}"); - $this->assertEquals('worked', $template->render(array('test' => 'worked'))); + $this->assertEquals('worked', $template->render(['test' => 'worked'])); } public function testSimpleWithWhitespaces() @@ -25,8 +25,8 @@ public function testSimpleWithWhitespaces() $template = new Template(); $template->parse(' {{ test }} '); - $this->assertEquals(' worked ', $template->render(array('test' => 'worked'))); - $this->assertEquals(' worked wonderfully ', $template->render(array('test' => 'worked wonderfully'))); + $this->assertEquals(' worked ', $template->render(['test' => 'worked'])); + $this->assertEquals(' worked wonderfully ', $template->render(['test' => 'worked wonderfully'])); } public function testIgnoreUnknown() @@ -42,7 +42,7 @@ public function testLineBreak() $template = new Template(); $template->parse("{{ test |\n strip_html }}"); - $this->assertEquals('worked', $template->render(array('test' => 'worked'))); + $this->assertEquals('worked', $template->render(['test' => 'worked'])); } public function testArrayScoping() @@ -50,7 +50,7 @@ public function testArrayScoping() $template = new Template(); $template->parse('{{ test.test }}'); - $this->assertEquals('worked', $template->render(array('test' => array('test' => 'worked')))); + $this->assertEquals('worked', $template->render(['test' => ['test' => 'worked']])); } public function testVariableArrayIndices() diff --git a/tests/Liquid/VariableTest.php b/tests/Liquid/VariableTest.php index 697f3996..311c9c03 100644 --- a/tests/Liquid/VariableTest.php +++ b/tests/Liquid/VariableTest.php @@ -23,65 +23,65 @@ public function testFilters() { $var = new Variable('hello | textileze'); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('textileze', array())), $var->getFilters()); + $this->assertEquals([['textileze', []]], $var->getFilters()); $var = new Variable('hello | textileze | paragraph'); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('textileze', array()), array('paragraph', array())), $var->getFilters()); + $this->assertEquals([['textileze', []], ['paragraph', []]], $var->getFilters()); $var = new Variable(" hello | strftime: '%Y'"); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('strftime', array("'%Y'"))), $var->getFilters()); + $this->assertEquals([['strftime', ["'%Y'"]]], $var->getFilters()); $var = new Variable(" 'typo' | link_to: 'Typo', true "); $this->assertEquals("'typo'", $var->getName()); - $this->assertEquals(array(array('link_to', array("'Typo'", "true"))), $var->getFilters()); + $this->assertEquals([['link_to', ["'Typo'", "true"]]], $var->getFilters()); $var = new Variable(" 'typo' | link_to: 'Typo', false "); $this->assertEquals("'typo'", $var->getName()); - $this->assertEquals(array(array('link_to', array("'Typo'", "false"))), $var->getFilters()); + $this->assertEquals([['link_to', ["'Typo'", "false"]]], $var->getFilters()); $var = new Variable(" 'foo' | repeat: 3 "); $this->assertEquals("'foo'", $var->getName()); - $this->assertEquals(array(array('repeat', array("3"))), $var->getFilters()); + $this->assertEquals([['repeat', ["3"]]], $var->getFilters()); $var = new Variable(" 'foo' | repeat: 3, 3"); $this->assertEquals("'foo'", $var->getName()); - $this->assertEquals(array(array('repeat', array("3", "3"))), $var->getFilters()); + $this->assertEquals([['repeat', ["3", "3"]]], $var->getFilters()); $var = new Variable(" 'foo' | repeat: 3, 3, 3 "); $this->assertEquals("'foo'", $var->getName()); - $this->assertEquals(array(array('repeat', array("3", "3", "3"))), $var->getFilters()); + $this->assertEquals([['repeat', ["3", "3", "3"]]], $var->getFilters()); $var = new Variable(" hello | strftime: '%Y, okay?'"); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('strftime', array("'%Y, okay?'"))), $var->getFilters()); + $this->assertEquals([['strftime', ["'%Y, okay?'"]]], $var->getFilters()); $var = new Variable(" hello | things: \"%Y, okay?\", 'the other one'"); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('things', array('"%Y, okay?"', "'the other one'"))), $var->getFilters()); + $this->assertEquals([['things', ['"%Y, okay?"', "'the other one'"]]], $var->getFilters()); $var = new Variable(" product.featured_image | img_url: '450x450', crop: 'center', scale: 2 "); $this->assertEquals("product.featured_image", $var->getName()); - $this->assertEquals(array(array('img_url', array("'450x450'", array("crop" => "'center'", "scale" => "2")))), $var->getFilters()); + $this->assertEquals([['img_url', ["'450x450'", ["crop" => "'center'", "scale" => "2"]]]], $var->getFilters()); } public function testFiltersWithoutWhitespace() { $var = new Variable('hello | textileze | paragraph'); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('textileze', array()), array('paragraph', array())), $var->getFilters()); + $this->assertEquals([['textileze', []], ['paragraph', []]], $var->getFilters()); $var = new Variable('hello|textileze|paragraph'); $this->assertEquals('hello', $var->getName()); - $this->assertEquals(array(array('textileze', array()), array('paragraph', array())), $var->getFilters()); + $this->assertEquals([['textileze', []], ['paragraph', []]], $var->getFilters()); } public function testSymbol() { $var = new Variable("http://disney.com/logo.gif | image: 'med' "); $this->assertEquals('http://disney.com/logo.gif', $var->getName()); - $this->assertEquals(array(array('image', array("'med'"))), $var->getFilters()); + $this->assertEquals([['image', ["'med'"]]], $var->getFilters()); } public function testStringSingleQuoted() diff --git a/tests/Liquid/VirtualFileSystemTest.php b/tests/Liquid/VirtualFileSystemTest.php index e78287a9..970625de 100644 --- a/tests/Liquid/VirtualFileSystemTest.php +++ b/tests/Liquid/VirtualFileSystemTest.php @@ -56,9 +56,9 @@ public function testWithFileCache() $template->setFileSystem(new Virtual(function ($templatePath) { return ''; })); - $template->setCache(new File(array( + $template->setCache(new File([ 'cache_dir' => __DIR__, - ))); + ])); $template->parse("Hello"); } @@ -70,10 +70,10 @@ public function virtualFileSystemCallback($templatePath) public function testWithRegularCallback() { $template = new Template(); - $template->setFileSystem(new Virtual(array($this, 'virtualFileSystemCallback'), true)); - $template->setCache(new File(array( + $template->setFileSystem(new Virtual([$this, 'virtualFileSystemCallback'], true)); + $template->setCache(new File([ 'cache_dir' => __DIR__.'/cache_dir/', - ))); + ])); try { $template->parse("Test: {% include 'hello' %}"); diff --git a/tests/Liquid/fixtures/assign.php b/tests/Liquid/fixtures/assign.php index b488a8ac..38789dbc 100644 --- a/tests/Liquid/fixtures/assign.php +++ b/tests/Liquid/fixtures/assign.php @@ -9,8 +9,8 @@ * @package Liquid */ -return array( - 'product' => array( +return [ + 'product' => [ 'description' => 'FirstSecond', - ), -); + ], +]; diff --git a/tests/Liquid/fixtures/case.php b/tests/Liquid/fixtures/case.php index 2e3fb4ae..5846393e 100644 --- a/tests/Liquid/fixtures/case.php +++ b/tests/Liquid/fixtures/case.php @@ -9,7 +9,7 @@ * @package Liquid */ -return array( +return [ 'max' => 5, 'post' => ['date' => 'May 28, 2019'], -); +]; diff --git a/tests/Liquid/fixtures/comment.php b/tests/Liquid/fixtures/comment.php index a1ea6892..9890e4eb 100644 --- a/tests/Liquid/fixtures/comment.php +++ b/tests/Liquid/fixtures/comment.php @@ -9,4 +9,4 @@ * @package Liquid */ -return array(); +return []; diff --git a/tests/Liquid/fixtures/cycle.php b/tests/Liquid/fixtures/cycle.php index a1ea6892..9890e4eb 100644 --- a/tests/Liquid/fixtures/cycle.php +++ b/tests/Liquid/fixtures/cycle.php @@ -9,4 +9,4 @@ * @package Liquid */ -return array(); +return []; diff --git a/tests/Liquid/fixtures/filters.php b/tests/Liquid/fixtures/filters.php index 00b6a927..8053a1b4 100644 --- a/tests/Liquid/fixtures/filters.php +++ b/tests/Liquid/fixtures/filters.php @@ -9,11 +9,11 @@ * @package Liquid */ -return array( - 'array' => array('z', 'g', 'n'), +return [ + 'array' => ['z', 'g', 'n'], 'foobar' => "Foo\nBar", - 'posts' => array( - array('id' => 2, 'title'=> 'FooBar', 'tags' => array('foo', 'bar')), - array('id' => 1, 'title'=> 'BazBar', 'tags' => array('baz', 'bar')), - ), -); + 'posts' => [ + ['id' => 2, 'title' => 'FooBar', 'tags' => ['foo', 'bar']], + ['id' => 1, 'title' => 'BazBar', 'tags' => ['baz', 'bar']], + ], +]; diff --git a/tests/Liquid/fixtures/for.php b/tests/Liquid/fixtures/for.php index 0f2246ef..cd0efe23 100644 --- a/tests/Liquid/fixtures/for.php +++ b/tests/Liquid/fixtures/for.php @@ -9,14 +9,14 @@ * @package Liquid */ -return array( +return [ 'array' => range(1, 5), - 'item' => array( + 'item' => [ 'quantity' => 5, - ), - 'articles' => array( - array('title' => 1), - array('title' => 2), - array('title' => 3), - ), -); + ], + 'articles' => [ + ['title' => 1], + ['title' => 2], + ['title' => 3], + ], +]; diff --git a/tests/Liquid/fixtures/include.php b/tests/Liquid/fixtures/include.php index a1ea6892..9890e4eb 100644 --- a/tests/Liquid/fixtures/include.php +++ b/tests/Liquid/fixtures/include.php @@ -9,4 +9,4 @@ * @package Liquid */ -return array(); +return []; diff --git a/tests/Liquid/fixtures/iterable.php b/tests/Liquid/fixtures/iterable.php index 6265127a..9a079a91 100644 --- a/tests/Liquid/fixtures/iterable.php +++ b/tests/Liquid/fixtures/iterable.php @@ -9,10 +9,10 @@ * @package Liquid */ -return array( +return [ 'generator' => call_user_func(function () { yield 'a'; yield 'b'; yield 'c'; }), -); +]; diff --git a/tests/Liquid/fixtures/output.php b/tests/Liquid/fixtures/output.php index ed4bf725..4d4882e7 100644 --- a/tests/Liquid/fixtures/output.php +++ b/tests/Liquid/fixtures/output.php @@ -9,10 +9,10 @@ * @package Liquid */ -return array( +return [ 'name' => 'Harald', 'company' => 'DELACAP', - 'user' => array( - 'name' => 'Superuser' - ) -); + 'user' => [ + 'name' => 'Superuser', + ], +]; diff --git a/tests/Liquid/fixtures/whitespace-control.php b/tests/Liquid/fixtures/whitespace-control.php index a1ea6892..9890e4eb 100644 --- a/tests/Liquid/fixtures/whitespace-control.php +++ b/tests/Liquid/fixtures/whitespace-control.php @@ -9,4 +9,4 @@ * @package Liquid */ -return array(); +return []; From 2d95d64dcd319011f15b7b245331019291eaf42a Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 19:21:53 +0900 Subject: [PATCH 293/296] Blame-ignore the previous commit --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 42492d25..d9ba9502 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -2,3 +2,4 @@ # https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt 72c7e3f4e34d2ed474b1399f2a7ab427fb6f3b14 +d837112369c0193def1c27636da1b9a8df5c98f3 From 1b74ad64001d21f27223849624f7aab0c379815a Mon Sep 17 00:00:00 2001 From: John Rayes Date: Sat, 31 May 2025 03:45:02 -0700 Subject: [PATCH 294/296] Improve performance (#216) * Improve performance I have identified three main bottlenecks when profiling the code with xdebug: 1. `array_shift()`: The array of tokens ended up being renumbered on each iteration. So we instead set consumed tokens to `null`. 2. `mb_substr()`: Using mutltibyte here is unnecessary and overkill, when we can just operate directly on the string. 3. `Liquid::get()`: This one surprised me, but due to the number of calls, here it is. Shave off more processing time by accessing the config array directly. Co-authored-by: Alexey Kopytko --- src/Liquid/AbstractBlock.php | 41 ++++++++++++++++++++++++++--------- src/Liquid/Tag/TagExtends.php | 8 ++++++- src/Liquid/Tag/TagRaw.php | 8 +++++-- src/Liquid/Template.php | 2 +- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/Liquid/AbstractBlock.php b/src/Liquid/AbstractBlock.php index 62a19fc6..45afee0b 100644 --- a/src/Liquid/AbstractBlock.php +++ b/src/Liquid/AbstractBlock.php @@ -33,6 +33,15 @@ class AbstractBlock extends AbstractTag */ protected static $trimWhitespace = false; + + private ?string $whitespaceControl; + + private ?Regexp $startRegexp; + private ?Regexp $tagRegexp; + private ?Regexp $variableStartRegexp; + + private ?Regexp $variableRegexp; + /** * @return array */ @@ -51,16 +60,25 @@ public function getNodelist() */ public function parse(array &$tokens) { - $startRegexp = new Regexp('/^' . Liquid::get('TAG_START') . '/'); - $tagRegexp = new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/s'); - $variableStartRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); + // Constructor is not reliably called by subclasses, so we need to ensure these are set + $this->startRegexp ??= new Regexp('/^' . Liquid::get('TAG_START') . '/'); + $this->tagRegexp ??= new Regexp('/^' . Liquid::get('TAG_START') . Liquid::get('WHITESPACE_CONTROL') . '?\s*(\w+)\s*(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('TAG_END') . '$/s'); + $this->variableStartRegexp ??= new Regexp('/^' . Liquid::get('VARIABLE_START') . '/'); + + $startRegexp = $this->startRegexp; + $tagRegexp = $this->tagRegexp; + $variableStartRegexp = $this->variableStartRegexp; $this->nodelist = []; $tags = Template::getTags(); - while (count($tokens)) { - $token = array_shift($tokens); + for ($i = 0, $n = count($tokens); $i < $n; $i++) { + if ($tokens[$i] === null) { + continue; + } + $token = $tokens[$i]; + $tokens[$i] = null; if ($startRegexp->match($token)) { $this->whitespaceHandler($token); @@ -114,11 +132,13 @@ public function parse(array &$tokens) */ protected function whitespaceHandler($token) { + $this->whitespaceControl ??= Liquid::get('WHITESPACE_CONTROL'); + /* * This assumes that TAG_START is always '{%', and a whitespace control indicator * is exactly one character long, on a third position. */ - if (mb_substr($token, 2, 1) === Liquid::get('WHITESPACE_CONTROL')) { + if ($token[2] === $this->whitespaceControl) { $previousToken = end($this->nodelist); if (is_string($previousToken)) { // this can also be a tag or a variable $this->nodelist[key($this->nodelist)] = rtrim($previousToken); @@ -129,7 +149,7 @@ protected function whitespaceHandler($token) * This assumes that TAG_END is always '%}', and a whitespace control indicator * is exactly one character long, on a third position from the end. */ - self::$trimWhitespace = mb_substr($token, -3, 1) === Liquid::get('WHITESPACE_CONTROL'); + self::$trimWhitespace = $token[-3] === $this->whitespaceControl; } /** @@ -254,9 +274,10 @@ private function blockName() */ private function createVariable($token) { - $variableRegexp = new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/s'); - if ($variableRegexp->match($token)) { - return new Variable($variableRegexp->matches[1]); + $this->variableRegexp ??= new Regexp('/^' . Liquid::get('VARIABLE_START') . Liquid::get('WHITESPACE_CONTROL') . '?(.*?)' . Liquid::get('WHITESPACE_CONTROL') . '?' . Liquid::get('VARIABLE_END') . '$/s'); + + if ($this->variableRegexp->match($token)) { + return new Variable($this->variableRegexp->matches[1]); } throw new ParseException("Variable $token was not properly terminated"); diff --git a/src/Liquid/Tag/TagExtends.php b/src/Liquid/Tag/TagExtends.php index 0a3ab2fb..417d9fd4 100644 --- a/src/Liquid/Tag/TagExtends.php +++ b/src/Liquid/Tag/TagExtends.php @@ -80,7 +80,13 @@ private function findBlocks(array $tokens) $b = []; $name = null; - foreach ($tokens as $token) { + for ($i = 0, $n = count($tokens); $i < $n; $i++) { + if ($tokens[$i] === null) { + continue; + } + $token = $tokens[$i]; + $tokens[$i] = null; + if ($blockstartRegexp->match($token)) { $name = $blockstartRegexp->matches[1]; $b[$name] = []; diff --git a/src/Liquid/Tag/TagRaw.php b/src/Liquid/Tag/TagRaw.php index b7c67ce1..922fdea8 100644 --- a/src/Liquid/Tag/TagRaw.php +++ b/src/Liquid/Tag/TagRaw.php @@ -36,8 +36,12 @@ public function parse(array &$tokens) $this->nodelist = []; - while (count($tokens)) { - $token = array_shift($tokens); + for ($i = 0, $n = count($tokens); $i < $n; $i++) { + if ($tokens[$i] === null) { + continue; + } + $token = $tokens[$i]; + $tokens[$i] = null; if ($tagRegexp->match($token)) { // If we found the proper block delimiter just end parsing here and let the outer block proceed diff --git a/src/Liquid/Template.php b/src/Liquid/Template.php index b5f2245f..1fe68147 100644 --- a/src/Liquid/Template.php +++ b/src/Liquid/Template.php @@ -83,7 +83,7 @@ public function setFileSystem(FileSystem $fileSystem) } /** - * @param array|Cache $cache + * @param array|Cache|null $cache * * @throws \Liquid\Exception\CacheException */ From b2ad21c0a0b4fd3339845604c135673f58f19fbb Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Sat, 31 May 2025 20:32:48 +0900 Subject: [PATCH 295/296] Ensure all subclasses of AbstractTag always call the constructor (#230) --- .github/workflows/mt.yaml | 1 + .github/workflows/tests.yaml | 1 + src/Liquid/Document.php | 3 +- src/Liquid/Tag/TagAssign.php | 2 + src/Liquid/Tag/TagCycle.php | 2 + src/Liquid/Tag/TagDecrement.php | 2 + src/Liquid/Tag/TagIncrement.php | 2 + tests/Liquid/StaticAnalysisTest.php | 107 ++++++++++++++++++++++++++++ 8 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 tests/Liquid/StaticAnalysisTest.php diff --git a/.github/workflows/mt.yaml b/.github/workflows/mt.yaml index ddab4efb..4846c7cd 100644 --- a/.github/workflows/mt.yaml +++ b/.github/workflows/mt.yaml @@ -42,6 +42,7 @@ jobs: - name: Install dependencies run: | composer update --prefer-dist --no-interaction --no-progress ${{ matrix.dependencies }} + composer dump-autoload --optimize - name: Run mutation testing run: | diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 09b3ea9f..c1e8b4b9 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -56,6 +56,7 @@ jobs: - name: Install dependencies run: | composer update --prefer-dist --no-interaction --no-progress ${{ matrix.dependencies }} + composer dump-autoload --optimize - name: Run tests run: | diff --git a/src/Liquid/Document.php b/src/Liquid/Document.php index e2398d99..166c81e0 100644 --- a/src/Liquid/Document.php +++ b/src/Liquid/Document.php @@ -28,8 +28,7 @@ class Document extends AbstractBlock */ public function __construct(array &$tokens, ?FileSystem $fileSystem = null) { - $this->fileSystem = $fileSystem; - $this->parse($tokens); + parent::__construct('', $tokens, $fileSystem); } /** diff --git a/src/Liquid/Tag/TagAssign.php b/src/Liquid/Tag/TagAssign.php index d47710f6..7fb54bed 100644 --- a/src/Liquid/Tag/TagAssign.php +++ b/src/Liquid/Tag/TagAssign.php @@ -50,6 +50,8 @@ class TagAssign extends AbstractTag */ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { + parent::__construct($markup, $tokens, $fileSystem); + $syntaxRegexp = new Regexp('/(\w+)\s*=\s*(.*)\s*/'); if ($syntaxRegexp->match($markup)) { diff --git a/src/Liquid/Tag/TagCycle.php b/src/Liquid/Tag/TagCycle.php index dd7e88dd..51d9fcad 100644 --- a/src/Liquid/Tag/TagCycle.php +++ b/src/Liquid/Tag/TagCycle.php @@ -57,6 +57,8 @@ class TagCycle extends AbstractTag */ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { + parent::__construct($markup, $tokens, $fileSystem); + $simpleSyntax = new Regexp("/" . Liquid::get('QUOTED_FRAGMENT') . "/"); $namedSyntax = new Regexp("/(" . Liquid::get('QUOTED_FRAGMENT') . ")\s*\:\s*(.*)/"); diff --git a/src/Liquid/Tag/TagDecrement.php b/src/Liquid/Tag/TagDecrement.php index dde684eb..30b230d2 100644 --- a/src/Liquid/Tag/TagDecrement.php +++ b/src/Liquid/Tag/TagDecrement.php @@ -47,6 +47,8 @@ class TagDecrement extends AbstractTag */ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { + parent::__construct($markup, $tokens, $fileSystem); + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { diff --git a/src/Liquid/Tag/TagIncrement.php b/src/Liquid/Tag/TagIncrement.php index 91fe0f85..dcbb3845 100644 --- a/src/Liquid/Tag/TagIncrement.php +++ b/src/Liquid/Tag/TagIncrement.php @@ -47,6 +47,8 @@ class TagIncrement extends AbstractTag */ public function __construct($markup, array &$tokens, ?FileSystem $fileSystem = null) { + parent::__construct($markup, $tokens, $fileSystem); + $syntax = new Regexp('/(' . Liquid::get('VARIABLE_NAME') . ')/'); if ($syntax->match($markup)) { diff --git a/tests/Liquid/StaticAnalysisTest.php b/tests/Liquid/StaticAnalysisTest.php new file mode 100644 index 00000000..df070ad5 --- /dev/null +++ b/tests/Liquid/StaticAnalysisTest.php @@ -0,0 +1,107 @@ + $filename) { + $path = str_replace(getcwd(), '.', $filename); + + if (strpos($path, './vendor/') === 0) { + continue; + } + + $seenNonVendor = true; + yield $class => [str_replace(getcwd(), '.', $filename), $class]; + } + + if ($seenNonVendor === false) { + throw new \RuntimeException('Please generate the classmap.'); + } + } + + /** + * @dataProvider provideClasses + * @param mixed $filename + * @param mixed $class + */ + public function testClassExists($filename, $class) + { + $this->assertTrue(class_exists($class) || trait_exists($class) || interface_exists($class)); + } + + public static function provideAbstractTagSubclasses() + { + foreach (self::provideClasses() as $class => $data) { + if (!is_subclass_of($class, AbstractTag::class)) { + continue; + } + + $refClass = new ReflectionClass($class); + if (!$refClass->hasMethod('__construct')) { + continue; + } + + if ($refClass->getMethod('__construct')->getDeclaringClass()->getName() === AbstractTag::class) { + continue; // Skip if the constructor is not overridden + } + + yield $class => [...$data, $refClass]; + } + } + + /** + * @dataProvider provideAbstractTagSubclasses + * @param string $filename + * @param class-string $class + * @param ReflectionClass $refClass + */ + public function testAbstractTagChildCallsConstruct($filename, $class, ReflectionClass $refClass) + { + $refMethod = $refClass->getMethod('__construct'); + $startLine = $refMethod->getStartLine(); + $endLine = $refMethod->getEndLine(); + + $code = array_slice(file($refMethod->getFileName()), $startLine - 1, $endLine - $startLine + 1); + + $this->assertNotEmpty($code); + + $linesWithConstruct = array_filter($code, function ($line) { + return strpos($line, 'parent::__construct') !== false; + }); + + $this->assertNotEmpty( + $linesWithConstruct, + "The constructor of {$refClass->getName()} should call parent::__construct()" + ); + } +} From 69dfccb0d6551c62d63ab557b91bb65625ced84d Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 4 Dec 2025 15:41:19 +0900 Subject: [PATCH 296/296] Let go of PHP versions 7.4, 8.0, and 8.1 (#237) * Let go of PHP versions 7.4, 8.0, and 8.1 Removed PHP versions 7.4, 8.0, and 8.1 from the workflow matrix and updated the include section to reflect only PHP 8.2 with lowest dependencies. * Update PHP requirement to version 8.2 * Update PHP version requirements in README --- .github/workflows/tests.yaml | 5 +---- README.md | 4 ++-- composer.json | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c1e8b4b9..068ffbda 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -17,14 +17,11 @@ jobs: strategy: matrix: php-version: - - '7.4' - - '8.0' - - '8.1' - '8.2' - '8.3' - '8.4' include: - - { php-version: '7.4', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } + - { php-version: '8.2', dependencies: '--prefer-lowest', legend: 'with lowest dependencies' } name: PHP ${{ matrix.php-version }} ${{ matrix.legend }} diff --git a/README.md b/README.md index 2a66e466..9f7148aa 100644 --- a/README.md +++ b/README.md @@ -115,9 +115,9 @@ Adding filters has never been easier. ## Requirements - * PHP 7.4+ + * PHP 8.2+ -Some earlier versions could be used with PHP 5.3/5.4/5.5/5.6, though they're not supported anymore. +Some earlier versions could be used with PHP 5.x/7.x, though they're not supported anymore. ## Issues diff --git a/composer.json b/composer.json index 3fdc946f..10ce7ee1 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ } ], "require": { - "php": "^7.4 || ^8.0" + "php": "^8.2" }, "require-dev": { "ergebnis/composer-normalize": ">=2.47",