diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index 08575590f..e94fbf1fe 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -206,6 +206,9 @@ + + + diff --git a/core/lib/Thelia/Constraint/ConstraintManager.php b/core/lib/Thelia/Constraint/ConstraintManager.php index 6cbcbb1be..28073abaa 100644 --- a/core/lib/Thelia/Constraint/ConstraintManager.php +++ b/core/lib/Thelia/Constraint/ConstraintManager.php @@ -23,6 +23,9 @@ namespace Thelia\Constraint; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Constraint\Rule\SerializableRule; use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponRuleCollection; @@ -40,6 +43,9 @@ use Thelia\Coupon\CouponRuleCollection; */ class ConstraintManager { + /** @var ContainerInterface Service Container */ + protected $container = null; + /** @var CouponAdapterInterface Provide necessary value from Thelia*/ protected $adapter; @@ -49,27 +55,28 @@ class ConstraintManager /** * Constructor * - * @param CouponAdapterInterface $adapter Provide necessary value from Thelia - * @param CouponRuleCollection $rules Rules associated with the Constraint + * @param ContainerInterface $container Service container */ - function __construct(CouponAdapterInterface $adapter, CouponRuleCollection $rules) + function __construct(ContainerInterface $container) { - $this->adapter = $adapter; - $this->rule = $rules; + $this->container = $container; + $this->adapter = $container->get('thelia.adapter'); } /** * Check if the current Coupon is matching its conditions (Rules) * Thelia variables are given by the CouponAdapterInterface * + * @param CouponRuleCollection $collection A collection of rules + * * @return bool */ - public function isMatching() + public function isMatching(CouponRuleCollection $collection) { $isMatching = true; /** @var CouponRuleInterface $rule */ - foreach ($this->rules->getRules() as $rule) { + foreach ($collection->getRules() as $rule) { if (!$rule->isMatching($this->adapter)) { $isMatching = false; } @@ -78,5 +85,53 @@ class ConstraintManager return $isMatching; } + /** + * Serialize a collection of rules + * + * @param CouponRuleCollection $collection A collection of rules + * + * @return string A ready to be stored Rule collection + */ + public function serializeCouponRuleCollection(CouponRuleCollection $collection) + { + $serializableRules = array(); + $rules = $collection->getRules(); + if ($rules !== null) { + /** @var $rule CouponRuleInterface */ + foreach ($rules as $rule) { + $serializableRules[] = $rule->getSerializableRule(); + } + } + return (string) base64_encode(serialize($serializableRules)); + } + /** + * Unserialize a collection of rules + * + * @param string $serializedRules Serialized Rules + * + * @return CouponRuleCollection Rules ready to be processed + */ + public function unserializeCouponRuleCollection($serializedRules) + { + $unserializedRules = unserialize(base64_decode($serializedRules)); + $collection = new CouponRuleCollection(); + + if (!empty($serializedRules) && !empty($unserializedRules)) { + /** @var SerializableRule $rule */ + foreach ($unserializedRules as $rule) { + if ($this->container->has($rule->ruleServiceId)) { + /** @var CouponRuleInterface $couponRule */ + $couponRule = $this->container->get($rule->ruleServiceId); + $couponRule->populateFromForm( + $rule->operators, + $rule->values + ); + $collection->add($couponRule); + } + } + } + + return $collection; + } } \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmount.php b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmount.php index 7b4629b0f..58c19d8fd 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmount.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmount.php @@ -62,30 +62,6 @@ class AvailableForTotalAmount extends CouponRuleAbstract /** @var PriceParam Price Validator */ protected $priceValidator = null; - /** - * Constructor - * - * @param CouponAdapterInterface $adapter allowing to gather - * all necessary Thelia variables - * @param array $validators Array of RuleValidator - * validating $paramsToValidate against - * - * @throws \Thelia\Exception\InvalidRuleException - */ - public function __construct(CouponAdapterInterface $adapter, array $validators) - { - parent::__construct($adapter, $validators); - - if (isset($validators[self::PARAM1_PRICE]) - && $validators[self::PARAM1_PRICE] instanceof RuleValidator - ) { - $this->priceValidator = $validators[self::PARAM1_PRICE]; - } else { - throw new InvalidRuleException(get_class()); - } - } - - /** * Check if backoffice inputs are relevant or not * @@ -171,17 +147,6 @@ class AvailableForTotalAmount extends CouponRuleAbstract return $this; } - /** - * Return all validators - * Serialization purpose - * - * @return array - */ - public function getValidators() - { - return $this->validators; - } - /** * Get I18n name * @@ -203,13 +168,11 @@ class AvailableForTotalAmount extends CouponRuleAbstract */ public function getToolTip() { - /** @var Translator $translator */ - $translator = $this->get('thelia.translator'); $i18nOperator = Operators::getI18n( - $translator, $this->priceValidator->getOperator() + $this->translator, $this->priceValidator->getOperator() ); - $toolTip = $translator->trans( + $toolTip = $this->translator->trans( 'If cart total amount is %operator% %amount% %currency%', array( '%operator%' => $i18nOperator, diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForXArticles.php b/core/lib/Thelia/Constraint/Rule/AvailableForXArticles.php index c60404218..95ea8e5b1 100644 --- a/core/lib/Thelia/Constraint/Rule/AvailableForXArticles.php +++ b/core/lib/Thelia/Constraint/Rule/AvailableForXArticles.php @@ -56,31 +56,6 @@ class AvailableForXArticles extends CouponRuleAbstract /** @var QuantityParam Quantity Validator */ protected $quantityValidator = null; - /** - * Constructor - * - * @param CouponAdapterInterface $adapter allowing to gather - * all necessary Thelia variables - * @param array $validators Array of RuleValidator - * validating $paramsToValidate against - * - * @throws InvalidRuleException - */ - public function __construct(CouponAdapterInterface $adapter, array $validators = null) - { - parent::__construct($adapter, $validators); - - if (isset($validators[self::PARAM1_QUANTITY]) - && $validators[self::PARAM1_QUANTITY] instanceof RuleValidator - ) { - $this->quantityValidator = $validators[self::PARAM1_QUANTITY]; - } else { - throw new InvalidRuleException(get_class()); - } - - $this->adapter = $adapter; - } - /** * Check if backoffice inputs are relevant or not * @@ -176,10 +151,7 @@ class AvailableForXArticles extends CouponRuleAbstract */ public function getName() { - /** @var Translator $translator */ - $translator = $this->adapter->get('thelia.translator'); - - return $translator->trans( + return $this->translator->trans( 'Number of articles in cart', array(), 'constraint' @@ -193,14 +165,11 @@ class AvailableForXArticles extends CouponRuleAbstract */ public function getToolTip() { - /** @var Translator $translator */ - $translator = $this->adapter->get('thelia.translator'); - $i18nOperator = Operators::getI18n( - $translator, $this->priceValidator->getOperator() + $this->translator, $this->priceValidator->getOperator() ); - $toolTip = $translator->trans( + $toolTip = $this->translator->trans( 'If cart products quantity is %operator% %quantity%', array( '%operator%' => $i18nOperator, @@ -256,5 +225,4 @@ class AvailableForXArticles extends CouponRuleAbstract return $serializableRule; } - } \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php index ff97ee3a0..ff8a26a8a 100644 --- a/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php +++ b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php @@ -24,6 +24,7 @@ namespace Thelia\Constraint\Rule; use Symfony\Component\Intl\Exception\NotImplementedException; +use Symfony\Component\Translation\Translator; use Thelia\Coupon\CouponAdapterInterface; use Thelia\Constraint\Validator\ComparableInterface; use Thelia\Constraint\Validator\RuleValidator; @@ -60,29 +61,17 @@ abstract class CouponRuleAbstract implements CouponRuleInterface /** @var CouponAdapterInterface Provide necessary value from Thelia */ protected $adapter = null; + /** @var Translator Service Translator */ + protected $translator = null; + /** * Constructor - * Ex: - * Param 1 : - * $priceValidator = new RuleValidator( - * Operators::INFERIOR, - * new IntegerParam(10) - * ) - * $validators[AvailableForTotalAmount::PARAM1_PRICE] = $priceValidator * - * Param 2 : - * $paramsToValidate[AvailableForTotalAmount::PARAM1_PRICE] = 9 - * - * @param CouponAdapterInterface $adapter allowing to gather - * all necessary Thelia variables - * @param array $validators Array of RuleValidator - * validating $paramsToValidate against + * @param Translator $translator Service translator */ - public function __construct(CouponAdapterInterface $adapter, array $validators) + function __construct(Translator $translator) { - $this->setValidators($validators); - $this->adapter = $adapter; - $this->setParametersToValidate($this->adapter); + $this->translator($translator); } /** @@ -180,4 +169,15 @@ abstract class CouponRuleAbstract implements CouponRuleInterface throw new \Thelia\Exception\NotImplementedException(); } + /** + * Return all validators + * Serialization purpose + * + * @return array + */ + public function getValidators() + { + return $this->validators; + } + } \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php b/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php index ce8e6c469..f2b9447e3 100644 --- a/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php +++ b/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php @@ -39,6 +39,13 @@ use Thelia\Coupon\CouponAdapterInterface; */ interface CouponRuleInterface { + /** + * Constructor + * + * @param Translator $translator Service translator + */ + function __construct(Translator $translator); + /** * Check if backoffice inputs are relevant or not * diff --git a/core/lib/Thelia/Constraint/Rule/SerializableRule.php b/core/lib/Thelia/Constraint/Rule/SerializableRule.php index 66caa793d..3cab5e70c 100644 --- a/core/lib/Thelia/Constraint/Rule/SerializableRule.php +++ b/core/lib/Thelia/Constraint/Rule/SerializableRule.php @@ -37,7 +37,7 @@ namespace Thelia\Constraint\Rule; class SerializableRule { /** @var string Rule Service id */ - public $ruleClassName = null; + public $ruleServiceId = null; /** @var array Operators set by Admin for this Rule */ public $operators = array(); diff --git a/core/lib/Thelia/Coupon/CouponFactory.php b/core/lib/Thelia/Coupon/CouponFactory.php index 23f082974..3ff064601 100644 --- a/core/lib/Thelia/Coupon/CouponFactory.php +++ b/core/lib/Thelia/Coupon/CouponFactory.php @@ -137,7 +137,7 @@ class CouponFactory // * // * @return CouponRuleInterface Ready to use Rule or false // */ -// public function buildCouponRuleFromForm($ruleClassName, $operator, array $values) +// public function buildCouponRuleFromForm($ruleServiceId, $operator, array $values) // { // /** @var CouponAdapterInterface $adapter */ // $adapter = $this->container->get('thelia.adapter'); diff --git a/core/lib/Thelia/Coupon/CouponManager.php b/core/lib/Thelia/Coupon/CouponManager.php index ad351081c..ee20b4fd0 100644 --- a/core/lib/Thelia/Coupon/CouponManager.php +++ b/core/lib/Thelia/Coupon/CouponManager.php @@ -52,7 +52,7 @@ class CouponManager /** * Constructor * - * @param ContainerInterface $container Service container + * @param ContainerInterface $container Service container */ function __construct(ContainerInterface $container) { diff --git a/core/lib/Thelia/Coupon/CouponRuleCollection.php b/core/lib/Thelia/Coupon/CouponRuleCollection.php index 2f1a51dc0..93db32beb 100644 --- a/core/lib/Thelia/Coupon/CouponRuleCollection.php +++ b/core/lib/Thelia/Coupon/CouponRuleCollection.php @@ -23,9 +23,9 @@ namespace Thelia\Coupon; -use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\DependencyInjection\ContainerInterface; use Thelia\Constraint\Rule\CouponRuleInterface; -use Thelia\Exception\InvalidRuleException; +use Thelia\Constraint\Rule\SerializableRule; /** * Created by JetBrains PhpStorm. @@ -45,19 +45,10 @@ class CouponRuleCollection /** * Constructor - * - * @param array $rules Array of CouponRuleInterface - * - * @throws \Thelia\Exception\InvalidRuleException */ - function __construct(array $rules) + function __construct() { - foreach ($rules as $rule) { - if (!$rule instanceof CouponRuleInterface) { - throw new InvalidRuleException(get_class()); - } - } - $this->rules = $rules; + } /** diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index 03a59b8e9..f5788ff4f 100755 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -24,6 +24,7 @@ namespace Thelia\Model; use Propel\Runtime\Propel; +use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Coupon\CouponRuleCollection; use Thelia\Model\Base\Coupon as BaseCoupon; use Thelia\Model\Map\CouponTableMap; @@ -98,37 +99,34 @@ class Coupon extends BaseCoupon } } - /** - * Set the value of [serialized_rules] column. - * - * @param CouponRuleCollection $rules A set of Rules - * - * @return \Thelia\Model\Coupon The current object (for fluent API support) - */ - public function setRules(CouponRuleCollection $rules) - { - $serializedRules = null; - if ($rules !== null) { - - $serializedRules = (string) base64_encode(serialize($rules)); - } - - if ($this->serialized_rules !== $serializedRules) { - $this->serialized_rules = $serializedRules; - $this->modifiedColumns[] = CouponTableMap::SERIALIZED_RULES; - } - - return $this; - } +// /** +// * Set the value of [serialized_rules] column. +// * Convert a CouponRuleCollection into a serialized array of SerializableRule +// * +// * @param CouponRuleCollection $rules A set of Rules +// * +// * @return \Thelia\Model\Coupon The current object (for fluent API support) +// */ +// public function setRules(CouponRuleCollection $rules) +// { +// $serializedRules = null; +// if ($rules !== null) { +// /** @var $rule CouponRuleInterface */ +// foreach ($rules->getRules() as $rule) { +// $serializedRules[] = $rule->getSerializableRule(); +// } +// +// $serializedRules = (string) base64_encode(serialize($serializedRules)); +// } +// +// if ($this->serialized_rules !== $serializedRules) { +// $this->serialized_rules = $serializedRules; +// $this->modifiedColumns[] = CouponTableMap::SERIALIZED_RULES; +// } +// +// return $this; +// } + - /** - * Get the [serialized_rules] column value. - * - * @return CouponRuleCollection Rules ready to be processed - */ - public function getRules() - { - return unserialize(base64_decode($this->serialized_rules)); - } } diff --git a/core/lib/Thelia/Tests/Constraint/ConstraintManagerTest.php b/core/lib/Thelia/Tests/Constraint/ConstraintManagerTest.php index 08389ef9e..5d0be5711 100644 --- a/core/lib/Thelia/Tests/Constraint/ConstraintManagerTest.php +++ b/core/lib/Thelia/Tests/Constraint/ConstraintManagerTest.php @@ -23,6 +23,8 @@ namespace Thelia\Constraint; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Thelia\Constraint\Rule\AvailableForXArticles; use Thelia\Constraint\Validator\PriceParam; use Thelia\Constraint\Validator\RuleValidator; use Thelia\Constraint\Rule\AvailableForTotalAmount; @@ -50,12 +52,10 @@ class ConstraintManagerTest extends \PHPUnit_Framework_TestCase * Sets up the fixture, for example, opens a network connection. * This method is called before a test is executed. */ - protected function setUp() + public function setUp() { } - - public function incompleteTest() { $this->markTestIncomplete( @@ -63,6 +63,62 @@ class ConstraintManagerTest extends \PHPUnit_Framework_TestCase ); } + /** + * Check the Rules serialization module + */ + public function testRuleSerialisation() + { + $translator = $this->getMock('\Thelia\Core\Translation\Translator'); + + $rule1 = new AvailableForTotalAmount($translator); + $operators = array(AvailableForTotalAmount::PARAM1_PRICE => Operators::SUPERIOR); + $values = array( + AvailableForTotalAmount::PARAM1_PRICE => 40.00, + AvailableForTotalAmount::PARAM1_CURRENCY => 'EUR' + ); + $rule1->populateFromForm($operators, $values); + + $rule2 = new AvailableForTotalAmount($translator); + $operators = array(AvailableForTotalAmount::PARAM1_PRICE => Operators::INFERIOR); + $values = array( + AvailableForTotalAmount::PARAM1_PRICE => 400.00, + AvailableForTotalAmount::PARAM1_CURRENCY => 'EUR' + ); + $rule2->populateFromForm($operators, $values); + + $rules = new CouponRuleCollection(array($rule1, $rule2)); + + /** @var ConstraintManager $constraintManager */ + $constraintManager = new ConstraintManager($this->getContainer()); + + $serializedRules = $constraintManager->serializeCouponRuleCollection($rules); + $unserializedRules = $constraintManager->unserializeCouponRuleCollection($serializedRules); + + $expected = $rules; + $actual = $unserializedRules; + + $this->assertEquals($expected, $actual); + } + + /** + * Get Mocked Container with 2 Rules + * + * @return ContainerBuilder + */ + public function getContainer() + { + $container = new ContainerBuilder(); + + $translator = $this->getMock('\Thelia\Core\Translation\Translator'); + $rule1 = new AvailableForTotalAmount($translator); + $rule2 = new AvailableForXArticles($translator); + + $container->set('thelia.constraint.rule.available_for_total_amount', $rule1); + $container->set('thelia.constraint.rule.available_for_x_articles', $rule2); + + return $container; + } + /** * Tears down the fixture, for example, closes a network connection. * This method is called after a test is executed.