From 73be9e96772b3aef823a1f181ee9682f7466fbd8 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Fri, 21 Jun 2013 16:55:05 +0200 Subject: [PATCH 01/10] loop argument management type management --- .../Core/Template/Loop/Argument/Argument.php | 44 +++++++ .../Loop/Argument/ArgumentCollection.php | 119 ++++++++++++++++++ .../Thelia/Core/Template/Loop/Category.php | 93 ++++++++++++-- core/lib/Thelia/Type/AnyType.php | 42 +++++++ core/lib/Thelia/Type/TypeCollection.php | 119 ++++++++++++++++++ core/lib/Thelia/Type/TypeInterface.php | 36 ++++++ 6 files changed, 441 insertions(+), 12 deletions(-) create mode 100644 core/lib/Thelia/Core/Template/Loop/Argument/Argument.php create mode 100644 core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php create mode 100644 core/lib/Thelia/Type/AnyType.php create mode 100644 core/lib/Thelia/Type/TypeCollection.php create mode 100644 core/lib/Thelia/Type/TypeInterface.php diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php b/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php new file mode 100644 index 000000000..1be69e18f --- /dev/null +++ b/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php @@ -0,0 +1,44 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Core\Template\Loop\Argument; + +/** + * + * @author Etienne Roudeix + * + */ +class Argument +{ + protected $name; + protected $type; + protected $mandatory; + protected $default; + + public function __construct($name, \Thelia\Type\TypeCollection $type, $mandatory = false, $default = null) + { + $this->name = $name; + $this->type = $type; + $this->mandatory = $mandatory ? true : false; + $this->default = $default; + } +} diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php b/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php new file mode 100644 index 000000000..84cf958db --- /dev/null +++ b/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php @@ -0,0 +1,119 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Core\Template\Loop\Argument; + +/** + * + * @author Etienne Roudeix + * + */ + +class ArgumentCollection implements \Iterator +{ + private $position; + protected $arguments = array(); + + public function __construct() + { + foreach(func_get_args() as $argument) { + $this->addArgument($argument); + } + } + + public function isEmpty() + { + return count($this->arguments) == 0; + } + + /** + * @param Argument $argument + * + * @return ArgumentCollection + */ + public function addArgument(Argument $argument) + { + $this->arguments[] = $argument; + return $this; + } + + public function getCount() + { + return count($this->arguments); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * @return \Thelia\Core\Template\Element\LoopResultRow + */ + public function current() + { + return $this->arguments[$this->position]; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + */ + public function next() + { + ++$this->arguments; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + */ + public function key() + { + return $this->arguments; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * @return boolean The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + */ + public function valid() + { + return isset($this->arguments[$this->position]); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + */ + public function rewind() + { + $this->position = 0; + } +} diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 6a996d813..645eabd64 100755 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -28,8 +28,12 @@ namespace Thelia\Core\Template\Loop; use Thelia\Core\Template\Element\BaseLoop; use Thelia\Core\Template\Element\LoopResult; use Thelia\Core\Template\Element\LoopResultRow; +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Core\Template\Loop\Argument\Argument; use Thelia\Log\Tlog; use Thelia\Model\CategoryQuery; +use Thelia\Type\TypeCollection; +use Thelia\Type; /** * @@ -77,18 +81,83 @@ class Category extends BaseLoop { public function defineArgs() { - return array( - "id" => "optional", - "parent" => "optional", - "current" => "optional", - "not_empty" => 0, - "visible" => 1, - "link" => "optional", - "order" => "optional", - "random" => 0, - "exclude" => "optional", - "limit" => 10, - "offset" => 0, + return new ArgumentCollection( + new Argument( + 'id', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'parent', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'current', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'not_empty', + new TypeCollection( + new Type\AnyType() + ), + false, + 0 + ), + new Argument( + 'visible', + new TypeCollection( + new Type\AnyType() + ), + false, + 1 + ), + new Argument( + 'link', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'order', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'random', + new TypeCollection( + new Type\AnyType() + ), + false, + 0 + ), + new Argument( + 'exclude', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'limit', + new TypeCollection( + new Type\AnyType() + ), + false, + 10 + ), + new Argument( + 'offset', + new TypeCollection( + new Type\AnyType() + ), + false, + 0 + ) ); } diff --git a/core/lib/Thelia/Type/AnyType.php b/core/lib/Thelia/Type/AnyType.php new file mode 100644 index 000000000..5b00a5aeb --- /dev/null +++ b/core/lib/Thelia/Type/AnyType.php @@ -0,0 +1,42 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class AnyType implements TypeInterface +{ + public function getType() + { + return 'Any type'; + } + + public function isValid($value) + { + return true; + } +} diff --git a/core/lib/Thelia/Type/TypeCollection.php b/core/lib/Thelia/Type/TypeCollection.php new file mode 100644 index 000000000..6ec10731b --- /dev/null +++ b/core/lib/Thelia/Type/TypeCollection.php @@ -0,0 +1,119 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class TypeCollection implements \Iterator +{ + private $position; + protected $types = array(); + + public function __construct() + { + foreach(func_get_args() as $type) { + $this->addType($type); + } + } + + public function isEmpty() + { + return count($this->types) == 0; + } + + /** + * @param TypeInterface $type + * + * @return TypeCollection + */ + public function addType(TypeInterface $type) + { + $this->types[] = $type; + return $this; + } + + public function getCount() + { + return count($this->types); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Return the current element + * @link http://php.net/manual/en/iterator.current.php + * @return \Thelia\Core\Template\Element\LoopResultRow + */ + public function current() + { + return $this->types[$this->position]; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Move forward to next element + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + */ + public function next() + { + ++$this->types; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Return the key of the current element + * @link http://php.net/manual/en/iterator.key.php + * @return mixed scalar on success, or null on failure. + */ + public function key() + { + return $this->types; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Checks if current position is valid + * @link http://php.net/manual/en/iterator.valid.php + * @return boolean The return value will be casted to boolean and then evaluated. + * Returns true on success or false on failure. + */ + public function valid() + { + return isset($this->types[$this->position]); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Rewind the Iterator to the first element + * @link http://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + */ + public function rewind() + { + $this->position = 0; + } +} diff --git a/core/lib/Thelia/Type/TypeInterface.php b/core/lib/Thelia/Type/TypeInterface.php new file mode 100644 index 000000000..ae626f0b9 --- /dev/null +++ b/core/lib/Thelia/Type/TypeInterface.php @@ -0,0 +1,36 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +interface TypeInterface +{ + public function getType(); + + public function isValid($value); +} From 539cce542f94a77975c73835c140ef5624e8fc7d Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 10:04:06 +0200 Subject: [PATCH 02/10] Loop arguments --- .../Thelia/Core/Template/Element/BaseLoop.php | 3 +- .../Core/Template/Loop/Argument/Argument.php | 11 ++-- .../Loop/Argument/ArgumentCollection.php | 6 +-- .../Thelia/Core/Template/Loop/Category.php | 5 -- .../Template/Smarty/Plugins/TheliaLoop.php | 53 ++++++++++--------- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Element/BaseLoop.php b/core/lib/Thelia/Core/Template/Element/BaseLoop.php index b6085ad7c..519aae4bd 100755 --- a/core/lib/Thelia/Core/Template/Element/BaseLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseLoop.php @@ -25,6 +25,7 @@ namespace Thelia\Core\Template\Element; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; /** * @@ -96,7 +97,7 @@ abstract class BaseLoop * ) * ); * - * @return array + * @return ArgumentCollection */ abstract public function defineArgs(); diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php b/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php index 1be69e18f..d2b6cdbb2 100644 --- a/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php +++ b/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php @@ -29,12 +29,13 @@ namespace Thelia\Core\Template\Loop\Argument; */ class Argument { - protected $name; - protected $type; - protected $mandatory; - protected $default; + public $name; + public $type; + public $default; + public $mandatory; + public $empty; - public function __construct($name, \Thelia\Type\TypeCollection $type, $mandatory = false, $default = null) + public function __construct($name, \Thelia\Type\TypeCollection $type, $default = null, $mandatory = false, $empty = true) { $this->name = $name; $this->type = $type; diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php b/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php index 84cf958db..d3422c1e9 100644 --- a/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php +++ b/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php @@ -65,7 +65,7 @@ class ArgumentCollection implements \Iterator * (PHP 5 >= 5.0.0)
* Return the current element * @link http://php.net/manual/en/iterator.current.php - * @return \Thelia\Core\Template\Element\LoopResultRow + * @return Argument */ public function current() { @@ -80,7 +80,7 @@ class ArgumentCollection implements \Iterator */ public function next() { - ++$this->arguments; + $this->position++; } /** @@ -91,7 +91,7 @@ class ArgumentCollection implements \Iterator */ public function key() { - return $this->arguments; + return $this->position; } /** diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 645eabd64..2541fc982 100755 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -105,7 +105,6 @@ class Category extends BaseLoop { new TypeCollection( new Type\AnyType() ), - false, 0 ), new Argument( @@ -113,7 +112,6 @@ class Category extends BaseLoop { new TypeCollection( new Type\AnyType() ), - false, 1 ), new Argument( @@ -133,7 +131,6 @@ class Category extends BaseLoop { new TypeCollection( new Type\AnyType() ), - false, 0 ), new Argument( @@ -147,7 +144,6 @@ class Category extends BaseLoop { new TypeCollection( new Type\AnyType() ), - false, 10 ), new Argument( @@ -155,7 +151,6 @@ class Category extends BaseLoop { new TypeCollection( new Type\AnyType() ), - false, 0 ) ); diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index d8b1abd9a..1810ad117 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -23,6 +23,7 @@ namespace Thelia\Core\Template\Smarty\Plugins; +use Thelia\Core\Template\Element\BaseLoop; use Thelia\Core\Template\Smarty\SmartyPluginInterface; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; @@ -202,7 +203,7 @@ class TheliaLoop implements SmartyPluginInterface { * @param unknown $smartyParam * @throws \InvalidArgumentException */ - protected function getLoopArgument($loop, $smartyParam) + protected function getLoopArgument(BaseLoop $loop, $smartyParam) { $defaultItemsParams = array('required' => true); @@ -212,35 +213,37 @@ class TheliaLoop implements SmartyPluginInterface { $faultActor = array(); $faultDetails = array(); - foreach($loop->defineArgs() as $name => $param){ - if(is_integer($name)){ - $name = $param; - $param = $defaultItemsParams; - } + $argumentsCollection = $loop->defineArgs(); + $argumentsCollection->rewind(); - if(is_string($param) && array_key_exists($param, $shortcutItemParams)){ - $param = $shortcutItemParams[$param]; - } + while ($argumentsCollection->valid()) { - if(!is_array($param)){ - $param = array('default' => $param); - } + $argument = $argumentsCollection->current(); + $argumentsCollection->next(); - $value = isset($smartyParam[$name]) ? $smartyParam[$name] : null; + $value = isset($smartyParam[$argument->name]) ? $smartyParam[$argument->name] : null; - if($value == null){ - if(isset($param['default'])){ - $value = $param['default']; - } - else if($param['required'] === true){ - $faultActor[] = $name; - $faultDetails[] = sprintf('"%s" parameter is missing', $name); - continue; - } - } + /* check if mandatory */ + if($value === null && $argument->mandatory) { + $faultActor[] = $argument->name; + $faultDetails[] = sprintf('"%s" parameter is missing', $argument->name); + continue; + } - $loop->{$name} = $value; - } + /* check if empty */ + if($value === '' && !$argument->empty) { + $faultActor[] = $argument->name; + $faultDetails[] = sprintf('"%s" parameter cannot be empty', $argument->name); + continue; + } + + /* check default */ + if($value === null) { + $value = $argument->default; + } + + $loop->{$argument->name} = $value; + } if(!empty($faultActor)){ From 06543bb68c560087b07fbdb4d874256b2122aa55 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 11:43:15 +0200 Subject: [PATCH 03/10] add unit testing --- .../Core/Template/Loop/Argument/Argument.php | 0 .../Loop/Argument/ArgumentCollection.php | 0 .../Template/Loop/Argument/ArgumentTest.php | 129 ++++++++++++++++++ core/lib/Thelia/Tests/Type/TypeTest.php | 82 +++++++++++ core/lib/Thelia/Type/AnyType.php | 0 core/lib/Thelia/Type/TypeCollection.php | 4 +- core/lib/Thelia/Type/TypeInterface.php | 0 7 files changed, 213 insertions(+), 2 deletions(-) mode change 100644 => 100755 core/lib/Thelia/Core/Template/Loop/Argument/Argument.php mode change 100644 => 100755 core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php create mode 100755 core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php create mode 100755 core/lib/Thelia/Tests/Type/TypeTest.php mode change 100644 => 100755 core/lib/Thelia/Type/AnyType.php mode change 100644 => 100755 core/lib/Thelia/Type/TypeCollection.php mode change 100644 => 100755 core/lib/Thelia/Type/TypeInterface.php diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php b/core/lib/Thelia/Core/Template/Loop/Argument/Argument.php old mode 100644 new mode 100755 diff --git a/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php b/core/lib/Thelia/Core/Template/Loop/Argument/ArgumentCollection.php old mode 100644 new mode 100755 diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php new file mode 100755 index 000000000..e5a240b8b --- /dev/null +++ b/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php @@ -0,0 +1,129 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\Template\Loop\Argument; + +use Thelia\Core\Template\Loop\Argument\ArgumentCollection; +use Thelia\Core\Template\Loop\Argument\Argument; +use Thelia\Type; +use Thelia\Type\TypeCollection; + +/** + * + * @author Etienne Roudeix + * + */ +class ArgumentTest extends \PHPUnit_Framework_TestCase +{ + function testArgumentCollectionConstruction() + { + $collection = new ArgumentCollection( + new Argument( + 'arg0', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'arg1', + new TypeCollection( + new Type\AnyType() + ) + ) + ); + + $collection->addArgument( + new Argument( + 'arg2', + new TypeCollection( + new Type\AnyType() + ) + ) + ); + + $this->assertAttributeEquals( + array( + 0 => new Argument( + 'arg0', + new TypeCollection( + new Type\AnyType() + ) + ), + 1 => new Argument( + 'arg1', + new TypeCollection( + new Type\AnyType() + ) + ), + 2 => new Argument( + 'arg2', + new TypeCollection( + new Type\AnyType() + ) + ), + ), + 'arguments', + $collection + ); + } + + function testArgumentCollectionFetch() + { + $collection = new ArgumentCollection( + new Argument( + 'arg0', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'arg1', + new TypeCollection( + new Type\AnyType() + ) + ), + new Argument( + 'arg2', + new TypeCollection( + new Type\AnyType() + ) + ) + ); + + + $arguments = \PHPUnit_Framework_Assert::readAttribute($collection, 'arguments'); + + $collection->rewind(); + while ($collection->valid()) { + + $argument = $collection->current(); + + $this->assertEquals( + $argument, + $arguments[$collection->key()] + ); + + $collection->next(); + } + } +} diff --git a/core/lib/Thelia/Tests/Type/TypeTest.php b/core/lib/Thelia/Tests/Type/TypeTest.php new file mode 100755 index 000000000..fa6e4ea31 --- /dev/null +++ b/core/lib/Thelia/Tests/Type/TypeTest.php @@ -0,0 +1,82 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Type; + +use Thelia\Type; +use Thelia\Type\TypeCollection; + +/** + * + * @author Etienne Roudeix + * + */ +class TypeTest extends \PHPUnit_Framework_TestCase +{ + function testTypeCollectionConstruction() + { + $collection = new TypeCollection( + new Type\AnyType(), + new Type\AnyType() + ); + + $collection->addType( + new Type\AnyType() + ); + + $this->assertAttributeEquals( + array( + new Type\AnyType(), + new Type\AnyType(), + new Type\AnyType(), + ), + 'types', + $collection + ); + } + + function testTypeCollectionFetch() + { + $collection = new TypeCollection( + new Type\AnyType(), + new Type\AnyType(), + new Type\AnyType() + ); + + + $types = \PHPUnit_Framework_Assert::readAttribute($collection, 'types'); + + $collection->rewind(); + while ($collection->valid()) { + + $type = $collection->current(); + + $this->assertEquals( + $type, + $types[$collection->key()] + ); + + $collection->next(); + } + } +} diff --git a/core/lib/Thelia/Type/AnyType.php b/core/lib/Thelia/Type/AnyType.php old mode 100644 new mode 100755 diff --git a/core/lib/Thelia/Type/TypeCollection.php b/core/lib/Thelia/Type/TypeCollection.php old mode 100644 new mode 100755 index 6ec10731b..621197776 --- a/core/lib/Thelia/Type/TypeCollection.php +++ b/core/lib/Thelia/Type/TypeCollection.php @@ -80,7 +80,7 @@ class TypeCollection implements \Iterator */ public function next() { - ++$this->types; + $this->position++; } /** @@ -91,7 +91,7 @@ class TypeCollection implements \Iterator */ public function key() { - return $this->types; + return $this->position; } /** diff --git a/core/lib/Thelia/Type/TypeInterface.php b/core/lib/Thelia/Type/TypeInterface.php old mode 100644 new mode 100755 From 00a8ad51b37d3b21cc1e807b5e3c2ecb74b0662c Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 12:31:47 +0200 Subject: [PATCH 04/10] check type in Smarty plugin --- .../Template/Smarty/Plugins/TheliaLoop.php | 10 ++- core/lib/Thelia/Type/TypeCollection.php | 23 ++++- templates/smarty-sample/index.html | 85 ++----------------- 3 files changed, 36 insertions(+), 82 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index 1810ad117..6d455d49d 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -237,7 +237,15 @@ class TheliaLoop implements SmartyPluginInterface { continue; } - /* check default */ + /* check type */ + if($value !== null && !$argument->type->isValid($value)) { + $faultActor[] = $argument->name; + $faultDetails[] = sprintf('Invalid value for "%s" argument', $argument->name); + continue; + } + + /* set default */ + /* did it as last checking for we consider default value is acceptable no matter type or empty restriction */ if($value === null) { $value = $argument->default; } diff --git a/core/lib/Thelia/Type/TypeCollection.php b/core/lib/Thelia/Type/TypeCollection.php index 621197776..ebbd3274b 100755 --- a/core/lib/Thelia/Type/TypeCollection.php +++ b/core/lib/Thelia/Type/TypeCollection.php @@ -65,7 +65,7 @@ class TypeCollection implements \Iterator * (PHP 5 >= 5.0.0)
* Return the current element * @link http://php.net/manual/en/iterator.current.php - * @return \Thelia\Core\Template\Element\LoopResultRow + * @return \Thelia\Type\TypeInterface */ public function current() { @@ -116,4 +116,25 @@ class TypeCollection implements \Iterator { $this->position = 0; } + + /** + * @param $value + * + * @return bool + */ + public function isValid($value) + { + $this->rewind(); + while ($this->valid()) { + $type = $this->current(); + + if($type->isValid($value)) { + return true; + } + + $this->next(); + } + + return false; + } } diff --git a/templates/smarty-sample/index.html b/templates/smarty-sample/index.html index f93dd3876..7bba1e5da 100755 --- a/templates/smarty-sample/index.html +++ b/templates/smarty-sample/index.html @@ -1,80 +1,5 @@ -{include file="includes/header.html"} -
-An image from asset directory : -{images file='assets/img/logo-thelia-34px.png'}{intl l='Thelia, solution e-commerce libre'}{/images} -
- -
-{intl l='An internationalized string'} -
- -
- jQuery data: -
- -
-

Category loop example

-
    - {loop type="category" name="catloop1"} -
  • {$__COUNT__}/{$__TOTAL__} : {$ID} {$TITLE}, children: {$NB_CHILD} - {ifloop rel="inner1"} -
      - {loop type="category" name="inner1" parent="{$ID}"} -
    • Sub cat {$ID} (parent is {$PARENT}): {$TITLE}
    • - {/loop} -
    - {/ifloop} -
  • - {/loop} -
-
- -
-

Conditional example #1

- - {ifloop rel="catloop2"} - Hey ! Loop catloop2 is not empty: -
    - {loop type="category" name="catloop2" parent="12"} -
  • {$__COUNT__}/{$__TOTAL__} : {$ID} {$TITLE}
  • - {/loop} -
- {/ifloop} - - {elseloop rel="catloop2"} -

Loop catloop2 is empty

- {/elseloop} -
- -
-

Conditional example #2

- - {ifloop rel="catloop3"} - Loop catloop3 is not empty: -
    - {loop type="category" name="catloop3" parent="0"} -
  • {$__COUNT__}/{$__TOTAL__} : {$ID} {$TITLE}
  • - {/loop} -
- {/ifloop} - - {elseloop rel="catloop3"} -

Loop catloop3 is empty

- {/elseloop} - - {elseloop rel="catloop2"} -

... but catloop2 is still empty :-)

- {/elseloop} - {ifloop rel="catloop1"} -

... and catloop1 is still NOT empty :-)

- {/ifloop} -
- -
-

Traditional for loop

- {for $index=5 to 12 step 1} - Compteur = {$index}
- {/for} -
- -{include file="includes/footer.html"} \ No newline at end of file +
    +{loop type="category" name="catloop1" id="1,3"} +
  • {$TITLE}
  • +{/loop} +
\ No newline at end of file From 29592da5b0ad3b89ae61731aea050f9689bb51b1 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 13:17:38 +0200 Subject: [PATCH 05/10] new types and their tests --- .../Thelia/Core/Template/Loop/Category.php | 18 +++---- .../Template/Loop/Argument/ArgumentTest.php | 4 +- core/lib/Thelia/Tests/Type/TypeTest.php | 35 ++++++++++++- core/lib/Thelia/Type/EnumType.php | 50 +++++++++++++++++++ core/lib/Thelia/Type/FloatType.php | 42 ++++++++++++++++ core/lib/Thelia/Type/IntListType.php | 47 +++++++++++++++++ core/lib/Thelia/Type/IntType.php | 42 ++++++++++++++++ core/lib/Thelia/Type/JsonType.php | 43 ++++++++++++++++ 8 files changed, 268 insertions(+), 13 deletions(-) create mode 100755 core/lib/Thelia/Type/EnumType.php create mode 100755 core/lib/Thelia/Type/FloatType.php create mode 100755 core/lib/Thelia/Type/IntListType.php create mode 100755 core/lib/Thelia/Type/IntType.php create mode 100755 core/lib/Thelia/Type/JsonType.php diff --git a/core/lib/Thelia/Core/Template/Loop/Category.php b/core/lib/Thelia/Core/Template/Loop/Category.php index 2541fc982..dadb69505 100755 --- a/core/lib/Thelia/Core/Template/Loop/Category.php +++ b/core/lib/Thelia/Core/Template/Loop/Category.php @@ -85,32 +85,32 @@ class Category extends BaseLoop { new Argument( 'id', new TypeCollection( - new Type\AnyType() + new Type\IntListType() ) ), new Argument( 'parent', new TypeCollection( - new Type\AnyType() + new Type\IntType() ) ), new Argument( 'current', new TypeCollection( - new Type\AnyType() + new Type\IntType() ) ), new Argument( 'not_empty', new TypeCollection( - new Type\AnyType() + new Type\IntType() ), 0 ), new Argument( 'visible', new TypeCollection( - new Type\AnyType() + new Type\IntType() ), 1 ), @@ -123,7 +123,7 @@ class Category extends BaseLoop { new Argument( 'order', new TypeCollection( - new Type\AnyType() + new Type\EnumType('alpha', 'alpha_reverse', 'reverse') ) ), new Argument( @@ -136,20 +136,20 @@ class Category extends BaseLoop { new Argument( 'exclude', new TypeCollection( - new Type\AnyType() + new Type\IntListType() ) ), new Argument( 'limit', new TypeCollection( - new Type\AnyType() + new Type\IntType() ), 10 ), new Argument( 'offset', new TypeCollection( - new Type\AnyType() + new Type\IntType() ), 0 ) diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php index e5a240b8b..7c5ce5d16 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/Argument/ArgumentTest.php @@ -35,7 +35,7 @@ use Thelia\Type\TypeCollection; */ class ArgumentTest extends \PHPUnit_Framework_TestCase { - function testArgumentCollectionConstruction() + public function testArgumentCollectionConstruction() { $collection = new ArgumentCollection( new Argument( @@ -87,7 +87,7 @@ class ArgumentTest extends \PHPUnit_Framework_TestCase ); } - function testArgumentCollectionFetch() + public function testArgumentCollectionFetch() { $collection = new ArgumentCollection( new Argument( diff --git a/core/lib/Thelia/Tests/Type/TypeTest.php b/core/lib/Thelia/Tests/Type/TypeTest.php index fa6e4ea31..4b7c65df8 100755 --- a/core/lib/Thelia/Tests/Type/TypeTest.php +++ b/core/lib/Thelia/Tests/Type/TypeTest.php @@ -33,7 +33,7 @@ use Thelia\Type\TypeCollection; */ class TypeTest extends \PHPUnit_Framework_TestCase { - function testTypeCollectionConstruction() + public function testTypeCollectionConstruction() { $collection = new TypeCollection( new Type\AnyType(), @@ -55,7 +55,7 @@ class TypeTest extends \PHPUnit_Framework_TestCase ); } - function testTypeCollectionFetch() + public function testTypeCollectionFetch() { $collection = new TypeCollection( new Type\AnyType(), @@ -79,4 +79,35 @@ class TypeTest extends \PHPUnit_Framework_TestCase $collection->next(); } } + + public function testTypes() + { + $anyType = new Type\AnyType(); + $this->assertTrue($anyType->isValid(md5(rand(1000, 10000)))); + + $intType = new Type\IntType(); + $this->assertTrue($intType->isValid('1')); + $this->assertTrue($intType->isValid(2)); + $this->assertFalse($intType->isValid('3.3')); + + $floatType = new Type\FloatType(); + $this->assertTrue($floatType->isValid('1.1')); + $this->assertTrue($floatType->isValid(2.2)); + $this->assertFalse($floatType->isValid('foo')); + + $enumType = new Type\EnumType(array("cat", "dog")); + $this->assertTrue($enumType->isValid('cat')); + $this->assertTrue($enumType->isValid('dog')); + $this->assertFalse($enumType->isValid('monkey')); + $this->assertFalse($enumType->isValid('catdog')); + + $intListType = new Type\IntListType(); + $this->assertTrue($intListType->isValid('1')); + $this->assertTrue($intListType->isValid('1,2,3')); + $this->assertFalse($intListType->isValid('1,2,3.3')); + + $jsonType = new Type\JsonType(); + $this->assertTrue($jsonType->isValid('{"k0":"v0","k1":"v1","k2":"v2"}')); + $this->assertFalse($jsonType->isValid('1,2,3')); + } } diff --git a/core/lib/Thelia/Type/EnumType.php b/core/lib/Thelia/Type/EnumType.php new file mode 100755 index 000000000..d0a1c9b89 --- /dev/null +++ b/core/lib/Thelia/Type/EnumType.php @@ -0,0 +1,50 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class EnumType implements TypeInterface +{ + protected $values = array(); + + public function __construct($values = array()) + { + if(is_array($values)) + $this->values = $values; + } + + public function getType() + { + return 'Enum type'; + } + + public function isValid($value) + { + return in_array($value, $this->values); + } +} diff --git a/core/lib/Thelia/Type/FloatType.php b/core/lib/Thelia/Type/FloatType.php new file mode 100755 index 000000000..e341b540f --- /dev/null +++ b/core/lib/Thelia/Type/FloatType.php @@ -0,0 +1,42 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class FloatType implements TypeInterface +{ + public function getType() + { + return 'Float type'; + } + + public function isValid($value) + { + return filter_var($value, FILTER_VALIDATE_FLOAT) === false ? false : true; + } +} diff --git a/core/lib/Thelia/Type/IntListType.php b/core/lib/Thelia/Type/IntListType.php new file mode 100755 index 000000000..74b0a6790 --- /dev/null +++ b/core/lib/Thelia/Type/IntListType.php @@ -0,0 +1,47 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class IntListType implements TypeInterface +{ + public function getType() + { + return 'Int list type'; + } + + public function isValid($values) + { + foreach(explode(',', $values) as $value) { + if(filter_var($value, FILTER_VALIDATE_INT) === false) + return false; + } + + return true; + } +} diff --git a/core/lib/Thelia/Type/IntType.php b/core/lib/Thelia/Type/IntType.php new file mode 100755 index 000000000..d077a6c89 --- /dev/null +++ b/core/lib/Thelia/Type/IntType.php @@ -0,0 +1,42 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class IntType implements TypeInterface +{ + public function getType() + { + return 'Int type'; + } + + public function isValid($value) + { + return filter_var($value, FILTER_VALIDATE_INT) === false ? false : true; + } +} diff --git a/core/lib/Thelia/Type/JsonType.php b/core/lib/Thelia/Type/JsonType.php new file mode 100755 index 000000000..805977a32 --- /dev/null +++ b/core/lib/Thelia/Type/JsonType.php @@ -0,0 +1,43 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Type; + +/** + * + * @author Etienne Roudeix + * + */ + +class JsonType implements TypeInterface +{ + public function getType() + { + return 'Json type'; + } + + public function isValid($value) + { + json_decode($value); + return (json_last_error() == JSON_ERROR_NONE); + } +} From 24ea8c78d22c8ff4530e75cc3e8f4c8f09aff7d4 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 14:33:47 +0200 Subject: [PATCH 06/10] refromat --- .../Template/Smarty/Plugins/TheliaLoop.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index 6d455d49d..01a67e57a 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -33,7 +33,8 @@ use Thelia\Core\Template\Element\Exception\InvalidElementException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -class TheliaLoop implements SmartyPluginInterface { +class TheliaLoop implements SmartyPluginInterface +{ protected $loopDefinition = array(); @@ -41,7 +42,8 @@ class TheliaLoop implements SmartyPluginInterface { protected $dispatcher; - public function __construct(Request $request, EventDispatcherInterface $dispatcher) { + public function __construct(Request $request, EventDispatcherInterface $dispatcher) + { $this->request = $request; $this->dispatcher = $dispatcher; } @@ -56,7 +58,8 @@ class TheliaLoop implements SmartyPluginInterface { * @throws \InvalidArgumentException * @return string */ - public function theliaLoop($params, $content, $template, &$repeat) { + public function theliaLoop($params, $content, $template, &$repeat) + { if (empty($params['name'])) throw new \InvalidArgumentException("Missing 'name' parameter in loop arguments"); @@ -116,7 +119,8 @@ class TheliaLoop implements SmartyPluginInterface { * @param unknown $repeat * @return Ambigous */ - public function theliaElseloop($params, $content, $template, &$repeat) { + public function theliaElseloop($params, $content, $template, &$repeat) + { // When encoutering close tag, check if loop has results. if ($repeat === false) { @@ -134,7 +138,8 @@ class TheliaLoop implements SmartyPluginInterface { * @param unknown $repeat * @return Ambigous */ - public function theliaIfLoop($params, $content, $template, &$repeat) { + public function theliaIfLoop($params, $content, $template, &$repeat) + { // When encountering close tag, check if loop has results. if ($repeat === false) { @@ -150,7 +155,8 @@ class TheliaLoop implements SmartyPluginInterface { * @param unknown $template * @throws \InvalidArgumentException */ - protected function checkEmptyLoop($params, $template) { + protected function checkEmptyLoop($params, $template) + { if (empty($params['rel'])) throw new \InvalidArgumentException("Missing 'rel' parameter in ifloop/elseloop arguments"); @@ -299,7 +305,7 @@ class TheliaLoop implements SmartyPluginInterface { return array( new SmartyPluginDescriptor('block', 'loop' , $this, 'theliaLoop'), new SmartyPluginDescriptor('block', 'elseloop' , $this, 'theliaElseloop'), - new SmartyPluginDescriptor('block', 'ifloop' , $this, 'theliaIfLoop') + new SmartyPluginDescriptor('block', 'ifloop' , $this, 'theliaIfLoop'), ); } } \ No newline at end of file From 8e4c3c72db0d7bb6ff4988e7db0b1332a8daef4b Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 14:44:52 +0200 Subject: [PATCH 07/10] prefilter test --- core/lib/Thelia/Core/Template/Smarty/SmartyParser.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index e85f53284..2f13d60c0 100755 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -62,6 +62,13 @@ class SmartyParser extends Smarty implements ParserInterface { // The default HTTP status $this->status = 200; + + $this->registerFilter("pre", array($this, 'prefunc')); + } + + public function prefunc($tpl_source, \Smarty_Internal_Template $template) + { + exit($tpl_source); } public function setTemplate($template_path_from_template_base) { From cd46f45ee6a47d5575f10d92a478b580d38ed745 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 15:08:14 +0200 Subject: [PATCH 08/10] test prefilters --- .../Core/Template/Smarty/SmartyParser.php | 28 +++++++++++++------ templates/smarty-sample/index.html | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index 2f13d60c0..252f2256c 100755 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -12,6 +12,7 @@ use Thelia\Core\Template\Loop\Category; use Thelia\Core\Template\Smarty\SmartyPluginInterface; use Thelia\Core\Template\Smarty\Assets\SmartyAssetsManager; +use Thelia\Core\Template\Exception\ResourceNotFoundException; /** * @@ -31,8 +32,9 @@ class SmartyParser extends Smarty implements ParserInterface { * @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher * @param bool $template + * @param string $env Environment define for the kernel application. Used for the cache directory */ - public function __construct(Request $request, EventDispatcherInterface $dispatcher, $template = false, $env = "prod") + public function __construct(Request $request, EventDispatcherInterface $dispatcher, $template = false, $env = "prod", $debug = false) { parent::__construct(); @@ -52,23 +54,33 @@ class SmartyParser extends Smarty implements ParserInterface { $this->setCompileDir($compile_dir); $this->setCacheDir($cache_dir); + $this->debugging = $debug; + // Prevent smarty ErrorException: Notice: Undefined index bla bla bla... $this->error_reporting = E_ALL ^ E_NOTICE; - // Activer le cache, avec une lifetime de 15mn, et en vérifiant que les templates sources n'ont pas été modifiés. - $this->caching = 1; - $this->cache_lifetime = 300; - $this->compile_check = true; + // Si on n'est pas en mode debug, activer le cache, avec une lifetime de 15mn, et en vérifiant que les templates sources n'ont pas été modifiés. + if($debug == false) { + $this->caching = Smarty::CACHING_LIFETIME_CURRENT; + $this->cache_lifetime = 300; + $this->compile_check = true; + } else { + $this->caching = Smarty::CACHING_OFF; + } // The default HTTP status $this->status = 200; - $this->registerFilter("pre", array($this, 'prefunc')); + $this->registerFilter('pre', array($this, "pretest")); } - public function prefunc($tpl_source, \Smarty_Internal_Template $template) + public function pretest($tpl_source, \Smarty_Internal_Template $template) { - exit($tpl_source); + echo 1; + + return $tpl_source; + + //return $tpl_source; } public function setTemplate($template_path_from_template_base) { diff --git a/templates/smarty-sample/index.html b/templates/smarty-sample/index.html index 7bba1e5da..512679551 100755 --- a/templates/smarty-sample/index.html +++ b/templates/smarty-sample/index.html @@ -1,5 +1,5 @@
    {loop type="category" name="catloop1" id="1,3"} -
  • {$TITLE}
  • +
  • {$TITLE} - #TITLE
  • {/loop}
\ No newline at end of file From 94586c3a9cde4d46785889c8096f9f466f607b4c Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Mon, 24 Jun 2013 16:30:56 +0200 Subject: [PATCH 09/10] useless namespaces --- core/lib/Thelia/Core/Template/Smarty/SmartyParser.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index 9f9df8a88..84ff1bb06 100755 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -8,10 +8,8 @@ use \Symfony\Component\EventDispatcher\EventDispatcherInterface; use \Smarty; use Thelia\Core\Template\ParserInterface; -use Thelia\Core\Template\Loop\Category; use Thelia\Core\Template\Smarty\SmartyPluginInterface; -use Thelia\Core\Template\Smarty\Assets\SmartyAssetsManager; use Thelia\Core\Template\Exception\ResourceNotFoundException; /** @@ -62,7 +60,7 @@ class SmartyParser extends Smarty implements ParserInterface $this->error_reporting = E_ALL ^ E_NOTICE; // Si on n'est pas en mode debug, activer le cache, avec une lifetime de 15mn, et en vérifiant que les templates sources n'ont pas été modifiés. - if($debug == false) { + if($debug === false) { $this->caching = Smarty::CACHING_LIFETIME_CURRENT; $this->cache_lifetime = 300; $this->compile_check = true; From 0be18e763a4f7cb9e2c2c60f826d1c7df77d1b82 Mon Sep 17 00:00:00 2001 From: Etienne Roudeix Date: Tue, 25 Jun 2013 08:55:08 +0200 Subject: [PATCH 10/10] correct use of type and argument collections --- .../lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php | 7 +------ core/lib/Thelia/Type/TypeCollection.php | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index 88146317b..67ccfcf98 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php @@ -219,12 +219,7 @@ class TheliaLoop implements SmartyPluginInterface $faultDetails = array(); $argumentsCollection = $loop->defineArgs(); - $argumentsCollection->rewind(); - - while ($argumentsCollection->valid()) { - - $argument = $argumentsCollection->current(); - $argumentsCollection->next(); + foreach( $argumentsCollection as $argument ) { $value = isset($smartyParam[$argument->name]) ? $smartyParam[$argument->name] : null; diff --git a/core/lib/Thelia/Type/TypeCollection.php b/core/lib/Thelia/Type/TypeCollection.php index ebbd3274b..4430be5df 100755 --- a/core/lib/Thelia/Type/TypeCollection.php +++ b/core/lib/Thelia/Type/TypeCollection.php @@ -124,15 +124,10 @@ class TypeCollection implements \Iterator */ public function isValid($value) { - $this->rewind(); - while ($this->valid()) { - $type = $this->current(); - + foreach($this as $type) { if($type->isValid($value)) { return true; } - - $this->next(); } return false;