- Add Coupon, Rules, CouponManager, Adapter as Services
- Refactor Coupon to use these services
This commit is contained in:
gmorel
2013-09-06 11:47:00 +02:00
parent eea29cba06
commit 8a5e12f814
12 changed files with 190 additions and 149 deletions

View File

@@ -206,6 +206,9 @@
<service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager"> <service id="thelia.coupon.manager" class="Thelia\Coupon\CouponManager">
<argument type="service" id="thelia.adapter" /> <argument type="service" id="thelia.adapter" />
</service> </service>
<service id="thelia.constraint.manager" class="Thelia\Constraint\ConstraintManager">
<argument type="service" id="service_container" />
</service>
<service id="thelia.constraint.rule.available_for_x_articles" class="Thelia\Constraint\Rule\AvailableForXArticles"> <service id="thelia.constraint.rule.available_for_x_articles" class="Thelia\Constraint\Rule\AvailableForXArticles">
<argument type="service" id="thelia.translator" /> <argument type="service" id="thelia.translator" />
<tag name="thelia.coupon.addRule"/> <tag name="thelia.coupon.addRule"/>

View File

@@ -23,6 +23,9 @@
namespace Thelia\Constraint; 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\CouponAdapterInterface;
use Thelia\Coupon\CouponRuleCollection; use Thelia\Coupon\CouponRuleCollection;
@@ -40,6 +43,9 @@ use Thelia\Coupon\CouponRuleCollection;
*/ */
class ConstraintManager class ConstraintManager
{ {
/** @var ContainerInterface Service Container */
protected $container = null;
/** @var CouponAdapterInterface Provide necessary value from Thelia*/ /** @var CouponAdapterInterface Provide necessary value from Thelia*/
protected $adapter; protected $adapter;
@@ -49,27 +55,28 @@ class ConstraintManager
/** /**
* Constructor * Constructor
* *
* @param CouponAdapterInterface $adapter Provide necessary value from Thelia * @param ContainerInterface $container Service container
* @param CouponRuleCollection $rules Rules associated with the Constraint
*/ */
function __construct(CouponAdapterInterface $adapter, CouponRuleCollection $rules) function __construct(ContainerInterface $container)
{ {
$this->adapter = $adapter; $this->container = $container;
$this->rule = $rules; $this->adapter = $container->get('thelia.adapter');
} }
/** /**
* Check if the current Coupon is matching its conditions (Rules) * Check if the current Coupon is matching its conditions (Rules)
* Thelia variables are given by the CouponAdapterInterface * Thelia variables are given by the CouponAdapterInterface
* *
* @param CouponRuleCollection $collection A collection of rules
*
* @return bool * @return bool
*/ */
public function isMatching() public function isMatching(CouponRuleCollection $collection)
{ {
$isMatching = true; $isMatching = true;
/** @var CouponRuleInterface $rule */ /** @var CouponRuleInterface $rule */
foreach ($this->rules->getRules() as $rule) { foreach ($collection->getRules() as $rule) {
if (!$rule->isMatching($this->adapter)) { if (!$rule->isMatching($this->adapter)) {
$isMatching = false; $isMatching = false;
} }
@@ -78,5 +85,53 @@ class ConstraintManager
return $isMatching; 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;
}
} }

View File

@@ -62,30 +62,6 @@ class AvailableForTotalAmount extends CouponRuleAbstract
/** @var PriceParam Price Validator */ /** @var PriceParam Price Validator */
protected $priceValidator = null; 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 * Check if backoffice inputs are relevant or not
* *
@@ -171,17 +147,6 @@ class AvailableForTotalAmount extends CouponRuleAbstract
return $this; return $this;
} }
/**
* Return all validators
* Serialization purpose
*
* @return array
*/
public function getValidators()
{
return $this->validators;
}
/** /**
* Get I18n name * Get I18n name
* *
@@ -203,13 +168,11 @@ class AvailableForTotalAmount extends CouponRuleAbstract
*/ */
public function getToolTip() public function getToolTip()
{ {
/** @var Translator $translator */
$translator = $this->get('thelia.translator');
$i18nOperator = Operators::getI18n( $i18nOperator = Operators::getI18n(
$translator, $this->priceValidator->getOperator() $this->translator, $this->priceValidator->getOperator()
); );
$toolTip = $translator->trans( $toolTip = $this->translator->trans(
'If cart total amount is <strong>%operator%</strong> %amount% %currency%', 'If cart total amount is <strong>%operator%</strong> %amount% %currency%',
array( array(
'%operator%' => $i18nOperator, '%operator%' => $i18nOperator,

View File

@@ -56,31 +56,6 @@ class AvailableForXArticles extends CouponRuleAbstract
/** @var QuantityParam Quantity Validator */ /** @var QuantityParam Quantity Validator */
protected $quantityValidator = null; 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 * Check if backoffice inputs are relevant or not
* *
@@ -176,10 +151,7 @@ class AvailableForXArticles extends CouponRuleAbstract
*/ */
public function getName() public function getName()
{ {
/** @var Translator $translator */ return $this->translator->trans(
$translator = $this->adapter->get('thelia.translator');
return $translator->trans(
'Number of articles in cart', 'Number of articles in cart',
array(), array(),
'constraint' 'constraint'
@@ -193,14 +165,11 @@ class AvailableForXArticles extends CouponRuleAbstract
*/ */
public function getToolTip() public function getToolTip()
{ {
/** @var Translator $translator */
$translator = $this->adapter->get('thelia.translator');
$i18nOperator = Operators::getI18n( $i18nOperator = Operators::getI18n(
$translator, $this->priceValidator->getOperator() $this->translator, $this->priceValidator->getOperator()
); );
$toolTip = $translator->trans( $toolTip = $this->translator->trans(
'If cart products quantity is <strong>%operator%</strong> %quantity%', 'If cart products quantity is <strong>%operator%</strong> %quantity%',
array( array(
'%operator%' => $i18nOperator, '%operator%' => $i18nOperator,
@@ -256,5 +225,4 @@ class AvailableForXArticles extends CouponRuleAbstract
return $serializableRule; return $serializableRule;
} }
} }

View File

@@ -24,6 +24,7 @@
namespace Thelia\Constraint\Rule; namespace Thelia\Constraint\Rule;
use Symfony\Component\Intl\Exception\NotImplementedException; use Symfony\Component\Intl\Exception\NotImplementedException;
use Symfony\Component\Translation\Translator;
use Thelia\Coupon\CouponAdapterInterface; use Thelia\Coupon\CouponAdapterInterface;
use Thelia\Constraint\Validator\ComparableInterface; use Thelia\Constraint\Validator\ComparableInterface;
use Thelia\Constraint\Validator\RuleValidator; use Thelia\Constraint\Validator\RuleValidator;
@@ -60,29 +61,17 @@ abstract class CouponRuleAbstract implements CouponRuleInterface
/** @var CouponAdapterInterface Provide necessary value from Thelia */ /** @var CouponAdapterInterface Provide necessary value from Thelia */
protected $adapter = null; protected $adapter = null;
/** @var Translator Service Translator */
protected $translator = null;
/** /**
* Constructor * Constructor
* Ex:
* Param 1 :
* $priceValidator = new RuleValidator(
* Operators::INFERIOR,
* new IntegerParam(10)
* )
* $validators[AvailableForTotalAmount::PARAM1_PRICE] = $priceValidator
* *
* Param 2 : * @param Translator $translator Service translator
* $paramsToValidate[AvailableForTotalAmount::PARAM1_PRICE] = 9
*
* @param CouponAdapterInterface $adapter allowing to gather
* all necessary Thelia variables
* @param array $validators Array of RuleValidator
* validating $paramsToValidate against
*/ */
public function __construct(CouponAdapterInterface $adapter, array $validators) function __construct(Translator $translator)
{ {
$this->setValidators($validators); $this->translator($translator);
$this->adapter = $adapter;
$this->setParametersToValidate($this->adapter);
} }
/** /**
@@ -180,4 +169,15 @@ abstract class CouponRuleAbstract implements CouponRuleInterface
throw new \Thelia\Exception\NotImplementedException(); throw new \Thelia\Exception\NotImplementedException();
} }
/**
* Return all validators
* Serialization purpose
*
* @return array
*/
public function getValidators()
{
return $this->validators;
}
} }

View File

@@ -39,6 +39,13 @@ use Thelia\Coupon\CouponAdapterInterface;
*/ */
interface CouponRuleInterface interface CouponRuleInterface
{ {
/**
* Constructor
*
* @param Translator $translator Service translator
*/
function __construct(Translator $translator);
/** /**
* Check if backoffice inputs are relevant or not * Check if backoffice inputs are relevant or not
* *

View File

@@ -37,7 +37,7 @@ namespace Thelia\Constraint\Rule;
class SerializableRule class SerializableRule
{ {
/** @var string Rule Service id */ /** @var string Rule Service id */
public $ruleClassName = null; public $ruleServiceId = null;
/** @var array Operators set by Admin for this Rule */ /** @var array Operators set by Admin for this Rule */
public $operators = array(); public $operators = array();

View File

@@ -137,7 +137,7 @@ class CouponFactory
// * // *
// * @return CouponRuleInterface Ready to use Rule or false // * @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 */ // /** @var CouponAdapterInterface $adapter */
// $adapter = $this->container->get('thelia.adapter'); // $adapter = $this->container->get('thelia.adapter');

View File

@@ -52,7 +52,7 @@ class CouponManager
/** /**
* Constructor * Constructor
* *
* @param ContainerInterface $container Service container * @param ContainerInterface $container Service container
*/ */
function __construct(ContainerInterface $container) function __construct(ContainerInterface $container)
{ {

View File

@@ -23,9 +23,9 @@
namespace Thelia\Coupon; namespace Thelia\Coupon;
use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\DependencyInjection\ContainerInterface;
use Thelia\Constraint\Rule\CouponRuleInterface; use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Exception\InvalidRuleException; use Thelia\Constraint\Rule\SerializableRule;
/** /**
* Created by JetBrains PhpStorm. * Created by JetBrains PhpStorm.
@@ -45,19 +45,10 @@ class CouponRuleCollection
/** /**
* Constructor * 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;
} }
/** /**

View File

@@ -24,6 +24,7 @@
namespace Thelia\Model; namespace Thelia\Model;
use Propel\Runtime\Propel; use Propel\Runtime\Propel;
use Thelia\Constraint\Rule\CouponRuleInterface;
use Thelia\Coupon\CouponRuleCollection; use Thelia\Coupon\CouponRuleCollection;
use Thelia\Model\Base\Coupon as BaseCoupon; use Thelia\Model\Base\Coupon as BaseCoupon;
use Thelia\Model\Map\CouponTableMap; use Thelia\Model\Map\CouponTableMap;
@@ -98,37 +99,34 @@ class Coupon extends BaseCoupon
} }
} }
/** // /**
* Set the value of [serialized_rules] column. // * Set the value of [serialized_rules] column.
* // * Convert a CouponRuleCollection into a serialized array of SerializableRule
* @param CouponRuleCollection $rules A set of Rules // *
* // * @param CouponRuleCollection $rules A set of Rules
* @return \Thelia\Model\Coupon The current object (for fluent API support) // *
*/ // * @return \Thelia\Model\Coupon The current object (for fluent API support)
public function setRules(CouponRuleCollection $rules) // */
{ // public function setRules(CouponRuleCollection $rules)
$serializedRules = null; // {
if ($rules !== null) { // $serializedRules = null;
// if ($rules !== null) {
$serializedRules = (string) base64_encode(serialize($rules)); // /** @var $rule CouponRuleInterface */
} // foreach ($rules->getRules() as $rule) {
// $serializedRules[] = $rule->getSerializableRule();
if ($this->serialized_rules !== $serializedRules) { // }
$this->serialized_rules = $serializedRules; //
$this->modifiedColumns[] = CouponTableMap::SERIALIZED_RULES; // $serializedRules = (string) base64_encode(serialize($serializedRules));
} // }
//
return $this; // 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));
}
} }

View File

@@ -23,6 +23,8 @@
namespace Thelia\Constraint; namespace Thelia\Constraint;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Thelia\Constraint\Rule\AvailableForXArticles;
use Thelia\Constraint\Validator\PriceParam; use Thelia\Constraint\Validator\PriceParam;
use Thelia\Constraint\Validator\RuleValidator; use Thelia\Constraint\Validator\RuleValidator;
use Thelia\Constraint\Rule\AvailableForTotalAmount; 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. * Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed. * This method is called before a test is executed.
*/ */
protected function setUp() public function setUp()
{ {
} }
public function incompleteTest() public function incompleteTest()
{ {
$this->markTestIncomplete( $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. * Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed. * This method is called after a test is executed.