Loop arguments should now be accessed using $this->getArgValue($argname),

or getArg($name)->value. Loop args initialisation is now located in
BaseLoop class
This commit is contained in:
franck
2013-07-08 10:57:05 +02:00
parent 61fc13309d
commit 7646c05cd4
7 changed files with 194 additions and 102 deletions

View File

@@ -38,16 +38,14 @@ abstract class BaseLoop
/** /**
* @var \Symfony\Component\HttpFoundation\Request * @var \Symfony\Component\HttpFoundation\Request
*/ */
public $request; protected $request;
/** /**
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/ */
public $dispatcher; protected $dispatcher;
public $limit; private $args;
public $page;
public $offset;
protected function getDefaultArgs() protected function getDefaultArgs()
{ {
@@ -59,6 +57,8 @@ abstract class BaseLoop
} }
/** /**
* Create a new Loop
*
* @param \Symfony\Component\HttpFoundation\Request $request * @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher
*/ */
@@ -66,11 +66,94 @@ abstract class BaseLoop
{ {
$this->request = $request; $this->request = $request;
$this->dispatcher = $dispatcher; $this->dispatcher = $dispatcher;
$this->args = $this->getArgDefinitions()->addArguments($this->getDefaultArgs());
} }
public function getArgs() /**
{ * Initialize the loop arguments.
return $this->defineArgs()->addArguments($this->getDefaultArgs()); *
* @param array $nameValuePairs a array of name => value pairs. The name is the name of the argument.
*
* @throws \InvalidArgumentException if somùe argument values are missing, or invalid
*/
public function initializeArgs(array $nameValuePairs) {
$faultActor = array();
$faultDetails = array();
while (($argument = $this->args->current()) !== false) {
$value = isset($nameValuePairs[$argument->name]) ? $nameValuePairs[$argument->name] : null;
/* check if mandatory */
if($value === null && $argument->mandatory) {
$faultActor[] = $argument->name;
$faultDetails[] = sprintf('"%s" parameter is missing', $argument->name);
continue;
}
/* check if empty */
if($value === '' && !$argument->empty) {
$faultActor[] = $argument->name;
$faultDetails[] = sprintf('"%s" parameter cannot be empty', $argument->name);
continue;
}
/* 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;
}
$argument->setValue($value);
$this->args->next();
}
if (!empty($faultActor)) {
$complement = sprintf('[%s]', implode(', ', $faultDetails));
throw new \InvalidArgumentException($complement);
}
}
/**
* Return a loop argument
*
* @param string $argumentName the argument name
*
* @throws \InvalidArgumentException if argument is not found in loop argument list
* @return Argument the loop argument.
*/
public function getArg($argumentName) {
$arg = $this->args->get($argumentName);
if ($arg === null)
throw new \InvalidArgumentException("Undefined loop argument '$argumentName'");
return $arg;
}
/**
* Return a loop argument value
*
* @param string $argumentName the argument name
*
* @throws \InvalidArgumentException if argument is not found in loop argument list
* @return Argument the loop argument.
*/
public function getArgValue($argumentName) {
return $this->getArg($argumentName)->getValue();
} }
/** /**
@@ -81,7 +164,7 @@ abstract class BaseLoop
*/ */
public function search(ModelCriteria $search, &$pagination = null) public function search(ModelCriteria $search, &$pagination = null)
{ {
if($this->page !== null) { if($this->getArgValue('page') !== null) {
return $this->searchWithPagination($search, $pagination); return $this->searchWithPagination($search, $pagination);
} else { } else {
return $this->searchWithOffset($search); return $this->searchWithOffset($search);
@@ -95,10 +178,10 @@ abstract class BaseLoop
*/ */
public function searchWithOffset(ModelCriteria $search) public function searchWithOffset(ModelCriteria $search)
{ {
if($this->limit >= 0) { if($this->getArgValue('limit') >= 0) {
$search->limit($this->limit); $search->limit($this->getArgValue('limit'));
} }
$search->offset($this->offset); $search->offset($this->getArgValue('offset'));
return $search->find(); return $search->find();
} }
@@ -111,9 +194,9 @@ abstract class BaseLoop
*/ */
public function searchWithPagination(ModelCriteria $search, &$pagination) public function searchWithPagination(ModelCriteria $search, &$pagination)
{ {
$pagination = $search->paginate($this->page, $this->limit); $pagination = $search->paginate($this->getArgValue('page'), $this->getArgValue('limit'));
if($this->page > $pagination->getLastPage()) { if($this->getArgValue('page') > $pagination->getLastPage()) {
return array(); return array();
} else { } else {
return $pagination; return $pagination;
@@ -145,7 +228,8 @@ abstract class BaseLoop
* @param $pagination * @param $pagination
* *
* @return mixed * @return mixed
*/abstract public function exec(&$pagination); */
abstract public function exec(&$pagination);
/** /**
* *
@@ -166,6 +250,6 @@ abstract class BaseLoop
* *
* @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection * @return \Thelia\Core\Template\Loop\Argument\ArgumentCollection
*/ */
abstract protected function defineArgs(); abstract protected function getArgDefinitions();
} }

View File

@@ -38,12 +38,25 @@ class Argument
public $mandatory; public $mandatory;
public $empty; public $empty;
public function __construct($name, \Thelia\Type\TypeCollection $type, $default = null, $mandatory = false, $empty = true) private $value;
public function __construct($name, \Thelia\Type\TypeCollection $type, $default = null, $mandatory = false, $empty = true, $value = null)
{ {
$this->name = $name; $this->name = $name;
$this->type = $type; $this->type = $type;
$this->mandatory = $mandatory ? true : false; $this->mandatory = $mandatory ? true : false;
$this->default = $default; $this->default = $default;
$this->empty = $empty;
$this->setValue($value);
}
public function getValue() {
return $this->value;
}
public function setValue($value) {
$this->value = $value;
} }
public static function createAnyTypeArgument($name, $default=null, $mandatory=false, $empty=true) public static function createAnyTypeArgument($name, $default=null, $mandatory=false, $empty=true)

View File

@@ -30,14 +30,21 @@ namespace Thelia\Core\Template\Loop\Argument;
class ArgumentCollection implements \Iterator class ArgumentCollection implements \Iterator
{ {
private $position; private $arguments = array();
protected $arguments = array();
public function __construct() public function __construct()
{ {
$this->addArguments(func_get_args()); $this->addArguments(func_get_args());
} }
public function hasKey($key) {
return isset($this->arguments[$key]);
}
public function get($key) {
return $this->hasKey($key) ? $this->arguments[$key] : null;
}
public function isEmpty() public function isEmpty()
{ {
return count($this->arguments) == 0; return count($this->arguments) == 0;
@@ -64,7 +71,8 @@ class ArgumentCollection implements \Iterator
*/ */
public function addArgument(Argument $argument) public function addArgument(Argument $argument)
{ {
$this->arguments[] = $argument; $this->arguments[$argument->name] = $argument;
return $this; return $this;
} }
@@ -81,7 +89,7 @@ class ArgumentCollection implements \Iterator
*/ */
public function current() public function current()
{ {
return $this->arguments[$this->position]; return current($this->arguments);
} }
/** /**
@@ -92,7 +100,7 @@ class ArgumentCollection implements \Iterator
*/ */
public function next() public function next()
{ {
$this->position++; next($this->arguments);
} }
/** /**
@@ -103,7 +111,7 @@ class ArgumentCollection implements \Iterator
*/ */
public function key() public function key()
{ {
return $this->position; return key($this->arguments);
} }
/** /**
@@ -115,7 +123,7 @@ class ArgumentCollection implements \Iterator
*/ */
public function valid() public function valid()
{ {
return isset($this->arguments[$this->position]); return $this->key() !== null;
} }
/** /**
@@ -126,6 +134,6 @@ class ArgumentCollection implements \Iterator
*/ */
public function rewind() public function rewind()
{ {
$this->position = 0; reset($this->arguments);
} }
} }

View File

@@ -80,7 +80,7 @@ class Category extends BaseLoop
/** /**
* @return ArgumentCollection * @return ArgumentCollection
*/ */
protected function defineArgs() protected function getArgDefinitions()
{ {
return new ArgumentCollection( return new ArgumentCollection(
Argument::createIntListTypeArgument('id'), Argument::createIntListTypeArgument('id'),
@@ -109,31 +109,41 @@ class Category extends BaseLoop
{ {
$search = CategoryQuery::create(); $search = CategoryQuery::create();
if (!is_null($this->id)) { $id = $this->getArgValue('id');
$search->filterById(explode(',', $this->id), Criteria::IN);
if (!is_null($id)) {
$search->filterById(explode(',', $id), Criteria::IN);
} }
if (!is_null($this->parent)) { $parent = $this->getArgValue('parent');
$search->filterByParent($this->parent);
if (!is_null($parent)) {
$search->filterByParent($parent);
} }
if ($this->current == 1) { $current = $this->getArgValue('current');
if ($current == 1) {
$search->filterById($this->request->get("category_id")); $search->filterById($this->request->get("category_id"));
} elseif (null !== $this->current && $this->current == 0) { } elseif (null !== $current && $current == 0) {
$search->filterById($this->request->get("category_id"), Criteria::NOT_IN); $search->filterById($this->request->get("category_id"), Criteria::NOT_IN);
} }
if (!is_null($this->exclude)) { $exclude = $this->getArgValue('exclude');
$search->filterById(explode(",", $this->exclude), Criteria::NOT_IN);
if (!is_null($exclude)) {
$search->filterById(explode(",", $exclude), Criteria::NOT_IN);
} }
if (!is_null($this->link)) { $link = $this->getArgValue('link');
$search->filterByLink($this->link);
if (!is_null($link)) {
$search->filterByLink($link);
} }
$search->filterByVisible($this->visible); $search->filterByVisible($this->getArgValue('visible'));
switch ($this->order) { switch ($this->getArgValue('order')) {
case "alpha": case "alpha":
$search->addAscendingOrderByColumn(\Thelia\Model\CategoryI18nPeer::TITLE); $search->addAscendingOrderByColumn(\Thelia\Model\CategoryI18nPeer::TITLE);
break; break;
@@ -148,7 +158,7 @@ class Category extends BaseLoop
break; break;
} }
if ($this->random == 1) { if ($this->getArgValue('random') == 1) {
$search->clearOrderByColumns(); $search->clearOrderByColumns();
$search->addAscendingOrderByColumn('RAND()'); $search->addAscendingOrderByColumn('RAND()');
} }

View File

@@ -41,25 +41,13 @@ use Thelia\Type;
*/ */
class Feed extends BaseLoop class Feed extends BaseLoop
{ {
public function getArgDefinitions()
public $url;
public $limit;
public $timeout;
public function defineArgs()
{ {
return new ArgumentCollection( return new ArgumentCollection(
new Argument( new Argument(
'url', 'url',
new TypeCollection(new Type\AnyType()) new TypeCollection(new Type\AnyType())
), ),
new Argument(
'limit',
new TypeCollection(
new Type\IntType()
),
3
),
new Argument( new Argument(
'timeout', 'timeout',
new TypeCollection( new TypeCollection(
@@ -75,7 +63,7 @@ class Feed extends BaseLoop
* *
* @return \Thelia\Core\Template\Element\LoopResult * @return \Thelia\Core\Template\Element\LoopResult
*/ */
public function exec() public function exec(&$pagination)
{ {
$cachedir = THELIA_ROOT . 'cache/feeds'; $cachedir = THELIA_ROOT . 'cache/feeds';

View File

@@ -35,7 +35,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class TheliaLoop implements SmartyPluginInterface class TheliaLoop implements SmartyPluginInterface
{ {
protected static $pagination = null; protected $pagination = null;
protected $loopDefinition = array(); protected $loopDefinition = array();
@@ -58,10 +58,10 @@ class TheliaLoop implements SmartyPluginInterface
* *
* @return \PropelModelPager * @return \PropelModelPager
*/ */
public static function getPagination($loopId) protected function getPagination($loopId)
{ {
if(!empty(self::$pagination[$loopId])) { if(!empty($this->pagination[$loopId])) {
return self::$pagination[$loopId]; return $this->pagination[$loopId];
} else { } else {
return null; return null;
} }
@@ -95,14 +95,11 @@ class TheliaLoop implements SmartyPluginInterface
throw new \InvalidArgumentException("A loop named '$name' already exists in the current scope."); throw new \InvalidArgumentException("A loop named '$name' already exists in the current scope.");
} }
$loop = $this->createLoopInstance(strtolower($params['type'])); $loop = $this->createLoopInstance($params);
$this->getLoopArgument($loop, $params); $this->pagination[$name] = null;
self::$pagination[$name] = null;
$loopResults = $loop->exec(self::$pagination[$name]);
$loopResults = $loop->exec($this->pagination[$name]);
$this->loopstack[$name] = $loopResults; $this->loopstack[$name] = $loopResults;
@@ -221,14 +218,15 @@ class TheliaLoop implements SmartyPluginInterface
$loopName = $params['rel']; $loopName = $params['rel'];
// Find loop results in the current template vars // Find loop results in the current template vars
$loopResults = $this->loopstack[$loopName]; if (! isset($this->loopstack[$loopName])) {
if (empty($loopResults)) {
throw new \InvalidArgumentException("Loop $loopName is not defined."); throw new \InvalidArgumentException("Loop $loopName is not defined.");
} }
$loopResults = $this->loopstack[$loopName];
// Find pagination // Find pagination
$pagination = self::getPagination($loopName); $pagination = $this->getPagination($loopName);
if ($pagination === null) { if ($pagination === null) {
throw new \InvalidArgumentException("Loop $loopName : no pagination found."); throw new \InvalidArgumentException("Loop $loopName : no pagination found.");
} }
@@ -285,24 +283,30 @@ class TheliaLoop implements SmartyPluginInterface
* @throws \Thelia\Tpex\Exception\InvalidElementException * @throws \Thelia\Tpex\Exception\InvalidElementException
* @throws \Thelia\Tpex\Exception\ElementNotFoundException * @throws \Thelia\Tpex\Exception\ElementNotFoundException
*/ */
protected function createLoopInstance($name) protected function createLoopInstance($smartyParams)
{ {
if (! isset($this->loopDefinition[$name])) { $type = strtolower($smartyParams['type']);
throw new ElementNotFoundException(sprintf("%s loop does not exists", $name));
if (! isset($this->loopDefinition[$type])) {
throw new ElementNotFoundException(sprintf("%s loop does not exists", $type));
} }
$class = new \ReflectionClass($this->loopDefinition[$name]); $class = new \ReflectionClass($this->loopDefinition[$type]);
if ($class->isSubclassOf("Thelia\Core\Template\Element\BaseLoop") === false) { if ($class->isSubclassOf("Thelia\Core\Template\Element\BaseLoop") === false) {
throw new InvalidElementException(sprintf("%s Loop class have to extends Thelia\Core\Template\Element\BaseLoop", throw new InvalidElementException(sprintf("%s Loop class have to extends Thelia\Core\Template\Element\BaseLoop",
$name)); $type));
} }
return $class->newInstance( $loop = $class->newInstance(
$this->request, $this->request,
$this->dispatcher $this->dispatcher
); );
$loop->initializeArgs($smartyParams);
return $loop;
} }
/** /**
@@ -314,10 +318,6 @@ class TheliaLoop implements SmartyPluginInterface
*/ */
protected function getLoopArgument(BaseLoop $loop, $smartyParam) protected function getLoopArgument(BaseLoop $loop, $smartyParam)
{ {
$defaultItemsParams = array('required' => true);
$shortcutItemParams = array('optional' => array('required' => false));
$faultActor = array(); $faultActor = array();
$faultDetails = array(); $faultDetails = array();

View File

@@ -35,7 +35,7 @@ use Thelia\Type\TypeCollection;
*/ */
class ArgumentTest extends \PHPUnit_Framework_TestCase class ArgumentTest extends \PHPUnit_Framework_TestCase
{ {
public function testArgumentCollectionConstruction() public function testArgumentCollectionCreateAndWalk()
{ {
$collection = new ArgumentCollection( $collection = new ArgumentCollection(
new Argument( new Argument(
@@ -61,30 +61,19 @@ class ArgumentTest extends \PHPUnit_Framework_TestCase
) )
); );
$this->assertAttributeEquals( $this->assertTrue($collection->getCount() == 3);
array(
0 => new Argument( $this->assertTrue($collection->key() == 'arg0');
'arg0', $collection->next();
new TypeCollection( $this->assertTrue($collection->key() == 'arg1');
new Type\AnyType() $collection->next();
) $this->assertTrue($collection->key() == 'arg2');
), $collection->next();
1 => new Argument(
'arg1', $this->assertFalse($collection->valid());
new TypeCollection(
new Type\AnyType() $collection->rewind();
) $this->assertTrue($collection->key() == 'arg0');
),
2 => new Argument(
'arg2',
new TypeCollection(
new Type\AnyType()
)
),
),
'arguments',
$collection
);
} }
public function testArgumentCollectionFetch() public function testArgumentCollectionFetch()