diff --git a/.gitignore b/.gitignore index cad92f7a8..8de5039ed 100755 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ web/cache/* web/.htaccess phpdoc*.log php-cs +xhprof +phpunit.phar +.DS_Store \ No newline at end of file diff --git a/composer.json b/composer.json index 47be312f6..9d179a987 100755 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "simplepie/simplepie": "dev-master", "imagine/imagine": "dev-master", + "symfony/serializer": "dev-master", "symfony/icu": "1.0" }, "require-dev" : { diff --git a/core/lib/Thelia/Action/Coupon.php b/core/lib/Thelia/Action/Coupon.php new file mode 100755 index 000000000..fee349585 --- /dev/null +++ b/core/lib/Thelia/Action/Coupon.php @@ -0,0 +1,179 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Action; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Model\Coupon as CouponModel; +use Propel\Runtime\ActiveQuery\Criteria; +use Propel\Runtime\Propel; +use Thelia\Model\Map\CategoryTableMap; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Process Coupon Events + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class Coupon extends BaseAction implements EventSubscriberInterface +{ + /** + * Occurring when a Coupon is about to be created + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function create(CouponCreateOrUpdateEvent $event) + { + $coupon = new CouponModel(); + + $this->createOrUpdate($coupon, $event); + } + + /** + * Occurring when a Coupon is about to be updated + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function update(CouponCreateOrUpdateEvent $event) + { + $coupon = $event->getCoupon(); + + $this->createOrUpdate($coupon, $event); + } + + /** + * Occurring when a Coupon rule is about to be created + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function createRule(CouponCreateOrUpdateEvent $event) + { + $coupon = $event->getCoupon(); + + $this->createOrUpdate($coupon, $event); + } + + /** + * Occurring when a Coupon rule is about to be updated + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function updateRule(CouponCreateOrUpdateEvent $event) + { + $coupon = $event->getCoupon(); + + $this->createOrUpdate($coupon, $event); + } + + /** + * Occurring when a Coupon rule is about to be deleted + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function deleteRule(CouponCreateOrUpdateEvent $event) + { + $coupon = $event->getCoupon(); + + $this->createOrUpdate($coupon, $event); + } + + /** + * Occurring when a Coupon rule is about to be consumed + * + * @param CouponCreateOrUpdateEvent $event Event creation or update Event + */ + public function consume(CouponCreateOrUpdateEvent $event) + { + // @todo implements + } + + /** + * Call the Model and delegate the create or delete action + * Feed the Event with the updated model + * + * @param CouponModel $coupon Model to save + * @param CouponCreateOrUpdateEvent $event Event containing data + */ + protected function createOrUpdate(CouponModel $coupon, CouponCreateOrUpdateEvent $event) + { + $coupon->setDispatcher($this->getDispatcher()); + + $coupon->createOrUpdate( + $event->getCode(), + $event->getTitle(), + $event->getAmount(), + $event->getEffect(), + $event->getShortDescription(), + $event->getDescription(), + $event->isEnabled(), + $event->getExpirationDate(), + $event->isAvailableOnSpecialOffers(), + $event->isCumulative(), + $event->getMaxUsage(), + $event->getRules(), + $event->getLocale() + ); + + $event->setCoupon($coupon); + } + + /** + * Returns an array of event names this subscriber listens to. + * + * The array keys are event names and the value can be: + * + * * The method name to call (priority defaults to 0) + * * An array composed of the method name to call and the priority + * * An array of arrays composed of the method names to call and respective + * priorities, or 0 if unset + * + * For instance: + * + * * array('eventName' => 'methodName') + * * array('eventName' => array('methodName', $priority)) + * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) + * + * @return array The event names to listen to + * + * @api + */ + public static function getSubscribedEvents() + { + return array( + TheliaEvents::COUPON_CREATE => array("create", 128), + TheliaEvents::COUPON_UPDATE => array("update", 128), + TheliaEvents::COUPON_DISABLE => array("disable", 128), + TheliaEvents::COUPON_ENABLE => array("enable", 128), + TheliaEvents::COUPON_CONSUME => array("consume", 128), + TheliaEvents::COUPON_RULE_UPDATE => array("updateRule", 128), + TheliaEvents::COUPON_RULE_DELETE => array("deleteRule", 128) + ); + } +} diff --git a/core/lib/Thelia/Command/CreateAdminUser.php b/core/lib/Thelia/Command/CreateAdminUser.php index dc7118399..868ca1496 100644 --- a/core/lib/Thelia/Command/CreateAdminUser.php +++ b/core/lib/Thelia/Command/CreateAdminUser.php @@ -41,6 +41,34 @@ class CreateAdminUser extends ContainerAwareCommand ->setName("thelia:create-admin") ->setDescription("Create a new adminsitration user") ->setHelp("The thelia:create-admin command create a new administration user.") + ->addOption( + 'login_name', + null, + InputOption::VALUE_OPTIONAL, + 'Admin login name', + null + ) + ->addOption( + 'first_name', + null, + InputOption::VALUE_OPTIONAL, + 'User first name', + null + ) + ->addOption( + "last_name", + null, + InputOption::VALUE_OPTIONAL, + 'User last name', + null + ) + ->addOption( + 'password', + null, + InputOption::VALUE_OPTIONAL, + 'Password', + null + ) ; } @@ -54,25 +82,25 @@ class CreateAdminUser extends ContainerAwareCommand $admin->save(); $output->writeln(array( - "", - "User ".$admin->getLogin()." successfully created.", - "" - )); + "", + "User ".$admin->getLogin()." successfully created.", + "" + )); } protected function enterData($dialog, $output, $label, $error_message) { return $dialog->askAndValidate( - $output, - $this->decorateInfo($label), - function ($answer) { - $answer = trim($answer); - if (empty($answer)) { - throw new \RuntimeException("This information is mandatory."); - } - - return $answer; + $output, + $this->decorateInfo($label), + function ($answer) { + $answer = trim($answer); + if (empty($answer)) { + throw new \RuntimeException("This information is mandatory."); } + + return $answer; + } ); } @@ -89,13 +117,13 @@ class CreateAdminUser extends ContainerAwareCommand $admin = new Admin(); - $admin->setLogin($this->enterData($dialog, $output, "Admin login name : ", "Please enter a login name.")); - $admin->setFirstname($this->enterData($dialog, $output, "User first name : ", "Please enter user first name.")); - $admin->setLastname($this->enterData($dialog, $output, "User last name : ", "Please enter user last name.")); + $admin->setLogin($input->getOption("login_name") ?: $this->enterData($dialog, $output, "Admin login name : ", "Please enter a login name.")); + $admin->setFirstname($input->getOption("first_name") ?: $this->enterData($dialog, $output, "User first name : ", "Please enter user first name.")); + $admin->setLastname($input->getOption("last_name") ?: $this->enterData($dialog, $output, "User last name : ", "Please enter user last name.")); do { - $password = $this->enterData($dialog, $output, "Password : ", "Please enter a password."); - $password_again = $this->enterData($dialog, $output, "Password (again): ", "Please enter the password again."); + $password = $input->getOption("password") ?: $this->enterData($dialog, $output, "Password : ", "Please enter a password."); + $password_again = $input->getOption("password") ?: $this->enterData($dialog, $output, "Password (again): ", "Please enter the password again."); if (! empty($password) && $password == $password_again) { @@ -109,11 +137,11 @@ class CreateAdminUser extends ContainerAwareCommand while (true); return $admin; - } + } protected function decorateInfo($text) { return sprintf("%s", $text); } -} +} \ No newline at end of file diff --git a/core/lib/Thelia/Config/Resources/action.xml b/core/lib/Thelia/Config/Resources/action.xml index 5bf4cbab8..dd43bbb91 100755 --- a/core/lib/Thelia/Config/Resources/action.xml +++ b/core/lib/Thelia/Config/Resources/action.xml @@ -47,6 +47,11 @@ + + + + + diff --git a/core/lib/Thelia/Config/Resources/config.xml b/core/lib/Thelia/Config/Resources/config.xml index e4cf3a475..74e1f4629 100755 --- a/core/lib/Thelia/Config/Resources/config.xml +++ b/core/lib/Thelia/Config/Resources/config.xml @@ -33,6 +33,7 @@ + @@ -63,6 +64,8 @@
+ + @@ -146,11 +149,7 @@ - - - - - + %thelia.parser.loops% @@ -210,6 +209,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/admin.xml b/core/lib/Thelia/Config/Resources/routing/admin.xml index 0f4e7bfae..09c95d2ff 100755 --- a/core/lib/Thelia/Config/Resources/routing/admin.xml +++ b/core/lib/Thelia/Config/Resources/routing/admin.xml @@ -31,6 +31,14 @@ Thelia\Controller\Admin\CategoryController::defaultAction + + + + Thelia\Controller\Admin\CustomerController::indexAction + + + + @@ -60,6 +68,41 @@ Thelia\Controller\Admin\CategoryController::updatePositionAction + + Thelia\Controller\Admin\CategoryController::getByParentIdAction + xml|json + + + + + + + + + + + Thelia\Controller\Admin\CouponController::browseAction + + + Thelia\Controller\Admin\CouponController::createAction + + + Thelia\Controller\Admin\CouponController::updateAction + + + Thelia\Controller\Admin\CouponController::readAction + + + Thelia\Controller\Admin\CouponController::getRuleInputAction + + + Thelia\Controller\Admin\CouponController::updateRulesAction + + + + + + diff --git a/core/lib/Thelia/Config/Resources/routing/front.xml b/core/lib/Thelia/Config/Resources/routing/front.xml index aeff55d7c..d06585f73 100755 --- a/core/lib/Thelia/Config/Resources/routing/front.xml +++ b/core/lib/Thelia/Config/Resources/routing/front.xml @@ -15,17 +15,29 @@ connexion + + Thelia\Controller\Front\DefaultController::noAction + register + + Thelia\Controller\Front\CustomerController::updateAction Thelia\Controller\Front\CustomerController::loginAction + login + + + + Thelia\Controller\Front\DefaultController::noAction + login Thelia\Controller\Front\CustomerController::logoutAction + diff --git a/core/lib/Thelia/Constraint/ConstraintFactory.php b/core/lib/Thelia/Constraint/ConstraintFactory.php new file mode 100644 index 000000000..e96509172 --- /dev/null +++ b/core/lib/Thelia/Constraint/ConstraintFactory.php @@ -0,0 +1,162 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint; + +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Constraint\Rule\SerializableRule; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\CouponRuleCollection; + + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Manage how Constraint could interact + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class ConstraintFactory +{ + /** @var ContainerInterface Service Container */ + protected $container = null; + + /** @var CouponAdapterInterface Provide necessary value from Thelia*/ + protected $adapter; + + /** @var array CouponRuleCollection to process*/ + protected $rules = null; + + /** + * Constructor + * + * @param ContainerInterface $container Service container + */ + function __construct(ContainerInterface $container) + { + $this->container = $container; + $this->adapter = $container->get('thelia.adapter'); + } + + /** + * 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 base64_encode(json_encode($serializableRules)); + } + + /** + * Unserialize a collection of rules + * + * @param string $serializedRules Serialized Rules + * + * @return CouponRuleCollection Rules ready to be processed + */ + public function unserializeCouponRuleCollection($serializedRules) + { + $unserializedRules = json_decode(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->build( + $rule->ruleServiceId, + (array) $rule->operators, + (array) $rule->values + ); + $collection->add(clone $couponRule); + } + } + } + + return $collection; + } + + + /** + * Build a Coupon Rule from form + * + * @param string $ruleServiceId Rule class name + * @param array $operators Rule Operator (<, >, = ) + * @param array $values Values setting this Rule + * + * @throws \InvalidArgumentException + * @return CouponRuleInterface Ready to use Rule or false + */ + public function build($ruleServiceId, array $operators, array $values) + { + if (!$this->container->has($ruleServiceId)) { + return false; + } + + /** @var CouponRuleInterface $rule */ + $rule = $this->container->get($ruleServiceId); + $rule->setValidatorsFromForm($operators, $values); + + return $rule; + } + + /** + * Get Coupon Rule inputs from serviceId + * + * @param string $ruleServiceId Rule class name + * + * @return array Ready to be drawn rule inputs + */ + public function getInputs($ruleServiceId) + { + if (!$this->container->has($ruleServiceId)) { + return false; + } + + /** @var CouponRuleInterface $rule */ + $rule = $this->container->get($ruleServiceId); + + return $rule->getValidators(); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/ConstraintValidator.php b/core/lib/Thelia/Constraint/ConstraintValidator.php new file mode 100644 index 000000000..edacee317 --- /dev/null +++ b/core/lib/Thelia/Constraint/ConstraintValidator.php @@ -0,0 +1,133 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint; + +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\CouponRuleCollection; + + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Validate Constraints + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class ConstraintValidator +{ + + /** + * Check if a Customer meets SerializableRule + * + * @param CouponRuleCollection $rules Rules to check against the Customer + * + * @return bool + */ + public function test(CouponRuleCollection $rules) + { + $isMatching = true; + /** @var CouponRuleInterface $rule */ + foreach ($rules->getRules() as $rule) { + if (!$rule->isMatching()) { + $isMatching = false; + } + } + + return $isMatching; + + } + + /** + * Do variable comparison + * + * @param mixed $v1 Variable 1 + * @param string $o Operator + * + * @param mixed $v2 Variable 2 + * @throws \Exception + * @return bool + */ + public function variableOpComparison($v1, $o, $v2) { + if ($o == Operators::DIFFERENT) { + return ($v1 != $v2); + } // could put this elsewhere... +// $operators = str_split($o); +// foreach($o as $operator) { + switch ($o) { // return will exit switch, foreach loop, function + case Operators::SUPERIOR : // > + if ($v1 > $v2) { + return true; + } else { + continue; + } break; + case Operators::SUPERIOR_OR_EQUAL : // >= + if ($v1 >= $v2) { + return true; + } else { + continue; + } break; + case Operators::INFERIOR : // < + if ($v1 < $v2) { + return true; + } else { + continue; + } break; + case Operators::INFERIOR_OR_EQUAL : // <= + if ($v1 <= $v2) { + return true; + } else { + continue; + } break; + case Operators::EQUAL : // == + if ($v1 == $v2) { + return true; + } else { + continue; + } break; + case Operators::IN: + if (in_array($v1, $v2)) { // in + return true; + } else { + continue; + } break; + case Operators::OUT: + if (!in_array($v1, $v2)) { // not in + return true; + } else { + continue; + } break; + default: throw new \Exception('Unrecognized operator ' . $o); + } +// } + return false; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForCustomer.php b/core/lib/Thelia/Constraint/Rule/AvailableForCustomer.php new file mode 100644 index 000000000..ad722eb5c --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForCustomer.php @@ -0,0 +1,178 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Thelia\Constraint\Validator\CustomerParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Exception\InvalidRuleException; +use Thelia\Exception\InvalidRuleOperatorException; +use Thelia\Exception\InvalidRuleValueException; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForCustomer extends CouponRuleAbstract +{ + + /** Rule 1st parameter : customer id */ + CONST PARAM1 = 'customerId'; + + /** @var array Available Operators (Operators::CONST) */ + protected $availableOperators = array( + Operators::EQUAL, + ); + + /** @var RuleValidator Customer Validator */ + protected $customerValidator = null; + + /** + * Check if backoffice inputs are relevant or not + * + * @throws InvalidRuleOperatorException if Operator is not allowed + * @throws InvalidRuleValueException if Value is not allowed + * @return bool + */ + public function checkBackOfficeInput() + { + if (!isset($this->validators) + || empty($this->validators) + ||!isset($this->validators[self::PARAM1]) + ||!isset($this->validators[self::PARAM1]) + ) { + throw new InvalidRuleValueException(get_class(), self::PARAM1); + } + + /** @var RuleValidator $ruleValidator */ + $ruleValidator = $this->validators[self::PARAM1]; + /** @var CustomerParam $customer */ + $customer = $ruleValidator->getParam(); + + if (!$customer instanceof CustomerParam) { + throw new InvalidRuleValueException(get_class(), self::PARAM1); + } + + $this->checkBackOfficeInputsOperators(); + + return $this->isCustomerValid($customer->getInteger()); + } + + /** + * Generate current Rule param to be validated from adapter + * + * @return $this + */ + protected function setParametersToValidate() + { + $this->paramsToValidate = array( + self::PARAM1 => $this->adapter->getCustomer()->getId() + ); + + return $this; + } + + /** + * Check if Checkout inputs are relevant or not + * + * @throws \Thelia\Exception\InvalidRuleValueException + * @return bool + */ + public function checkCheckoutInput() + { + if (!isset($this->paramsToValidate) + || empty($this->paramsToValidate) + ||!isset($this->paramsToValidate[self::PARAM1]) + ) { + throw new InvalidRuleValueException(get_class(), self::PARAM1); + } + + $customerId = $this->paramsToValidate[self::PARAM1]; + + return $this->isCustomerValid($customerId); + } + + /** + * Check if a Customer is valid + * + * @param int $customerId Customer to check + * + * @throws InvalidRuleValueException if Value is not allowed + * @return bool + */ + protected function isCustomerValid($customerId) + { + $customerValidator = $this->customerValidator; + try { + $customerValidator->getParam()->compareTo($customerId); + } catch(\InvalidArgumentException $e) { + throw new InvalidRuleValueException(get_class(), self::PARAM1); + } + + return true; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->adapter + ->getTranslator() + ->trans('Customer', null, 'constraint'); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + /** @var CustomerParam $param */ + $param = $this->customerValidator->getParam(); + $toolTip = $this->adapter + ->getTranslator() + ->trans( + 'If customer is %fistname% %lastname% (%email%)', + array( + '%fistname%' => $param->getFirstName(), + '%lastname%' => $param->getLastName(), + '%email%' => $param->getEmail(), + ), + 'constraint' + ); + + return $toolTip; + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForDate.php b/core/lib/Thelia/Constraint/Rule/AvailableForDate.php new file mode 100644 index 000000000..1ddfd0350 --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForDate.php @@ -0,0 +1,59 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForDate extends AvailableForPeriod +{ + + /** + * Check if backoffice inputs are relevant or not + * + * @return bool + */ + public function checkBackOfficeInput() + { + // TODO: Implement checkBackOfficeInput() method. + } + + /** + * Check if Checkout inputs are relevant or not + * + * @return bool + */ + public function checkCheckoutInput() + { + // TODO: Implement checkCheckoutInput() method. + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForEveryoneManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForEveryoneManager.php new file mode 100644 index 000000000..15e0e3ab7 --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForEveryoneManager.php @@ -0,0 +1,135 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use InvalidArgumentException; +use Symfony\Component\Translation\Translator; +use Thelia\Constraint\ConstraintValidator; +use Thelia\Constraint\Validator\QuantityParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Exception\InvalidRuleException; +use Thelia\Exception\InvalidRuleValueException; +use Thelia\Type\FloatType; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Allow every one, perform no check + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForEveryoneManager extends CouponRuleAbstract +{ + /** @var string Service Id from Resources/config.xml */ + protected $serviceId = 'thelia.constraint.rule.available_for_everyone'; + + /** @var array Available Operators (Operators::CONST) */ + protected $availableOperators = array(); + + /** + * Check validators relevancy and store them + * + * @param array $operators Operators the Admin set in BackOffice + * @param array $values Values the Admin set in BackOffice + * + * @throws \InvalidArgumentException + * @return $this + */ + public function setValidatorsFromForm(array $operators, array $values) + { + $this->setValidators(); + + return $this; + } + + /** + * Check validators relevancy and store them + * + * @throws \InvalidArgumentException + * @return $this + */ + protected function setValidators() + { + $this->operators = array(); + $this->values = array(); + + return $this; + } + + /** + * Test if Customer meets conditions + * + * @return bool + */ + public function isMatching() + { + return true; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->translator->trans( + 'Everybody can use it (no condition)', + array(), + 'constraint' + ); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + $toolTip = $this->translator->trans( + 'Will return always true', + array(), + 'constraint' + ); + + return $toolTip; + } + + /** + * Generate inputs ready to be drawn + * + * @return array + */ + protected function generateInputs() + { + return array(); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForLocationX.php b/core/lib/Thelia/Constraint/Rule/AvailableForLocationX.php new file mode 100644 index 000000000..5c3ec494c --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForLocationX.php @@ -0,0 +1,59 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForLocationX extends CouponRuleAbstract +{ + + /** + * Check if backoffice inputs are relevant or not + * + * @return bool + */ + public function checkBackOfficeInput() + { + // TODO: Implement checkBackOfficeInput() method. + } + + /** + * Check if Checkout inputs are relevant or not + * + * @return bool + */ + public function checkCheckoutInput() + { + // TODO: Implement checkCheckoutInput() method. + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForPeriod.php b/core/lib/Thelia/Constraint/Rule/AvailableForPeriod.php new file mode 100644 index 000000000..30679a973 --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForPeriod.php @@ -0,0 +1,57 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForPeriod extends CouponRuleAbstract +{ + + /** + * Check if backoffice inputs are relevant or not + * + * @return bool + */ + public function checkBackOfficeInput() + { + // TODO: Implement checkBackOfficeInput() method. + } + + /** + * Check if Checkout inputs are relevant or not + * + * @return bool + */ + public function checkCheckoutInput() + { + // TODO: Implement checkCheckoutInput() method. + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedDate.php b/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedDate.php new file mode 100644 index 000000000..3449a7f5b --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedDate.php @@ -0,0 +1,57 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForRepeatedDate extends AvailableForDate +{ + + /** + * Check if backoffice inputs are relevant or not + * + * @return bool + */ + public function checkBackOfficeInput() + { + // TODO: Implement checkBackOfficeInput() method. + } + + /** + * Check if Checkout inputs are relevant or not + * + * @return bool + */ + public function checkCheckoutInput() + { + // TODO: Implement checkCheckoutInput() method. + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedPeriod.php b/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedPeriod.php new file mode 100644 index 000000000..f5bf9bafc --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForRepeatedPeriod.php @@ -0,0 +1,73 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForRepeatedPeriod extends AvailableForPeriod +{ + + /** + * Generate current Rule param to be validated from adapter + * + * @param CouponAdapterInterface $adapter allowing to gather + * all necessary Thelia variables + * + * @throws \Symfony\Component\Intl\Exception\NotImplementedException + * @return $this + */ + public function setParametersToValidate(CouponAdapterInterface $adapter) + { + // @todo implement + } + + /** + * Check if backoffice inputs are relevant or not + * + * @return bool + */ + public function checkBackOfficeInput() + { + // TODO: Implement checkBackOfficeInput() method. + } + + /** + * Check if Checkout inputs are relevant or not + * + * @return bool + */ + public function checkCheckoutInput() + { + // TODO: Implement checkCheckoutInput() method. + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountForCategoryY.php b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountForCategoryY.php new file mode 100644 index 000000000..0f9f7f10b --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountForCategoryY.php @@ -0,0 +1,38 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForTotalAmountForCategoryY extends AvailableForTotalAmount +{ + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php new file mode 100644 index 000000000..6ab746e6c --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForTotalAmountManager.php @@ -0,0 +1,417 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Symfony\Component\Intl\Exception\NotImplementedException; +use Symfony\Component\Translation\Translator; +use Thelia\Constraint\ConstraintValidator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Exception\InvalidRuleException; +use Thelia\Exception\InvalidRuleOperatorException; +use Thelia\Exception\InvalidRuleValueException; +use Thelia\Model\Currency; +use Thelia\Model\CurrencyQuery; +use Thelia\Type\FloatType; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Rule AvailableForTotalAmount + * Check if a Checkout total amount match criteria + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForTotalAmountManager extends CouponRuleAbstract +{ + /** Rule 1st parameter : price */ + CONST INPUT1 = 'price'; + + /** Rule 1st parameter : currency */ + CONST INPUT2 = 'currency'; + + /** @var string Service Id from Resources/config.xml */ + protected $serviceId = 'thelia.constraint.rule.available_for_total_amount'; + + /** @var array Available Operators (Operators::CONST) */ + protected $availableOperators = array( + self::INPUT1 => array( + Operators::INFERIOR, + Operators::INFERIOR_OR_EQUAL, + Operators::EQUAL, + Operators::SUPERIOR_OR_EQUAL, + Operators::SUPERIOR + ), + self::INPUT2 => array( + Operators::EQUAL, + ) + ); + +// /** @var RuleValidator Price Validator */ +// protected $priceValidator = null; + +// /** +// * Check if backoffice inputs are relevant or not +// * +// * @throws InvalidRuleOperatorException if Operator is not allowed +// * @throws InvalidRuleValueException if Value is not allowed +// * @return bool +// */ +// public function checkBackOfficeInput() +// { +// if (!isset($this->validators) +// || empty($this->validators) +// ||!isset($this->validators[self::PARAM1_PRICE]) +// ||!isset($this->validators[self::PARAM1_PRICE]) +// ) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); +// } +// +// /** @var RuleValidator $ruleValidator */ +// $ruleValidator = $this->validators[self::PARAM1_PRICE]; +// /** @var PriceParam $price */ +// $price = $ruleValidator->getParam(); +// +// if (!$price instanceof PriceParam) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); +// } +// +// $this->checkBackOfficeInputsOperators(); +// +// return $this->isPriceValid($price->getPrice(), $price->getCurrency()); +// } + +// /** +// * Check if Checkout inputs are relevant or not +// * +// * @throws InvalidRuleValueException if Value is not allowed +// * @return bool +// */ +// public function checkCheckoutInput() +// { +// $currency = $this->adapter->getCheckoutCurrency(); +// if (empty($currency)) { +// throw new InvalidRuleValueException( +// get_class(), self::PARAM1_CURRENCY +// ); +// } +// +// $price = $this->adapter->getCartTotalPrice(); +// if (empty($price)) { +// throw new InvalidRuleValueException( +// get_class(), self::PARAM1_PRICE +// ); +// } +// +// $this->paramsToValidate = array( +// self::PARAM1_PRICE => $this->adapter->getCartTotalPrice(), +// self::PARAM1_CURRENCY => $this->adapter->getCheckoutCurrency() +// ); +// +// return $this->isPriceValid($price, $currency); +// } + + /** + * Check validators relevancy and store them + * + * @param array $operators Operators the Admin set in BackOffice + * @param array $values Values the Admin set in BackOffice + * + * @throws \InvalidArgumentException + * @return $this + */ + public function setValidatorsFromForm(array $operators, array $values) + { + $this->setValidators( + $operators[self::INPUT1], + $values[self::INPUT1], + $operators[self::INPUT2], + $values[self::INPUT2] + ); + + return $this; + } + + /** + * Check validators relevancy and store them + * + * @param string $priceOperator Price Operator ex < + * @param float $priceValue Price set to meet condition + * @param string $currencyOperator Currency Operator ex = + * @param string $currencyValue Currency set to meet condition + * + * @throws \InvalidArgumentException + * @return $this + */ + protected function setValidators($priceOperator, $priceValue, $currencyOperator, $currencyValue) + { + $isOperator1Legit = $this->isOperatorLegit( + $priceOperator, + $this->availableOperators[self::INPUT1] + ); + if (!$isOperator1Legit) { + throw new \InvalidArgumentException( + 'Operator for price field is not legit' + ); + } + + $isOperator1Legit = $this->isOperatorLegit( + $currencyOperator, + $this->availableOperators[self::INPUT2] + ); + if (!$isOperator1Legit) { + throw new \InvalidArgumentException( + 'Operator for currency field is not legit' + ); + } + + $floatType = new FloatType(); + if (!$floatType->isValid($priceValue) || $priceValue <= 0) { + throw new \InvalidArgumentException( + 'Value for price field is not legit' + ); + } + + // @todo check currency is legit or not + + $this->operators = array( + self::INPUT1 => $priceOperator, + self::INPUT2 => $currencyOperator, + ); + $this->values = array( + self::INPUT1 => $priceValue, + self::INPUT2 => $currencyValue, + ); + + return $this; + } + + /** + * Test if Customer meets conditions + * + * @return bool + */ + public function isMatching() + { + $isOperator1Legit = $this->isOperatorLegit( + $this->operators[self::INPUT1], + $this->availableOperators[self::INPUT1] + ); + $isOperator2Legit = $this->isOperatorLegit( + $this->operators[self::INPUT2], + $this->availableOperators[self::INPUT2] + ); + + if (!$isOperator1Legit || !$isOperator2Legit) { + return false; + } + + $constrainValidator = new ConstraintValidator(); + $constraint1 =$constrainValidator->variableOpComparison( + $this->adapter->getCartTotalPrice(), + $this->operators[self::INPUT1], + $this->values[self::INPUT1] + ); + $constraint2 =$constrainValidator->variableOpComparison( + $this->adapter->getCheckoutCurrency(), + $this->operators[self::INPUT2], + $this->values[self::INPUT2] + ); + if ($constraint1 && $constraint2) { + return true; + } + return false; + } + +// /** +// * Check if a price is valid +// * +// * @param float $price Price to check +// * @param string $currency Price currency +// * +// * @throws InvalidRuleValueException if Value is not allowed +// * @return bool +// */ +// protected function isPriceValid($price, $currency) +// { +// $priceValidator = $this->priceValidator; +// +// /** @var PriceParam $param */ +// $param = $priceValidator->getParam(); +// if ($currency == $param->getCurrency()) { +// try { +// $priceValidator->getParam()->compareTo($price); +// } catch(\InvalidArgumentException $e) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_PRICE); +// } +// } else { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_CURRENCY); +// } +// +// return true; +// } + +// /** +// * Generate current Rule param to be validated from adapter +// * +// * @return $this +// */ +// protected function setParametersToValidate() +// { +// $this->paramsToValidate = array( +// self::PARAM1_PRICE => $this->adapter->getCartTotalPrice(), +// self::PARAM1_CURRENCY => $this->adapter->getCheckoutCurrency() +// ); +// +// return $this; +// } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->translator->trans( + 'Cart total amount', + array(), + 'constraint' + ); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + $i18nOperator = Operators::getI18n( + $this->translator, $this->operators[self::INPUT1] + ); + + $toolTip = $this->translator->trans( + 'If cart total amount is %operator% %amount% %currency%', + array( + '%operator%' => $i18nOperator, + '%amount%' => $this->values[self::INPUT1], + '%currency%' => $this->values[self::INPUT2] + ), + 'constraint' + ); + + return $toolTip; + } + + /** + * Generate inputs ready to be drawn + * + * @return array + */ + protected function generateInputs() + { + $currencies = CurrencyQuery::create()->find(); + $cleanedCurrencies = array(); + /** @var Currency $currency */ + foreach ($currencies as $currency) { + $cleanedCurrencies[$currency->getCode()] = $currency->getSymbol(); + } + + $name1 = $this->translator->trans( + 'Price', + array(), + 'constraint' + ); + $name2 = $this->translator->trans( + 'Currency', + array(), + 'constraint' + ); + + return array( + self::INPUT1 => array( + 'title' => $name1, + 'availableOperators' => $this->availableOperators[self::INPUT1], + 'availableValues' => '', + 'type' => 'text', + 'class' => 'form-control', + 'value' => '', + 'selectedOperator' => '' + ), + self::INPUT2 => array( + 'title' => $name2, + 'availableOperators' => $this->availableOperators[self::INPUT2], + 'availableValues' => $cleanedCurrencies, + 'type' => 'select', + 'class' => 'form-control', + 'value' => '', + 'selectedOperator' => Operators::EQUAL + ) + ); + } + +// /** +// * Populate a Rule from a form admin +// * +// * @param array $operators Rule Operator set by the Admin +// * @param array $values Rule Values set by the Admin +// * +// * @throws \InvalidArgumentException +// * @return $this +// */ +// public function populateFromForm(array $operators, array $values) +// { +// if ($values[self::PARAM1_PRICE] === null +// || $values[self::PARAM1_CURRENCY] === null +// ) { +// throw new \InvalidArgumentException( +// 'The Rule ' . get_class() . 'needs at least a quantity set (' . self::PARAM1_PRICE . ', ' . self::PARAM1_CURRENCY . ')' +// ); +// } +// +// $this->priceValidator = new RuleValidator( +// $operators[self::PARAM1_PRICE], +// new PriceParam( +// $this->translator, +// $values[self::PARAM1_PRICE], +// $values[self::PARAM1_CURRENCY] +// ) +// ); +// +// $this->validators = array(self::PARAM1_PRICE => $this->priceValidator); +// +// return $this; +// } + + + + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php new file mode 100644 index 000000000..20d7eddca --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/AvailableForXArticlesManager.php @@ -0,0 +1,325 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use InvalidArgumentException; +use Symfony\Component\Translation\Translator; +use Thelia\Constraint\ConstraintValidator; +use Thelia\Constraint\Validator\QuantityParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Exception\InvalidRuleException; +use Thelia\Exception\InvalidRuleValueException; +use Thelia\Type\FloatType; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Check a Checkout against its Product number + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForXArticlesManager extends CouponRuleAbstract +{ + /** Rule 1st parameter : quantity */ + CONST INPUT1 = 'quantity'; + + /** @var string Service Id from Resources/config.xml */ + protected $serviceId = 'thelia.constraint.rule.available_for_x_articles'; + + /** @var array Available Operators (Operators::CONST) */ + protected $availableOperators = array( + self::INPUT1 => array( + Operators::INFERIOR, + Operators::INFERIOR_OR_EQUAL, + Operators::EQUAL, + Operators::SUPERIOR_OR_EQUAL, + Operators::SUPERIOR + ) + ); + +// /** @var QuantityParam Quantity Validator */ +// protected $quantityValidator = null; + +// /** +// * Check if backoffice inputs are relevant or not +// * +// * @throws InvalidRuleOperatorException if Operator is not allowed +// * @throws InvalidRuleValueException if Value is not allowed +// * @return bool +// */ +// public function checkBackOfficeInput() +// { +// if (!isset($this->validators) +// || empty($this->validators) +// ||!isset($this->validators[self::PARAM1_QUANTITY]) +// ||!isset($this->validators[self::PARAM1_QUANTITY]) +// ) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); +// } +// +// /** @var RuleValidator $ruleValidator */ +// $ruleValidator = $this->validators[self::PARAM1_QUANTITY]; +// /** @var QuantityParam $quantity */ +// $quantity = $ruleValidator->getParam(); +// +// if (!$quantity instanceof QuantityParam) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); +// } +// +// $this->checkBackOfficeInputsOperators(); +// +// return $this->isQuantityValid($quantity->getInteger()); +// } + +// /** +// * Generate current Rule param to be validated from adapter +// * +// * @param CouponAdapterInterface $adapter allowing to gather +// * all necessary Thelia variables +// * +// * @return $this +// */ +// protected function setParametersToValidate() +// { +// $this->paramsToValidate = array( +// self::PARAM1_QUANTITY => $this->adapter->getNbArticlesInCart() +// ); +// +// return $this; +// } + +// /** +// * Check if Checkout inputs are relevant or not +// * +// * @throws \Thelia\Exception\InvalidRuleValueException +// * @return bool +// */ +// public function checkCheckoutInput() +// { +// if (!isset($this->paramsToValidate) +// || empty($this->paramsToValidate) +// ||!isset($this->paramsToValidate[self::PARAM1_QUANTITY]) +// ) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); +// } +// +// $price = $this->paramsToValidate[self::PARAM1_QUANTITY]; +// +// return $this->isQuantityValid($price); +// } + + /** + * Check validators relevancy and store them + * + * @param array $operators Operators the Admin set in BackOffice + * @param array $values Values the Admin set in BackOffice + * + * @throws \InvalidArgumentException + * @return $this + */ + public function setValidatorsFromForm(array $operators, array $values) + { + $this->setValidators( + $operators[self::INPUT1], + $values[self::INPUT1] + ); + + return $this; + } + + /** + * Check validators relevancy and store them + * + * @param string $quantityOperator Quantity Operator ex < + * @param int $quantityValue Quantity set to meet condition + * + * @throws \InvalidArgumentException + * @return $this + */ + protected function setValidators($quantityOperator, $quantityValue) + { + $isOperator1Legit = $this->isOperatorLegit( + $quantityOperator, + $this->availableOperators[self::INPUT1] + ); + if (!$isOperator1Legit) { + throw new \InvalidArgumentException( + 'Operator for quantity field is not legit' + ); + } + + if (!is_int($quantityValue) || $quantityValue <= 0) { + throw new \InvalidArgumentException( + 'Value for quantity field is not legit' + ); + } + + $this->operators = array( + self::INPUT1 => $quantityOperator, + ); + $this->values = array( + self::INPUT1 => $quantityValue, + ); + + return $this; + } + + /** + * Test if Customer meets conditions + * + * @return bool + */ + public function isMatching() + { + $constrainValidator = new ConstraintValidator(); + $constraint1 =$constrainValidator->variableOpComparison( + $this->adapter->getNbArticlesInCart(), + $this->operators[self::INPUT1], + $this->values[self::INPUT1] + ); + + if ($constraint1) { + return true; + } + return false; + } + +// /** +// * Check if a quantity is valid +// * +// * @param int $quantity Quantity to check +// * +// * @throws InvalidRuleValueException if Value is not allowed +// * @return bool +// */ +// protected function isQuantityValid($quantity) +// { +// $quantityValidator = $this->quantityValidator; +// try { +// $quantityValidator->getParam()->compareTo($quantity); +// } catch(InvalidArgumentException $e) { +// throw new InvalidRuleValueException(get_class(), self::PARAM1_QUANTITY); +// } +// +// return true; +// } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->translator->trans( + 'Number of articles in cart', + array(), + 'constraint' + ); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + $i18nOperator = Operators::getI18n( + $this->translator, $this->operators[self::INPUT1] + ); + + $toolTip = $this->translator->trans( + 'If cart products quantity is %operator% %quantity%', + array( + '%operator%' => $i18nOperator, + '%quantity%' => $this->values[self::INPUT1] + ), + 'constraint' + ); + + return $toolTip; + } + +// /** +// * Populate a Rule from a form admin +// * +// * @param array $operators Rule Operator set by the Admin +// * @param array $values Rule Values set by the Admin +// * +// * @throws InvalidArgumentException +// * @return $this +// */ +// public function populateFromForm(array $operators, array $values) +// { +// if ($values[self::PARAM1_QUANTITY] === null) { +// throw new InvalidArgumentException( +// 'The Rule ' . get_class() . 'needs at least a quantity set (' . self::PARAM1_QUANTITY. ')' +// ); +// } +// +// $this->quantityValidator = new RuleValidator( +// $operators[self::PARAM1_QUANTITY], +// new QuantityParam( +// $this->adapter, +// $values[self::PARAM1_QUANTITY] +// ) +// ); +// +// $this->validators = array(self::PARAM1_QUANTITY => $this->quantityValidator); +// +// return $this; +// } + + /** + * Generate inputs ready to be drawn + * + * @return array + */ + protected function generateInputs() + { + $name1 = $this->translator->trans( + 'Quantity', + array(), + 'constraint' + ); + + return array( + self::INPUT1 => array( + 'title' => $name1, + 'availableOperators' => $this->availableOperators[self::INPUT1], + 'type' => 'text', + 'class' => 'form-control', + 'value' => '', + 'selectedOperator' => '' + ) + ); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php new file mode 100644 index 000000000..1cab6c48b --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/CouponRuleAbstract.php @@ -0,0 +1,266 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Symfony\Component\Intl\Exception\NotImplementedException; +use Thelia\Core\Translation\Translator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Constraint\Validator\ComparableInterface; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Exception\InvalidRuleException; +use Thelia\Exception\InvalidRuleOperatorException; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Assist in writing a condition of whether the Rule is applied or not + * + * @package Constraint + * @author Guillaume MOREL + * + */ +abstract class CouponRuleAbstract implements CouponRuleInterface +{ +// /** Operator key in $validators */ +// CONST OPERATOR = 'operator'; +// /** Value key in $validators */ +// CONST VALUE = 'value'; + + /** @var string Service Id from Resources/config.xml */ + protected $serviceId = null; + + /** @var array Available Operators (Operators::CONST) */ + protected $availableOperators = array(); + + /** @var array Parameters validating parameters against */ + protected $validators = array(); + +// /** @var array Parameters to be validated */ +// protected $paramsToValidate = array(); + + /** @var CouponAdapterInterface Provide necessary value from Thelia */ + protected $adapter = null; + + /** @var Translator Service Translator */ + protected $translator = null; + + /** @var array Operators set by Admin in BackOffice */ + protected $operators = array(); + + /** @var array Values set by Admin in BackOffice */ + protected $values = array(); + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Service adapter + */ + function __construct(CouponAdapterInterface $adapter) + { + $this->adapter = $adapter; + $this->translator = $adapter->getTranslator(); + } + +// /** +// * Check validator relevancy and store them +// * +// * @param array $validators Array of RuleValidator +// * validating $paramsToValidate against +// * +// * @return $this +// * @throws InvalidRuleException +// */ +// protected function setValidators(array $validators) +// { +// foreach ($validators as $validator) { +// if (!$validator instanceof RuleValidator) { +// throw new InvalidRuleException(get_class()); +// } +// if (!in_array($validator->getOperator(), $this->availableOperators)) { +// throw new InvalidRuleOperatorException( +// get_class(), +// $validator->getOperator() +// ); +// } +// } +// $this->validators = $validators; +// +// return $this; +// } + + + +// /** +// * Check if the current Checkout matches this condition +// * +// * @return bool +// */ +// public function isMatching() +// { +// $this->checkBackOfficeInput(); +// $this->checkCheckoutInput(); +// +// $isMatching = true; +// /** @var $validator RuleValidator*/ +// foreach ($this->validators as $param => $validator) { +// $a = $this->paramsToValidate[$param]; +// $operator = $validator->getOperator(); +// /** @var ComparableInterface, RuleParameterAbstract $b */ +// $b = $validator->getParam(); +// +// if (!Operators::isValid($a, $operator, $b)) { +// $isMatching = false; +// } +// } +// +// return $isMatching; +// +// } + + /** + * Return all available Operators for this Rule + * + * @return array Operators::CONST + */ + public function getAvailableOperators() + { + return $this->availableOperators; + } + +// /** +// * Check if Operators set for this Rule in the BackOffice are legit +// * +// * @throws InvalidRuleOperatorException if Operator is not allowed +// * @return bool +// */ +// protected function checkBackOfficeInputsOperators() +// { +// /** @var RuleValidator $param */ +// foreach ($this->validators as $key => $param) { +// $operator = $param->getOperator(); +// if (!isset($operator) +// ||!in_array($operator, $this->availableOperators) +// ) { +// throw new InvalidRuleOperatorException(get_class(), $key); +// } +// } +// return true; +// } + +// /** +// * Generate current Rule param to be validated from adapter +// * +// * @throws \Thelia\Exception\NotImplementedException +// * @return $this +// */ +// protected function setParametersToValidate() +// { +// throw new \Thelia\Exception\NotImplementedException(); +// } + + /** + * Return all validators + * + * @return array + */ + public function getValidators() + { + $this->validators = $this->generateInputs(); + + $translatedInputs = array(); + foreach ($this->validators as $key => $validator) { + $translatedOperators = array(); + foreach ($validator['availableOperators'] as $availableOperators) { + $translatedOperators[$availableOperators] = Operators::getI18n( + $this->translator, + $availableOperators + ); + } + + $validator['availableOperators'] = $translatedOperators; + $translatedInputs[$key] = $validator; + } + $validators = array(); + $validators['inputs'] = $translatedInputs; + $validators['setOperators'] = $this->operators; + $validators['setValues'] = $this->values; + + return $validators; + } + + /** + * Generate inputs ready to be drawn + * + * @throws \Thelia\Exception\NotImplementedException + * @return array + */ + protected function generateInputs() + { + throw new \Thelia\Exception\NotImplementedException( + 'The generateInputs method must be implemented in ' . get_class() + ); + } + + /** + * Get Rule Service id + * + * @return string + */ + public function getServiceId() + { + return $this->serviceId; + } + + /** + * Validate if Operator given is available for this Coupon + * + * @param string $operator Operator to validate ex < + * @param array $availableOperators Available operators + * + * @return bool + */ + protected function isOperatorLegit($operator, array $availableOperators) + { + return in_array($operator, $availableOperators); + } + + /** + * Return a serializable Rule + * + * @return SerializableRule + */ + public function getSerializableRule() + { + $serializableRule = new SerializableRule(); + $serializableRule->ruleServiceId = $this->serviceId; + $serializableRule->operators = $this->operators; + + $serializableRule->values = $this->values; + + return $serializableRule; + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php b/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php new file mode 100644 index 000000000..ac9579094 --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/CouponRuleInterface.php @@ -0,0 +1,146 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Thelia\Core\Translation\Translator; +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represents a condition of whether the Rule is applied or not + * + * @package Constraint + * @author Guillaume MOREL + * + */ +interface CouponRuleInterface +{ + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Service adapter + */ + function __construct(CouponAdapterInterface $adapter); + + /** + * Get Rule Service id + * + * @return string + */ + public function getServiceId(); + +// /** +// * Check if backoffice inputs are relevant or not +// * +// * @return bool +// */ +// public function checkBackOfficeInput(); + +// /** +// * Check if Checkout inputs are relevant or not +// * +// * @return bool +// */ +// public function checkCheckoutInput(); + + /** + * Check validators relevancy and store them + * + * @param array $operators Operators the Admin set in BackOffice + * @param array $values Values the Admin set in BackOffice + * + * @throws \InvalidArgumentException + * @return $this + */ + public function setValidatorsFromForm(array $operators, array $values); + +// /** +// * Check if the current Checkout matches this condition +// * +// * @return bool +// */ +// public function isMatching(); + + /** + * Test if Customer meets conditions + * + * @return bool + */ + public function isMatching(); + + /** + * Return all available Operators for this Rule + * + * @return array Operators::CONST + */ + public function getAvailableOperators(); + + + /** + * Get I18n name + * + * @return string + */ + public function getName(); + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip(); + + /** + * Return all validators + * + * @return array + */ + public function getValidators(); + +// /** +// * Populate a Rule from a form admin +// * +// * @param array $operators Rule Operator set by the Admin +// * @param array $values Rule Values set by the Admin +// * +// * @return bool +// */ +// public function populateFromForm(array$operators, array $values); + + + /** + * Return a serializable Rule + * + * @return SerializableRule + */ + public function getSerializableRule(); + + + + + +} diff --git a/core/lib/Thelia/Constraint/Rule/Operators.php b/core/lib/Thelia/Constraint/Rule/Operators.php new file mode 100644 index 000000000..41640810c --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/Operators.php @@ -0,0 +1,188 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +use Symfony\Component\Translation\Translator; +use Thelia\Constraint\Validator\ComparableInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent available Operations in rule checking + * + * @package Constraint + * @author Guillaume MOREL + * + */ +abstract class Operators +{ + /** Param1 is inferior to Param2 */ + CONST INFERIOR = '<'; + /** Param1 is inferior to Param2 */ + CONST INFERIOR_OR_EQUAL = '<='; + /** Param1 is equal to Param2 */ + CONST EQUAL = '=='; + /** Param1 is superior to Param2 */ + CONST SUPERIOR_OR_EQUAL = '>='; + /** Param1 is superior to Param2 */ + CONST SUPERIOR = '>'; + /** Param1 is different to Param2 */ + CONST DIFFERENT = '!='; + /** Param1 is in Param2 */ + CONST IN = 'in'; + /** Param1 is not in Param2 */ + CONST OUT = 'out'; + +// /** +// * Check if a parameter is valid against a ComparableInterface from its operator +// * +// * @param mixed $a Parameter to validate +// * @param string $operator Operator to validate against +// * @param ComparableInterface $b Comparable to validate against +// * +// * @return bool +// */ +// public static function isValid($a, $operator, ComparableInterface $b) +// { +// $ret = false; +// +// try { +// $comparison = $b->compareTo($a); +// } catch (\Exception $e) { +// return false; +// } +// +// switch ($operator) { +// case self::INFERIOR: +// if ($comparison == 1) { +// return true; +// } +// break; +// case self::INFERIOR_OR_EQUAL: +// if ($comparison == 1 || $comparison == 0) { +// return true; +// } +// break; +// case self::EQUAL: +// if ($comparison == 0) { +// return true; +// } +// break; +// case self::SUPERIOR_OR_EQUAL: +// if ($comparison == -1 || $comparison == 0) { +// return true; +// } +// break; +// case self::SUPERIOR: +// if ($comparison == -1) { +// return true; +// } +// break; +// case self::DIFFERENT: +// if ($comparison != 0) { +// return true; +// } +// break; +// default: +// } +// +// return $ret; +// } + + /** + * Get operator translation + * + * @param Translator $translator Provide necessary value from Thelia + * @param string $operator Operator const + * + * @return string + */ + public static function getI18n(Translator $translator, $operator) + { + $ret = $operator; + switch ($operator) { + case self::INFERIOR: + $ret = $translator->trans( + 'inferior to', + array(), + 'constraint' + ); + break; + case self::INFERIOR_OR_EQUAL: + $ret = $translator->trans( + 'inferior or equals to', + array(), + 'constraint' + ); + break; + case self::EQUAL: + $ret = $translator->trans( + 'equals to', + array(), + 'constraint' + ); + break; + case self::SUPERIOR_OR_EQUAL: + $ret = $translator->trans( + 'superior or equals to', + array(), + 'constraint' + ); + break; + case self::SUPERIOR: + $ret = $translator->trans( + 'superior to', + array(), + 'constraint' + ); + break; + case self::DIFFERENT: + $ret = $translator->trans( + 'different from', + array(), + 'constraint' + ); + break; + case self::IN: + $ret = $translator->trans( + 'in', + array(), + 'constraint' + ); + break; + case self::OUT: + $ret = $translator->trans( + 'not in', + array(), + 'constraint' + ); + break; + default: + } + + return $ret; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Rule/SerializableRule.php b/core/lib/Thelia/Constraint/Rule/SerializableRule.php new file mode 100644 index 000000000..011c3e261 --- /dev/null +++ b/core/lib/Thelia/Constraint/Rule/SerializableRule.php @@ -0,0 +1,81 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Rule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * A rule set by an admin ready to be serialized and stored in DataBase + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class SerializableRule +{ + /** @var string Rule Service id */ + public $ruleServiceId = null; + + /** @var array Operators set by Admin for this Rule */ + public $operators = array(); + + /** @var array Values set by Admin for this Rule */ + public $values = array(); + + /** + * Get Operators set by Admin for this Rule + * + * @return array + */ + public function getOperators() + { + return $this->operators; + } + + /** + * Get Rule Service id + * + * @return string + */ + public function getRuleServiceId() + { + return $this->ruleServiceId; + } + + /** + * Get Values set by Admin for this Rule + * + * @return array + */ + public function getValues() + { + return $this->values; + } + + + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/ComparableInterface.php b/core/lib/Thelia/Constraint/Validator/ComparableInterface.php new file mode 100644 index 000000000..d06187fb0 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/ComparableInterface.php @@ -0,0 +1,49 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +/** + * Comparable interface + * Allows to compare two value objects to each other for similarity. + * + * @author Benjamin Eberlei + * @author Guilherme Blanco + */ +interface ComparableInterface +{ + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @return int + */ + public function compareTo($other); +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/CustomerParam.php b/core/lib/Thelia/Constraint/Validator/CustomerParam.php new file mode 100644 index 000000000..5b4390ddc --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/CustomerParam.php @@ -0,0 +1,158 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use InvalidArgumentException; +use Propel\Runtime\ActiveQuery\ModelCriteria; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Model\Customer; +use Thelia\Model\CustomerQuery; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent a Customer + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class CustomerParam extends IntegerParam +{ + /** @var string Model Class name */ + protected $modelClass = '\Thelia\Model\Customer'; + + /** @var ModelCriteria */ + protected $queryBuilder = null; + + /** @var string Customer firstname */ + protected $firstName = null; + + /** @var string Customer lastname */ + protected $lastName = null; + + /** @var string Customer email */ + protected $email = null; + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param int $integer Integer + * + * @throws InvalidArgumentException + */ + public function __construct(CouponAdapterInterface $adapter, $integer) + { + $this->integer = $integer; + $this->adapter = $adapter; + + $this->queryBuilder = CustomerQuery::create(); + /** @var Customer $customer */ + $customer = $this->queryBuilder->findById($integer); + if ($customer !== null) { + $this->firstName = $customer->getFirstname(); + $this->lastName = $customer->getLastname(); + $this->email = $customer->getEmail(); + } else { + throw new \InvalidArgumentException( + 'CustomerParam can compare only existing Customers' + ); + } + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!is_integer($other) || $other < 0) { + throw new InvalidArgumentException( + 'IntegerParam can compare only positive int' + ); + } + + return parent::compareTo($other); + } + + /** + * Customer email + * + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * Customer first name + * + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * Customer last name + * + * @return string + */ + public function getLastName() + { + return $this->lastName; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans( + 'A Customer', + null, + 'constraint' + ); + } + +} diff --git a/core/lib/Thelia/Constraint/Validator/DateParam.php b/core/lib/Thelia/Constraint/Validator/DateParam.php new file mode 100644 index 000000000..ae7eff858 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/DateParam.php @@ -0,0 +1,120 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent a DateTime + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class DateParam extends RuleParameterAbstract +{ + /** @var \DateTime Date */ + protected $dateTime = null; + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param \DateTime $dateTime DateTime + */ + public function __construct(CouponAdapterInterface $adapter, \DateTime $dateTime) + { + $this->dateTime = $dateTime; + $this->adapter = $adapter; + } + + /** + * Get DateTime + * + * @return \DateTime + */ + public function getDateTime() + { + return clone $this->dateTime; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!$other instanceof \DateTime) { + throw new \InvalidArgumentException('DateParam can compare only DateTime'); + } + + $ret = -1; + if ($this->dateTime == $other) { + $ret = 0; + } elseif ($this->dateTime > $other) { + $ret = 1; + } else { + $ret = -1; + } + + return $ret; + } + + /** + * Get Parameter value to test against + * + * @return \Datetime + */ + public function getValue() + { + return clone $this->dateTime; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans('A date (ex: YYYY-MM-DD HH:MM:SS)', null, 'constraint'); + } + +} diff --git a/core/lib/Thelia/Constraint/Validator/IntegerParam.php b/core/lib/Thelia/Constraint/Validator/IntegerParam.php new file mode 100644 index 000000000..c783655c8 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/IntegerParam.php @@ -0,0 +1,121 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent an Integer + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class IntegerParam extends RuleParameterAbstract +{ + /** @var int Integer to compare with */ + protected $integer = 0; + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param int $integer Integer + */ + public function __construct(CouponAdapterInterface $adapter, $integer) + { + $this->integer = $integer; + $this->adapter = $adapter; + } + + /** + * Get integer + * + * @return int + */ + public function getInteger() + { + return $this->integer; + } + + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!is_integer($other)) { + throw new \InvalidArgumentException('IntegerParam can compare only int'); + } + + $ret = -1; + if ($this->integer == $other) { + $ret = 0; + } elseif ($this->integer > $other) { + $ret = 1; + } else { + $ret = -1; + } + + return $ret; + } + + /** + * Get Parameter value to test against + * + * @return int + */ + public function getValue() + { + return $this->integer; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans('A number (ex: 42)', null, 'constraint'); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/IntervalParam.php b/core/lib/Thelia/Constraint/Validator/IntervalParam.php new file mode 100644 index 000000000..a4554760a --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/IntervalParam.php @@ -0,0 +1,165 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent an DateTime period + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class IntervalParam extends RuleParameterAbstract +{ + /** @var \DatePeriod Date period */ + protected $datePeriod = null; + + /** @var \DateTime Start date */ + protected $start = null; + + /** @var \DateInterval Interval date */ + protected $interval = null; + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param \DateTime $start Start interval + * @param \DateInterval $interval Period + */ + public function __construct(CouponAdapterInterface $adapter, \DateTime $start, \DateInterval $interval) + { + $this->datePeriod = new \DatePeriod($start, $interval, 1); + $this->adapter = $adapter; + + $this->start = $start; + $this->interval = $interval; + } + + /** + * Get Interval + * + * @return \DateInterval + */ + public function getInterval() + { + return $this->interval; + } + + /** + * Get start date + * + * @return \DateTime + */ + public function getStart() + { + return $this->start; + } + + + + /** + * Get DatePeriod + * + * @return \DatePeriod + */ + public function getDatePeriod() + { + return clone $this->datePeriod; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!$other instanceof \DateTime) { + throw new \InvalidArgumentException('IntervalParam can compare only DateTime'); + } + + /** @var \DateTime Start Date */ + $startDate = null; + /** @var \DateTime End Date */ + $endDate = null; + + foreach ($this->datePeriod as $key => $value) { + if ($key == 0) { + $startDate = $value; + } + if ($key == 1) { + $endDate = $value; + } + } + + $ret = -1; + if ($startDate <= $other && $other <= $endDate) { + $ret = 0; + } elseif ($startDate > $other) { + $ret = 1; + } else { + $ret = -1; + } + + return $ret; + } + + /** + * Get Parameter value to test against + * + * @return \DatePeriod + */ + public function getValue() + { + return clone $this->datePeriod; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans('An interval between two dates', null, 'constraint'); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/ModelParam.php b/core/lib/Thelia/Constraint/Validator/ModelParam.php new file mode 100644 index 000000000..7ff4567b8 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/ModelParam.php @@ -0,0 +1,115 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use InvalidArgumentException; +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent a Model + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class ModelParam extends IntegerParam +{ + /** @var string Model Class name */ + protected $modelClass = null; + + /** @var ModelCriteria */ + protected $queryBuilder = null; + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param int $integer Integer + * @param string $modelClass Model class name + * + * @throws InvalidArgumentException + */ + public function __construct(CouponAdapterInterface $adapter, $integer, $modelClass) + { + if ($integer < 0) { + $integer = 0; + } + $this->integer = $integer; + $this->adapter = $adapter; + + $this->modelClass = $modelClass; + $queryClassName = $modelClass . 'Query'; + try { + $this->queryBuilder = $queryClassName::create(); + } catch (\Exception $e) { + throw new InvalidArgumentException('ModelParam can only compare Models'); + } + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!is_integer($other) || $other < 0) { + throw new InvalidArgumentException( + 'IntegerParam can compare only positive int' + ); + } + + return parent::compareTo($other); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans( + 'A Model', + null, + 'constraint' + ); + } + +} diff --git a/core/lib/Thelia/Constraint/Validator/PriceParam.php b/core/lib/Thelia/Constraint/Validator/PriceParam.php new file mode 100644 index 000000000..e965d6aba --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/PriceParam.php @@ -0,0 +1,145 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Core\Translation\Translator; +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent a Price + * Positive value with currency + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class PriceParam extends RuleParameterAbstract +{ + /** @var float Positive Float to compare with */ + protected $price = null; + + /** @var string Currency Code ISO 4217 EUR|USD|GBP */ + protected $currency = null; + + /** + * Constructor + * + * @param Translator $translator Service translator + * @param float $price Positive float + * @param string $currency Currency Code ISO 4217 EUR|USD|GBP + */ + public function __construct(Translator $translator, $price, $currency) + { + $this->price = $price; + $this->currency = $currency; + $this->translator = $translator; + } + + /** + * Get currency code + * + * @return string + */ + public function getCurrency() + { + return $this->currency; + } + + /** + * Get price + * + * @return float + */ + public function getPrice() + { + return $this->price; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!is_float($other)) { + throw new \InvalidArgumentException( + 'PriceParam can compare only positive float' + ); + } + + $epsilon = 0.00001; + + $ret = -1; + if (abs($this->price - $other) < $epsilon) { + $ret = 0; + } elseif ($this->price > $other) { + $ret = 1; + } else { + $ret = -1; + } + + return $ret; + } + + /** + * Get Parameter value to test against + * + * @return float + */ + public function getValue() + { + return $this->price; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->translator + ->trans( + 'A price in %currency% (ex: 14.50)', + array( + '%currency%' => $this->currency + ), + 'constraint' + ); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/QuantityParam.php b/core/lib/Thelia/Constraint/Validator/QuantityParam.php new file mode 100644 index 000000000..ac6fcf851 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/QuantityParam.php @@ -0,0 +1,96 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent a Quantity + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class QuantityParam extends IntegerParam +{ + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + * @param int $integer Integer + */ + public function __construct(CouponAdapterInterface $adapter, $integer) + { + $this->integer = $integer; + $this->adapter = $adapter; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!is_integer($other) || $other < 0) { + throw new \InvalidArgumentException( + 'IntegerParam can compare only positive int' + ); + } + + return parent::compareTo($other); + } + + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans( + 'A positive quantity (ex: 42)', + null, + 'constraint' + ); + } + +} diff --git a/core/lib/Thelia/Constraint/Validator/RepeatedDateParam.php b/core/lib/Thelia/Constraint/Validator/RepeatedDateParam.php new file mode 100644 index 000000000..0e8a558cf --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/RepeatedDateParam.php @@ -0,0 +1,117 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent A repeated Date across the time + * Ex : + * A date repeated every 1 months 5 times + * ---------*---*---*---*---*---*---------------------------> time + * 1 2 3 4 5 6 + * 1 : $this->from Start date of the repetition + * *--- : $this->interval Duration of a whole cycle + * x5 : $this->recurrences How many repeated cycle, 1st excluded + * x6 : How many occurrence + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class RepeatedDateParam extends RepeatedParam +{ + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + */ + public function __construct(CouponAdapterInterface $adapter) + { + $this->defaultConstructor(); + $this->adapter = $adapter; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!$other instanceof \DateTime) { + throw new \InvalidArgumentException('RepeatedDateParam can compare only DateTime'); + } + + $ret = -1; + $dates = array(); + /** @var $value \DateTime */ + foreach ($this->datePeriod as $value) { + $dates[$value->getTimestamp()] = $value; + } + + foreach ($dates as $date) { + if ($date == $other) { + return 0; + } + } + + return $ret; + } + + /** + * Get Parameter value to test against + * + * @return \DatePeriod + */ + public function getValue() + { + return clone $this->datePeriod; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans('A date (ex: YYYY-MM-DD HH:MM:SS)', null, 'constraint'); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/RepeatedIntervalParam.php b/core/lib/Thelia/Constraint/Validator/RepeatedIntervalParam.php new file mode 100644 index 000000000..e37cd3b45 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/RepeatedIntervalParam.php @@ -0,0 +1,151 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Coupon\CouponAdapterInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represent A repeated DateInterval across the time + * Ex : + * A duration of 1 month repeated every 2 months 5 times + * ---------****----****----****----****----****----****-----------------> time + * 1 2 3 4 5 6 + * 1 : $this->from Start date of the repetition + * ****---- : $this->interval Duration of a whole cycle + * x5 : $this->recurrences How many repeated cycle, 1st excluded + * x6 : How many occurrence + * **** : $this->durationInDays Duration of a period + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class RepeatedIntervalParam extends RepeatedParam +{ + + /** @var int duration of the param */ + protected $durationInDays = 1; + + /** + * Get how many day a Param is lasting + * + * @return int + */ + public function getDurationInDays() + { + return $this->durationInDays; + } + + /** + * Set how many day a Param is lasting + * + * @param int $durationInDays How many day a Param is lasting + * + * @return $this + */ + public function setDurationInDays($durationInDays = 1) + { + $this->durationInDays = $durationInDays; + + return $this; + } + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Provide necessary value from Thelia + */ + public function __construct(CouponAdapterInterface $adapter) + { + $this->defaultConstructor(); + $this->adapter = $adapter; + } + + /** + * Compare the current object to the passed $other. + * + * Returns 0 if they are semantically equal, 1 if the other object + * is less than the current one, or -1 if its more than the current one. + * + * This method should not check for identity using ===, only for semantically equality for example + * when two different DateTime instances point to the exact same Date + TZ. + * + * @param mixed $other Object + * + * @throws \InvalidArgumentException + * @return int + */ + public function compareTo($other) + { + if (!$other instanceof \DateTime) { + throw new \InvalidArgumentException('RepeatedIntervalParam can compare only DateTime'); + } + + $ret = -1; + $dates = array(); + /** @var $value \DateTime */ + foreach ($this->datePeriod as $value) { + $dates[$value->getTimestamp()]['startDate'] = $value; + $endDate = new \DateTime(); + $dates[$value->getTimestamp()]['endDate'] = $endDate->setTimestamp( + $value->getTimestamp() + ($this->durationInDays * 60 *60 *24) + ); + } + + foreach ($dates as $date) { + if ($date['startDate'] <= $other && $other <= $date['endDate']) { + return 0; + } + } + + return $ret; + + } + + /** + * Get Parameter value to test against + * + * @return \DatePeriod + */ + public function getValue() + { + return clone $this->datePeriod; + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return $this->adapter + ->getTranslator() + ->trans('A date (ex: YYYY-MM-DD HH:MM:SS)', null, 'constraint'); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/RepeatedParam.php b/core/lib/Thelia/Constraint/Validator/RepeatedParam.php new file mode 100644 index 000000000..1188e4fbb --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/RepeatedParam.php @@ -0,0 +1,297 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use DateInterval; +use DatePeriod; +use DateTime; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Allow to set the way a parameter can be repeated across the time + * + * @package Constraint + * @author Guillaume MOREL + * + */ +abstract class RepeatedParam extends RuleParameterAbstract +{ + /** @var DateTime The start date of the period. */ + protected $from = null; + + /** @var DateInterval The interval between recurrences within the period. */ + protected $interval = null; + + /** @var int Nb time the object will be repeated (1st occurrence excluded). */ + protected $recurrences = null; + + /** @var DatePeriod dates recurring at regular intervals, over a given period */ + protected $datePeriod = null; + + /** @var int Frequency the object will be repeated */ + protected $frequency = null; + + /** @var int $nbRepetition Time the object will be repeated */ + protected $nbRepetition = null; + + /** + * Get frequency + * + * @return int + */ + public function getFrequency() + { + return $this->frequency; + } + + /** + * Get Interval + * + * @return \DateInterval + */ + public function getInterval() + { + return $this->interval; + } + + /** + * Get number of time it will be repeated + * + * @return int + */ + public function getNbRepetition() + { + return $this->nbRepetition; + } + + /** + * Get number of recurrences + * + * @return int + */ + public function getRecurrences() + { + return $this->recurrences; + } + + /** + * Generate default repetition + * Every 1 week 100 times from now + * + * @return $this + */ + protected function defaultConstructor() + { + $this->from = new \DateTime(); + $this->interval = new \DateInterval('P1W'); // 1 week + $this->recurrences = 100; + $this->generateDatePeriod(); + + return $this; + } + + /** + * Generate DatePeriod from class attributes + * Will repeat every DatePeriod + * + * @return $this + */ + protected function generateDatePeriod() + { + $this->datePeriod = new DatePeriod( + $this->from, + $this->interval, + $this->recurrences + ); + + return $this; + } + + /** + * Set the Object to be repeated every days + * Ex : $obj->repeatEveryDay() will occur once + * $obj->repeatEveryDay(10) will occur once + * $obj->repeatEveryDay(10, 0) will occur once + * $obj->repeatEveryDay(10, 4) will occur every 10 days 5 times + * + * @param int $frequency Frequency the object will be repeated + * @param int $nbRepetition Time the object will be repeated + * + * @return $this + */ + public function repeatEveryDay($frequency = 1, $nbRepetition = 0) + { + $this->_repeatEveryPeriod($period = 'D', $frequency, $nbRepetition); + + return $this; + } + + /** + * Set the Object to be repeated every week + * Ex : $obj->repeatEveryWeek() will occur once + * $obj->repeatEveryWeek(10) will occur once + * $obj->repeatEveryWeek(10, 0) will occur once + * $obj->repeatEveryWeek(10, 4) will occur every 10 weeks (70days) 5 times + * + * @param int $frequency Frequency the object will be repeated + * @param int $nbRepetition Time the object will be repeated + * + * @return $this + */ + public function repeatEveryWeek($frequency = 1, $nbRepetition = 0) + { + $this->_repeatEveryPeriod($period = 'W', $frequency, $nbRepetition); + + return $this; + } + + /** + * Set the Object to be repeated every month + * Ex : $obj->repeatEveryWeek() will occur once + * $obj->repeatEveryWeek(10) will occur once + * $obj->repeatEveryWeek(10, 0) will occur once + * $obj->repeatEveryWeek(10, 4) will occur every 10 month (70days) 5times + * + * @param int $frequency Frequency the object will be repeated + * @param int $nbRepetition Time the object will be repeated + * + * @return $this + */ + public function repeatEveryMonth($frequency = 1, $nbRepetition = 0) + { + $this->_repeatEveryPeriod($period = 'M', $frequency, $nbRepetition); + + return $this; + } + + /** + * Set the Object to be repeated every year + * Ex : $obj->repeatEveryWeek() will occur once + * $obj->repeatEveryWeek(10) will occur once + * $obj->repeatEveryWeek(10, 0) will occur once + * $obj->repeatEveryWeek(10, 4) will occur every 10 year 5 times + * + * @param int $frequency Frequency the object will be repeated + * @param int $nbRepetition Time the object will be repeated + * + * @return $this + */ + public function repeatEveryYear($frequency = 1, $nbRepetition = 0) + { + $this->_repeatEveryPeriod($period = 'Y', $frequency, $nbRepetition); + + return $this; + } + + /** + * Set the Object to be repeated every Period + * Ex : $obj->repeatEveryPeriod('D') will occur once + * $obj->repeatEveryPeriod('W', 10) will occur once + * $obj->repeatEveryPeriod('W', 10, 0) will occur once + * $obj->repeatEveryPeriod('M', 10, 4) will occur every 10 month 5 times + * + * @param string $period Period Y|M||D|W + * @param int $frequency Frequency the object will be repeated + * @param int $nbRepetition Time the object will be repeated + * + * @return $this + */ + private function _repeatEveryPeriod($period, $frequency = 1, $nbRepetition = 0) + { + if (is_numeric($frequency) && $frequency > 0) { + $this->interval = new \DateInterval('P' . $frequency . $period); + } + + if (is_numeric($nbRepetition) && $nbRepetition >= 0) { + $this->recurrences = $nbRepetition; + } + + $this->generateDatePeriod(); + + return $this; + } + + + + /** + * Set Start time + * + * @param \DateTime $from Start time + * + * @return $this + */ + public function setFrom($from) + { + $this->from = $from; + + return $this; + } + + /** + * Get Start time + * + * @return \DateTime + */ + public function getFrom() + { + return clone $this->from; + } + + /** + * Set DatePeriod + * + * @param DatePeriod $datePeriod DatePeriod + * + * @return $this + */ + public function setDatePeriod(DatePeriod $datePeriod) + { + $this->datePeriod = $datePeriod; + + return $this; + } + + /** + * Get date DatePeriod + * + * @return \DatePeriod + */ + public function getDatePeriod() + { + return clone $this->datePeriod; + } + + /** + * Get Parameter value to test against + * + * @return \DatePeriod + */ + public function getValue() + { + return clone $this->datePeriod; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/RuleParameterAbstract.php b/core/lib/Thelia/Constraint/Validator/RuleParameterAbstract.php new file mode 100644 index 000000000..2be4c581f --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/RuleParameterAbstract.php @@ -0,0 +1,67 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +use Thelia\Core\Translation\Translator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Exception\NotImplementedException; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Get a Param value + * + * @package Constraint + * @author Guillaume MOREL + * + */ +abstract class RuleParameterAbstract implements ComparableInterface +{ + /** @var Translator Service Translator */ + protected $translator = null; + + /** + * Get Parameter value to test against + * + * @return mixed + */ + public function getValue() + { + return new NotImplementedException(); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + return new NotImplementedException(); + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Constraint/Validator/RuleValidator.php b/core/lib/Thelia/Constraint/Validator/RuleValidator.php new file mode 100644 index 000000000..9b0093bc9 --- /dev/null +++ b/core/lib/Thelia/Constraint/Validator/RuleValidator.php @@ -0,0 +1,77 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint\Validator; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Allow to validate parameters + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class RuleValidator +{ + /** @var string Operator ex: Operators::INFERIOR */ + protected $operator = null; + + /** @var ComparableInterface Validator */ + protected $param = null; + + /** + * Constructor + * + * @param string $operator Operator ex: Operators::INFERIOR + * @param ComparableInterface $param Validator ex: PriceParam + */ + function __construct($operator, ComparableInterface $param) + { + $this->operator = $operator; + $this->param = $param; + } + + /** + * Get Validator Operator + * + * @return string + */ + public function getOperator() + { + return $this->operator; + } + + /** + * Get Validator Param + * + * @return ComparableInterface + */ + public function getParam() + { + return $this->param; + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Admin/BaseAdminController.php b/core/lib/Thelia/Controller/Admin/BaseAdminController.php index 298cd0182..5461b8d3f 100755 --- a/core/lib/Thelia/Controller/Admin/BaseAdminController.php +++ b/core/lib/Thelia/Controller/Admin/BaseAdminController.php @@ -22,6 +22,9 @@ /*************************************************************************************/ namespace Thelia\Controller\Admin; +use Symfony\Component\Routing\Exception\InvalidParameterException; +use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; +use Symfony\Component\Routing\Exception\RouteNotFoundException; use Thelia\Controller\BaseController; use Symfony\Component\HttpFoundation\Response; use Thelia\Core\Security\Exception\AuthorizationException; @@ -211,12 +214,26 @@ class BaseAdminController extends BaseController /** * Return the route path defined for the givent route ID * - * @param string $routeId a route ID, as defines in Config/Resources/routing/admin.xml + * @param string $routeId a route ID, as defines in Config/Resources/routing/admin.xml + * @param mixed $parameters An array of parameters + * @param Boolean|string $referenceType The type of reference to be generated (one of the constants) + * + * @throws RouteNotFoundException If the named route doesn't exist + * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route + * @throws InvalidParameterException When a parameter value for a placeholder is not correct because + * it does not match the requirement + * @throws \InvalidArgumentException When the router doesn't exist + * @return string The generated URL * * @see \Thelia\Controller\BaseController::getRouteFromRouter() */ - protected function getRoute($routeId) { - return $this->getRouteFromRouter('router.admin', $routeId); + protected function getRoute($routeId, $parameters = array(), $referenceType = Router::ABSOLUTE_PATH) { + return $this->getRouteFromRouter( + 'router.admin', + $routeId, + $parameters, + $referenceType + ); } /** diff --git a/core/lib/Thelia/Controller/Admin/CouponController.php b/core/lib/Thelia/Controller/Admin/CouponController.php new file mode 100755 index 000000000..e11fcf09e --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/CouponController.php @@ -0,0 +1,702 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Controller\Admin; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Router; +use Thelia\Constraint\ConstraintFactory; +use Thelia\Constraint\ConstraintFactoryTest; +use Thelia\Constraint\Rule\AvailableForTotalAmount; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Core\Event\Coupon\CouponCreateEvent; +use Thelia\Core\Event\Coupon\CouponCreateOrUpdateEvent; +use Thelia\Core\Event\Coupon\CouponEvent; +use Thelia\Core\Event\TheliaEvents; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Core\Security\Exception\AuthenticationException; +use Thelia\Core\Security\Exception\AuthorizationException; +use Thelia\Core\Translation\Translator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\CouponManager; +use Thelia\Coupon\CouponRuleCollection; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Form\CouponCreationForm; +use Thelia\Form\Exception\FormValidationException; +use Thelia\Log\Tlog; +use Thelia\Model\Coupon; +use Thelia\Model\CouponQuery; +use Thelia\Model\Lang; +use Thelia\Tools\I18n; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Control View and Action (Model) via Events + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponController extends BaseAdminController +{ + /** + * Manage Coupons list display + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function browseAction() + { + $this->checkAuth('ADMIN', 'admin.coupon.view'); + + return $this->render('coupon-list'); + } + + /** + * Manage Coupons creation display + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function createAction() + { + // Check current user authorization + $response = $this->checkAuth('admin.coupon.create'); + if ($response !== null) { + return $response; + } + + // Parameters given to the template + $args = array(); + + $i18n = new I18n(); + /** @var Lang $lang */ + $lang = $this->getSession()->get('lang'); + $eventToDispatch = TheliaEvents::COUPON_CREATE; + + if ($this->getRequest()->isMethod('POST')) { + $this->validateCreateOrUpdateForm( + $i18n, + $lang, + $eventToDispatch, + 'created', + 'creation' + ); + } else { + // If no input for expirationDate, now + 2 months + $defaultDate = new \DateTime(); + $args['defaultDate'] = $defaultDate->modify('+2 month') + ->format($lang->getDateFormat()); + } + + $args['formAction'] = 'admin/coupon/create'; + + return $this->render( + 'coupon-create', + $args + ); + } + + /** + * Manage Coupons edition display + * + * @param int $couponId Coupon id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function updateAction($couponId) + { + // Check current user authorization + $response = $this->checkAuth('admin.coupon.update'); + if ($response !== null) { + return $response; + } + + /** @var Coupon $coupon */ + $coupon = CouponQuery::create()->findOneById($couponId); + if (!$coupon) { + $this->pageNotFound(); + } + + // Parameters given to the template + $args = array(); + + $i18n = new I18n(); + /** @var Lang $lang */ + $lang = $this->getSession()->getLang(); + $eventToDispatch = TheliaEvents::COUPON_UPDATE; + + if ($this->getRequest()->isMethod('POST')) { + $this->validateCreateOrUpdateForm( + $i18n, + $lang, + $eventToDispatch, + 'updated', + 'update' + ); + } else { + // Prepare the data that will hydrate the form + $data = array( + 'code' => $coupon->getCode(), + 'title' => $coupon->getTitle(), + 'amount' => $coupon->getAmount(), + 'effect' => $coupon->getType(), + 'shortDescription' => $coupon->getShortDescription(), + 'description' => $coupon->getDescription(), + 'isEnabled' => ($coupon->getIsEnabled() == 1), + 'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()), + 'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1), + 'isCumulative' => ($coupon->getIsCumulative() == 1), + 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), + 'maxUsage' => $coupon->getMaxUsage(), + 'rules' => new CouponRuleCollection(array()), + 'locale' => $coupon->getLocale(), + ); + + $args['rulesObject'] = array(); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + $rules = $constraintFactory->unserializeCouponRuleCollection( + $coupon->getSerializedRules() + ); + + /** @var CouponRuleInterface $rule */ + foreach ($rules->getRules() as $rule) { + $args['rulesObject'][] = array( + 'serviceId' => $rule->getServiceId(), + 'name' => $rule->getName(), + 'tooltip' => $rule->getToolTip(), + 'validators' => $rule->getValidators() + ); + } + + // Setup the object form + $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); + + // Pass it to the parser + $this->getParserContext()->addForm($changeForm); + } + + $args['availableCoupons'] = $this->getAvailableCoupons(); + $args['availableRules'] = $this->getAvailableRules(); + $args['urlAjaxGetRuleInput'] = $this->getRoute( + 'admin.coupon.rule.input', + array('ruleId' => 'ruleId'), + Router::ABSOLUTE_URL + ); + + $args['urlAjaxUpdateRules'] = $this->getRoute( + 'admin.coupon.rule.update', + array('couponId' => $couponId), + Router::ABSOLUTE_URL + ); + + $args['formAction'] = 'admin/coupon/update/' . $couponId; + + return $this->render( + 'coupon-update', + $args + ); + } + + + /** + * Manage Coupons Rule creation display + * + * @param int $couponId Coupon id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function createRuleAction($couponId) + { + // Check current user authorization + $response = $this->checkAuth('admin.coupon.update'); + if ($response !== null) { + return $response; + } + + /** @var Coupon $coupon */ + $coupon = CouponQuery::create()->findOneById($couponId); + if (!$coupon) { + $this->pageNotFound(); + } + + // Parameters given to the template + $args = array(); + + $i18n = new I18n(); + /** @var Lang $lang */ + $lang = $this->getSession()->get('lang'); + $eventToDispatch = TheliaEvents::COUPON_RULE_CREATE; + + if ($this->getRequest()->isMethod('POST')) { + $this->validateCreateOrUpdateForm( + $i18n, + $lang, + $eventToDispatch, + 'updated', + 'update' + ); + } else { + // Prepare the data that will hydrate the form + $data = array( + 'code' => $coupon->getCode(), + 'title' => $coupon->getTitle(), + 'amount' => $coupon->getAmount(), + 'effect' => $coupon->getType(), + 'shortDescription' => $coupon->getShortDescription(), + 'description' => $coupon->getDescription(), + 'isEnabled' => ($coupon->getIsEnabled() == 1), + 'expirationDate' => $coupon->getExpirationDate($lang->getDateFormat()), + 'isAvailableOnSpecialOffers' => ($coupon->getIsAvailableOnSpecialOffers() == 1), + 'isCumulative' => ($coupon->getIsCumulative() == 1), + 'isRemovingPostage' => ($coupon->getIsRemovingPostage() == 1), + 'maxUsage' => $coupon->getMaxUsage(), + 'rules' => new CouponRuleCollection(array()), + 'locale' => $coupon->getLocale(), + ); + + /** @var CouponAdapterInterface $adapter */ + $adapter = $this->container->get('thelia.adapter'); + /** @var Translator $translator */ + $translator = $this->container->get('thelia.translator'); + + $args['rulesObject'] = array(); + /** @var CouponRuleInterface $rule */ + foreach ($coupon->getRules()->getRules() as $rule) { + $args['rulesObject'][] = array( + 'name' => $rule->getName($translator), + 'tooltip' => $rule->getToolTip($translator), + 'validators' => $rule->getValidators() + ); + } + +// $args['rules'] = $this->cleanRuleForTemplate($coupon->getRules()->getRules()); + + // Setup the object form + $changeForm = new CouponCreationForm($this->getRequest(), 'form', $data); + + // Pass it to the parser + $this->getParserContext()->addForm($changeForm); + } + + $args['formAction'] = 'admin/coupon/update/' . $couponId; + + return $this->render( + 'coupon-update', + $args + ); + } + + + + /** + * Manage Coupons read display + * + * @param int $couponId Coupon Id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function readAction($couponId) + { + $this->checkAuth('ADMIN', 'admin.coupon.read'); + + // Database request repeated in the loop but cached + $search = CouponQuery::create(); + $coupon = $search->findOneById($couponId); + + if ($coupon === null) { + return $this->pageNotFound(); + } + + return $this->render('coupon-read', array('couponId' => $couponId)); + } + + /** + * Manage Coupons read display + * + * @param string $ruleId Rule service id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function getRuleInputAction($ruleId) + { + $this->checkAuth('ADMIN', 'admin.coupon.read'); + + if ($this->isDebug()) { + if (!$this->getRequest()->isXmlHttpRequest()) { + $this->redirect( + $this->getRoute( + 'admin', + array(), + Router::ABSOLUTE_URL + ) + ); + } + } + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + $inputs = $constraintFactory->getInputs($ruleId); + + if ($inputs === null) { + return $this->pageNotFound(); + } + + return $this->render( + 'coupon/rule-input-ajax', + array( + 'ruleId' => $ruleId, + 'inputs' => $inputs + ) + ); + } + + + /** + * Manage Coupons read display + * + * @param int $couponId Coupon id + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function updateRulesAction($couponId) + { + $this->checkAuth('ADMIN', 'admin.coupon.read'); + + if ($this->isDebug()) { + if (!$this->getRequest()->isXmlHttpRequest()) { + $this->redirect( + $this->getRoute( + 'admin', + array(), + Router::ABSOLUTE_URL + ) + ); + } + } + + $search = CouponQuery::create(); + /** @var Coupon $coupon */ + $coupon = $search->findOneById($couponId); + + if (!$coupon) { + return $this->pageNotFound(); + } + + $rules = new CouponRuleCollection(); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + $rulesReceived = json_decode($this->getRequest()->get('rules')); + foreach ($rulesReceived as $ruleReceived) { + var_dump('building ', $ruleReceived->values); + $rule = $constraintFactory->build( + $ruleReceived->serviceId, + (array) $ruleReceived->operators, + (array) $ruleReceived->values + ); + $rules->add(clone $rule); + } + + $coupon->setSerializedRules( + $constraintFactory->serializeCouponRuleCollection($rules) + ); + + $couponEvent = new CouponCreateOrUpdateEvent( + $coupon->getCode(), + $coupon->getTitle(), + $coupon->getAmount(), + $coupon->getType(), + $coupon->getShortDescription(), + $coupon->getDescription(), + $coupon->getIsEnabled(), + $coupon->getExpirationDate(), + $coupon->getIsAvailableOnSpecialOffers(), + $coupon->getIsCumulative(), + $coupon->getIsRemovingPostage(), + $coupon->getMaxUsage(), + $rules, + $coupon->getLocale() + ); + + $eventToDispatch = TheliaEvents::COUPON_RULE_UPDATE; + // Dispatch Event to the Action + $this->dispatch( + $eventToDispatch, + $couponEvent + ); + + $this->adminLogAppend( + sprintf( + 'Coupon %s (ID %s) rules updated', + $couponEvent->getTitle(), + $couponEvent->getCoupon()->getId() + ) + ); + + $cleanedRules = $this->cleanRuleForTemplate($rules); + + return $this->render( + 'coupon/rules', + array( + 'couponId' => $couponId, + 'rules' => $cleanedRules, + 'urlEdit' => $couponId, + 'urlDelete' => $couponId + ) + ); + } + + /** + * Build a Coupon from its form + * + * @param array $data Form data + * + * @return Coupon + */ + protected function buildCouponFromForm(array $data) + { + $couponBeingCreated = new Coupon(); + $couponBeingCreated->setCode($data['code']); + $couponBeingCreated->setType($data['type']); + $couponBeingCreated->setTitle($data['title']); + $couponBeingCreated->setShortDescription($data['shortDescription']); + $couponBeingCreated->setDescription($data['description']); + $couponBeingCreated->setAmount($data['amount']); + $couponBeingCreated->setIsEnabled($data['isEnabled']); + $couponBeingCreated->setExpirationDate($data['expirationDate']); + $couponBeingCreated->setSerializedRules( + new CouponRuleCollection( + array() + ) + ); + $couponBeingCreated->setIsCumulative($data['isCumulative']); + $couponBeingCreated->setIsRemovingPostage( + $data['isRemovingPostage'] + ); + $couponBeingCreated->setMaxUsage($data['maxUsage']); + $couponBeingCreated->setIsAvailableOnSpecialOffers( + $data['isAvailableOnSpecialOffers'] + ); + + return $couponBeingCreated; + } + + /** + * Log error message + * + * @param string $action Creation|Update|Delete + * @param string $message Message to log + * @param \Exception $e Exception to log + * + * @return $this + */ + protected function logError($action, $message, $e) + { + Tlog::getInstance()->error( + sprintf( + 'Error during Coupon ' . $action . ' process : %s. Exception was %s', + $message, + $e->getMessage() + ) + ); + + return $this; + } + + /** + * Validate the CreateOrUpdate form + * + * @param string $i18n Local code (fr_FR) + * @param Lang $lang Local variables container + * @param string $eventToDispatch Event which will activate actions + * @param string $log created|edited + * @param string $action creation|edition + * + * @return $this + */ + protected function validateCreateOrUpdateForm($i18n, $lang, $eventToDispatch, $log, $action) + { + // Create the form from the request + $creationForm = new CouponCreationForm($this->getRequest()); + + $message = false; + try { + // Check the form against constraints violations + $form = $this->validateForm($creationForm, 'POST'); + + // Get the form field values + $data = $form->getData(); + $couponEvent = new CouponCreateOrUpdateEvent( + $data['code'], + $data['title'], + $data['amount'], + $data['effect'], + $data['shortDescription'], + $data['description'], + $data['isEnabled'], + $i18n->getDateTimeFromForm($lang, $data['expirationDate']), + $data['isAvailableOnSpecialOffers'], + $data['isCumulative'], + $data['isRemovingPostage'], + $data['maxUsage'], + new CouponRuleCollection(array()), + $data['locale'] + ); + + // Dispatch Event to the Action + $this->dispatch( + $eventToDispatch, + $couponEvent + ); + + $this->adminLogAppend( + sprintf( + 'Coupon %s (ID ) ' . $log, + $couponEvent->getTitle(), + $couponEvent->getCoupon()->getId() + ) + ); + + $this->redirect( + str_replace( + '{id}', + $couponEvent->getCoupon()->getId(), + $creationForm->getSuccessUrl() + ) + ); + + } catch (FormValidationException $e) { + // Invalid data entered + $message = 'Please check your input:'; + $this->logError($action, $message, $e); + + } catch (\Exception $e) { + // Any other error + $message = 'Sorry, an error occurred:'; + $this->logError($action, $message, $e); + } + + if ($message !== false) { + // Mark the form as with error + $creationForm->setErrorMessage($message); + + // Send the form and the error to the parser + $this->getParserContext() + ->addForm($creationForm) + ->setGeneralError($message); + } + + return $this; + } + + /** + * Get all available rules + * + * @return array + */ + protected function getAvailableRules() + { + /** @var CouponManager $couponManager */ + $couponManager = $this->container->get('thelia.coupon.manager'); + $availableRules = $couponManager->getAvailableRules(); + $cleanedRules = array(); + /** @var CouponRuleInterface $availableRule */ + foreach ($availableRules as $availableRule) { + $rule = array(); + $rule['serviceId'] = $availableRule->getServiceId(); + $rule['name'] = $availableRule->getName(); + $rule['toolTip'] = $availableRule->getToolTip(); + $cleanedRules[] = $rule; + } + + return $cleanedRules; + } + + /** + * Get all available coupons + * + * @return array + */ + protected function getAvailableCoupons() + { + /** @var CouponManager $couponManager */ + $couponManager = $this->container->get('thelia.coupon.manager'); + $availableCoupons = $couponManager->getAvailableCoupons(); + $cleanedRules = array(); + /** @var CouponInterface $availableCoupon */ + foreach ($availableCoupons as $availableCoupon) { + $rule = array(); + $rule['serviceId'] = $availableCoupon->getServiceId(); + $rule['name'] = $availableCoupon->getName(); + $rule['toolTip'] = $availableCoupon->getToolTip(); + $cleanedRules[] = $rule; + } + + return $cleanedRules; + } + + /** + * @param $rules + * @return array + */ + protected function cleanRuleForTemplate($rules) + { + $cleanedRules = array(); + /** @var $rule CouponRuleInterface */ + foreach ($rules->getRules() as $rule) { + $cleanedRules[] = $rule->getToolTip(); + } + + return $cleanedRules; + } + +// /** +// * Validation Rule creation +// * +// * @param string $type Rule class type +// * @param string $operator Rule operator (<, >, =, etc) +// * @param array $values Rules values +// * +// * @return bool +// */ +// protected function validateRulesCreation($type, $operator, $values) +// { +// /** @var CouponAdapterInterface $adapter */ +// $adapter = $this->container->get('thelia.adapter'); +// $validator = new PriceParam() +// try { +// $rule = new AvailableForTotalAmount($adapter, $validators); +// $rule = new $type($adapter, $validators); +// } catch (\Exception $e) { +// return false; +// } +// } + + + +} diff --git a/core/lib/Thelia/Controller/Admin/CustomerController.php b/core/lib/Thelia/Controller/Admin/CustomerController.php new file mode 100644 index 000000000..04c8842cd --- /dev/null +++ b/core/lib/Thelia/Controller/Admin/CustomerController.php @@ -0,0 +1,40 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Controller\Admin; + + +/** + * Class CustomerController + * @package Thelia\Controller\Admin + * @author Manuel Raynaud + */ +class CustomerController extends BaseAdminController +{ + public function indexAction() + { + if (null !== $response = $this->checkAuth("admin.customers.view")) return $response; + + return $this->render("customers", array("display_customer" => 20)); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Controller/BaseController.php b/core/lib/Thelia/Controller/BaseController.php index e5b098f02..95ba9a524 100755 --- a/core/lib/Thelia/Controller/BaseController.php +++ b/core/lib/Thelia/Controller/BaseController.php @@ -25,6 +25,10 @@ namespace Thelia\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\DependencyInjection\ContainerAware; +use Symfony\Component\Routing\Exception\InvalidParameterException; +use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; +use Symfony\Component\Routing\Exception\RouteNotFoundException; +use Symfony\Component\Routing\Router; use Thelia\Core\Security\SecurityContext; use Thelia\Tools\URL; use Thelia\Tools\Redirect; @@ -175,7 +179,14 @@ class BaseController extends ContainerAware return $form; } else { - throw new FormValidationException(sprintf("Missing or invalid data: %s", $this->getErrorMessages($form))); + $errorMessage = null; + if ($form->get("error_message")->getData() != null) { + $errorMessage = $form->get("error_message")->getData(); + } else { + $errorMessage = sprintf("Missing or invalid data: %s", $this->getErrorMessages($form)); + } + + throw new FormValidationException($errorMessage); } } else { @@ -216,20 +227,27 @@ class BaseController extends ContainerAware /** * Get a route path from the route id. * - * @param $routerName - * @param $routeId + * @param string $routerName Router name + * @param string $routeId The name of the route + * @param mixed $parameters An array of parameters + * @param Boolean|string $referenceType The type of reference to be generated (one of the constants) * - * @return mixed - * @throws InvalidArgumentException + * @throws RouteNotFoundException If the named route doesn't exist + * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route + * @throws InvalidParameterException When a parameter value for a placeholder is not correct because + * it does not match the requirement + * @throws \InvalidArgumentException When the router doesn't exist + * @return string The generated URL */ - protected function getRouteFromRouter($routerName, $routeId) { - $route = $this->container->get($routerName)->getRouteCollection()->get($routeId); + protected function getRouteFromRouter($routerName, $routeId, $parameters = array(), $referenceType = Router::ABSOLUTE_PATH) { + /** @var Router $router */ + $router = $this->container->get($routerName); - if ($route == null) { - throw new \InvalidArgumentException(sprintf("Route ID '%s' does not exists.", $routeId)); + if ($router == null) { + throw new \InvalidArgumentException(sprintf("Router '%s' does not exists.", $routerName)); } - return $route->getPath(); + return $router->generate($routeId, $parameters, $referenceType); } /** @@ -240,4 +258,14 @@ class BaseController extends ContainerAware { throw new NotFoundHttpException(); } + + /** + * Check if environment is in debug mode + * + * @return bool + */ + protected function isDebug() + { + return $this->container->getParameter('kernel.debug'); + } } \ No newline at end of file diff --git a/core/lib/Thelia/Controller/Front/BaseFrontController.php b/core/lib/Thelia/Controller/Front/BaseFrontController.php index e92387a83..ed6774c8b 100755 --- a/core/lib/Thelia/Controller/Front/BaseFrontController.php +++ b/core/lib/Thelia/Controller/Front/BaseFrontController.php @@ -22,6 +22,7 @@ /*************************************************************************************/ namespace Thelia\Controller\Front; +use Symfony\Component\Routing\Router; use Thelia\Controller\BaseController; use Thelia\Tools\URL; @@ -34,8 +35,8 @@ class BaseFrontController extends BaseController * * @see \Thelia\Controller\BaseController::getRouteFromRouter() */ - protected function getRoute($routeId) { - return $this->getRouteFromRouter('router.front', $routeId); + protected function getRoute($routeId, $parameters = array(), $referenceType = Router::ABSOLUTE_PATH) { + return $this->getRouteFromRouter('router.front', $routeId, $parameters, $referenceType); } /** @@ -44,7 +45,7 @@ class BaseFrontController extends BaseController * @param unknown $routeId the route ID, as found in Config/Resources/routing/admin.xml * @param unknown $urlParameters the URL parametrs, as a var/value pair array */ - public function redirectToRoute($routeId, $urlParameters = array()) { - $this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId), $urlParameters)); + public function redirectToRoute($routeId, $urlParameters = array(), $referenceType = Router::ABSOLUTE_PATH) { + $this->redirect(URL::getInstance()->absoluteUrl($this->getRoute($routeId, array(), $referenceType), $urlParameters)); } } diff --git a/core/lib/Thelia/Controller/Front/CustomerController.php b/core/lib/Thelia/Controller/Front/CustomerController.php index d753510a6..58d578955 100755 --- a/core/lib/Thelia/Controller/Front/CustomerController.php +++ b/core/lib/Thelia/Controller/Front/CustomerController.php @@ -39,6 +39,7 @@ use Thelia\Core\Factory\ActionEventFactory; use Thelia\Tools\URL; use Thelia\Log\Tlog; use Thelia\Core\Security\Exception\WrongPasswordException; +use Symfony\Component\Routing\Router; /** * Class CustomerController @@ -167,16 +168,25 @@ class CustomerController extends BaseFrontController } catch (FormValidationException $e) { + + if ($request->request->has("account")) { + $account = $request->request->get("account"); + $form = $customerLoginForm->getForm(); + if($account == 0 && $form->get("email")->getData() !== null) { + $this->redirectToRoute("customer.create.view", array("email" => $form->get("email")->getData())); + } + } + $message = sprintf("Please check your input: %s", $e->getMessage()); } catch(UsernameNotFoundException $e) { - $message = "This customer email was not found."; + $message = "Wrong email or password. Please try again"; } catch (WrongPasswordException $e) { - $message = "Wrong password. Please try again."; + $message = "Wrong email or password. Please try again"; } catch(AuthenticationException $e) { - $message = "Sorry, we failed to authentify you. Please try again."; + $message = "Wrong email or password. Please try again"; } catch (\Exception $e) { $message = sprintf("Sorry, an error occured: %s", $e->getMessage()); diff --git a/core/lib/Thelia/Core/Bundle/TheliaBundle.php b/core/lib/Thelia/Core/Bundle/TheliaBundle.php index 9c8b8fedf..a9704b350 100755 --- a/core/lib/Thelia/Core/Bundle/TheliaBundle.php +++ b/core/lib/Thelia/Core/Bundle/TheliaBundle.php @@ -26,9 +26,11 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Scope; +use Thelia\Core\DependencyInjection\Compiler\RegisterCouponPass; use Thelia\Core\DependencyInjection\Compiler\RegisterListenersPass; use Thelia\Core\DependencyInjection\Compiler\RegisterParserPluginPass; use Thelia\Core\DependencyInjection\Compiler\RegisterRouterPass; +use Thelia\Core\DependencyInjection\Compiler\RegisterRulePass; /** * First Bundle use in Thelia @@ -60,6 +62,8 @@ class TheliaBundle extends Bundle ->addCompilerPass(new RegisterListenersPass()) ->addCompilerPass(new RegisterParserPluginPass()) ->addCompilerPass(new RegisterRouterPass()) + ->addCompilerPass(new RegisterCouponPass()) + ->addCompilerPass(new RegisterRulePass()) ; } diff --git a/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterCouponPass.php b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterCouponPass.php new file mode 100755 index 000000000..cf6f32842 --- /dev/null +++ b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterCouponPass.php @@ -0,0 +1,69 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Created by JetBrains PhpStorm. + * Date: 9/05/13 + * Time: 3:24 PM + * + * Class RegisterListenersPass + * Source code come from Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass class + * + * @package Thelia\Core\DependencyInjection\Compiler + * @author Guillaume MOREL + * + */ +class RegisterCouponPass implements CompilerPassInterface +{ + /** + * You can modify the container here before it is dumped to PHP code. + * + * @param ContainerBuilder $container Container + * + * @api + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('thelia.coupon.manager')) { + return; + } + + $couponManager = $container->getDefinition('thelia.coupon.manager'); + $services = $container->findTaggedServiceIds("thelia.coupon.addCoupon"); + + foreach ($services as $id => $rule) { + $couponManager->addMethodCall( + 'addAvailableCoupon', + array( + new Reference($id) + ) + ); + } + } +} diff --git a/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterRulePass.php b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterRulePass.php new file mode 100755 index 000000000..dcc54cf8e --- /dev/null +++ b/core/lib/Thelia/Core/DependencyInjection/Compiler/RegisterRulePass.php @@ -0,0 +1,69 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Created by JetBrains PhpStorm. + * Date: 9/05/13 + * Time: 3:24 PM + * + * Class RegisterListenersPass + * Source code come from Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass class + * + * @package Thelia\Core\DependencyInjection\Compiler + * @author Guillaume MOREL + * + */ +class RegisterRulePass implements CompilerPassInterface +{ + /** + * You can modify the container here before it is dumped to PHP code. + * + * @param ContainerBuilder $container Container + * + * @api + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('thelia.coupon.manager')) { + return; + } + + $couponManager = $container->getDefinition('thelia.coupon.manager'); + $services = $container->findTaggedServiceIds("thelia.coupon.addRule"); + + foreach ($services as $id => $rule) { + $couponManager->addMethodCall( + 'addAvailableRule', + array( + new Reference($id) + ) + ); + } + } +} diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php new file mode 100644 index 000000000..796baed08 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Coupon/CouponCreateOrUpdateEvent.php @@ -0,0 +1,312 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\Event\Coupon; +use Thelia\Core\Event\ActionEvent; +use Thelia\Coupon\CouponRuleCollection; +use Thelia\Model\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/29/13 + * Time: 3:45 PM + * + * Occurring when a Coupon is created + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponCreateOrUpdateEvent extends ActionEvent +{ + /** @var CouponRuleCollection Array of CouponRuleInterface */ + protected $rules = null; + + /** @var string Coupon code (ex: XMAS) */ + protected $code = null; + + /** @var string Coupon title (ex: Coupon for XMAS) */ + protected $title = null; + + /** @var string Coupon short description */ + protected $shortDescription = null; + + /** @var string Coupon description */ + protected $description = null; + + /** @var bool if Coupon is enabled */ + protected $isEnabled = false; + + /** @var \DateTime Coupon expiration date */ + protected $expirationDate = null; + + /** @var bool if Coupon is cumulative */ + protected $isCumulative = false; + + /** @var bool if Coupon is removing postage */ + protected $isRemovingPostage = false; + + /** @var float Amount that will be removed from the Checkout (Coupon Effect) */ + protected $amount = 0; + + /** @var int Max time a Coupon can be used (-1 = unlimited) */ + protected $maxUsage = -1; + + /** @var bool if Coupon is available for Products already on special offers */ + protected $isAvailableOnSpecialOffers = false; + + /** @var Coupon Coupon model */ + protected $coupon = null; + + /** @var string Coupon effect */ + protected $effect; + + /** @var string Language code ISO (ex: fr_FR) */ + protected $locale = null; + + /** + * Constructor + * + * @param string $code Coupon Code + * @param string $title Coupon title + * @param float $amount Amount removed from the Total Checkout + * @param string $effect Coupon effect + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param boolean $isEnabled Enable/Disable + * @param \DateTime $expirationDate Coupon expiration date + * @param boolean $isAvailableOnSpecialOffers Is available on special offers + * @param boolean $isCumulative Is cumulative + * @param boolean $isRemovingPostage Is removing Postage + * @param int $maxUsage Coupon quantity + * @param CouponRuleCollection $rules CouponRuleInterface to add + * @param string $locale Coupon Language code ISO (ex: fr_FR) + */ + function __construct( + $code, + $title, + $amount, + $effect, + $shortDescription, + $description, + $isEnabled, + \DateTime $expirationDate, + $isAvailableOnSpecialOffers, + $isCumulative, + $isRemovingPostage, + $maxUsage, + $rules, + $locale + ) { + $this->amount = $amount; + $this->code = $code; + $this->description = $description; + $this->expirationDate = $expirationDate; + $this->isAvailableOnSpecialOffers = $isAvailableOnSpecialOffers; + $this->isCumulative = $isCumulative; + $this->isEnabled = $isEnabled; + $this->isRemovingPostage = $isRemovingPostage; + $this->maxUsage = $maxUsage; + $this->rules = $rules; + $this->shortDescription = $shortDescription; + $this->title = $title; + $this->effect = $effect; + $this->locale = $locale; + } + + /** + * Return Coupon code (ex: XMAS) + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * Return Coupon title (ex: Coupon for XMAS) + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Return Coupon short description + * + * @return string + */ + public function getShortDescription() + { + return $this->shortDescription; + } + + /** + * Return Coupon description + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * If Coupon is cumulative or prevent any accumulation + * If is cumulative you can sum Coupon effects + * If not cancel all other Coupon and take the last given + * + * @return bool + */ + public function isCumulative() + { + return $this->isCumulative; + } + + /** + * If Coupon is removing Checkout Postage + * + * @return bool + */ + public function isRemovingPostage() + { + return $this->isRemovingPostage; + } + + /** + * Return effects generated by the coupon + * + * @return float Amount removed from the Total Checkout + */ + public function getAmount() + { + return $this->amount; + } + + /** + * Return condition to validate the Coupon or not + * + * @return CouponRuleCollection + */ + public function getRules() + { + if ($this->rules === null || !is_object($this->rules)) { + $rules = $this->rules; + } else { + $rules = clone $this->rules; + } + + return $rules; + } + + /** + * Return Coupon expiration date + * + * @return \DateTime + */ + public function getExpirationDate() + { + return clone $this->expirationDate; + } + + /** + * If Coupon is available on special offers + * + * @return boolean + */ + public function isAvailableOnSpecialOffers() + { + return $this->isAvailableOnSpecialOffers; + } + + /** + * Get if Coupon is enabled or not + * + * @return boolean + */ + public function isEnabled() + { + return $this->isEnabled; + } + + /** + * Return how many time the Coupon can be used again + * Ex : -1 unlimited + * + * @return int + */ + public function getMaxUsage() + { + return $this->maxUsage; + } + + /** + * Get Coupon effect + * + * @return string + */ + public function getEffect() + { + return $this->effect; + } + + /** + * Coupon Language code ISO (ex: fr_FR) + * + * @return string + */ + public function getLocale() + { + return $this->locale; + } + + /** + * Set Coupon Model + * + * @param \Thelia\Model\Coupon $coupon Coupon Model + * + * @return $this + */ + public function setCoupon($coupon) + { + $this->coupon = $coupon; + + return $this; + } + + /** + * Return Coupon Model + * + * @return \Thelia\Model\Coupon + */ + public function getCoupon() + { + return $this->coupon; + } + + + +} diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php new file mode 100644 index 000000000..db8e14243 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Coupon/CouponDisableEvent.php @@ -0,0 +1,103 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\Event\Coupon; +use Thelia\Model\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/29/13 + * Time: 3:45 PM + * + * Occurring when a Coupon is disabled + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponDisableEvent extends ActionEvent +{ + /** @var int Coupon id */ + protected $couponId; + + /** @var Coupon Coupon being disabled */ + protected $disabledCoupon; + + /** + * Constructor + * + * @param int $id Coupon Id + */ + public function __construct($id) + { + $this->id = $id; + } + + /** + * Get Coupon id + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Set Coupon id + * + * @param int $id Coupon id + * + * @return $this + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * Get Coupon being disabled + * + * @return Coupon + */ + public function getDisabledCoupon() + { + return $this->disabledCoupon; + } + + /** + * Set Coupon to be disabled + * + * @param Coupon $disabledCoupon Coupon to disable + * + * @return $this + */ + public function setDisabledCoupon(Coupon $disabledCoupon) + { + $this->disabledCoupon = $disabledCoupon; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php b/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php new file mode 100644 index 000000000..ab06953e5 --- /dev/null +++ b/core/lib/Thelia/Core/Event/Coupon/CouponEnableEvent.php @@ -0,0 +1,103 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\Event\Coupon; +use Thelia\Model\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/29/13 + * Time: 3:45 PM + * + * Occurring when a Coupon is enabled + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponEnableEvent extends ActionEvent +{ + /** @var int Coupon id */ + protected $couponId; + + /** @var Coupon Coupon being enabled */ + protected $enabledCoupon; + + /** + * Constructor + * + * @param int $id Coupon Id + */ + public function __construct($id) + { + $this->id = $id; + } + + /** + * Get Coupon id + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Set Coupon id + * + * @param int $id Coupon id + * + * @return $this + */ + public function setId($id) + { + $this->id = $id; + + return $this; + } + + /** + * Get Coupon being enabled + * + * @return Coupon + */ + public function getEnabledCoupon() + { + return $this->enabledCoupon; + } + + /** + * Set Coupon to be enabled + * + * @param Coupon $enabledCoupon Coupon to enabled + * + * @return $this + */ + public function setEnabledCoupon(Coupon $enabledCoupon) + { + $this->enabledCoupon = $enabledCoupon; + + return $this; + } +} diff --git a/core/lib/Thelia/Core/Event/TheliaEvents.php b/core/lib/Thelia/Core/Event/TheliaEvents.php index 1efd6c4d2..500803f53 100755 --- a/core/lib/Thelia/Core/Event/TheliaEvents.php +++ b/core/lib/Thelia/Core/Event/TheliaEvents.php @@ -204,6 +204,114 @@ final class TheliaEvents */ const IMAGE_CLEAR_CACHE = "action.clearImageCache"; + + + /** + * Sent when creating a Coupon + */ + const COUPON_CREATE = "action.create_coupon"; + + /** + * Sent just before a successful insert of a new Coupon in the database. + */ + const BEFORE_CREATE_COUPON = "action.before_create_coupon"; + + /** + * Sent just after a successful insert of a new Coupon in the database. + */ + const AFTER_CREATE_COUPON = "action.after_create_coupon"; + + /** + * Sent when editing a Coupon + */ + const COUPON_UPDATE = "action.update_coupon"; + + /** + * Sent just before a successful update of a new Coupon in the database. + */ + const BEFORE_UPDATE_COUPON = "action.before_update_coupon"; + + /** + * Sent just after a successful update of a new Coupon in the database. + */ + const AFTER_UPDATE_COUPON = "action.after_update_coupon"; + + /** + * Sent when disabling a Coupon + */ + const COUPON_DISABLE = "action.disable_coupon"; + + /** + * Sent just before a successful disable of a new Coupon in the database. + */ + const BEFORE_DISABLE_COUPON = "action.before_disable_coupon"; + + /** + * Sent just after a successful disable of a new Coupon in the database. + */ + const AFTER_DISABLE_COUPON = "action.after_disable_coupon"; + + /** + * Sent when enabling a Coupon + */ + const COUPON_ENABLE = "action.enable_coupon"; + + /** + * Sent just before a successful enable of a new Coupon in the database. + */ + const BEFORE_ENABLE_COUPON = "action.before_enable_coupon"; + + /** + * Sent just after a successful enable of a new Coupon in the database. + */ + const AFTER_ENABLE_COUPON = "action.after_enable_coupon"; + + /** + * Sent when attempting to use a Coupon + */ + const COUPON_CONSUME = "action.consume_coupon"; + + /** + * Sent just before an attempt to use a Coupon + */ + const BEFORE_CONSUME_COUPON = "action.before_consume_coupon"; + + /** + * Sent just after an attempt to use a Coupon + */ + const AFTER_CONSUME_COUPON = "action.after_consume_coupon"; + + /** + * Sent when attempting to update Coupon Rule + */ + const COUPON_RULE_UPDATE = "action.update_coupon_rule"; + + /** + * Sent just before an attempt to update a Coupon Rule + */ + const BEFORE_COUPON_RULE_UPDATE = "action.before_update_coupon_rule"; + + /** + * Sent just after an attempt to update a Coupon Rule + */ + const AFTER_COUPON_RULE_UPDATE = "action.after_update_coupon_rule"; + + /** + * Sent when attempting to delete Coupon Rule + */ + const COUPON_RULE_DELETE = "action.delete_coupon_rule"; + + /** + * Sent just before an attempt to delete a Coupon Rule + */ + const BEFORE_COUPON_RULE_DELETE = "action.before_delete_coupon_rule"; + + /** + * Sent just after an attempt to delete a Coupon Rule + */ + const AFTER_COUPON_RULE_DELETE = "action.after_delete_coupon_rule"; + + // -- Configuration management --------------------------------------------- const CONFIG_CREATE = "action.createConfig"; diff --git a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php index 8c6a241ec..fc2726647 100755 --- a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php +++ b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php @@ -28,6 +28,7 @@ use Thelia\Core\Security\User\UserInterface; use Thelia\Exception\InvalidCartException; use Thelia\Model\CartQuery; use Thelia\Model\Cart; +use Thelia\Model\Currency; use Thelia\Tools\URL; use Thelia\Model\Lang; @@ -44,9 +45,9 @@ class Session extends BaseSession /** * @return \Thelia\Model\Lang|null */ - public function getLang() + public function getLang($forceDefault = true) { - return $this->get("thelia.current.lang", Lang::getDefaultLanguage()); + return $this->get("thelia.current.lang", $forceDefault ? Lang::getDefaultLanguage():null); } public function setLang(Lang $lang) @@ -68,6 +69,16 @@ class Session extends BaseSession return $this; } + public function setCurrency(Currency $currency) + { + $this->set("thelia.current.currency", $currency); + } + + public function getCurrency($forceDefault = true) + { + return $this->get("thelia.current.currency", $forceDefault ? Currency::getDefaultCurrency():null); + } + // -- Customer user -------------------------------------------------------- public function setCustomerUser(UserInterface $user) diff --git a/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php b/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php index 18eadce3c..792389b1c 100644 --- a/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseI18nLoop.php @@ -59,11 +59,12 @@ abstract class BaseI18nLoop extends BaseLoop * @param array $columns the i18n columns * @param string $foreignTable the specified table (default to criteria table) * @param string $foreignKey the foreign key in this table (default to criteria table) + * @param bool $forceReturn * * @return mixed the locale */ - protected function configureI18nProcessing(ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false) { - + protected function configureI18nProcessing(ModelCriteria $search, $columns = array('TITLE', 'CHAPO', 'DESCRIPTION', 'POSTSCRIPTUM'), $foreignTable = null, $foreignKey = 'ID', $forceReturn = false) + { /* manage translations */ return ModelCriteriaTools::getI18n( $this->getBackend_context(), diff --git a/core/lib/Thelia/Core/Template/Element/BaseLoop.php b/core/lib/Thelia/Core/Template/Element/BaseLoop.php index d74f9894b..209973112 100755 --- a/core/lib/Thelia/Core/Template/Element/BaseLoop.php +++ b/core/lib/Thelia/Core/Template/Element/BaseLoop.php @@ -23,6 +23,7 @@ namespace Thelia\Core\Template\Element; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Thelia\Core\Template\Loop\Argument\Argument; @@ -52,6 +53,9 @@ abstract class BaseLoop */ protected $securityContext; + /** @var ContainerInterface Service Container */ + protected $container = null; + protected $args; public $countable = true; @@ -61,15 +65,15 @@ abstract class BaseLoop /** * Create a new Loop * - * @param Request $request - * @param EventDispatcherInterface $dispatcher - * @param SecurityContext $securityContext + * @param ContainerInterface $container */ - public function __construct(Request $request, EventDispatcherInterface $dispatcher, SecurityContext $securityContext) + public function __construct(ContainerInterface $container) { - $this->request = $request; - $this->dispatcher = $dispatcher; - $this->securityContext = $securityContext; + $this->container = $container; + + $this->request = $container->get('request'); + $this->dispatcher = $container->get('event_dispatcher'); + $this->securityContext = $container->get('thelia.securityContext'); $this->args = $this->getArgDefinitions()->addArguments($this->getDefaultArgs(), false); } diff --git a/core/lib/Thelia/Core/Template/Loop/Address.php b/core/lib/Thelia/Core/Template/Loop/Address.php index 757cc11b8..3ac9370f8 100755 --- a/core/lib/Thelia/Core/Template/Loop/Address.php +++ b/core/lib/Thelia/Core/Template/Loop/Address.php @@ -87,7 +87,7 @@ class Address extends BaseLoop $customer = $this->getCustomer(); if ($customer === 'current') { - $currentCustomer = $this->request->getSession()->getCustomerUser(); + $currentCustomer = $this->securityContext->getCustomerUser(); if ($currentCustomer === null) { return new LoopResult(); } else { diff --git a/core/lib/Thelia/Core/Template/Loop/Coupon.php b/core/lib/Thelia/Core/Template/Loop/Coupon.php new file mode 100755 index 000000000..9b3ebb615 --- /dev/null +++ b/core/lib/Thelia/Core/Template/Loop/Coupon.php @@ -0,0 +1,130 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Core\Template\Loop; + +use Propel\Runtime\ActiveQuery\Criteria; +use Thelia\Constraint\ConstraintFactory; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\Template\Element\BaseI18nLoop; +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\Model\Base\CategoryQuery; +use Thelia\Model\ConfigQuery; +use Thelia\Model\CouponQuery; +use Thelia\Model\Coupon as MCoupon; +use Thelia\Model\Map\ProductCategoryTableMap; +use Thelia\Type; +use Thelia\Type\BooleanOrBothType; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Coupon Loop + * + * @package Thelia\Core\Template\Loop + * @author Guillaume MOREL + * + */ +class Coupon extends BaseI18nLoop +{ + /** + * @return ArgumentCollection + */ + protected function getArgDefinitions() + { + return new ArgumentCollection( + Argument::createIntListTypeArgument('id') + ); + } + + /** + * @param $pagination + * + * @return \Thelia\Core\Template\Element\LoopResult + */ + public function exec(&$pagination) + { + $search = CouponQuery::create(); + + /* manage translations */ + $locale = $this->configureI18nProcessing($search, array('TITLE', 'DESCRIPTION', 'SHORT_DESCRIPTION')); + + $id = $this->getId(); + + if (null !== $id) { + $search->filterById($id, Criteria::IN); + } + + // Perform search + $coupons = $this->search($search, $pagination); + + $loopResult = new LoopResult(); + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + + /** @var Request $request */ + $request = $this->container->get('request'); + /** @var Lang $lang */ + $lang = $request->getSession()->getLang(); + + + /** @var MCoupon $coupon */ + foreach ($coupons as $coupon) { + $loopResultRow = new LoopResultRow(); + $rules = $constraintFactory->unserializeCouponRuleCollection( + $coupon->getSerializedRules() + ); + + $cleanedRules = array(); + /** @var CouponRuleInterface $rule */ + foreach ($rules->getRules() as $key => $rule) { + $cleanedRules[] = $rule->getToolTip(); + } + $loopResultRow->set("ID", $coupon->getId()) + ->set("IS_TRANSLATED", $coupon->getVirtualColumn('IS_TRANSLATED')) + ->set("LOCALE", $locale) + ->set("CODE", $coupon->getCode()) + ->set("TITLE", $coupon->getVirtualColumn('i18n_TITLE')) + ->set("SHORT_DESCRIPTION", $coupon->getVirtualColumn('i18n_SHORT_DESCRIPTION')) + ->set("DESCRIPTION", $coupon->getVirtualColumn('i18n_DESCRIPTION')) + ->set("EXPIRATION_DATE", $coupon->getExpirationDate($lang->getDateFormat())) + ->set("USAGE_LEFT", $coupon->getMaxUsage()) + ->set("IS_CUMULATIVE", $coupon->getIsCumulative()) + ->set("IS_REMOVING_POSTAGE", $coupon->getIsRemovingPostage()) + ->set("IS_ENABLED", $coupon->getIsEnabled()) + ->set("AMOUNT", $coupon->getAmount()) + ->set("APPLICATION_CONDITIONS", $cleanedRules); + $loopResult->addRow($loopResultRow); + } + + return $loopResult; + } +} diff --git a/core/lib/Thelia/Core/Template/Loop/Customer.php b/core/lib/Thelia/Core/Template/Loop/Customer.php index 1a4b84105..9861be29a 100755 --- a/core/lib/Thelia/Core/Template/Loop/Customer.php +++ b/core/lib/Thelia/Core/Template/Loop/Customer.php @@ -64,6 +64,7 @@ class Customer extends BaseLoop ) ), Argument::createBooleanTypeArgument('reseller'), + Argument::createBooleanTypeArgument('last_order'), Argument::createIntTypeArgument('sponsor') ); } @@ -80,7 +81,7 @@ class Customer extends BaseLoop $current = $this->getCurrent(); if ($current === true) { - $currentCustomer = $this->request->getSession()->getCustomerUser(); + $currentCustomer = $this->securityContext->getCustomerUser(); if ($currentCustomer === null) { return new LoopResult(); } else { @@ -130,6 +131,20 @@ class Customer extends BaseLoop $loopResultRow->set("SPONSOR", $customer->getSponsor()); $loopResultRow->set("DISCOUNT", $customer->getDiscount()); + $lastOrderDate = ""; + $lastOrderAmount = ""; + + if ($this->getLastOrder()) { + $order = $customer->getOrders()->getFirst(); + if ($order) { + $lastOrderDate = $order->getCreatedAt(); + $lastOrderAmount = $order->getTotalAmount(); + } + } + + $loopResultRow->set("LASTORDER_DATE", $lastOrderDate); + $loopResultRow->set("LASTORDER_AMOUNT", $lastOrderAmount); + $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Loop/Product.php b/core/lib/Thelia/Core/Template/Loop/Product.php index 4d785b8b0..b7a7c13fe 100755 --- a/core/lib/Thelia/Core/Template/Loop/Product.php +++ b/core/lib/Thelia/Core/Template/Loop/Product.php @@ -34,6 +34,7 @@ use Thelia\Core\Template\Loop\Argument\Argument; use Thelia\Log\Tlog; use Thelia\Model\CategoryQuery; +use Thelia\Model\CountryQuery; use Thelia\Model\Map\FeatureProductTableMap; use Thelia\Model\Map\ProductPriceTableMap; use Thelia\Model\Map\ProductSaleElementsTableMap; @@ -333,10 +334,10 @@ class Product extends BaseI18nLoop foreach($isProductPriceLeftJoinList as $pSE => $isProductPriceLeftJoin) { $booleanMatchedPriceList[] = 'CASE WHEN `' . $pSE . '`.PROMO=1 THEN `' . $isProductPriceLeftJoin . '`.PROMO_PRICE ELSE `' . $isProductPriceLeftJoin . '`.PRICE END'; } - $search->withColumn('MAX(' . implode(' OR ', $booleanMatchedPromoList) . ')', 'main_product_is_promo'); - $search->withColumn('MAX(' . implode(' OR ', $booleanMatchedNewnessList) . ')', 'main_product_is_new'); - $search->withColumn('MAX(' . implode(' OR ', $booleanMatchedPriceList) . ')', 'real_highest_price'); - $search->withColumn('MIN(' . implode(' OR ', $booleanMatchedPriceList) . ')', 'real_lowest_price'); + $search->withColumn('ROUND(MAX(' . implode(' OR ', $booleanMatchedPromoList) . '), 2)', 'main_product_is_promo'); + $search->withColumn('ROUND(MAX(' . implode(' OR ', $booleanMatchedNewnessList) . '), 2)', 'main_product_is_new'); + $search->withColumn('ROUND(MAX(' . implode(' OR ', $booleanMatchedPriceList) . '), 2)', 'real_highest_price'); + $search->withColumn('ROUND(MIN(' . implode(' OR ', $booleanMatchedPriceList) . '), 2)', 'real_lowest_price'); $current = $this->getCurrent(); @@ -509,6 +510,12 @@ class Product extends BaseI18nLoop foreach ($products as $product) { $loopResultRow = new LoopResultRow($loopResult, $product, $this->versionable, $this->timestampable, $this->countable); + $price = $product->getRealLowestPrice(); + $taxedPrice = $product->getTaxedPrice( + CountryQuery::create()->findOneById(64) // @TODO : make it magic + ); + + $loopResultRow->set("ID", $product->getId()) ->set("REF",$product->getRef()) ->set("IS_TRANSLATED",$product->getVirtualColumn('IS_TRANSLATED')) @@ -518,7 +525,9 @@ class Product extends BaseI18nLoop ->set("DESCRIPTION", $product->getVirtualColumn('i18n_DESCRIPTION')) ->set("POSTSCRIPTUM", $product->getVirtualColumn('i18n_POSTSCRIPTUM')) ->set("URL", $product->getUrl($locale)) - ->set("BEST_PRICE", $product->getVirtualColumn('real_lowest_price')) + ->set("BEST_PRICE", $price) + ->set("BEST_PRICE_TAX", $taxedPrice - $price) + ->set("BEST_TAXED_PRICE", $taxedPrice) ->set("IS_PROMO", $product->getVirtualColumn('main_product_is_promo')) ->set("IS_NEW", $product->getVirtualColumn('main_product_is_new')) ->set("POSITION", $product->getPosition()) diff --git a/core/lib/Thelia/Core/Template/Loop/ProductSaleElement.php b/core/lib/Thelia/Core/Template/Loop/ProductSaleElements.php similarity index 87% rename from core/lib/Thelia/Core/Template/Loop/ProductSaleElement.php rename to core/lib/Thelia/Core/Template/Loop/ProductSaleElements.php index 7a1a0b8c8..ec4c73230 100755 --- a/core/lib/Thelia/Core/Template/Loop/ProductSaleElement.php +++ b/core/lib/Thelia/Core/Template/Loop/ProductSaleElements.php @@ -35,6 +35,7 @@ use Thelia\Log\Tlog; use Thelia\Model\Base\ProductSaleElementsQuery; use Thelia\Model\ConfigQuery; +use Thelia\Model\CountryQuery; use Thelia\Type\TypeCollection; use Thelia\Type; @@ -124,6 +125,15 @@ class ProductSaleElements extends BaseLoop foreach ($PSEValues as $PSEValue) { $loopResultRow = new LoopResultRow($loopResult, $PSEValue, $this->versionable, $this->timestampable, $this->countable); + $price = $PSEValue->getPrice(); + $taxedPrice = $PSEValue->getTaxedPrice( + CountryQuery::create()->findOneById(64) // @TODO : make it magic + ); + $promoPrice = $PSEValue->getPromoPrice(); + $taxedPromoPrice = $PSEValue->getTaxedPromoPrice( + CountryQuery::create()->findOneById(64) // @TODO : make it magic + ); + $loopResultRow->set("ID", $PSEValue->getId()) ->set("QUANTITY", $PSEValue->getQuantity()) ->set("IS_PROMO", $PSEValue->getPromo() === 1 ? 1 : 0) @@ -131,8 +141,12 @@ class ProductSaleElements extends BaseLoop ->set("WEIGHT", $PSEValue->getWeight()) ->set("CURRENCY", $PSEValue->getVirtualColumn('price_CURRENCY_ID')) - ->set("PRICE", $PSEValue->getVirtualColumn('price_PRICE')) - ->set("PROMO_PRICE", $PSEValue->getVirtualColumn('price_PROMO_PRICE')); + ->set("PRICE", $price) + ->set("PRICE_TAX", $taxedPrice - $price) + ->set("TAXED_PRICE", $taxedPrice) + ->set("PROMO_PRICE", $promoPrice) + ->set("PROMO_PRICE_TAX", $taxedPromoPrice - $promoPrice) + ->set("TAXED_PROMO_PRICE", $taxedPromoPrice); $loopResult->addRow($loopResultRow); } diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php index 1fdb6e4bf..fded12c0e 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/DataAccessFunctions.php @@ -31,6 +31,7 @@ use Thelia\Core\Template\ParserContext; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; use Thelia\Model\CategoryQuery; use Thelia\Model\ContentQuery; +use Thelia\Model\CurrencyQuery; use Thelia\Model\FolderQuery; use Thelia\Model\Product; use Thelia\Model\ProductQuery; @@ -132,6 +133,35 @@ class DataAccessFunctions extends AbstractSmartyPlugin } } + /** + * currency global data + * + * @param $params + * @param $smarty + */ + public function currencyDataAccess($params, $smarty) + { + $currency = $this->request->getSession()->getCurrency(); + + if ($currency) { + $currencyQuery = CurrencyQuery::create() + ->filterById($currency->getId()); + + return $this->dataAccessWithI18n("Currency", $params, $currencyQuery, array("NAME")); + } + } + + /** + * Lang global data + * + * @param $params + * @param $smarty + */ + public function langDataAccess($params, $smarty) + { + return $this->dataAccess("Lang", $params, $this->request->getSession()->getLang()); + } + /** * @param $objectLabel * @param $params @@ -231,6 +261,8 @@ class DataAccessFunctions extends AbstractSmartyPlugin new SmartyPluginDescriptor('function', 'category', $this, 'categoryDataAccess'), new SmartyPluginDescriptor('function', 'content', $this, 'contentDataAccess'), new SmartyPluginDescriptor('function', 'folder', $this, 'folderDataAccess'), + new SmartyPluginDescriptor('function', 'currency', $this, 'currencyDataAccess'), + new SmartyPluginDescriptor('function', 'lang', $this, 'langDataAccess'), ); } } diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php index 0b22111cd..625c89e1f 100755 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Form.php @@ -120,8 +120,15 @@ class Form extends AbstractSmartyPlugin $formFieldView = $this->getFormFieldView($params); $template->assign("options", $formFieldView->vars); + $template->assign("name", $formFieldView->vars["full_name"]); $template->assign("value", $formFieldView->vars["value"]); + + // If Checkbox input type + if ($formFieldView->vars['checked'] !== null) { + $this->renderFormFieldCheckBox($template, $formFieldView); + } + $template->assign("label", $formFieldView->vars["label"]); $template->assign("label_attr", $formFieldView->vars["label_attr"]); @@ -266,4 +273,17 @@ class Form extends AbstractSmartyPlugin new SmartyPluginDescriptor("block", "form_error", $this, "formError") ); } + + /** + * @param \Smarty_Internal_Template $template + * @param $formFieldView + */ + public function renderFormFieldCheckBox(\Smarty_Internal_Template $template, $formFieldView) + { + $template->assign("value", 0); + if ($formFieldView->vars['checked']) { + $template->assign("value", 1); + } + $template->assign("value", $formFieldView->vars['checked']); + } } diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php index daaff3fc1..3deffc1aa 100644 --- a/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php +++ b/core/lib/Thelia/Core/Template/Smarty/Plugins/Format.php @@ -113,9 +113,15 @@ class Format extends AbstractSmartyPlugin throw new SmartyPluginException("number is a mandatory parameter in format_number function"); } + $number = $params["number"]; + + if(empty($number)) { + return ""; + } + $lang = $this->request->getSession()->getLang(); - $number = $params["number"]; + $decimals = array_key_exists("decimals", $params) ? $params["decimals"] : $lang->getDecimals(); $decPoint = array_key_exists("dec_point", $params) ? $params["dec_point"] : $lang->getDecimalSeparator(); $thousandsSep = array_key_exists("thousands_sep", $params) ? $params["thousands_sep"] : $lang->getThousandsSeparator(); diff --git a/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php b/core/lib/Thelia/Core/Template/Smarty/Plugins/TheliaLoop.php index e9c91b7df..2c7601dc4 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 Symfony\Component\DependencyInjection\ContainerInterface; use Thelia\Core\Template\Element\BaseLoop; use Thelia\Core\Template\Smarty\AbstractSmartyPlugin; use Thelia\Core\Template\Smarty\SmartyPluginDescriptor; @@ -44,14 +45,22 @@ class TheliaLoop extends AbstractSmartyPlugin protected $dispatcher; protected $securityContext; + /** @var ContainerInterface Service Container */ + protected $container = null; + protected $loopstack = array(); protected $varstack = array(); - public function __construct(Request $request, EventDispatcherInterface $dispatcher, SecurityContext $securityContext) + /** + * @param ContainerInterface $container + */ + public function __construct(ContainerInterface $container) { - $this->request = $request; - $this->dispatcher = $dispatcher; - $this->securityContext = $securityContext; + $this->container = $container; + + $this->request = $container->get('request'); + $this->dispatcher = $container->get('event_dispatcher'); + $this->securityContext = $container->get('thelia.securityContext'); } /** @@ -315,9 +324,7 @@ class TheliaLoop extends AbstractSmartyPlugin } $loop = $class->newInstance( - $this->request, - $this->dispatcher, - $this->securityContext + $this->container ); $loop->initializeArgs($smartyParams); diff --git a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php index 85619bc8a..30144a263 100755 --- a/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php +++ b/core/lib/Thelia/Core/Template/Smarty/SmartyParser.php @@ -65,9 +65,7 @@ class SmartyParser extends Smarty implements ParserInterface $this->setTemplate($template ?: ConfigQuery::read('active-template', 'default')); $this->debugging = $debug; - - $this->escape_html = true; - + // Prevent smarty ErrorException: Notice: Undefined index bla bla bla... $this->error_reporting = E_ALL ^ E_NOTICE; @@ -86,12 +84,13 @@ class SmartyParser extends Smarty implements ParserInterface $this->registerFilter('pre', array($this, "preThelia")); $this->registerFilter('output', array($this, "removeBlankLines")); + $this->registerFilter('variable', array(__CLASS__, "theliaEscape")); } public function preThelia($tpl_source, \Smarty_Internal_Template $template) { - $new_source = preg_replace('`{#([a-zA-Z][a-zA-Z0-9\-_]*)(.*)}`', '{\$$1$2}', $tpl_source); - $new_source = preg_replace('`#([a-zA-Z][a-zA-Z0-9\-_]*)`', '{\$$1|dieseCanceller:\'#$1\'}', $new_source); + $new_source = preg_replace('`{#([a-zA-Z][a-zA-Z0-9_]*)(.*)}`', '{\$$1$2}', $tpl_source); + $new_source = preg_replace('`#([a-zA-Z][a-zA-Z0-9_]*)`', '{\$$1|dieseCanceller:\'#$1\'}', $new_source); return $new_source; } @@ -101,6 +100,15 @@ class SmartyParser extends Smarty implements ParserInterface return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $tpl_source); } + public static function theliaEscape($content, $smarty) + { + if(is_scalar($content)) { + return htmlspecialchars($content ,ENT_QUOTES, Smarty::$_CHARSET); + } else { + return $content; + } + } + public function setTemplate($template_path_from_template_base) { $this->template = $template_path_from_template_base; diff --git a/core/lib/Thelia/Core/TheliaHttpKernel.php b/core/lib/Thelia/Core/TheliaHttpKernel.php index 3c0f14808..319173f5f 100755 --- a/core/lib/Thelia/Core/TheliaHttpKernel.php +++ b/core/lib/Thelia/Core/TheliaHttpKernel.php @@ -135,9 +135,26 @@ class TheliaHttpKernel extends HttpKernel if ($lang) { $request->getSession() ->setLang($lang) - ->setLocale($lang->getLocale()) ; } + + $request->getSession()->setCurrency($this->defineCurrency($request)); + } + + protected function defineCurrency(Request $request) + { + $currency = null; + if ($request->query->has("currency")) { + $currency = Model\CurrencyQuery::create()->findOneByCode($request->query->get("currency")); + } else { + $currency = $request->getSession()->getCurrency(false); + } + + if(null === $currency) { + $currency = Model\Currency::getDefaultCurrency(); + } + + return $currency; } /** @@ -153,7 +170,7 @@ class TheliaHttpKernel extends HttpKernel $lang = Model\LangQuery::create()->findOneByCode($request->query->get("lang")); if (is_null($lang)) { - return; + return Model\Lang::getDefaultLanguage(); } //if each lang had is own domain, we redirect the user to the good one. @@ -175,7 +192,7 @@ class TheliaHttpKernel extends HttpKernel } //check if lang is not defined. If not we have to search the good one. - if (null === $request->getSession()->getLang()) { + if (null === $request->getSession()->getLang(false)) { if (Model\ConfigQuery::read("one_domain_foreach_lang", false) == 1) { //find lang with domain @@ -183,7 +200,7 @@ class TheliaHttpKernel extends HttpKernel } //find default lang - return Model\LangQuery::create()->findOneByByDefault(1); + return Model\Lang::getDefaultLanguage(); } } diff --git a/core/lib/Thelia/Core/Translation/Translator.php b/core/lib/Thelia/Core/Translation/Translator.php index d941fefb7..770091403 100755 --- a/core/lib/Thelia/Core/Translation/Translator.php +++ b/core/lib/Thelia/Core/Translation/Translator.php @@ -20,7 +20,7 @@ class Translator extends BaseTranslator * Return this class instance, only once instanciated. * * @throws \RuntimeException if the class has not been instanciated. - * @return Thelia\Core\Translation\Translator the instance. + * @return \Thelia\Core\Translation\Translator the instance. */ public static function getInstance() { if (self::$instance == null) throw new \RuntimeException("Translator instance is not initialized."); diff --git a/core/lib/Thelia/Coupon/CouponAdapterInterface.php b/core/lib/Thelia/Coupon/CouponAdapterInterface.php new file mode 100644 index 000000000..134d061be --- /dev/null +++ b/core/lib/Thelia/Coupon/CouponAdapterInterface.php @@ -0,0 +1,158 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Translation\Translator; +use Symfony\Component\Translation\TranslatorInterface; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Model\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Allow a CouponManager class to be fed with relevant Thelia data + * + * @package Coupon + * @author Guillaume MOREL + * + */ +interface CouponAdapterInterface +{ + + /** + * Constructor + * + * @param ContainerInterface $container Service container + */ + function __construct(ContainerInterface $container); + + /** + * Return a Cart a CouponManager can process + * + * @return \Thelia\Model\Cart + */ + public function getCart(); + + /** + * Return an Address a CouponManager can process + * + * @return \Thelia\Model\Address + */ + public function getDeliveryAddress(); + + /** + * Return an Customer a CouponManager can process + * + * @return \Thelia\Model\Customer + */ + public function getCustomer(); + + /** + * Return Checkout total price + * + * @return float + */ + public function getCheckoutTotalPrice(); + + /** + * Return Products total price + * CartTotalPrice = Checkout total - discount - postage + * + * @return float + */ + public function getCartTotalPrice(); + + /** + * Return the Checkout currency EUR|USD + * + * @return string + */ + public function getCheckoutCurrency(); + + /** + * Return Checkout total postage (only) price + * + * @return float + */ + public function getCheckoutPostagePrice(); + + /** + * Return the number of Products in the Cart + * + * @return int + */ + public function getNbArticlesInCart(); + + /** + * Return all Coupon given during the Checkout + * + * @return array Array of CouponInterface + */ + public function getCurrentCoupons(); + + /** + * Find one Coupon in the database from its code + * + * @param string $code Coupon code + * + * @return Coupon + */ + public function findOneCouponByCode($code); + + /** + * Save a Coupon in the database + * + * @param CouponInterface $coupon Coupon + * + * @return $this + */ + public function saveCoupon(CouponInterface $coupon); + + /** + * Return platform Container + * + * @return Container + */ + public function getContainer(); + + /** + * Return platform TranslatorInterface + * + * @return TranslatorInterface + */ + public function getTranslator(); + + /** + * Return the main currency + * THe one used to set prices in BackOffice + * + * @return string + */ + public function getMainCurrency(); + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/CouponBaseAdapter.php b/core/lib/Thelia/Coupon/CouponBaseAdapter.php new file mode 100644 index 000000000..3e77a56be --- /dev/null +++ b/core/lib/Thelia/Coupon/CouponBaseAdapter.php @@ -0,0 +1,235 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Translation\Translator; +use Symfony\Component\Translation\TranslatorInterface; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Model\Coupon; +use Thelia\Model\CouponQuery; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * @todo implements + * + */ +class CouponBaseAdapter implements CouponAdapterInterface +{ + /** @var ContainerInterface Service Container */ + protected $container = null; + + /** @var Translator Service Translator */ + protected $translator = null; + + /** + * Constructor + * + * @param ContainerInterface $container Service container + */ + function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * Return a Cart a CouponManager can process + * + * @return \Thelia\Model\Cart + */ + public function getCart() + { + // TODO: Implement getCart() method. + } + + /** + * Return an Address a CouponManager can process + * + * @return \Thelia\Model\Address + */ + public function getDeliveryAddress() + { + // TODO: Implement getDeliveryAddress() method. + } + + /** + * Return an Customer a CouponManager can process + * + * @return \Thelia\Model\Customer + */ + public function getCustomer() + { + // TODO: Implement getCustomer() method. + } + + /** + * Return Checkout total price + * + * @return float + */ + public function getCheckoutTotalPrice() + { + // TODO: Implement getCheckoutTotalPrice() method. + } + + /** + * Return Checkout total postage (only) price + * + * @return float + */ + public function getCheckoutPostagePrice() + { + // TODO: Implement getCheckoutPostagePrice() method. + } + + /** + * Return Products total price + * + * @return float + */ + public function getCartTotalPrice() + { + // TODO: Implement getCartTotalPrice() method. + } + + /** + * Return the Checkout currency EUR|USD + * + * @return string + */ + public function getCheckoutCurrency() + { + // TODO: Implement getCheckoutCurrency() method. + } + + + /** + * Return the number of Products in the Cart + * + * @return int + */ + public function getNbArticlesInCart() + { + // TODO: Implement getNbArticlesInCart() method. + } + + /** + * Return all Coupon given during the Checkout + * + * @return array Array of CouponInterface + */ + public function getCurrentCoupons() + { + $couponFactory = $this->container->get('thelia.coupon.factory'); + + // @todo Get from Session + $couponCodes = array('XMAS', 'SPRINGBREAK'); + + $coupons = array(); + foreach ($couponCodes as $couponCode) { + $coupons[] = $couponFactory->buildCouponFromCode($couponCode); + } + + return $coupons; + } + + /** + * Find one Coupon in the database from its code + * + * @param string $code Coupon code + * + * @return Coupon + */ + public function findOneCouponByCode($code) + { + $couponQuery = CouponQuery::create(); + + return $couponQuery->findOneByCode($code); + } + + /** + * Save a Coupon in the database + * + * @param CouponInterface $coupon Coupon + * + * @return $this + */ + public function saveCoupon(CouponInterface $coupon) + { +// $couponModel = new Coupon(); +// $couponModel->setCode($coupon->getCode()); +// $couponModel->setType(get_class($coupon)); +// $couponModel->setTitle($coupon->getTitle()); +// $couponModel->setShortDescription($coupon->getShortDescription()); +// $couponModel->setDescription($coupon->getDescription()); +// $couponModel->setAmount($coupon->getDiscount()); +// $couponModel->setIsUsed(0); +// $couponModel->setIsEnabled(1); +// $couponModel->set +// $couponModel->set +// $couponModel->set +// $couponModel->set +// $couponModel->set +// $couponModel->set +// $couponModel->set + } + + /** + * Return plateform Container + * + * @return Container + */ + public function getContainer() + { + // TODO: Implement getContainer() method. + } + + /** + * Return platform TranslatorInterface + * + * @return TranslatorInterface + */ + public function getTranslator() + { + return $this->container->get('thelia.translator'); + } + + + /** + * Return the main currency + * THe one used to set prices in BackOffice + * + * @return string + */ + public function getMainCurrency() + { + // TODO: Implement getMainCurrency() method. + } +} diff --git a/core/lib/Thelia/Coupon/CouponFactory.php b/core/lib/Thelia/Coupon/CouponFactory.php new file mode 100644 index 000000000..2f0c799a8 --- /dev/null +++ b/core/lib/Thelia/Coupon/CouponFactory.php @@ -0,0 +1,146 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Translation\Exception\NotFoundResourceException; +use Thelia\Constraint\ConstraintFactory; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Exception\CouponExpiredException; +use Thelia\Exception\InvalidRuleException; +use Thelia\Model\Coupon; +use Symfony\Component\Serializer\Encoder\JsonEncoder; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Generate a CouponInterface + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponFactory +{ + /** @var ContainerInterface Service Container */ + protected $container = null; + + /** @var CouponAdapterInterface Provide necessary value from Thelia*/ + protected $adapter; + + /** + * Constructor + * + * @param ContainerInterface $container Service container + */ + function __construct(ContainerInterface $container) + { + $this->container = $container; + $this->adapter = $container->get('thelia.adapter'); + } + + /** + * Build a CouponInterface from its database data + * + * @param string $couponCode Coupon code ex: XMAS + * + * @throws \Thelia\Exception\CouponExpiredException + * @throws \Symfony\Component\Translation\Exception\NotFoundResourceException + * @return CouponInterface ready to be processed + */ + public function buildCouponFromCode($couponCode) + { + /** @var Coupon $couponModel */ + $couponModel = $this->adapter->findOneCouponByCode($couponCode); + if ($couponModel === null) { + throw new NotFoundResourceException( + 'Coupon ' . $couponCode . ' not found in Database' + ); + } + + if ($couponModel->getExpirationDate() < new \DateTime()) { + throw new CouponExpiredException($couponCode); + } + + /** @var CouponInterface $couponInterface */ + $couponInterface = $this->buildCouponInterfacFromModel($couponModel); + if ($couponInterface->getRules()->isEmpty()) { + throw new InvalidRuleException( + get_class($couponInterface) + ); + } + + return $couponInterface; + } + + /** + * Build a CouponInterface from its Model data contained in the DataBase + * + * @param Coupon $model Database data + * + * @return CouponInterface ready to use CouponInterface object instance + */ + protected function buildCouponInterfacFromModel(Coupon $model) + { + $isCumulative = ($model->getIsCumulative() == 1 ? true : false); + $isRemovingPostage = ($model->getIsRemovingPostage() == 1 ? true : false); + + if (!$this->container->has($model->getType())) { + return false; + } + + /** @var CouponInterface $couponManager*/ + $couponManager = $this->container->get($model->getType()); + $couponManager->set( + $this->adapter, + $model->getCode(), + $model->getTitle(), + $model->getShortDescription(), + $model->getDescription(), + $model->getAmount(), + $isCumulative, + $isRemovingPostage, + $model->getIsAvailableOnSpecialOffers(), + $model->getIsEnabled(), + $model->getMaxUsage(), + $model->getExpirationDate() + ); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $this->container->get('thelia.constraint.factory'); + $rules = $constraintFactory->unserializeCouponRuleCollection( + $model->getSerializedRules() + ); + + $couponManager->setRules($rules); + + return $couponManager; + } + + + +} diff --git a/core/lib/Thelia/Coupon/CouponManager.php b/core/lib/Thelia/Coupon/CouponManager.php new file mode 100644 index 000000000..93cdd21fe --- /dev/null +++ b/core/lib/Thelia/Coupon/CouponManager.php @@ -0,0 +1,257 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\DependencyInjection\ContainerInterface; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Coupon\Type\CouponInterface; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Manage how Coupons could interact with a Checkout + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponManager +{ + /** @var CouponAdapterInterface Provides necessary value from Thelia */ + protected $adapter = null; + + /** @var ContainerInterface Service Container */ + protected $container = null; + + /** @var array CouponInterface to process*/ + protected $coupons = array(); + + /** @var array Available Coupons (Services) */ + protected $availableCoupons = array(); + + /** @var array Available Rules (Services) */ + protected $availableRules = array(); + + /** + * Constructor + * + * @param ContainerInterface $container Service container + */ + function __construct(ContainerInterface $container) + { + $this->container = $container; + $this->adapter = $container->get('thelia.adapter'); + $this->coupons = $this->adapter->getCurrentCoupons(); + } + + + /** + * Get Discount for the given Coupons + * + * @api + * @return float checkout discount + */ + public function getDiscount() + { + $discount = 0.00; + + if (count($this->coupons) > 0) { + $couponsKept = $this->sortCoupons($this->coupons); + + $isRemovingPostage = $this->isCouponRemovingPostage($couponsKept); + + $discount = $this->getEffect($couponsKept); + + if ($isRemovingPostage) { + $postage = $this->adapter->getCheckoutPostagePrice(); + $discount += $postage; + } + + // Just In Case test + $checkoutTotalPrice = $this->adapter->getCartTotalPrice(); + if ($discount >= $checkoutTotalPrice) { + $discount = $checkoutTotalPrice; + } + } + + return $discount; + } + + /** + * Check if there is a Coupon removing Postage + * + * @param array $couponsKept Array of CouponInterface sorted + * + * @return bool + */ + protected function isCouponRemovingPostage(array $couponsKept) + { + $isRemovingPostage = false; + + /** @var CouponInterface $coupon */ + foreach ($couponsKept as $coupon) { + if ($coupon->isRemovingPostage()) { + $isRemovingPostage = true; + } + } + + return $isRemovingPostage; + } + + /** + * Sort Coupon to keep + * Coupon not cumulative cancels previous + * + * @param array $coupons CouponInterface to process + * + * @return array Array of CouponInterface sorted + */ + protected function sortCoupons(array $coupons) + { + $couponsKept = array(); + + /** @var CouponInterface $coupon */ + foreach ($coupons as $coupon) { + if (!$coupon->isExpired()) { + if ($coupon->isCumulative()) { + if (isset($couponsKept[0])) { + /** @var CouponInterface $previousCoupon */ + $previousCoupon = $couponsKept[0]; + if ($previousCoupon->isCumulative()) { + // Add Coupon + $couponsKept[] = $coupon; + } else { + // Reset Coupons, add last + $couponsKept = array($coupon); + } + } else { + // Reset Coupons, add last + $couponsKept = array($coupon); + } + } else { + // Reset Coupons, add last + $couponsKept = array($coupon); + } + } + } + + $coupons = $couponsKept; + $couponsKept = array(); + + /** @var CouponInterface $coupon */ + foreach ($coupons as $coupon) { + if ($coupon->isMatching($this->adapter)) { + $couponsKept[] = $coupon; + } + } + + return $couponsKept; + } + + /** + * Process given Coupon in order to get their cumulative effects + * + * @param array $coupons CouponInterface to process + * + * @return float discount + */ + protected function getEffect(array $coupons) + { + $discount = 0.00; + /** @var CouponInterface $coupon */ + foreach ($coupons as $coupon) { + $discount += $coupon->getDiscount($this->adapter); + } + + return $discount; + } + + /** + * Build a CouponRuleInterface from data coming from a form + * + * @param string $ruleServiceId Rule service id you want to instantiate + * @param array $operators Rule Operator set by the Admin + * @param array $values Rule Values set by the Admin + * + * @return CouponRuleInterface + */ + public function buildRuleFromForm($ruleServiceId, array $operators, array $values) + { + $rule = false; + try { + + if ($this->container->has($ruleServiceId)) { + /** @var CouponRuleInterface $rule */ + $rule = $this->container->get($ruleServiceId); + $rule->populateFromForm($operators, $values); + } + } catch (\InvalidArgumentException $e) { + + } + + return $rule; + } + + /** + * Add an available CouponManager (Services) + * + * @param CouponInterface $coupon CouponManager + */ + public function addAvailableCoupon(CouponInterface $coupon) + { + $this->availableCoupons[] = $coupon; + } + + /** + * Get all available CouponManagers (Services) + * + * @return array + */ + public function getAvailableCoupons() + { + return $this->availableCoupons; + } + + /** + * Add an available ConstraintManager (Services) + * + * @param CouponRuleInterface $rule CouponRuleInterface + */ + public function addAvailableRule(CouponRuleInterface $rule) + { + $this->availableRules[] = $rule; + } + + /** + * Get all available ConstraintManagers (Services) + * + * @return array + */ + public function getAvailableRules() + { + return $this->availableRules; + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/CouponRuleCollection.php b/core/lib/Thelia/Coupon/CouponRuleCollection.php new file mode 100644 index 000000000..29bf170e9 --- /dev/null +++ b/core/lib/Thelia/Coupon/CouponRuleCollection.php @@ -0,0 +1,105 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\DependencyInjection\ContainerInterface; +use Thelia\Constraint\Rule\CouponRuleInterface; +use Thelia\Constraint\Rule\SerializableRule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Manage a set of CouponRuleInterface + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponRuleCollection +{ + /** @var array Array of CouponRuleInterface */ + protected $rules = array(); + + /** + * Constructor + */ + function __construct() + { + + } + + /** + * Get Rules + * + * @return array Array of CouponRuleInterface + */ + public function getRules() + { + return $this->rules; + } + + /** + * Add a CouponRuleInterface to the Collection + * + * @param CouponRuleInterface $rule Rule + * + * @return $this + */ + public function add(CouponRuleInterface $rule) + { + $this->rules[] = $rule; + + return $this; + } + + /** + * Check if there is at least one rule in the collection + * + * @return bool + */ + public function isEmpty() + { + return (empty($this->rules)); + } + + /** + * Allow to compare 2 set of rules + * + * @return string Jsoned data + */ + public function __toString() + { + $arrayToSerialize = array(); + /** @var CouponRuleInterface $rule */ + foreach ($this->getRules() as $rule) { + $arrayToSerialize[] = $rule->getSerializableRule(); + } + + return json_encode($arrayToSerialize); + } + + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/RuleOrganizer.php b/core/lib/Thelia/Coupon/RuleOrganizer.php new file mode 100644 index 000000000..4c16ea1ff --- /dev/null +++ b/core/lib/Thelia/Coupon/RuleOrganizer.php @@ -0,0 +1,51 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Manage how Coupons could interact with a Checkout + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RuleOrganizer implements RuleOrganizerInterface +{ + /** + * Organize CouponRuleInterface + * + * @param array $rules Array of CouponRuleInterface + * + * @return array Array of CouponRuleInterface sorted + */ + public function organize(array $rules) + { + // TODO: Implement organize() method. + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/RuleOrganizerInterface.php b/core/lib/Thelia/Coupon/RuleOrganizerInterface.php new file mode 100644 index 000000000..b8b222028 --- /dev/null +++ b/core/lib/Thelia/Coupon/RuleOrganizerInterface.php @@ -0,0 +1,47 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Manage how Coupons could interact with a Checkout + * + * @package Coupon + * @author Guillaume MOREL + * + */ +interface RuleOrganizerInterface +{ + /** + * Organize CouponRuleInterface + * + * @param array $rules Array of CouponRuleInterface + * + * @return array Array of CouponRuleInterface sorted + */ + public function organize(array $rules); +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/Type/CouponAbstract.php b/core/lib/Thelia/Coupon/Type/CouponAbstract.php new file mode 100644 index 000000000..647635024 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/CouponAbstract.php @@ -0,0 +1,305 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +use Symfony\Component\Intl\Exception\NotImplementedException; +use Thelia\Constraint\ConstraintManager; +use Thelia\Constraint\ConstraintValidator; +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\CouponRuleCollection; +use Thelia\Coupon\RuleOrganizerInterface; +use Thelia\Exception\InvalidRuleException; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Assist in writing a CouponInterface + * + * @package Coupon + * @author Guillaume MOREL + * + */ +abstract class CouponAbstract implements CouponInterface +{ + /** @var string Service Id */ + protected $serviceId = null; + + /** @var CouponAdapterInterface Provide necessary value from Thelia */ + protected $adapter = null; + + /** @var Translator Service Translator */ + protected $translator = null; + + /** @var RuleOrganizerInterface */ + protected $organizer = null; + + /** @var CouponRuleCollection Array of CouponRuleInterface */ + protected $rules = null; + + /** @var ConstraintValidator Constraint validator */ + protected $constraintValidator = null; + + /** @var string Coupon code (ex: XMAS) */ + protected $code = null; + + /** @var string Coupon title (ex: Coupon for XMAS) */ + protected $title = null; + + /** @var string Coupon short description */ + protected $shortDescription = null; + + /** @var string Coupon description */ + protected $description = null; + + /** @var bool if Coupon is enabled */ + protected $isEnabled = false; + + /** @var \DateTime Coupon expiration date */ + protected $expirationDate = null; + + /** @var bool if Coupon is cumulative */ + protected $isCumulative = false; + + /** @var bool if Coupon is removing postage */ + protected $isRemovingPostage = false; + + /** @var float Amount that will be removed from the Checkout (Coupon Effect) */ + protected $amount = 0; + + /** @var int Max time a Coupon can be used (-1 = unlimited) */ + protected $maxUsage = -1; + + /** @var bool if Coupon is available for Products already on special offers */ + protected $isAvailableOnSpecialOffers = false; + + + /** + * Constructor + * + * @param CouponAdapterInterface $adapter Service adapter + */ + function __construct(CouponAdapterInterface $adapter) + { + $this->adapter = $adapter; + $this->translator = $adapter->getTranslator(); + } + + /** + * Set Rule Organizer + * + * @param RuleOrganizerInterface $organizer Manage Rule groups (&& and ||) + * + * @return $this + */ + public function setOrganizer($organizer) + { + $this->organizer = $organizer; + + return $this; + } + + /** + * Return Coupon code (ex: XMAS) + * + * @return string + */ + public function getCode() + { + return $this->code; + } + + /** + * Return Coupon title (ex: Coupon for XMAS) + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Return Coupon short description + * + * @return string + */ + public function getShortDescription() + { + return $this->shortDescription; + } + + /** + * Return Coupon description + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * If Coupon is cumulative or prevent any accumulation + * If is cumulative you can sum Coupon effects + * If not cancel all other Coupon and take the last given + * + * @return bool + */ + public function isCumulative() + { + return $this->isCumulative; + } + + /** + * If Coupon is removing Checkout Postage + * + * @return bool + */ + public function isRemovingPostage() + { + return $this->isRemovingPostage; + } + + /** + * Return effects generated by the coupon + * A negative value + * + * @return float Amount removed from the Total Checkout + */ + public function getDiscount() + { + return $this->amount; + } + + /** + * Return condition to validate the Coupon or not + * + * @return CouponRuleCollection + */ + public function getRules() + { + return clone $this->rules; + } + + /** + * Replace the existing Rules by those given in parameter + * If one Rule is badly implemented, no Rule will be added + * + * @param CouponRuleCollection $rules CouponRuleInterface to add + * + * @return $this + * @throws \Thelia\Exception\InvalidRuleException + */ + public function setRules(CouponRuleCollection $rules) + { + $this->rules = $rules; + + return $this; + } + + /** + * Check if the current Coupon is matching its conditions (Rules) + * Thelia variables are given by the CouponAdapterInterface + * + * @return bool + */ + public function isMatching() + { + return $this->constraintValidator->test($this->rules); + } + + /** + * Return Coupon expiration date + * + * @return \DateTime + */ + public function getExpirationDate() + { + return clone $this->expirationDate; + } + + /** + * Check if the Coupon can be used against a + * product already with a special offer price + * + * @return boolean + */ + public function isAvailableOnSpecialOffers() + { + return $this->isAvailableOnSpecialOffers; + } + + + /** + * Check if Coupon has been disabled by admin + * + * @return boolean + */ + public function isEnabled() + { + return $this->isEnabled; + } + + /** + * Return how many time the Coupon can be used again + * Ex : -1 unlimited + * + * @return int + */ + public function getMaxUsage() + { + return $this->maxUsage; + } + + /** + * Check if the Coupon is already Expired + * + * @return bool + */ + public function isExpired() + { + $ret = true; + + $now = new \DateTime(); + if ($this->expirationDate > $now) { + $ret = false; + } + + return $ret; + } + + /** + * Get Coupon Manager service Id + * + * @return string + */ + public function getServiceId() + { + return $this->serviceId; + } + + +} diff --git a/core/lib/Thelia/Coupon/Type/CouponInterface.php b/core/lib/Thelia/Coupon/Type/CouponInterface.php new file mode 100644 index 000000000..f0426298f --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/CouponInterface.php @@ -0,0 +1,215 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\CouponRuleCollection; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Represents a Coupon ready to be processed in a Checkout process + * + * @package Coupon + * @author Guillaume MOREL + * + */ +interface CouponInterface +{ + /** + * Set Coupon + * + * @param CouponInterface $adapter Provides necessary value from Thelia + * @param string $code Coupon code (ex: XMAS) + * @param string $title Coupon title (ex: Coupon for XMAS) + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param float $effect Coupon amount/percentage to deduce + * @param bool $isCumulative If Coupon is cumulative + * @param bool $isRemovingPostage If Coupon is removing postage + * @param bool $isAvailableOnSpecialOffers If available on Product already + * on special offer price + * @param bool $isEnabled False if Coupon is disabled by admin + * @param int $maxUsage How many usage left + * @param \Datetime $expirationDate When the Code is expiring + */ + public function set( + $adapter, + $code, + $title, + $shortDescription, + $description, + $effect, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate); + + /** + * Return Coupon code (ex: XMAS) + * + * @return string + */ + public function getCode(); + + /** + * Return Coupon title (ex: Coupon for XMAS) + * + * @return string + */ + public function getTitle(); + + /** + * Return Coupon short description + * + * @return string + */ + public function getShortDescription(); + + /** + * Return Coupon description + * + * @return string + */ + public function getDescription(); + + /** + * If Coupon is cumulative or prevent any accumulation + * If is cumulative you can sum Coupon effects + * If not cancel all other Coupon and take the last given + * + * @return bool + */ + public function isCumulative(); + + /** + * If Coupon is removing Checkout Postage + * + * @return bool + */ + public function isRemovingPostage(); + + /** + * Return effects generated by the coupon + * A positive value + * + * Effects could also affect something else than the final Checkout price + * CouponAdapter $adapter could be use to directly pass a Session value + * some would wish to modify + * Hence affecting a wide variety of Thelia elements + * + * @return float Amount removed from the Total Checkout + */ + public function getDiscount(); + + /** + * Return condition to validate the Coupon or not + * + * @return CouponRuleCollection A set of CouponRuleInterface + */ + public function getRules(); + + /** + * Check if the current Coupon is matching its conditions (Rules) + * Thelia variables are given by the CouponAdapterInterface + * + * @return bool + */ + public function isMatching(); + + /** + * Replace the existing Rules by those given in parameter + * If one Rule is badly implemented, no Rule will be added + * + * @param CouponRuleCollection $rules CouponRuleInterface to add + * + * @return $this + * @throws \Thelia\Exception\InvalidRuleException + */ + public function setRules(CouponRuleCollection $rules); + + /** + * Return Coupon expiration date + * + * @return \DateTime + */ + public function getExpirationDate(); + + /** + * Check if the Coupon can be used against a + * product already with a special offer price + * + * @return boolean + */ + public function isAvailableOnSpecialOffers(); + + + /** + * Check if Coupon has been disabled by admin + * + * @return boolean + */ + public function isEnabled(); + + /** + * Return how many time the Coupon can be used again + * Ex : -1 unlimited + * + * @return int + */ + public function getMaxUsage(); + + /** + * Check if the Coupon is already Expired + * + * @return bool + */ + public function isExpired(); + + /** + * Get I18n name + * + * @return string + */ + public function getName(); + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip(); + + /** + * Get Coupon Manager service Id + * + * @return string + */ + public function getServiceId(); + +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveXAmountManager.php b/core/lib/Thelia/Coupon/Type/RemoveXAmountManager.php new file mode 100644 index 000000000..eb5dc4548 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXAmountManager.php @@ -0,0 +1,123 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +use Thelia\Constraint\ConstraintManager; +use Thelia\Coupon\Type\CouponAbstract; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Allow to remove an amount from the checkout total + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXAmountManager extends CouponAbstract +{ + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_x_amount'; + + /** + * Set Coupon + * + * @param CouponInterface $adapter Provides necessary value from Thelia + * @param string $code Coupon code (ex: XMAS) + * @param string $title Coupon title (ex: Coupon for XMAS) + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param float $amount Coupon amount to deduce + * @param bool $isCumulative If Coupon is cumulative + * @param bool $isRemovingPostage If Coupon is removing postage + * @param bool $isAvailableOnSpecialOffers If available on Product already + * on special offer price + * @param bool $isEnabled False if Coupon is disabled by admin + * @param int $maxUsage How many usage left + * @param \Datetime $expirationDate When the Code is expiring + */ + public function set( + $adapter, + $code, + $title, + $shortDescription, + $description, + $amount, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate + ) + { + $this->code = $code; + $this->title = $title; + $this->shortDescription = $shortDescription; + $this->description = $description; + + $this->isCumulative = $isCumulative; + $this->isRemovingPostage = $isRemovingPostage; + + $this->amount = $amount; + + $this->isAvailableOnSpecialOffers = $isAvailableOnSpecialOffers; + $this->isEnabled = $isEnabled; + $this->maxUsage = $maxUsage; + $this->expirationDate = $expirationDate; + $this->adapter = $adapter; + } + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->adapter + ->getTranslator() + ->trans('Remove X amount to total cart', array(), 'constraint'); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + $toolTip = $this->adapter + ->getTranslator() + ->trans( + 'This coupon will remove the entered amount to the customer total checkout. If the discount is superior to the total checkout price the customer will only pay the postage. Unless if the coupon is set to remove postage too.', + array(), + 'constraint' + ); + + return $toolTip; + } +} diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercentForAttributeY.php b/core/lib/Thelia/Coupon/Type/RemoveXPercentForAttributeY.php new file mode 100644 index 000000000..f0a7ef472 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercentForAttributeY.php @@ -0,0 +1,38 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentForAttributeY extends RemoveXPercent +{ + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercentForCategoryY.php b/core/lib/Thelia/Coupon/Type/RemoveXPercentForCategoryY.php new file mode 100644 index 000000000..717807da7 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercentForCategoryY.php @@ -0,0 +1,38 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentForCategoryY extends RemoveXPercent +{ + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductSaleElementIdY.php b/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductSaleElementIdY.php new file mode 100644 index 000000000..bb052cd68 --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductSaleElementIdY.php @@ -0,0 +1,38 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentForProductSaleElementIdY extends RemoveXPercent +{ + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductY.php b/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductY.php new file mode 100644 index 000000000..0b88ca44d --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercentForProductY.php @@ -0,0 +1,38 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentForProductY extends RemoveXPercent +{ + +} \ No newline at end of file diff --git a/core/lib/Thelia/Coupon/Type/RemoveXPercentManager.php b/core/lib/Thelia/Coupon/Type/RemoveXPercentManager.php new file mode 100644 index 000000000..c200c620e --- /dev/null +++ b/core/lib/Thelia/Coupon/Type/RemoveXPercentManager.php @@ -0,0 +1,146 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon\Type; + +use Thelia\Coupon\CouponAdapterInterface; +use Thelia\Coupon\Type\CouponAbstract; +use Thelia\Exception\MissingAdapterException; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentManager extends CouponAbstract +{ + /** @var string Service Id */ + protected $serviceId = 'thelia.coupon.type.remove_x_percent'; + + protected $percent = 0; + + /** + * Set Coupon + * + * @param CouponInterface $adapter Provides necessary value from Thelia + * @param string $code Coupon code (ex: XMAS) + * @param string $title Coupon title (ex: Coupon for XMAS) + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param float $percent Coupon percentage to deduce + * @param bool $isCumulative If Coupon is cumulative + * @param bool $isRemovingPostage If Coupon is removing postage + * @param bool $isAvailableOnSpecialOffers If available on Product already + * on special offer price + * @param bool $isEnabled False if Coupon is disabled by admin + * @param int $maxUsage How many usage left + * @param \Datetime $expirationDate When the Code is expiring + */ + public function set( + $adapter, + $code, + $title, + $shortDescription, + $description, + $percent, + $isCumulative, + $isRemovingPostage, + $isAvailableOnSpecialOffers, + $isEnabled, + $maxUsage, + \DateTime $expirationDate) + { + $this->code = $code; + $this->title = $title; + $this->shortDescription = $shortDescription; + $this->description = $description; + + $this->isCumulative = $isCumulative; + $this->isRemovingPostage = $isRemovingPostage; + + $this->percent = $percent; + + $this->isAvailableOnSpecialOffers = $isAvailableOnSpecialOffers; + $this->isEnabled = $isEnabled; + $this->maxUsage = $maxUsage; + $this->expirationDate = $expirationDate; + $this->adapter = $adapter; + } + + /** + * Return effects generated by the coupon + * A negative value + * + * @throws \Thelia\Exception\MissingAdapterException + * @throws \InvalidArgumentException + * @return float + */ + public function getDiscount() + { + if ($this->percent >= 100) { + throw new \InvalidArgumentException( + 'Percentage must be inferior to 100' + ); + } + + $basePrice = $this->adapter->getCartTotalPrice(); + + return $basePrice * (( $this->percent ) / 100); + } + + + /** + * Get I18n name + * + * @return string + */ + public function getName() + { + return $this->adapter + ->getTranslator() + ->trans('Remove X percent to total cart', array(), 'constraint'); + } + + /** + * Get I18n tooltip + * + * @return string + */ + public function getToolTip() + { + $toolTip = $this->adapter + ->getTranslator() + ->trans( + 'This coupon will remove the entered percentage to the customer total checkout. If the discount is superior to the total checkout price the customer will only pay the postage. Unless if the coupon is set to remove postage too.', + array(), + 'constraint' + ); + + return $toolTip; + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Exception/CouponExpiredException.php b/core/lib/Thelia/Exception/CouponExpiredException.php new file mode 100644 index 000000000..c1ccace0a --- /dev/null +++ b/core/lib/Thelia/Exception/CouponExpiredException.php @@ -0,0 +1,53 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when an Expired Coupon is tried + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponExpiredException extends \Exception +{ + /** + * CouponExpiredException thrown when a Coupon is expired + * + * @param string $couponCode Coupon code + */ + public function __construct($couponCode) + { + $message = 'Expired Coupon ' . $couponCode . 'attempt'; + Tlog::getInstance()->addInfo($message); + + parent::__construct($message); + } +} diff --git a/core/lib/Thelia/Exception/InvalidRuleException.php b/core/lib/Thelia/Exception/InvalidRuleException.php new file mode 100644 index 000000000..a891ded4a --- /dev/null +++ b/core/lib/Thelia/Exception/InvalidRuleException.php @@ -0,0 +1,54 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when a Rule is badly implemented + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class InvalidRuleException extends \RuntimeException +{ + /** + * InvalidRuleOperatorException thrown when a Rule is badly implemented + * + * @param string $className Class name + */ + public function __construct($className) + { + + $message = 'Invalid Rule given to ' . $className; + Tlog::getInstance()->addError($message); + + parent::__construct($message); + } +} diff --git a/core/lib/Thelia/Exception/InvalidRuleOperatorException.php b/core/lib/Thelia/Exception/InvalidRuleOperatorException.php new file mode 100644 index 000000000..d40c723c2 --- /dev/null +++ b/core/lib/Thelia/Exception/InvalidRuleOperatorException.php @@ -0,0 +1,55 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when a Rule receive an invalid Operator + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class InvalidRuleOperatorException extends \RuntimeException +{ + /** + * InvalidRuleOperatorException thrown when a Rule is given a bad Operator + * + * @param string $className Class name + * @param string $parameter array key parameter + */ + public function __construct($className, $parameter) + { + + $message = 'Invalid Operator for Rule ' . $className . ' on parameter ' . $parameter; + Tlog::getInstance()->addError($message); + + parent::__construct($message); + } +} diff --git a/core/lib/Thelia/Exception/InvalidRuleValueException.php b/core/lib/Thelia/Exception/InvalidRuleValueException.php new file mode 100644 index 000000000..2f16f32f1 --- /dev/null +++ b/core/lib/Thelia/Exception/InvalidRuleValueException.php @@ -0,0 +1,55 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when a Rule receive an invalid Parameter + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class InvalidRuleValueException extends \RuntimeException +{ + /** + * InvalidRuleValueException thrown when a Rule is given a bad Parameter + * + * @param string $className Class name + * @param string $parameter array key parameter + */ + public function __construct($className, $parameter) + { + + $message = 'Invalid Parameter for Rule ' . $className . ' on parameter ' . $parameter; + Tlog::getInstance()->addError($message); + + parent::__construct($message); + } +} diff --git a/core/lib/Thelia/Exception/MissingAdapterException.php b/core/lib/Thelia/Exception/MissingAdapterException.php new file mode 100644 index 000000000..645020cab --- /dev/null +++ b/core/lib/Thelia/Exception/MissingAdapterException.php @@ -0,0 +1,50 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when the Adapter is not set + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class MissingAdapterException extends \RuntimeException +{ + /** + * {@inheritdoc} + */ + public function __construct($message, $code = null, $previous = null) { + + Tlog::getInstance()->addError($message); + + parent::__construct($message, $code, $previous); + } +} diff --git a/core/lib/Thelia/Exception/NotImplementedException.php b/core/lib/Thelia/Exception/NotImplementedException.php new file mode 100644 index 000000000..991f4d325 --- /dev/null +++ b/core/lib/Thelia/Exception/NotImplementedException.php @@ -0,0 +1,43 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Exception; + +use Symfony\Component\DependencyInjection\Exception\BadMethodCallException; +use Thelia\Log\Tlog; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Thrown when an Abstract method has not been implemented + * + * @package Exception + * @author Guillaume MOREL + * + */ +class NotImplementedException extends BadMethodCallException +{ + +} diff --git a/core/lib/Thelia/Exception/TaxEngineException.php b/core/lib/Thelia/Exception/TaxEngineException.php new file mode 100755 index 000000000..2a2718d4b --- /dev/null +++ b/core/lib/Thelia/Exception/TaxEngineException.php @@ -0,0 +1,44 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Exception; + +use Thelia\Log\Tlog; + +class TaxEngineException extends \RuntimeException +{ + const UNKNOWN_EXCEPTION = 0; + + const UNDEFINED_PRODUCT = 501; + const UNDEFINED_COUNTRY = 502; + const UNDEFINED_TAX_RULES_COLLECTION = 503; + + const BAD_AMOUNT_FORMAT = 601; + + public function __construct($message, $code = null, $previous = null) { + if($code === null) { + $code = self::UNKNOWN_EXCEPTION; + } + parent::__construct($message, $code, $previous); + } +} diff --git a/core/lib/Thelia/Form/BaseForm.php b/core/lib/Thelia/Form/BaseForm.php index 0eb6b828b..f15dd7525 100755 --- a/core/lib/Thelia/Form/BaseForm.php +++ b/core/lib/Thelia/Form/BaseForm.php @@ -102,6 +102,10 @@ abstract class BaseForm $this->formBuilder->add("success_url", "text"); } + if (! $this->formBuilder->has('error_message')) { + $this->formBuilder->add("error_message", "text"); + } + $this->form = $this->formBuilder->getForm(); } diff --git a/core/lib/Thelia/Form/CouponCreationForm.php b/core/lib/Thelia/Form/CouponCreationForm.php new file mode 100755 index 000000000..4761bb28f --- /dev/null +++ b/core/lib/Thelia/Form/CouponCreationForm.php @@ -0,0 +1,160 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Form; + +use Symfony\Component\Validator\Constraints\NotBlank; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/29/13 + * Time: 3:45 PM + * + * Allow to build a form Coupon + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponCreationForm extends BaseForm +{ + /** + * Build Coupon form + * + * @return void + */ + protected function buildForm() + { + $this->formBuilder + ->add( + 'code', + 'text', + array( + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'title', + 'text', + array( + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'shortDescription', + 'text', + array( + 'invalid_message' => 'test', + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'description', + 'textarea', + array( + 'invalid_message' => 'test', + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'effect', + 'text', + array( + 'invalid_message' => 'test', + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'amount', + 'money', + array() + ) + ->add( + 'isEnabled', + 'checkbox', + array() + ) + ->add( + 'expirationDate', + 'text', + array( + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'isCumulative', + 'checkbox', + array() + ) + ->add( + 'isRemovingPostage', + 'checkbox', + array() + ) + ->add( + 'isAvailableOnSpecialOffers', + 'checkbox', + array() + ) + ->add( + 'maxUsage', + 'text', + array( + 'constraints' => array( + new NotBlank() + ) + ) + ) + ->add( + 'locale', + 'hidden', + array( + 'constraints' => array( + new NotBlank() + ) + ) + ); + } + + /** + * Get form name + * + * @return string + */ + public function getName() + { + return 'thelia_coupon_creation'; + } +} diff --git a/core/lib/Thelia/Form/CustomerLogin.php b/core/lib/Thelia/Form/CustomerLogin.php index 12b5a2775..3081ceed7 100755 --- a/core/lib/Thelia/Form/CustomerLogin.php +++ b/core/lib/Thelia/Form/CustomerLogin.php @@ -22,24 +22,38 @@ /*************************************************************************************/ namespace Thelia\Form; +use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Validator\ExecutionContextInterface; +use Thelia\Core\Translation\Translator; +use Thelia\Model\CustomerQuery; class CustomerLogin extends BaseForm { protected function buildForm() { $this->formBuilder - ->add("email", "text", array( + ->add("email", "email", array( "constraints" => array( new NotBlank(), new Email() - ) + ), + "label" => Translator::getInstance()->trans("Please enter your email address"), + "label_attr" => array( + "for" => "email" + ), + "required" => true )) ->add("password", "password", array( "constraints" => array( new NotBlank() - ) + ), + "label" => Translator::getInstance()->trans("Please enter your password"), + "label_attr" => array( + "for" => "password" + ), + "required" => true )) ->add("remember_me", "checkbox") ; @@ -49,4 +63,5 @@ class CustomerLogin extends BaseForm { return "thelia_customer_login"; } + } diff --git a/core/lib/Thelia/Model/Base/Accessory.php b/core/lib/Thelia/Model/Base/Accessory.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AccessoryQuery.php b/core/lib/Thelia/Model/Base/AccessoryQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Address.php b/core/lib/Thelia/Model/Base/Address.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AddressQuery.php b/core/lib/Thelia/Model/Base/AddressQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Admin.php b/core/lib/Thelia/Model/Base/Admin.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AdminGroup.php b/core/lib/Thelia/Model/Base/AdminGroup.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AdminGroupQuery.php b/core/lib/Thelia/Model/Base/AdminGroupQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AdminLog.php b/core/lib/Thelia/Model/Base/AdminLog.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AdminLogQuery.php b/core/lib/Thelia/Model/Base/AdminLogQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AdminQuery.php b/core/lib/Thelia/Model/Base/AdminQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Area.php b/core/lib/Thelia/Model/Base/Area.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AreaQuery.php b/core/lib/Thelia/Model/Base/AreaQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Attribute.php b/core/lib/Thelia/Model/Base/Attribute.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeAv.php b/core/lib/Thelia/Model/Base/AttributeAv.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeAvI18n.php b/core/lib/Thelia/Model/Base/AttributeAvI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeAvI18nQuery.php b/core/lib/Thelia/Model/Base/AttributeAvI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeAvQuery.php b/core/lib/Thelia/Model/Base/AttributeAvQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeCategory.php b/core/lib/Thelia/Model/Base/AttributeCategory.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeCategoryQuery.php b/core/lib/Thelia/Model/Base/AttributeCategoryQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeCombination.php b/core/lib/Thelia/Model/Base/AttributeCombination.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeCombinationQuery.php b/core/lib/Thelia/Model/Base/AttributeCombinationQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeI18n.php b/core/lib/Thelia/Model/Base/AttributeI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeI18nQuery.php b/core/lib/Thelia/Model/Base/AttributeI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/AttributeQuery.php b/core/lib/Thelia/Model/Base/AttributeQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Cart.php b/core/lib/Thelia/Model/Base/Cart.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CartItem.php b/core/lib/Thelia/Model/Base/CartItem.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CartItemQuery.php b/core/lib/Thelia/Model/Base/CartItemQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CartQuery.php b/core/lib/Thelia/Model/Base/CartQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Category.php b/core/lib/Thelia/Model/Base/Category.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryDocument.php b/core/lib/Thelia/Model/Base/CategoryDocument.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryDocumentI18n.php b/core/lib/Thelia/Model/Base/CategoryDocumentI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryDocumentI18nQuery.php b/core/lib/Thelia/Model/Base/CategoryDocumentI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryDocumentQuery.php b/core/lib/Thelia/Model/Base/CategoryDocumentQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryI18n.php b/core/lib/Thelia/Model/Base/CategoryI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryI18nQuery.php b/core/lib/Thelia/Model/Base/CategoryI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryImage.php b/core/lib/Thelia/Model/Base/CategoryImage.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryImageI18n.php b/core/lib/Thelia/Model/Base/CategoryImageI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryImageI18nQuery.php b/core/lib/Thelia/Model/Base/CategoryImageI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryImageQuery.php b/core/lib/Thelia/Model/Base/CategoryImageQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryQuery.php b/core/lib/Thelia/Model/Base/CategoryQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryVersion.php b/core/lib/Thelia/Model/Base/CategoryVersion.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CategoryVersionQuery.php b/core/lib/Thelia/Model/Base/CategoryVersionQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Config.php b/core/lib/Thelia/Model/Base/Config.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ConfigI18n.php b/core/lib/Thelia/Model/Base/ConfigI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ConfigI18nQuery.php b/core/lib/Thelia/Model/Base/ConfigI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ConfigQuery.php b/core/lib/Thelia/Model/Base/ConfigQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Content.php b/core/lib/Thelia/Model/Base/Content.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentDocument.php b/core/lib/Thelia/Model/Base/ContentDocument.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentDocumentI18n.php b/core/lib/Thelia/Model/Base/ContentDocumentI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentDocumentI18nQuery.php b/core/lib/Thelia/Model/Base/ContentDocumentI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentDocumentQuery.php b/core/lib/Thelia/Model/Base/ContentDocumentQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentFolder.php b/core/lib/Thelia/Model/Base/ContentFolder.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentFolderQuery.php b/core/lib/Thelia/Model/Base/ContentFolderQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentI18n.php b/core/lib/Thelia/Model/Base/ContentI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentI18nQuery.php b/core/lib/Thelia/Model/Base/ContentI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentImage.php b/core/lib/Thelia/Model/Base/ContentImage.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentImageI18n.php b/core/lib/Thelia/Model/Base/ContentImageI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentImageI18nQuery.php b/core/lib/Thelia/Model/Base/ContentImageI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentImageQuery.php b/core/lib/Thelia/Model/Base/ContentImageQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentQuery.php b/core/lib/Thelia/Model/Base/ContentQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentVersion.php b/core/lib/Thelia/Model/Base/ContentVersion.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ContentVersionQuery.php b/core/lib/Thelia/Model/Base/ContentVersionQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Country.php b/core/lib/Thelia/Model/Base/Country.php old mode 100755 new mode 100644 index e0541a151..90fd48880 --- a/core/lib/Thelia/Model/Base/Country.php +++ b/core/lib/Thelia/Model/Base/Country.php @@ -1631,7 +1631,10 @@ abstract class Country implements ActiveRecordInterface $taxRuleCountriesToDelete = $this->getTaxRuleCountries(new Criteria(), $con)->diff($taxRuleCountries); - $this->taxRuleCountriesScheduledForDeletion = $taxRuleCountriesToDelete; + //since at least one column in the foreign key is at the same time a PK + //we can not just set a PK to NULL in the lines below. We have to store + //a backup of all values, so we are able to manipulate these items based on the onDelete value later. + $this->taxRuleCountriesScheduledForDeletion = clone $taxRuleCountriesToDelete; foreach ($taxRuleCountriesToDelete as $taxRuleCountryRemoved) { $taxRuleCountryRemoved->setCountry(null); @@ -1724,7 +1727,7 @@ abstract class Country implements ActiveRecordInterface $this->taxRuleCountriesScheduledForDeletion = clone $this->collTaxRuleCountries; $this->taxRuleCountriesScheduledForDeletion->clear(); } - $this->taxRuleCountriesScheduledForDeletion[]= $taxRuleCountry; + $this->taxRuleCountriesScheduledForDeletion[]= clone $taxRuleCountry; $taxRuleCountry->setCountry(null); } diff --git a/core/lib/Thelia/Model/Base/CountryI18n.php b/core/lib/Thelia/Model/Base/CountryI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CountryI18nQuery.php b/core/lib/Thelia/Model/Base/CountryI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CountryQuery.php b/core/lib/Thelia/Model/Base/CountryQuery.php old mode 100755 new mode 100644 index 6c3a1c950..1e565e9c0 --- a/core/lib/Thelia/Model/Base/CountryQuery.php +++ b/core/lib/Thelia/Model/Base/CountryQuery.php @@ -616,7 +616,7 @@ abstract class CountryQuery extends ModelCriteria * * @return ChildCountryQuery The current query, for fluid interface */ - public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('TaxRuleCountry'); @@ -651,7 +651,7 @@ abstract class CountryQuery extends ModelCriteria * * @return \Thelia\Model\TaxRuleCountryQuery A secondary query class using the current class as primary query */ - public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinTaxRuleCountry($relationAlias, $joinType) diff --git a/core/lib/Thelia/Model/Base/Coupon.php b/core/lib/Thelia/Model/Base/Coupon.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CouponOrder.php b/core/lib/Thelia/Model/Base/CouponOrder.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CouponOrderQuery.php b/core/lib/Thelia/Model/Base/CouponOrderQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CouponQuery.php b/core/lib/Thelia/Model/Base/CouponQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CouponRule.php b/core/lib/Thelia/Model/Base/CouponRule.php deleted file mode 100755 index 8a34f5d0b..000000000 --- a/core/lib/Thelia/Model/Base/CouponRule.php +++ /dev/null @@ -1,1534 +0,0 @@ -modifiedColumns); - } - - /** - * Has specified column been modified? - * - * @param string $col column fully qualified name (TableMap::TYPE_COLNAME), e.g. Book::AUTHOR_ID - * @return boolean True if $col has been modified. - */ - public function isColumnModified($col) - { - return in_array($col, $this->modifiedColumns); - } - - /** - * Get the columns that have been modified in this object. - * @return array A unique list of the modified column names for this object. - */ - public function getModifiedColumns() - { - return array_unique($this->modifiedColumns); - } - - /** - * Returns whether the object has ever been saved. This will - * be false, if the object was retrieved from storage or was created - * and then saved. - * - * @return true, if the object has never been persisted. - */ - public function isNew() - { - return $this->new; - } - - /** - * Setter for the isNew attribute. This method will be called - * by Propel-generated children and objects. - * - * @param boolean $b the state of the object. - */ - public function setNew($b) - { - $this->new = (Boolean) $b; - } - - /** - * Whether this object has been deleted. - * @return boolean The deleted state of this object. - */ - public function isDeleted() - { - return $this->deleted; - } - - /** - * Specify whether this object has been deleted. - * @param boolean $b The deleted state of this object. - * @return void - */ - public function setDeleted($b) - { - $this->deleted = (Boolean) $b; - } - - /** - * Sets the modified state for the object to be false. - * @param string $col If supplied, only the specified column is reset. - * @return void - */ - public function resetModified($col = null) - { - if (null !== $col) { - while (false !== ($offset = array_search($col, $this->modifiedColumns))) { - array_splice($this->modifiedColumns, $offset, 1); - } - } else { - $this->modifiedColumns = array(); - } - } - - /** - * Compares this with another CouponRule instance. If - * obj is an instance of CouponRule, delegates to - * equals(CouponRule). Otherwise, returns false. - * - * @param obj The object to compare to. - * @return Whether equal to the object specified. - */ - public function equals($obj) - { - $thisclazz = get_class($this); - if (!is_object($obj) || !($obj instanceof $thisclazz)) { - return false; - } - - if ($this === $obj) { - return true; - } - - if (null === $this->getPrimaryKey() - || null === $obj->getPrimaryKey()) { - return false; - } - - return $this->getPrimaryKey() === $obj->getPrimaryKey(); - } - - /** - * If the primary key is not null, return the hashcode of the - * primary key. Otherwise, return the hash code of the object. - * - * @return int Hashcode - */ - public function hashCode() - { - if (null !== $this->getPrimaryKey()) { - return crc32(serialize($this->getPrimaryKey())); - } - - return crc32(serialize(clone $this)); - } - - /** - * Get the associative array of the virtual columns in this object - * - * @param string $name The virtual column name - * - * @return array - */ - public function getVirtualColumns() - { - return $this->virtualColumns; - } - - /** - * Checks the existence of a virtual column in this object - * - * @return boolean - */ - public function hasVirtualColumn($name) - { - return array_key_exists($name, $this->virtualColumns); - } - - /** - * Get the value of a virtual column in this object - * - * @return mixed - */ - public function getVirtualColumn($name) - { - if (!$this->hasVirtualColumn($name)) { - throw new PropelException(sprintf('Cannot get value of inexistent virtual column %s.', $name)); - } - - return $this->virtualColumns[$name]; - } - - /** - * Set the value of a virtual column in this object - * - * @param string $name The virtual column name - * @param mixed $value The value to give to the virtual column - * - * @return CouponRule The current object, for fluid interface - */ - public function setVirtualColumn($name, $value) - { - $this->virtualColumns[$name] = $value; - - return $this; - } - - /** - * Logs a message using Propel::log(). - * - * @param string $msg - * @param int $priority One of the Propel::LOG_* logging levels - * @return boolean - */ - protected function log($msg, $priority = Propel::LOG_INFO) - { - return Propel::log(get_class($this) . ': ' . $msg, $priority); - } - - /** - * Populate the current object from a string, using a given parser format - * - * $book = new Book(); - * $book->importFrom('JSON', '{"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); - * - * - * @param mixed $parser A AbstractParser instance, - * or a format name ('XML', 'YAML', 'JSON', 'CSV') - * @param string $data The source data to import from - * - * @return CouponRule The current object, for fluid interface - */ - public function importFrom($parser, $data) - { - if (!$parser instanceof AbstractParser) { - $parser = AbstractParser::getParser($parser); - } - - return $this->fromArray($parser->toArray($data), TableMap::TYPE_PHPNAME); - } - - /** - * Export the current object properties to a string, using a given parser format - * - * $book = BookQuery::create()->findPk(9012); - * echo $book->exportTo('JSON'); - * => {"Id":9012,"Title":"Don Juan","ISBN":"0140422161","Price":12.99,"PublisherId":1234,"AuthorId":5678}'); - * - * - * @param mixed $parser A AbstractParser instance, or a format name ('XML', 'YAML', 'JSON', 'CSV') - * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy load(ed) columns. Defaults to TRUE. - * @return string The exported data - */ - public function exportTo($parser, $includeLazyLoadColumns = true) - { - if (!$parser instanceof AbstractParser) { - $parser = AbstractParser::getParser($parser); - } - - return $parser->fromArray($this->toArray(TableMap::TYPE_PHPNAME, $includeLazyLoadColumns, array(), true)); - } - - /** - * Clean up internal collections prior to serializing - * Avoids recursive loops that turn into segmentation faults when serializing - */ - public function __sleep() - { - $this->clearAllReferences(); - - return array_keys(get_object_vars($this)); - } - - /** - * Get the [id] column value. - * - * @return int - */ - public function getId() - { - - return $this->id; - } - - /** - * Get the [coupon_id] column value. - * - * @return int - */ - public function getCouponId() - { - - return $this->coupon_id; - } - - /** - * Get the [controller] column value. - * - * @return string - */ - public function getController() - { - - return $this->controller; - } - - /** - * Get the [operation] column value. - * - * @return string - */ - public function getOperation() - { - - return $this->operation; - } - - /** - * Get the [value] column value. - * - * @return double - */ - public function getValue() - { - - return $this->value; - } - - /** - * Get the [optionally formatted] temporal [created_at] column value. - * - * - * @param string $format The date/time format string (either date()-style or strftime()-style). - * If format is NULL, then the raw \DateTime object will be returned. - * - * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 - * - * @throws PropelException - if unable to parse/validate the date/time value. - */ - public function getCreatedAt($format = NULL) - { - if ($format === null) { - return $this->created_at; - } else { - return $this->created_at !== null ? $this->created_at->format($format) : null; - } - } - - /** - * Get the [optionally formatted] temporal [updated_at] column value. - * - * - * @param string $format The date/time format string (either date()-style or strftime()-style). - * If format is NULL, then the raw \DateTime object will be returned. - * - * @return mixed Formatted date/time value as string or \DateTime object (if format is NULL), NULL if column is NULL, and 0 if column value is 0000-00-00 00:00:00 - * - * @throws PropelException - if unable to parse/validate the date/time value. - */ - public function getUpdatedAt($format = NULL) - { - if ($format === null) { - return $this->updated_at; - } else { - return $this->updated_at !== null ? $this->updated_at->format($format) : null; - } - } - - /** - * Set the value of [id] column. - * - * @param int $v new value - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setId($v) - { - if ($v !== null) { - $v = (int) $v; - } - - if ($this->id !== $v) { - $this->id = $v; - $this->modifiedColumns[] = CouponRuleTableMap::ID; - } - - - return $this; - } // setId() - - /** - * Set the value of [coupon_id] column. - * - * @param int $v new value - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setCouponId($v) - { - if ($v !== null) { - $v = (int) $v; - } - - if ($this->coupon_id !== $v) { - $this->coupon_id = $v; - $this->modifiedColumns[] = CouponRuleTableMap::COUPON_ID; - } - - if ($this->aCoupon !== null && $this->aCoupon->getId() !== $v) { - $this->aCoupon = null; - } - - - return $this; - } // setCouponId() - - /** - * Set the value of [controller] column. - * - * @param string $v new value - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setController($v) - { - if ($v !== null) { - $v = (string) $v; - } - - if ($this->controller !== $v) { - $this->controller = $v; - $this->modifiedColumns[] = CouponRuleTableMap::CONTROLLER; - } - - - return $this; - } // setController() - - /** - * Set the value of [operation] column. - * - * @param string $v new value - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setOperation($v) - { - if ($v !== null) { - $v = (string) $v; - } - - if ($this->operation !== $v) { - $this->operation = $v; - $this->modifiedColumns[] = CouponRuleTableMap::OPERATION; - } - - - return $this; - } // setOperation() - - /** - * Set the value of [value] column. - * - * @param double $v new value - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setValue($v) - { - if ($v !== null) { - $v = (double) $v; - } - - if ($this->value !== $v) { - $this->value = $v; - $this->modifiedColumns[] = CouponRuleTableMap::VALUE; - } - - - return $this; - } // setValue() - - /** - * Sets the value of [created_at] column to a normalized version of the date/time value specified. - * - * @param mixed $v string, integer (timestamp), or \DateTime value. - * Empty strings are treated as NULL. - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setCreatedAt($v) - { - $dt = PropelDateTime::newInstance($v, null, '\DateTime'); - if ($this->created_at !== null || $dt !== null) { - if ($dt !== $this->created_at) { - $this->created_at = $dt; - $this->modifiedColumns[] = CouponRuleTableMap::CREATED_AT; - } - } // if either are not null - - - return $this; - } // setCreatedAt() - - /** - * Sets the value of [updated_at] column to a normalized version of the date/time value specified. - * - * @param mixed $v string, integer (timestamp), or \DateTime value. - * Empty strings are treated as NULL. - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - */ - public function setUpdatedAt($v) - { - $dt = PropelDateTime::newInstance($v, null, '\DateTime'); - if ($this->updated_at !== null || $dt !== null) { - if ($dt !== $this->updated_at) { - $this->updated_at = $dt; - $this->modifiedColumns[] = CouponRuleTableMap::UPDATED_AT; - } - } // if either are not null - - - return $this; - } // setUpdatedAt() - - /** - * Indicates whether the columns in this object are only set to default values. - * - * This method can be used in conjunction with isModified() to indicate whether an object is both - * modified _and_ has some values set which are non-default. - * - * @return boolean Whether the columns in this object are only been set with default values. - */ - public function hasOnlyDefaultValues() - { - // otherwise, everything was equal, so return TRUE - return true; - } // hasOnlyDefaultValues() - - /** - * Hydrates (populates) the object variables with values from the database resultset. - * - * An offset (0-based "start column") is specified so that objects can be hydrated - * with a subset of the columns in the resultset rows. This is needed, for example, - * for results of JOIN queries where the resultset row includes columns from two or - * more tables. - * - * @param array $row The row returned by DataFetcher->fetch(). - * @param int $startcol 0-based offset column which indicates which restultset column to start with. - * @param boolean $rehydrate Whether this object is being re-hydrated from the database. - * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). - One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * - * @return int next starting column - * @throws PropelException - Any caught Exception will be rewrapped as a PropelException. - */ - public function hydrate($row, $startcol = 0, $rehydrate = false, $indexType = TableMap::TYPE_NUM) - { - try { - - - $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : CouponRuleTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; - $this->id = (null !== $col) ? (int) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : CouponRuleTableMap::translateFieldName('CouponId', TableMap::TYPE_PHPNAME, $indexType)]; - $this->coupon_id = (null !== $col) ? (int) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : CouponRuleTableMap::translateFieldName('Controller', TableMap::TYPE_PHPNAME, $indexType)]; - $this->controller = (null !== $col) ? (string) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : CouponRuleTableMap::translateFieldName('Operation', TableMap::TYPE_PHPNAME, $indexType)]; - $this->operation = (null !== $col) ? (string) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : CouponRuleTableMap::translateFieldName('Value', TableMap::TYPE_PHPNAME, $indexType)]; - $this->value = (null !== $col) ? (double) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : CouponRuleTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; - if ($col === '0000-00-00 00:00:00') { - $col = null; - } - $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : CouponRuleTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; - if ($col === '0000-00-00 00:00:00') { - $col = null; - } - $this->updated_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - $this->resetModified(); - - $this->setNew(false); - - if ($rehydrate) { - $this->ensureConsistency(); - } - - return $startcol + 7; // 7 = CouponRuleTableMap::NUM_HYDRATE_COLUMNS. - - } catch (Exception $e) { - throw new PropelException("Error populating \Thelia\Model\CouponRule object", 0, $e); - } - } - - /** - * Checks and repairs the internal consistency of the object. - * - * This method is executed after an already-instantiated object is re-hydrated - * from the database. It exists to check any foreign keys to make sure that - * the objects related to the current object are correct based on foreign key. - * - * You can override this method in the stub class, but you should always invoke - * the base method from the overridden method (i.e. parent::ensureConsistency()), - * in case your model changes. - * - * @throws PropelException - */ - public function ensureConsistency() - { - if ($this->aCoupon !== null && $this->coupon_id !== $this->aCoupon->getId()) { - $this->aCoupon = null; - } - } // ensureConsistency - - /** - * Reloads this object from datastore based on primary key and (optionally) resets all associated objects. - * - * This will only work if the object has been saved and has a valid primary key set. - * - * @param boolean $deep (optional) Whether to also de-associated any related objects. - * @param ConnectionInterface $con (optional) The ConnectionInterface connection to use. - * @return void - * @throws PropelException - if this object is deleted, unsaved or doesn't have pk match in db - */ - public function reload($deep = false, ConnectionInterface $con = null) - { - if ($this->isDeleted()) { - throw new PropelException("Cannot reload a deleted object."); - } - - if ($this->isNew()) { - throw new PropelException("Cannot reload an unsaved object."); - } - - if ($con === null) { - $con = Propel::getServiceContainer()->getReadConnection(CouponRuleTableMap::DATABASE_NAME); - } - - // We don't need to alter the object instance pool; we're just modifying this instance - // already in the pool. - - $dataFetcher = ChildCouponRuleQuery::create(null, $this->buildPkeyCriteria())->setFormatter(ModelCriteria::FORMAT_STATEMENT)->find($con); - $row = $dataFetcher->fetch(); - $dataFetcher->close(); - if (!$row) { - throw new PropelException('Cannot find matching row in the database to reload object values.'); - } - $this->hydrate($row, 0, true, $dataFetcher->getIndexType()); // rehydrate - - if ($deep) { // also de-associate any related objects? - - $this->aCoupon = null; - } // if (deep) - } - - /** - * Removes this object from datastore and sets delete attribute. - * - * @param ConnectionInterface $con - * @return void - * @throws PropelException - * @see CouponRule::setDeleted() - * @see CouponRule::isDeleted() - */ - public function delete(ConnectionInterface $con = null) - { - if ($this->isDeleted()) { - throw new PropelException("This object has already been deleted."); - } - - if ($con === null) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - - $con->beginTransaction(); - try { - $deleteQuery = ChildCouponRuleQuery::create() - ->filterByPrimaryKey($this->getPrimaryKey()); - $ret = $this->preDelete($con); - if ($ret) { - $deleteQuery->delete($con); - $this->postDelete($con); - $con->commit(); - $this->setDeleted(true); - } else { - $con->commit(); - } - } catch (Exception $e) { - $con->rollBack(); - throw $e; - } - } - - /** - * Persists this object to the database. - * - * If the object is new, it inserts it; otherwise an update is performed. - * All modified related objects will also be persisted in the doSave() - * method. This method wraps all precipitate database operations in a - * single transaction. - * - * @param ConnectionInterface $con - * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. - * @throws PropelException - * @see doSave() - */ - public function save(ConnectionInterface $con = null) - { - if ($this->isDeleted()) { - throw new PropelException("You cannot save an object that has been deleted."); - } - - if ($con === null) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - - $con->beginTransaction(); - $isInsert = $this->isNew(); - try { - $ret = $this->preSave($con); - if ($isInsert) { - $ret = $ret && $this->preInsert($con); - // timestampable behavior - if (!$this->isColumnModified(CouponRuleTableMap::CREATED_AT)) { - $this->setCreatedAt(time()); - } - if (!$this->isColumnModified(CouponRuleTableMap::UPDATED_AT)) { - $this->setUpdatedAt(time()); - } - } else { - $ret = $ret && $this->preUpdate($con); - // timestampable behavior - if ($this->isModified() && !$this->isColumnModified(CouponRuleTableMap::UPDATED_AT)) { - $this->setUpdatedAt(time()); - } - } - if ($ret) { - $affectedRows = $this->doSave($con); - if ($isInsert) { - $this->postInsert($con); - } else { - $this->postUpdate($con); - } - $this->postSave($con); - CouponRuleTableMap::addInstanceToPool($this); - } else { - $affectedRows = 0; - } - $con->commit(); - - return $affectedRows; - } catch (Exception $e) { - $con->rollBack(); - throw $e; - } - } - - /** - * Performs the work of inserting or updating the row in the database. - * - * If the object is new, it inserts it; otherwise an update is performed. - * All related objects are also updated in this method. - * - * @param ConnectionInterface $con - * @return int The number of rows affected by this insert/update and any referring fk objects' save() operations. - * @throws PropelException - * @see save() - */ - protected function doSave(ConnectionInterface $con) - { - $affectedRows = 0; // initialize var to track total num of affected rows - if (!$this->alreadyInSave) { - $this->alreadyInSave = true; - - // We call the save method on the following object(s) if they - // were passed to this object by their corresponding set - // method. This object relates to these object(s) by a - // foreign key reference. - - if ($this->aCoupon !== null) { - if ($this->aCoupon->isModified() || $this->aCoupon->isNew()) { - $affectedRows += $this->aCoupon->save($con); - } - $this->setCoupon($this->aCoupon); - } - - if ($this->isNew() || $this->isModified()) { - // persist changes - if ($this->isNew()) { - $this->doInsert($con); - } else { - $this->doUpdate($con); - } - $affectedRows += 1; - $this->resetModified(); - } - - $this->alreadyInSave = false; - - } - - return $affectedRows; - } // doSave() - - /** - * Insert the row in the database. - * - * @param ConnectionInterface $con - * - * @throws PropelException - * @see doSave() - */ - protected function doInsert(ConnectionInterface $con) - { - $modifiedColumns = array(); - $index = 0; - - $this->modifiedColumns[] = CouponRuleTableMap::ID; - if (null !== $this->id) { - throw new PropelException('Cannot insert a value for auto-increment primary key (' . CouponRuleTableMap::ID . ')'); - } - - // check the columns in natural order for more readable SQL queries - if ($this->isColumnModified(CouponRuleTableMap::ID)) { - $modifiedColumns[':p' . $index++] = 'ID'; - } - if ($this->isColumnModified(CouponRuleTableMap::COUPON_ID)) { - $modifiedColumns[':p' . $index++] = 'COUPON_ID'; - } - if ($this->isColumnModified(CouponRuleTableMap::CONTROLLER)) { - $modifiedColumns[':p' . $index++] = 'CONTROLLER'; - } - if ($this->isColumnModified(CouponRuleTableMap::OPERATION)) { - $modifiedColumns[':p' . $index++] = 'OPERATION'; - } - if ($this->isColumnModified(CouponRuleTableMap::VALUE)) { - $modifiedColumns[':p' . $index++] = 'VALUE'; - } - if ($this->isColumnModified(CouponRuleTableMap::CREATED_AT)) { - $modifiedColumns[':p' . $index++] = 'CREATED_AT'; - } - if ($this->isColumnModified(CouponRuleTableMap::UPDATED_AT)) { - $modifiedColumns[':p' . $index++] = 'UPDATED_AT'; - } - - $sql = sprintf( - 'INSERT INTO coupon_rule (%s) VALUES (%s)', - implode(', ', $modifiedColumns), - implode(', ', array_keys($modifiedColumns)) - ); - - try { - $stmt = $con->prepare($sql); - foreach ($modifiedColumns as $identifier => $columnName) { - switch ($columnName) { - case 'ID': - $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); - break; - case 'COUPON_ID': - $stmt->bindValue($identifier, $this->coupon_id, PDO::PARAM_INT); - break; - case 'CONTROLLER': - $stmt->bindValue($identifier, $this->controller, PDO::PARAM_STR); - break; - case 'OPERATION': - $stmt->bindValue($identifier, $this->operation, PDO::PARAM_STR); - break; - case 'VALUE': - $stmt->bindValue($identifier, $this->value, PDO::PARAM_STR); - break; - case 'CREATED_AT': - $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); - break; - case 'UPDATED_AT': - $stmt->bindValue($identifier, $this->updated_at ? $this->updated_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); - break; - } - } - $stmt->execute(); - } catch (Exception $e) { - Propel::log($e->getMessage(), Propel::LOG_ERR); - throw new PropelException(sprintf('Unable to execute INSERT statement [%s]', $sql), 0, $e); - } - - try { - $pk = $con->lastInsertId(); - } catch (Exception $e) { - throw new PropelException('Unable to get autoincrement id.', 0, $e); - } - $this->setId($pk); - - $this->setNew(false); - } - - /** - * Update the row in the database. - * - * @param ConnectionInterface $con - * - * @return Integer Number of updated rows - * @see doSave() - */ - protected function doUpdate(ConnectionInterface $con) - { - $selectCriteria = $this->buildPkeyCriteria(); - $valuesCriteria = $this->buildCriteria(); - - return $selectCriteria->doUpdate($valuesCriteria, $con); - } - - /** - * Retrieves a field from the object by name passed in as a string. - * - * @param string $name name - * @param string $type The type of fieldname the $name is of: - * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * Defaults to TableMap::TYPE_PHPNAME. - * @return mixed Value of field. - */ - public function getByName($name, $type = TableMap::TYPE_PHPNAME) - { - $pos = CouponRuleTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); - $field = $this->getByPosition($pos); - - return $field; - } - - /** - * Retrieves a field from the object by Position as specified in the xml schema. - * Zero-based. - * - * @param int $pos position in xml schema - * @return mixed Value of field at $pos - */ - public function getByPosition($pos) - { - switch ($pos) { - case 0: - return $this->getId(); - break; - case 1: - return $this->getCouponId(); - break; - case 2: - return $this->getController(); - break; - case 3: - return $this->getOperation(); - break; - case 4: - return $this->getValue(); - break; - case 5: - return $this->getCreatedAt(); - break; - case 6: - return $this->getUpdatedAt(); - break; - default: - return null; - break; - } // switch() - } - - /** - * Exports the object as an array. - * - * You can specify the key type of the array by passing one of the class - * type constants. - * - * @param string $keyType (optional) One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME, - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * Defaults to TableMap::TYPE_PHPNAME. - * @param boolean $includeLazyLoadColumns (optional) Whether to include lazy loaded columns. Defaults to TRUE. - * @param array $alreadyDumpedObjects List of objects to skip to avoid recursion - * @param boolean $includeForeignObjects (optional) Whether to include hydrated related objects. Default to FALSE. - * - * @return array an associative array containing the field names (as keys) and field values - */ - public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) - { - if (isset($alreadyDumpedObjects['CouponRule'][$this->getPrimaryKey()])) { - return '*RECURSION*'; - } - $alreadyDumpedObjects['CouponRule'][$this->getPrimaryKey()] = true; - $keys = CouponRuleTableMap::getFieldNames($keyType); - $result = array( - $keys[0] => $this->getId(), - $keys[1] => $this->getCouponId(), - $keys[2] => $this->getController(), - $keys[3] => $this->getOperation(), - $keys[4] => $this->getValue(), - $keys[5] => $this->getCreatedAt(), - $keys[6] => $this->getUpdatedAt(), - ); - $virtualColumns = $this->virtualColumns; - foreach($virtualColumns as $key => $virtualColumn) - { - $result[$key] = $virtualColumn; - } - - if ($includeForeignObjects) { - if (null !== $this->aCoupon) { - $result['Coupon'] = $this->aCoupon->toArray($keyType, $includeLazyLoadColumns, $alreadyDumpedObjects, true); - } - } - - return $result; - } - - /** - * Sets a field from the object by name passed in as a string. - * - * @param string $name - * @param mixed $value field value - * @param string $type The type of fieldname the $name is of: - * one of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * Defaults to TableMap::TYPE_PHPNAME. - * @return void - */ - public function setByName($name, $value, $type = TableMap::TYPE_PHPNAME) - { - $pos = CouponRuleTableMap::translateFieldName($name, $type, TableMap::TYPE_NUM); - - return $this->setByPosition($pos, $value); - } - - /** - * Sets a field from the object by Position as specified in the xml schema. - * Zero-based. - * - * @param int $pos position in xml schema - * @param mixed $value field value - * @return void - */ - public function setByPosition($pos, $value) - { - switch ($pos) { - case 0: - $this->setId($value); - break; - case 1: - $this->setCouponId($value); - break; - case 2: - $this->setController($value); - break; - case 3: - $this->setOperation($value); - break; - case 4: - $this->setValue($value); - break; - case 5: - $this->setCreatedAt($value); - break; - case 6: - $this->setUpdatedAt($value); - break; - } // switch() - } - - /** - * Populates the object using an array. - * - * This is particularly useful when populating an object from one of the - * request arrays (e.g. $_POST). This method goes through the column - * names, checking to see whether a matching key exists in populated - * array. If so the setByName() method is called for that column. - * - * You can specify the key type of the array by additionally passing one - * of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME, - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * The default key type is the column's TableMap::TYPE_PHPNAME. - * - * @param array $arr An array to populate the object from. - * @param string $keyType The type of keys the array uses. - * @return void - */ - public function fromArray($arr, $keyType = TableMap::TYPE_PHPNAME) - { - $keys = CouponRuleTableMap::getFieldNames($keyType); - - if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); - if (array_key_exists($keys[1], $arr)) $this->setCouponId($arr[$keys[1]]); - if (array_key_exists($keys[2], $arr)) $this->setController($arr[$keys[2]]); - if (array_key_exists($keys[3], $arr)) $this->setOperation($arr[$keys[3]]); - if (array_key_exists($keys[4], $arr)) $this->setValue($arr[$keys[4]]); - if (array_key_exists($keys[5], $arr)) $this->setCreatedAt($arr[$keys[5]]); - if (array_key_exists($keys[6], $arr)) $this->setUpdatedAt($arr[$keys[6]]); - } - - /** - * Build a Criteria object containing the values of all modified columns in this object. - * - * @return Criteria The Criteria object containing all modified values. - */ - public function buildCriteria() - { - $criteria = new Criteria(CouponRuleTableMap::DATABASE_NAME); - - if ($this->isColumnModified(CouponRuleTableMap::ID)) $criteria->add(CouponRuleTableMap::ID, $this->id); - if ($this->isColumnModified(CouponRuleTableMap::COUPON_ID)) $criteria->add(CouponRuleTableMap::COUPON_ID, $this->coupon_id); - if ($this->isColumnModified(CouponRuleTableMap::CONTROLLER)) $criteria->add(CouponRuleTableMap::CONTROLLER, $this->controller); - if ($this->isColumnModified(CouponRuleTableMap::OPERATION)) $criteria->add(CouponRuleTableMap::OPERATION, $this->operation); - if ($this->isColumnModified(CouponRuleTableMap::VALUE)) $criteria->add(CouponRuleTableMap::VALUE, $this->value); - if ($this->isColumnModified(CouponRuleTableMap::CREATED_AT)) $criteria->add(CouponRuleTableMap::CREATED_AT, $this->created_at); - if ($this->isColumnModified(CouponRuleTableMap::UPDATED_AT)) $criteria->add(CouponRuleTableMap::UPDATED_AT, $this->updated_at); - - return $criteria; - } - - /** - * Builds a Criteria object containing the primary key for this object. - * - * Unlike buildCriteria() this method includes the primary key values regardless - * of whether or not they have been modified. - * - * @return Criteria The Criteria object containing value(s) for primary key(s). - */ - public function buildPkeyCriteria() - { - $criteria = new Criteria(CouponRuleTableMap::DATABASE_NAME); - $criteria->add(CouponRuleTableMap::ID, $this->id); - - return $criteria; - } - - /** - * Returns the primary key for this object (row). - * @return int - */ - public function getPrimaryKey() - { - return $this->getId(); - } - - /** - * Generic method to set the primary key (id column). - * - * @param int $key Primary key. - * @return void - */ - public function setPrimaryKey($key) - { - $this->setId($key); - } - - /** - * Returns true if the primary key for this object is null. - * @return boolean - */ - public function isPrimaryKeyNull() - { - - return null === $this->getId(); - } - - /** - * Sets contents of passed object to values from current object. - * - * If desired, this method can also make copies of all associated (fkey referrers) - * objects. - * - * @param object $copyObj An object of \Thelia\Model\CouponRule (or compatible) type. - * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. - * @param boolean $makeNew Whether to reset autoincrement PKs and make the object new. - * @throws PropelException - */ - public function copyInto($copyObj, $deepCopy = false, $makeNew = true) - { - $copyObj->setCouponId($this->getCouponId()); - $copyObj->setController($this->getController()); - $copyObj->setOperation($this->getOperation()); - $copyObj->setValue($this->getValue()); - $copyObj->setCreatedAt($this->getCreatedAt()); - $copyObj->setUpdatedAt($this->getUpdatedAt()); - if ($makeNew) { - $copyObj->setNew(true); - $copyObj->setId(NULL); // this is a auto-increment column, so set to default value - } - } - - /** - * Makes a copy of this object that will be inserted as a new row in table when saved. - * It creates a new object filling in the simple attributes, but skipping any primary - * keys that are defined for the table. - * - * If desired, this method can also make copies of all associated (fkey referrers) - * objects. - * - * @param boolean $deepCopy Whether to also copy all rows that refer (by fkey) to the current row. - * @return \Thelia\Model\CouponRule Clone of current object. - * @throws PropelException - */ - public function copy($deepCopy = false) - { - // we use get_class(), because this might be a subclass - $clazz = get_class($this); - $copyObj = new $clazz(); - $this->copyInto($copyObj, $deepCopy); - - return $copyObj; - } - - /** - * Declares an association between this object and a ChildCoupon object. - * - * @param ChildCoupon $v - * @return \Thelia\Model\CouponRule The current object (for fluent API support) - * @throws PropelException - */ - public function setCoupon(ChildCoupon $v = null) - { - if ($v === null) { - $this->setCouponId(NULL); - } else { - $this->setCouponId($v->getId()); - } - - $this->aCoupon = $v; - - // Add binding for other direction of this n:n relationship. - // If this object has already been added to the ChildCoupon object, it will not be re-added. - if ($v !== null) { - $v->addCouponRule($this); - } - - - return $this; - } - - - /** - * Get the associated ChildCoupon object - * - * @param ConnectionInterface $con Optional Connection object. - * @return ChildCoupon The associated ChildCoupon object. - * @throws PropelException - */ - public function getCoupon(ConnectionInterface $con = null) - { - if ($this->aCoupon === null && ($this->coupon_id !== null)) { - $this->aCoupon = ChildCouponQuery::create()->findPk($this->coupon_id, $con); - /* The following can be used additionally to - guarantee the related object contains a reference - to this object. This level of coupling may, however, be - undesirable since it could result in an only partially populated collection - in the referenced object. - $this->aCoupon->addCouponRules($this); - */ - } - - return $this->aCoupon; - } - - /** - * Clears the current object and sets all attributes to their default values - */ - public function clear() - { - $this->id = null; - $this->coupon_id = null; - $this->controller = null; - $this->operation = null; - $this->value = null; - $this->created_at = null; - $this->updated_at = null; - $this->alreadyInSave = false; - $this->clearAllReferences(); - $this->resetModified(); - $this->setNew(true); - $this->setDeleted(false); - } - - /** - * Resets all references to other model objects or collections of model objects. - * - * This method is a user-space workaround for PHP's inability to garbage collect - * objects with circular references (even in PHP 5.3). This is currently necessary - * when using Propel in certain daemon or large-volume/high-memory operations. - * - * @param boolean $deep Whether to also clear the references on all referrer objects. - */ - public function clearAllReferences($deep = false) - { - if ($deep) { - } // if ($deep) - - $this->aCoupon = null; - } - - /** - * Return the string representation of this object - * - * @return string - */ - public function __toString() - { - return (string) $this->exportTo(CouponRuleTableMap::DEFAULT_STRING_FORMAT); - } - - // timestampable behavior - - /** - * Mark the current object so that the update date doesn't get updated during next save - * - * @return ChildCouponRule The current object (for fluent API support) - */ - public function keepUpdateDateUnchanged() - { - $this->modifiedColumns[] = CouponRuleTableMap::UPDATED_AT; - - return $this; - } - - /** - * Code to be run before persisting the object - * @param ConnectionInterface $con - * @return boolean - */ - public function preSave(ConnectionInterface $con = null) - { - return true; - } - - /** - * Code to be run after persisting the object - * @param ConnectionInterface $con - */ - public function postSave(ConnectionInterface $con = null) - { - - } - - /** - * Code to be run before inserting to database - * @param ConnectionInterface $con - * @return boolean - */ - public function preInsert(ConnectionInterface $con = null) - { - return true; - } - - /** - * Code to be run after inserting to database - * @param ConnectionInterface $con - */ - public function postInsert(ConnectionInterface $con = null) - { - - } - - /** - * Code to be run before updating the object in database - * @param ConnectionInterface $con - * @return boolean - */ - public function preUpdate(ConnectionInterface $con = null) - { - return true; - } - - /** - * Code to be run after updating the object in database - * @param ConnectionInterface $con - */ - public function postUpdate(ConnectionInterface $con = null) - { - - } - - /** - * Code to be run before deleting the object in database - * @param ConnectionInterface $con - * @return boolean - */ - public function preDelete(ConnectionInterface $con = null) - { - return true; - } - - /** - * Code to be run after deleting the object in database - * @param ConnectionInterface $con - */ - public function postDelete(ConnectionInterface $con = null) - { - - } - - - /** - * Derived method to catches calls to undefined methods. - * - * Provides magic import/export method support (fromXML()/toXML(), fromYAML()/toYAML(), etc.). - * Allows to define default __call() behavior if you overwrite __call() - * - * @param string $name - * @param mixed $params - * - * @return array|string - */ - public function __call($name, $params) - { - if (0 === strpos($name, 'get')) { - $virtualColumn = substr($name, 3); - if ($this->hasVirtualColumn($virtualColumn)) { - return $this->getVirtualColumn($virtualColumn); - } - - $virtualColumn = lcfirst($virtualColumn); - if ($this->hasVirtualColumn($virtualColumn)) { - return $this->getVirtualColumn($virtualColumn); - } - } - - if (0 === strpos($name, 'from')) { - $format = substr($name, 4); - - return $this->importFrom($format, reset($params)); - } - - if (0 === strpos($name, 'to')) { - $format = substr($name, 2); - $includeLazyLoadColumns = isset($params[0]) ? $params[0] : true; - - return $this->exportTo($format, $includeLazyLoadColumns); - } - - throw new BadMethodCallException(sprintf('Call to undefined method: %s.', $name)); - } - -} diff --git a/core/lib/Thelia/Model/Base/CouponRuleQuery.php b/core/lib/Thelia/Model/Base/CouponRuleQuery.php deleted file mode 100755 index 0789f84d6..000000000 --- a/core/lib/Thelia/Model/Base/CouponRuleQuery.php +++ /dev/null @@ -1,744 +0,0 @@ -setModelAlias($modelAlias); - } - if ($criteria instanceof Criteria) { - $query->mergeWith($criteria); - } - - return $query; - } - - /** - * Find object by primary key. - * Propel uses the instance pool to skip the database if the object exists. - * Go fast if the query is untouched. - * - * - * $obj = $c->findPk(12, $con); - * - * - * @param mixed $key Primary key to use for the query - * @param ConnectionInterface $con an optional connection object - * - * @return ChildCouponRule|array|mixed the result, formatted by the current formatter - */ - public function findPk($key, $con = null) - { - if ($key === null) { - return null; - } - if ((null !== ($obj = CouponRuleTableMap::getInstanceFromPool((string) $key))) && !$this->formatter) { - // the object is already in the instance pool - return $obj; - } - if ($con === null) { - $con = Propel::getServiceContainer()->getReadConnection(CouponRuleTableMap::DATABASE_NAME); - } - $this->basePreSelect($con); - if ($this->formatter || $this->modelAlias || $this->with || $this->select - || $this->selectColumns || $this->asColumns || $this->selectModifiers - || $this->map || $this->having || $this->joins) { - return $this->findPkComplex($key, $con); - } else { - return $this->findPkSimple($key, $con); - } - } - - /** - * Find object by primary key using raw SQL to go fast. - * Bypass doSelect() and the object formatter by using generated code. - * - * @param mixed $key Primary key to use for the query - * @param ConnectionInterface $con A connection object - * - * @return ChildCouponRule A model object, or null if the key is not found - */ - protected function findPkSimple($key, $con) - { - $sql = 'SELECT ID, COUPON_ID, CONTROLLER, OPERATION, VALUE, CREATED_AT, UPDATED_AT FROM coupon_rule WHERE ID = :p0'; - try { - $stmt = $con->prepare($sql); - $stmt->bindValue(':p0', $key, PDO::PARAM_INT); - $stmt->execute(); - } catch (Exception $e) { - Propel::log($e->getMessage(), Propel::LOG_ERR); - throw new PropelException(sprintf('Unable to execute SELECT statement [%s]', $sql), 0, $e); - } - $obj = null; - if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { - $obj = new ChildCouponRule(); - $obj->hydrate($row); - CouponRuleTableMap::addInstanceToPool($obj, (string) $key); - } - $stmt->closeCursor(); - - return $obj; - } - - /** - * Find object by primary key. - * - * @param mixed $key Primary key to use for the query - * @param ConnectionInterface $con A connection object - * - * @return ChildCouponRule|array|mixed the result, formatted by the current formatter - */ - protected function findPkComplex($key, $con) - { - // As the query uses a PK condition, no limit(1) is necessary. - $criteria = $this->isKeepQuery() ? clone $this : $this; - $dataFetcher = $criteria - ->filterByPrimaryKey($key) - ->doSelect($con); - - return $criteria->getFormatter()->init($criteria)->formatOne($dataFetcher); - } - - /** - * Find objects by primary key - * - * $objs = $c->findPks(array(12, 56, 832), $con); - * - * @param array $keys Primary keys to use for the query - * @param ConnectionInterface $con an optional connection object - * - * @return ObjectCollection|array|mixed the list of results, formatted by the current formatter - */ - public function findPks($keys, $con = null) - { - if (null === $con) { - $con = Propel::getServiceContainer()->getReadConnection($this->getDbName()); - } - $this->basePreSelect($con); - $criteria = $this->isKeepQuery() ? clone $this : $this; - $dataFetcher = $criteria - ->filterByPrimaryKeys($keys) - ->doSelect($con); - - return $criteria->getFormatter()->init($criteria)->format($dataFetcher); - } - - /** - * Filter the query by primary key - * - * @param mixed $key Primary key to use for the query - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByPrimaryKey($key) - { - - return $this->addUsingAlias(CouponRuleTableMap::ID, $key, Criteria::EQUAL); - } - - /** - * Filter the query by a list of primary keys - * - * @param array $keys The list of primary key to use for the query - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByPrimaryKeys($keys) - { - - return $this->addUsingAlias(CouponRuleTableMap::ID, $keys, Criteria::IN); - } - - /** - * Filter the query on the id column - * - * Example usage: - * - * $query->filterById(1234); // WHERE id = 1234 - * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) - * $query->filterById(array('min' => 12)); // WHERE id > 12 - * - * - * @param mixed $id The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterById($id = null, $comparison = null) - { - if (is_array($id)) { - $useMinMax = false; - if (isset($id['min'])) { - $this->addUsingAlias(CouponRuleTableMap::ID, $id['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($id['max'])) { - $this->addUsingAlias(CouponRuleTableMap::ID, $id['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::ID, $id, $comparison); - } - - /** - * Filter the query on the coupon_id column - * - * Example usage: - * - * $query->filterByCouponId(1234); // WHERE coupon_id = 1234 - * $query->filterByCouponId(array(12, 34)); // WHERE coupon_id IN (12, 34) - * $query->filterByCouponId(array('min' => 12)); // WHERE coupon_id > 12 - * - * - * @see filterByCoupon() - * - * @param mixed $couponId The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByCouponId($couponId = null, $comparison = null) - { - if (is_array($couponId)) { - $useMinMax = false; - if (isset($couponId['min'])) { - $this->addUsingAlias(CouponRuleTableMap::COUPON_ID, $couponId['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($couponId['max'])) { - $this->addUsingAlias(CouponRuleTableMap::COUPON_ID, $couponId['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::COUPON_ID, $couponId, $comparison); - } - - /** - * Filter the query on the controller column - * - * Example usage: - * - * $query->filterByController('fooValue'); // WHERE controller = 'fooValue' - * $query->filterByController('%fooValue%'); // WHERE controller LIKE '%fooValue%' - * - * - * @param string $controller The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByController($controller = null, $comparison = null) - { - if (null === $comparison) { - if (is_array($controller)) { - $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $controller)) { - $controller = str_replace('*', '%', $controller); - $comparison = Criteria::LIKE; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::CONTROLLER, $controller, $comparison); - } - - /** - * Filter the query on the operation column - * - * Example usage: - * - * $query->filterByOperation('fooValue'); // WHERE operation = 'fooValue' - * $query->filterByOperation('%fooValue%'); // WHERE operation LIKE '%fooValue%' - * - * - * @param string $operation The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByOperation($operation = null, $comparison = null) - { - if (null === $comparison) { - if (is_array($operation)) { - $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $operation)) { - $operation = str_replace('*', '%', $operation); - $comparison = Criteria::LIKE; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::OPERATION, $operation, $comparison); - } - - /** - * Filter the query on the value column - * - * Example usage: - * - * $query->filterByValue(1234); // WHERE value = 1234 - * $query->filterByValue(array(12, 34)); // WHERE value IN (12, 34) - * $query->filterByValue(array('min' => 12)); // WHERE value > 12 - * - * - * @param mixed $value The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByValue($value = null, $comparison = null) - { - if (is_array($value)) { - $useMinMax = false; - if (isset($value['min'])) { - $this->addUsingAlias(CouponRuleTableMap::VALUE, $value['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($value['max'])) { - $this->addUsingAlias(CouponRuleTableMap::VALUE, $value['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::VALUE, $value, $comparison); - } - - /** - * Filter the query on the created_at column - * - * Example usage: - * - * $query->filterByCreatedAt('2011-03-14'); // WHERE created_at = '2011-03-14' - * $query->filterByCreatedAt('now'); // WHERE created_at = '2011-03-14' - * $query->filterByCreatedAt(array('max' => 'yesterday')); // WHERE created_at > '2011-03-13' - * - * - * @param mixed $createdAt The value to use as filter. - * Values can be integers (unix timestamps), DateTime objects, or strings. - * Empty strings are treated as NULL. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByCreatedAt($createdAt = null, $comparison = null) - { - if (is_array($createdAt)) { - $useMinMax = false; - if (isset($createdAt['min'])) { - $this->addUsingAlias(CouponRuleTableMap::CREATED_AT, $createdAt['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($createdAt['max'])) { - $this->addUsingAlias(CouponRuleTableMap::CREATED_AT, $createdAt['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::CREATED_AT, $createdAt, $comparison); - } - - /** - * Filter the query on the updated_at column - * - * Example usage: - * - * $query->filterByUpdatedAt('2011-03-14'); // WHERE updated_at = '2011-03-14' - * $query->filterByUpdatedAt('now'); // WHERE updated_at = '2011-03-14' - * $query->filterByUpdatedAt(array('max' => 'yesterday')); // WHERE updated_at > '2011-03-13' - * - * - * @param mixed $updatedAt The value to use as filter. - * Values can be integers (unix timestamps), DateTime objects, or strings. - * Empty strings are treated as NULL. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByUpdatedAt($updatedAt = null, $comparison = null) - { - if (is_array($updatedAt)) { - $useMinMax = false; - if (isset($updatedAt['min'])) { - $this->addUsingAlias(CouponRuleTableMap::UPDATED_AT, $updatedAt['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($updatedAt['max'])) { - $this->addUsingAlias(CouponRuleTableMap::UPDATED_AT, $updatedAt['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } - } - - return $this->addUsingAlias(CouponRuleTableMap::UPDATED_AT, $updatedAt, $comparison); - } - - /** - * Filter the query by a related \Thelia\Model\Coupon object - * - * @param \Thelia\Model\Coupon|ObjectCollection $coupon The related object(s) to use as filter - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function filterByCoupon($coupon, $comparison = null) - { - if ($coupon instanceof \Thelia\Model\Coupon) { - return $this - ->addUsingAlias(CouponRuleTableMap::COUPON_ID, $coupon->getId(), $comparison); - } elseif ($coupon instanceof ObjectCollection) { - if (null === $comparison) { - $comparison = Criteria::IN; - } - - return $this - ->addUsingAlias(CouponRuleTableMap::COUPON_ID, $coupon->toKeyValue('PrimaryKey', 'Id'), $comparison); - } else { - throw new PropelException('filterByCoupon() only accepts arguments of type \Thelia\Model\Coupon or Collection'); - } - } - - /** - * Adds a JOIN clause to the query using the Coupon relation - * - * @param string $relationAlias optional alias for the relation - * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function joinCoupon($relationAlias = null, $joinType = Criteria::INNER_JOIN) - { - $tableMap = $this->getTableMap(); - $relationMap = $tableMap->getRelation('Coupon'); - - // create a ModelJoin object for this join - $join = new ModelJoin(); - $join->setJoinType($joinType); - $join->setRelationMap($relationMap, $this->useAliasInSQL ? $this->getModelAlias() : null, $relationAlias); - if ($previousJoin = $this->getPreviousJoin()) { - $join->setPreviousJoin($previousJoin); - } - - // add the ModelJoin to the current object - if ($relationAlias) { - $this->addAlias($relationAlias, $relationMap->getRightTable()->getName()); - $this->addJoinObject($join, $relationAlias); - } else { - $this->addJoinObject($join, 'Coupon'); - } - - return $this; - } - - /** - * Use the Coupon relation Coupon object - * - * @see useQuery() - * - * @param string $relationAlias optional alias for the relation, - * to be used as main alias in the secondary query - * @param string $joinType Accepted values are null, 'left join', 'right join', 'inner join' - * - * @return \Thelia\Model\CouponQuery A secondary query class using the current class as primary query - */ - public function useCouponQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) - { - return $this - ->joinCoupon($relationAlias, $joinType) - ->useQuery($relationAlias ? $relationAlias : 'Coupon', '\Thelia\Model\CouponQuery'); - } - - /** - * Exclude object from result - * - * @param ChildCouponRule $couponRule Object to remove from the list of results - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function prune($couponRule = null) - { - if ($couponRule) { - $this->addUsingAlias(CouponRuleTableMap::ID, $couponRule->getId(), Criteria::NOT_EQUAL); - } - - return $this; - } - - /** - * Deletes all rows from the coupon_rule table. - * - * @param ConnectionInterface $con the connection to use - * @return int The number of affected rows (if supported by underlying database driver). - */ - public function doDeleteAll(ConnectionInterface $con = null) - { - if (null === $con) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - $affectedRows = 0; // initialize var to track total num of affected rows - try { - // use transaction because $criteria could contain info - // for more than one table or we could emulating ON DELETE CASCADE, etc. - $con->beginTransaction(); - $affectedRows += parent::doDeleteAll($con); - // Because this db requires some delete cascade/set null emulation, we have to - // clear the cached instance *after* the emulation has happened (since - // instances get re-added by the select statement contained therein). - CouponRuleTableMap::clearInstancePool(); - CouponRuleTableMap::clearRelatedInstancePool(); - - $con->commit(); - } catch (PropelException $e) { - $con->rollBack(); - throw $e; - } - - return $affectedRows; - } - - /** - * Performs a DELETE on the database, given a ChildCouponRule or Criteria object OR a primary key value. - * - * @param mixed $values Criteria or ChildCouponRule object or primary key or array of primary keys - * which is used to create the DELETE statement - * @param ConnectionInterface $con the connection to use - * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows - * if supported by native driver or if emulated using Propel. - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public function delete(ConnectionInterface $con = null) - { - if (null === $con) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - - $criteria = $this; - - // Set the correct dbName - $criteria->setDbName(CouponRuleTableMap::DATABASE_NAME); - - $affectedRows = 0; // initialize var to track total num of affected rows - - try { - // use transaction because $criteria could contain info - // for more than one table or we could emulating ON DELETE CASCADE, etc. - $con->beginTransaction(); - - - CouponRuleTableMap::removeInstanceFromPool($criteria); - - $affectedRows += ModelCriteria::delete($con); - CouponRuleTableMap::clearRelatedInstancePool(); - $con->commit(); - - return $affectedRows; - } catch (PropelException $e) { - $con->rollBack(); - throw $e; - } - } - - // timestampable behavior - - /** - * Filter by the latest updated - * - * @param int $nbDays Maximum age of the latest update in days - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function recentlyUpdated($nbDays = 7) - { - return $this->addUsingAlias(CouponRuleTableMap::UPDATED_AT, time() - $nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL); - } - - /** - * Filter by the latest created - * - * @param int $nbDays Maximum age of in days - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function recentlyCreated($nbDays = 7) - { - return $this->addUsingAlias(CouponRuleTableMap::CREATED_AT, time() - $nbDays * 24 * 60 * 60, Criteria::GREATER_EQUAL); - } - - /** - * Order by update date desc - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function lastUpdatedFirst() - { - return $this->addDescendingOrderByColumn(CouponRuleTableMap::UPDATED_AT); - } - - /** - * Order by update date asc - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function firstUpdatedFirst() - { - return $this->addAscendingOrderByColumn(CouponRuleTableMap::UPDATED_AT); - } - - /** - * Order by create date desc - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function lastCreatedFirst() - { - return $this->addDescendingOrderByColumn(CouponRuleTableMap::CREATED_AT); - } - - /** - * Order by create date asc - * - * @return ChildCouponRuleQuery The current query, for fluid interface - */ - public function firstCreatedFirst() - { - return $this->addAscendingOrderByColumn(CouponRuleTableMap::CREATED_AT); - } - -} // CouponRuleQuery diff --git a/core/lib/Thelia/Model/Base/Currency.php b/core/lib/Thelia/Model/Base/Currency.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CurrencyI18n.php b/core/lib/Thelia/Model/Base/CurrencyI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CurrencyI18nQuery.php b/core/lib/Thelia/Model/Base/CurrencyI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CurrencyQuery.php b/core/lib/Thelia/Model/Base/CurrencyQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Customer.php b/core/lib/Thelia/Model/Base/Customer.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CustomerQuery.php b/core/lib/Thelia/Model/Base/CustomerQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CustomerTitle.php b/core/lib/Thelia/Model/Base/CustomerTitle.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CustomerTitleI18n.php b/core/lib/Thelia/Model/Base/CustomerTitleI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CustomerTitleI18nQuery.php b/core/lib/Thelia/Model/Base/CustomerTitleI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/CustomerTitleQuery.php b/core/lib/Thelia/Model/Base/CustomerTitleQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Delivzone.php b/core/lib/Thelia/Model/Base/Delivzone.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/DelivzoneQuery.php b/core/lib/Thelia/Model/Base/DelivzoneQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Feature.php b/core/lib/Thelia/Model/Base/Feature.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureAv.php b/core/lib/Thelia/Model/Base/FeatureAv.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureAvI18n.php b/core/lib/Thelia/Model/Base/FeatureAvI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureAvI18nQuery.php b/core/lib/Thelia/Model/Base/FeatureAvI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureAvQuery.php b/core/lib/Thelia/Model/Base/FeatureAvQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureCategory.php b/core/lib/Thelia/Model/Base/FeatureCategory.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureCategoryQuery.php b/core/lib/Thelia/Model/Base/FeatureCategoryQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureI18n.php b/core/lib/Thelia/Model/Base/FeatureI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureI18nQuery.php b/core/lib/Thelia/Model/Base/FeatureI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureProduct.php b/core/lib/Thelia/Model/Base/FeatureProduct.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureProductQuery.php b/core/lib/Thelia/Model/Base/FeatureProductQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FeatureQuery.php b/core/lib/Thelia/Model/Base/FeatureQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Folder.php b/core/lib/Thelia/Model/Base/Folder.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderDocument.php b/core/lib/Thelia/Model/Base/FolderDocument.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderDocumentI18n.php b/core/lib/Thelia/Model/Base/FolderDocumentI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderDocumentI18nQuery.php b/core/lib/Thelia/Model/Base/FolderDocumentI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderDocumentQuery.php b/core/lib/Thelia/Model/Base/FolderDocumentQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderI18n.php b/core/lib/Thelia/Model/Base/FolderI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderI18nQuery.php b/core/lib/Thelia/Model/Base/FolderI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderImage.php b/core/lib/Thelia/Model/Base/FolderImage.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderImageI18n.php b/core/lib/Thelia/Model/Base/FolderImageI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderImageI18nQuery.php b/core/lib/Thelia/Model/Base/FolderImageI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderImageQuery.php b/core/lib/Thelia/Model/Base/FolderImageQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderQuery.php b/core/lib/Thelia/Model/Base/FolderQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderVersion.php b/core/lib/Thelia/Model/Base/FolderVersion.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/FolderVersionQuery.php b/core/lib/Thelia/Model/Base/FolderVersionQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Group.php b/core/lib/Thelia/Model/Base/Group.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupI18n.php b/core/lib/Thelia/Model/Base/GroupI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupI18nQuery.php b/core/lib/Thelia/Model/Base/GroupI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupModule.php b/core/lib/Thelia/Model/Base/GroupModule.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupModuleQuery.php b/core/lib/Thelia/Model/Base/GroupModuleQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupQuery.php b/core/lib/Thelia/Model/Base/GroupQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupResource.php b/core/lib/Thelia/Model/Base/GroupResource.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/GroupResourceQuery.php b/core/lib/Thelia/Model/Base/GroupResourceQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Lang.php b/core/lib/Thelia/Model/Base/Lang.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/LangQuery.php b/core/lib/Thelia/Model/Base/LangQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Message.php b/core/lib/Thelia/Model/Base/Message.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/MessageI18n.php b/core/lib/Thelia/Model/Base/MessageI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/MessageI18nQuery.php b/core/lib/Thelia/Model/Base/MessageI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/MessageQuery.php b/core/lib/Thelia/Model/Base/MessageQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/MessageVersion.php b/core/lib/Thelia/Model/Base/MessageVersion.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/MessageVersionQuery.php b/core/lib/Thelia/Model/Base/MessageVersionQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Module.php b/core/lib/Thelia/Model/Base/Module.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ModuleI18n.php b/core/lib/Thelia/Model/Base/ModuleI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ModuleI18nQuery.php b/core/lib/Thelia/Model/Base/ModuleI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ModuleQuery.php b/core/lib/Thelia/Model/Base/ModuleQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Order.php b/core/lib/Thelia/Model/Base/Order.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderAddress.php b/core/lib/Thelia/Model/Base/OrderAddress.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderAddressQuery.php b/core/lib/Thelia/Model/Base/OrderAddressQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderFeature.php b/core/lib/Thelia/Model/Base/OrderFeature.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderFeatureQuery.php b/core/lib/Thelia/Model/Base/OrderFeatureQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderProduct.php b/core/lib/Thelia/Model/Base/OrderProduct.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderProductQuery.php b/core/lib/Thelia/Model/Base/OrderProductQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderQuery.php b/core/lib/Thelia/Model/Base/OrderQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderStatus.php b/core/lib/Thelia/Model/Base/OrderStatus.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderStatusI18n.php b/core/lib/Thelia/Model/Base/OrderStatusI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderStatusI18nQuery.php b/core/lib/Thelia/Model/Base/OrderStatusI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/OrderStatusQuery.php b/core/lib/Thelia/Model/Base/OrderStatusQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Product.php b/core/lib/Thelia/Model/Base/Product.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductCategory.php b/core/lib/Thelia/Model/Base/ProductCategory.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductCategoryQuery.php b/core/lib/Thelia/Model/Base/ProductCategoryQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductDocument.php b/core/lib/Thelia/Model/Base/ProductDocument.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductDocumentI18n.php b/core/lib/Thelia/Model/Base/ProductDocumentI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductDocumentI18nQuery.php b/core/lib/Thelia/Model/Base/ProductDocumentI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductDocumentQuery.php b/core/lib/Thelia/Model/Base/ProductDocumentQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductI18n.php b/core/lib/Thelia/Model/Base/ProductI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductI18nQuery.php b/core/lib/Thelia/Model/Base/ProductI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductImage.php b/core/lib/Thelia/Model/Base/ProductImage.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductImageI18n.php b/core/lib/Thelia/Model/Base/ProductImageI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductImageI18nQuery.php b/core/lib/Thelia/Model/Base/ProductImageI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductImageQuery.php b/core/lib/Thelia/Model/Base/ProductImageQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductPrice.php b/core/lib/Thelia/Model/Base/ProductPrice.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductPriceQuery.php b/core/lib/Thelia/Model/Base/ProductPriceQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductQuery.php b/core/lib/Thelia/Model/Base/ProductQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductSaleElements.php b/core/lib/Thelia/Model/Base/ProductSaleElements.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductSaleElementsQuery.php b/core/lib/Thelia/Model/Base/ProductSaleElementsQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductVersion.php b/core/lib/Thelia/Model/Base/ProductVersion.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ProductVersionQuery.php b/core/lib/Thelia/Model/Base/ProductVersionQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Resource.php b/core/lib/Thelia/Model/Base/Resource.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ResourceI18n.php b/core/lib/Thelia/Model/Base/ResourceI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ResourceI18nQuery.php b/core/lib/Thelia/Model/Base/ResourceI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/ResourceQuery.php b/core/lib/Thelia/Model/Base/ResourceQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/Tax.php b/core/lib/Thelia/Model/Base/Tax.php old mode 100755 new mode 100644 index 02e6bc3b0..ed4bb40f7 --- a/core/lib/Thelia/Model/Base/Tax.php +++ b/core/lib/Thelia/Model/Base/Tax.php @@ -791,10 +791,9 @@ abstract class Tax implements ActiveRecordInterface if ($this->taxRuleCountriesScheduledForDeletion !== null) { if (!$this->taxRuleCountriesScheduledForDeletion->isEmpty()) { - foreach ($this->taxRuleCountriesScheduledForDeletion as $taxRuleCountry) { - // need to save related object because we set the relation to null - $taxRuleCountry->save($con); - } + \Thelia\Model\TaxRuleCountryQuery::create() + ->filterByPrimaryKeys($this->taxRuleCountriesScheduledForDeletion->getPrimaryKeys(false)) + ->delete($con); $this->taxRuleCountriesScheduledForDeletion = null; } } @@ -1346,7 +1345,10 @@ abstract class Tax implements ActiveRecordInterface $taxRuleCountriesToDelete = $this->getTaxRuleCountries(new Criteria(), $con)->diff($taxRuleCountries); - $this->taxRuleCountriesScheduledForDeletion = $taxRuleCountriesToDelete; + //since at least one column in the foreign key is at the same time a PK + //we can not just set a PK to NULL in the lines below. We have to store + //a backup of all values, so we are able to manipulate these items based on the onDelete value later. + $this->taxRuleCountriesScheduledForDeletion = clone $taxRuleCountriesToDelete; foreach ($taxRuleCountriesToDelete as $taxRuleCountryRemoved) { $taxRuleCountryRemoved->setTax(null); @@ -1439,7 +1441,7 @@ abstract class Tax implements ActiveRecordInterface $this->taxRuleCountriesScheduledForDeletion = clone $this->collTaxRuleCountries; $this->taxRuleCountriesScheduledForDeletion->clear(); } - $this->taxRuleCountriesScheduledForDeletion[]= $taxRuleCountry; + $this->taxRuleCountriesScheduledForDeletion[]= clone $taxRuleCountry; $taxRuleCountry->setTax(null); } diff --git a/core/lib/Thelia/Model/Base/TaxI18n.php b/core/lib/Thelia/Model/Base/TaxI18n.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/TaxI18nQuery.php b/core/lib/Thelia/Model/Base/TaxI18nQuery.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Base/TaxQuery.php b/core/lib/Thelia/Model/Base/TaxQuery.php old mode 100755 new mode 100644 index 307ace57c..07316bf69 --- a/core/lib/Thelia/Model/Base/TaxQuery.php +++ b/core/lib/Thelia/Model/Base/TaxQuery.php @@ -432,7 +432,7 @@ abstract class TaxQuery extends ModelCriteria * * @return ChildTaxQuery The current query, for fluid interface */ - public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('TaxRuleCountry'); @@ -467,7 +467,7 @@ abstract class TaxQuery extends ModelCriteria * * @return \Thelia\Model\TaxRuleCountryQuery A secondary query class using the current class as primary query */ - public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinTaxRuleCountry($relationAlias, $joinType) diff --git a/core/lib/Thelia/Model/Base/TaxRule.php b/core/lib/Thelia/Model/Base/TaxRule.php old mode 100755 new mode 100644 index d33d47e2b..61f21d4e1 --- a/core/lib/Thelia/Model/Base/TaxRule.php +++ b/core/lib/Thelia/Model/Base/TaxRule.php @@ -67,24 +67,6 @@ abstract class TaxRule implements ActiveRecordInterface */ protected $id; - /** - * The value for the code field. - * @var string - */ - protected $code; - - /** - * The value for the title field. - * @var string - */ - protected $title; - - /** - * The value for the description field. - * @var string - */ - protected $description; - /** * The value for the created_at field. * @var string @@ -420,39 +402,6 @@ abstract class TaxRule implements ActiveRecordInterface return $this->id; } - /** - * Get the [code] column value. - * - * @return string - */ - public function getCode() - { - - return $this->code; - } - - /** - * Get the [title] column value. - * - * @return string - */ - public function getTitle() - { - - return $this->title; - } - - /** - * Get the [description] column value. - * - * @return string - */ - public function getDescription() - { - - return $this->description; - } - /** * Get the [optionally formatted] temporal [created_at] column value. * @@ -514,69 +463,6 @@ abstract class TaxRule implements ActiveRecordInterface return $this; } // setId() - /** - * Set the value of [code] column. - * - * @param string $v new value - * @return \Thelia\Model\TaxRule The current object (for fluent API support) - */ - public function setCode($v) - { - if ($v !== null) { - $v = (string) $v; - } - - if ($this->code !== $v) { - $this->code = $v; - $this->modifiedColumns[] = TaxRuleTableMap::CODE; - } - - - return $this; - } // setCode() - - /** - * Set the value of [title] column. - * - * @param string $v new value - * @return \Thelia\Model\TaxRule The current object (for fluent API support) - */ - public function setTitle($v) - { - if ($v !== null) { - $v = (string) $v; - } - - if ($this->title !== $v) { - $this->title = $v; - $this->modifiedColumns[] = TaxRuleTableMap::TITLE; - } - - - return $this; - } // setTitle() - - /** - * Set the value of [description] column. - * - * @param string $v new value - * @return \Thelia\Model\TaxRule The current object (for fluent API support) - */ - public function setDescription($v) - { - if ($v !== null) { - $v = (string) $v; - } - - if ($this->description !== $v) { - $this->description = $v; - $this->modifiedColumns[] = TaxRuleTableMap::DESCRIPTION; - } - - - return $this; - } // setDescription() - /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. * @@ -659,22 +545,13 @@ abstract class TaxRule implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : TaxRuleTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; $this->id = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxRuleTableMap::translateFieldName('Code', TableMap::TYPE_PHPNAME, $indexType)]; - $this->code = (null !== $col) ? (string) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxRuleTableMap::translateFieldName('Title', TableMap::TYPE_PHPNAME, $indexType)]; - $this->title = (null !== $col) ? (string) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxRuleTableMap::translateFieldName('Description', TableMap::TYPE_PHPNAME, $indexType)]; - $this->description = (null !== $col) ? (string) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : TaxRuleTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxRuleTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : TaxRuleTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxRuleTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -687,7 +564,7 @@ abstract class TaxRule implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 6; // 6 = TaxRuleTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 3; // 3 = TaxRuleTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\TaxRule object", 0, $e); @@ -968,15 +845,6 @@ abstract class TaxRule implements ActiveRecordInterface if ($this->isColumnModified(TaxRuleTableMap::ID)) { $modifiedColumns[':p' . $index++] = 'ID'; } - if ($this->isColumnModified(TaxRuleTableMap::CODE)) { - $modifiedColumns[':p' . $index++] = 'CODE'; - } - if ($this->isColumnModified(TaxRuleTableMap::TITLE)) { - $modifiedColumns[':p' . $index++] = 'TITLE'; - } - if ($this->isColumnModified(TaxRuleTableMap::DESCRIPTION)) { - $modifiedColumns[':p' . $index++] = 'DESCRIPTION'; - } if ($this->isColumnModified(TaxRuleTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; } @@ -997,15 +865,6 @@ abstract class TaxRule implements ActiveRecordInterface case 'ID': $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); break; - case 'CODE': - $stmt->bindValue($identifier, $this->code, PDO::PARAM_STR); - break; - case 'TITLE': - $stmt->bindValue($identifier, $this->title, PDO::PARAM_STR); - break; - case 'DESCRIPTION': - $stmt->bindValue($identifier, $this->description, PDO::PARAM_STR); - break; case 'CREATED_AT': $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); break; @@ -1078,18 +937,9 @@ abstract class TaxRule implements ActiveRecordInterface return $this->getId(); break; case 1: - return $this->getCode(); - break; - case 2: - return $this->getTitle(); - break; - case 3: - return $this->getDescription(); - break; - case 4: return $this->getCreatedAt(); break; - case 5: + case 2: return $this->getUpdatedAt(); break; default: @@ -1122,11 +972,8 @@ abstract class TaxRule implements ActiveRecordInterface $keys = TaxRuleTableMap::getFieldNames($keyType); $result = array( $keys[0] => $this->getId(), - $keys[1] => $this->getCode(), - $keys[2] => $this->getTitle(), - $keys[3] => $this->getDescription(), - $keys[4] => $this->getCreatedAt(), - $keys[5] => $this->getUpdatedAt(), + $keys[1] => $this->getCreatedAt(), + $keys[2] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1182,18 +1029,9 @@ abstract class TaxRule implements ActiveRecordInterface $this->setId($value); break; case 1: - $this->setCode($value); - break; - case 2: - $this->setTitle($value); - break; - case 3: - $this->setDescription($value); - break; - case 4: $this->setCreatedAt($value); break; - case 5: + case 2: $this->setUpdatedAt($value); break; } // switch() @@ -1221,11 +1059,8 @@ abstract class TaxRule implements ActiveRecordInterface $keys = TaxRuleTableMap::getFieldNames($keyType); if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); - if (array_key_exists($keys[1], $arr)) $this->setCode($arr[$keys[1]]); - if (array_key_exists($keys[2], $arr)) $this->setTitle($arr[$keys[2]]); - if (array_key_exists($keys[3], $arr)) $this->setDescription($arr[$keys[3]]); - if (array_key_exists($keys[4], $arr)) $this->setCreatedAt($arr[$keys[4]]); - if (array_key_exists($keys[5], $arr)) $this->setUpdatedAt($arr[$keys[5]]); + if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setUpdatedAt($arr[$keys[2]]); } /** @@ -1238,9 +1073,6 @@ abstract class TaxRule implements ActiveRecordInterface $criteria = new Criteria(TaxRuleTableMap::DATABASE_NAME); if ($this->isColumnModified(TaxRuleTableMap::ID)) $criteria->add(TaxRuleTableMap::ID, $this->id); - if ($this->isColumnModified(TaxRuleTableMap::CODE)) $criteria->add(TaxRuleTableMap::CODE, $this->code); - if ($this->isColumnModified(TaxRuleTableMap::TITLE)) $criteria->add(TaxRuleTableMap::TITLE, $this->title); - if ($this->isColumnModified(TaxRuleTableMap::DESCRIPTION)) $criteria->add(TaxRuleTableMap::DESCRIPTION, $this->description); if ($this->isColumnModified(TaxRuleTableMap::CREATED_AT)) $criteria->add(TaxRuleTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(TaxRuleTableMap::UPDATED_AT)) $criteria->add(TaxRuleTableMap::UPDATED_AT, $this->updated_at); @@ -1306,9 +1138,6 @@ abstract class TaxRule implements ActiveRecordInterface */ public function copyInto($copyObj, $deepCopy = false, $makeNew = true) { - $copyObj->setCode($this->getCode()); - $copyObj->setTitle($this->getTitle()); - $copyObj->setDescription($this->getDescription()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); @@ -1723,7 +1552,10 @@ abstract class TaxRule implements ActiveRecordInterface $taxRuleCountriesToDelete = $this->getTaxRuleCountries(new Criteria(), $con)->diff($taxRuleCountries); - $this->taxRuleCountriesScheduledForDeletion = $taxRuleCountriesToDelete; + //since at least one column in the foreign key is at the same time a PK + //we can not just set a PK to NULL in the lines below. We have to store + //a backup of all values, so we are able to manipulate these items based on the onDelete value later. + $this->taxRuleCountriesScheduledForDeletion = clone $taxRuleCountriesToDelete; foreach ($taxRuleCountriesToDelete as $taxRuleCountryRemoved) { $taxRuleCountryRemoved->setTaxRule(null); @@ -1816,7 +1648,7 @@ abstract class TaxRule implements ActiveRecordInterface $this->taxRuleCountriesScheduledForDeletion = clone $this->collTaxRuleCountries; $this->taxRuleCountriesScheduledForDeletion->clear(); } - $this->taxRuleCountriesScheduledForDeletion[]= $taxRuleCountry; + $this->taxRuleCountriesScheduledForDeletion[]= clone $taxRuleCountry; $taxRuleCountry->setTaxRule(null); } @@ -2104,9 +1936,6 @@ abstract class TaxRule implements ActiveRecordInterface public function clear() { $this->id = null; - $this->code = null; - $this->title = null; - $this->description = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; @@ -2286,6 +2115,54 @@ abstract class TaxRule implements ActiveRecordInterface return $this->getTranslation($this->getLocale(), $con); } + + /** + * Get the [title] column value. + * + * @return string + */ + public function getTitle() + { + return $this->getCurrentTranslation()->getTitle(); + } + + + /** + * Set the value of [title] column. + * + * @param string $v new value + * @return \Thelia\Model\TaxRuleI18n The current object (for fluent API support) + */ + public function setTitle($v) + { $this->getCurrentTranslation()->setTitle($v); + + return $this; + } + + + /** + * Get the [description] column value. + * + * @return string + */ + public function getDescription() + { + return $this->getCurrentTranslation()->getDescription(); + } + + + /** + * Set the value of [description] column. + * + * @param string $v new value + * @return \Thelia\Model\TaxRuleI18n The current object (for fluent API support) + */ + public function setDescription($v) + { $this->getCurrentTranslation()->setDescription($v); + + return $this; + } + /** * Code to be run before persisting the object * @param ConnectionInterface $con diff --git a/core/lib/Thelia/Model/Base/TaxRuleCountry.php b/core/lib/Thelia/Model/Base/TaxRuleCountry.php old mode 100755 new mode 100644 index 66f6f585b..0cc3e74eb --- a/core/lib/Thelia/Model/Base/TaxRuleCountry.php +++ b/core/lib/Thelia/Model/Base/TaxRuleCountry.php @@ -60,12 +60,6 @@ abstract class TaxRuleCountry implements ActiveRecordInterface */ protected $virtualColumns = array(); - /** - * The value for the id field. - * @var int - */ - protected $id; - /** * The value for the tax_rule_id field. * @var int @@ -85,10 +79,10 @@ abstract class TaxRuleCountry implements ActiveRecordInterface protected $tax_id; /** - * The value for the none field. + * The value for the position field. * @var int */ - protected $none; + protected $position; /** * The value for the created_at field. @@ -379,17 +373,6 @@ abstract class TaxRuleCountry implements ActiveRecordInterface return array_keys(get_object_vars($this)); } - /** - * Get the [id] column value. - * - * @return int - */ - public function getId() - { - - return $this->id; - } - /** * Get the [tax_rule_id] column value. * @@ -424,14 +407,14 @@ abstract class TaxRuleCountry implements ActiveRecordInterface } /** - * Get the [none] column value. + * Get the [position] column value. * * @return int */ - public function getNone() + public function getPosition() { - return $this->none; + return $this->position; } /** @@ -474,27 +457,6 @@ abstract class TaxRuleCountry implements ActiveRecordInterface } } - /** - * Set the value of [id] column. - * - * @param int $v new value - * @return \Thelia\Model\TaxRuleCountry The current object (for fluent API support) - */ - public function setId($v) - { - if ($v !== null) { - $v = (int) $v; - } - - if ($this->id !== $v) { - $this->id = $v; - $this->modifiedColumns[] = TaxRuleCountryTableMap::ID; - } - - - return $this; - } // setId() - /** * Set the value of [tax_rule_id] column. * @@ -571,25 +533,25 @@ abstract class TaxRuleCountry implements ActiveRecordInterface } // setTaxId() /** - * Set the value of [none] column. + * Set the value of [position] column. * * @param int $v new value * @return \Thelia\Model\TaxRuleCountry The current object (for fluent API support) */ - public function setNone($v) + public function setPosition($v) { if ($v !== null) { $v = (int) $v; } - if ($this->none !== $v) { - $this->none = $v; - $this->modifiedColumns[] = TaxRuleCountryTableMap::NONE; + if ($this->position !== $v) { + $this->position = $v; + $this->modifiedColumns[] = TaxRuleCountryTableMap::POSITION; } return $this; - } // setNone() + } // setPosition() /** * Sets the value of [created_at] column to a normalized version of the date/time value specified. @@ -670,28 +632,25 @@ abstract class TaxRuleCountry implements ActiveRecordInterface try { - $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : TaxRuleCountryTableMap::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; - $this->id = (null !== $col) ? (int) $col : null; - - $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxRuleCountryTableMap::translateFieldName('TaxRuleId', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 0 + $startcol : TaxRuleCountryTableMap::translateFieldName('TaxRuleId', TableMap::TYPE_PHPNAME, $indexType)]; $this->tax_rule_id = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxRuleCountryTableMap::translateFieldName('CountryId', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxRuleCountryTableMap::translateFieldName('CountryId', TableMap::TYPE_PHPNAME, $indexType)]; $this->country_id = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxRuleCountryTableMap::translateFieldName('TaxId', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxRuleCountryTableMap::translateFieldName('TaxId', TableMap::TYPE_PHPNAME, $indexType)]; $this->tax_id = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : TaxRuleCountryTableMap::translateFieldName('None', TableMap::TYPE_PHPNAME, $indexType)]; - $this->none = (null !== $col) ? (int) $col : null; + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxRuleCountryTableMap::translateFieldName('Position', TableMap::TYPE_PHPNAME, $indexType)]; + $this->position = (null !== $col) ? (int) $col : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : TaxRuleCountryTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 4 + $startcol : TaxRuleCountryTableMap::translateFieldName('CreatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } $this->created_at = (null !== $col) ? PropelDateTime::newInstance($col, null, '\DateTime') : null; - $col = $row[TableMap::TYPE_NUM == $indexType ? 6 + $startcol : TaxRuleCountryTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; + $col = $row[TableMap::TYPE_NUM == $indexType ? 5 + $startcol : TaxRuleCountryTableMap::translateFieldName('UpdatedAt', TableMap::TYPE_PHPNAME, $indexType)]; if ($col === '0000-00-00 00:00:00') { $col = null; } @@ -704,7 +663,7 @@ abstract class TaxRuleCountry implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 7; // 7 = TaxRuleCountryTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 6; // 6 = TaxRuleCountryTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\TaxRuleCountry object", 0, $e); @@ -958,9 +917,6 @@ abstract class TaxRuleCountry implements ActiveRecordInterface // check the columns in natural order for more readable SQL queries - if ($this->isColumnModified(TaxRuleCountryTableMap::ID)) { - $modifiedColumns[':p' . $index++] = 'ID'; - } if ($this->isColumnModified(TaxRuleCountryTableMap::TAX_RULE_ID)) { $modifiedColumns[':p' . $index++] = 'TAX_RULE_ID'; } @@ -970,8 +926,8 @@ abstract class TaxRuleCountry implements ActiveRecordInterface if ($this->isColumnModified(TaxRuleCountryTableMap::TAX_ID)) { $modifiedColumns[':p' . $index++] = 'TAX_ID'; } - if ($this->isColumnModified(TaxRuleCountryTableMap::NONE)) { - $modifiedColumns[':p' . $index++] = 'NONE'; + if ($this->isColumnModified(TaxRuleCountryTableMap::POSITION)) { + $modifiedColumns[':p' . $index++] = 'POSITION'; } if ($this->isColumnModified(TaxRuleCountryTableMap::CREATED_AT)) { $modifiedColumns[':p' . $index++] = 'CREATED_AT'; @@ -990,9 +946,6 @@ abstract class TaxRuleCountry implements ActiveRecordInterface $stmt = $con->prepare($sql); foreach ($modifiedColumns as $identifier => $columnName) { switch ($columnName) { - case 'ID': - $stmt->bindValue($identifier, $this->id, PDO::PARAM_INT); - break; case 'TAX_RULE_ID': $stmt->bindValue($identifier, $this->tax_rule_id, PDO::PARAM_INT); break; @@ -1002,8 +955,8 @@ abstract class TaxRuleCountry implements ActiveRecordInterface case 'TAX_ID': $stmt->bindValue($identifier, $this->tax_id, PDO::PARAM_INT); break; - case 'NONE': - $stmt->bindValue($identifier, $this->none, PDO::PARAM_INT); + case 'POSITION': + $stmt->bindValue($identifier, $this->position, PDO::PARAM_INT); break; case 'CREATED_AT': $stmt->bindValue($identifier, $this->created_at ? $this->created_at->format("Y-m-d H:i:s") : null, PDO::PARAM_STR); @@ -1067,24 +1020,21 @@ abstract class TaxRuleCountry implements ActiveRecordInterface { switch ($pos) { case 0: - return $this->getId(); - break; - case 1: return $this->getTaxRuleId(); break; - case 2: + case 1: return $this->getCountryId(); break; - case 3: + case 2: return $this->getTaxId(); break; - case 4: - return $this->getNone(); + case 3: + return $this->getPosition(); break; - case 5: + case 4: return $this->getCreatedAt(); break; - case 6: + case 5: return $this->getUpdatedAt(); break; default: @@ -1110,19 +1060,18 @@ abstract class TaxRuleCountry implements ActiveRecordInterface */ public function toArray($keyType = TableMap::TYPE_PHPNAME, $includeLazyLoadColumns = true, $alreadyDumpedObjects = array(), $includeForeignObjects = false) { - if (isset($alreadyDumpedObjects['TaxRuleCountry'][$this->getPrimaryKey()])) { + if (isset($alreadyDumpedObjects['TaxRuleCountry'][serialize($this->getPrimaryKey())])) { return '*RECURSION*'; } - $alreadyDumpedObjects['TaxRuleCountry'][$this->getPrimaryKey()] = true; + $alreadyDumpedObjects['TaxRuleCountry'][serialize($this->getPrimaryKey())] = true; $keys = TaxRuleCountryTableMap::getFieldNames($keyType); $result = array( - $keys[0] => $this->getId(), - $keys[1] => $this->getTaxRuleId(), - $keys[2] => $this->getCountryId(), - $keys[3] => $this->getTaxId(), - $keys[4] => $this->getNone(), - $keys[5] => $this->getCreatedAt(), - $keys[6] => $this->getUpdatedAt(), + $keys[0] => $this->getTaxRuleId(), + $keys[1] => $this->getCountryId(), + $keys[2] => $this->getTaxId(), + $keys[3] => $this->getPosition(), + $keys[4] => $this->getCreatedAt(), + $keys[5] => $this->getUpdatedAt(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -1175,24 +1124,21 @@ abstract class TaxRuleCountry implements ActiveRecordInterface { switch ($pos) { case 0: - $this->setId($value); - break; - case 1: $this->setTaxRuleId($value); break; - case 2: + case 1: $this->setCountryId($value); break; - case 3: + case 2: $this->setTaxId($value); break; - case 4: - $this->setNone($value); + case 3: + $this->setPosition($value); break; - case 5: + case 4: $this->setCreatedAt($value); break; - case 6: + case 5: $this->setUpdatedAt($value); break; } // switch() @@ -1219,13 +1165,12 @@ abstract class TaxRuleCountry implements ActiveRecordInterface { $keys = TaxRuleCountryTableMap::getFieldNames($keyType); - if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); - if (array_key_exists($keys[1], $arr)) $this->setTaxRuleId($arr[$keys[1]]); - if (array_key_exists($keys[2], $arr)) $this->setCountryId($arr[$keys[2]]); - if (array_key_exists($keys[3], $arr)) $this->setTaxId($arr[$keys[3]]); - if (array_key_exists($keys[4], $arr)) $this->setNone($arr[$keys[4]]); - if (array_key_exists($keys[5], $arr)) $this->setCreatedAt($arr[$keys[5]]); - if (array_key_exists($keys[6], $arr)) $this->setUpdatedAt($arr[$keys[6]]); + if (array_key_exists($keys[0], $arr)) $this->setTaxRuleId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setCountryId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setTaxId($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setPosition($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setCreatedAt($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setUpdatedAt($arr[$keys[5]]); } /** @@ -1237,11 +1182,10 @@ abstract class TaxRuleCountry implements ActiveRecordInterface { $criteria = new Criteria(TaxRuleCountryTableMap::DATABASE_NAME); - if ($this->isColumnModified(TaxRuleCountryTableMap::ID)) $criteria->add(TaxRuleCountryTableMap::ID, $this->id); if ($this->isColumnModified(TaxRuleCountryTableMap::TAX_RULE_ID)) $criteria->add(TaxRuleCountryTableMap::TAX_RULE_ID, $this->tax_rule_id); if ($this->isColumnModified(TaxRuleCountryTableMap::COUNTRY_ID)) $criteria->add(TaxRuleCountryTableMap::COUNTRY_ID, $this->country_id); if ($this->isColumnModified(TaxRuleCountryTableMap::TAX_ID)) $criteria->add(TaxRuleCountryTableMap::TAX_ID, $this->tax_id); - if ($this->isColumnModified(TaxRuleCountryTableMap::NONE)) $criteria->add(TaxRuleCountryTableMap::NONE, $this->none); + if ($this->isColumnModified(TaxRuleCountryTableMap::POSITION)) $criteria->add(TaxRuleCountryTableMap::POSITION, $this->position); if ($this->isColumnModified(TaxRuleCountryTableMap::CREATED_AT)) $criteria->add(TaxRuleCountryTableMap::CREATED_AT, $this->created_at); if ($this->isColumnModified(TaxRuleCountryTableMap::UPDATED_AT)) $criteria->add(TaxRuleCountryTableMap::UPDATED_AT, $this->updated_at); @@ -1259,29 +1203,39 @@ abstract class TaxRuleCountry implements ActiveRecordInterface public function buildPkeyCriteria() { $criteria = new Criteria(TaxRuleCountryTableMap::DATABASE_NAME); - $criteria->add(TaxRuleCountryTableMap::ID, $this->id); + $criteria->add(TaxRuleCountryTableMap::TAX_RULE_ID, $this->tax_rule_id); + $criteria->add(TaxRuleCountryTableMap::COUNTRY_ID, $this->country_id); + $criteria->add(TaxRuleCountryTableMap::TAX_ID, $this->tax_id); return $criteria; } /** - * Returns the primary key for this object (row). - * @return int + * Returns the composite primary key for this object. + * The array elements will be in same order as specified in XML. + * @return array */ public function getPrimaryKey() { - return $this->getId(); + $pks = array(); + $pks[0] = $this->getTaxRuleId(); + $pks[1] = $this->getCountryId(); + $pks[2] = $this->getTaxId(); + + return $pks; } /** - * Generic method to set the primary key (id column). + * Set the [composite] primary key. * - * @param int $key Primary key. + * @param array $keys The elements of the composite key (order must match the order in XML file). * @return void */ - public function setPrimaryKey($key) + public function setPrimaryKey($keys) { - $this->setId($key); + $this->setTaxRuleId($keys[0]); + $this->setCountryId($keys[1]); + $this->setTaxId($keys[2]); } /** @@ -1291,7 +1245,7 @@ abstract class TaxRuleCountry implements ActiveRecordInterface public function isPrimaryKeyNull() { - return null === $this->getId(); + return (null === $this->getTaxRuleId()) && (null === $this->getCountryId()) && (null === $this->getTaxId()); } /** @@ -1307,11 +1261,10 @@ abstract class TaxRuleCountry implements ActiveRecordInterface */ public function copyInto($copyObj, $deepCopy = false, $makeNew = true) { - $copyObj->setId($this->getId()); $copyObj->setTaxRuleId($this->getTaxRuleId()); $copyObj->setCountryId($this->getCountryId()); $copyObj->setTaxId($this->getTaxId()); - $copyObj->setNone($this->getNone()); + $copyObj->setPosition($this->getPosition()); $copyObj->setCreatedAt($this->getCreatedAt()); $copyObj->setUpdatedAt($this->getUpdatedAt()); if ($makeNew) { @@ -1499,11 +1452,10 @@ abstract class TaxRuleCountry implements ActiveRecordInterface */ public function clear() { - $this->id = null; $this->tax_rule_id = null; $this->country_id = null; $this->tax_id = null; - $this->none = null; + $this->position = null; $this->created_at = null; $this->updated_at = null; $this->alreadyInSave = false; diff --git a/core/lib/Thelia/Model/Base/TaxRuleCountryQuery.php b/core/lib/Thelia/Model/Base/TaxRuleCountryQuery.php old mode 100755 new mode 100644 index b4d4cd1c2..5674643f7 --- a/core/lib/Thelia/Model/Base/TaxRuleCountryQuery.php +++ b/core/lib/Thelia/Model/Base/TaxRuleCountryQuery.php @@ -21,19 +21,17 @@ use Thelia\Model\Map\TaxRuleCountryTableMap; * * * - * @method ChildTaxRuleCountryQuery orderById($order = Criteria::ASC) Order by the id column * @method ChildTaxRuleCountryQuery orderByTaxRuleId($order = Criteria::ASC) Order by the tax_rule_id column * @method ChildTaxRuleCountryQuery orderByCountryId($order = Criteria::ASC) Order by the country_id column * @method ChildTaxRuleCountryQuery orderByTaxId($order = Criteria::ASC) Order by the tax_id column - * @method ChildTaxRuleCountryQuery orderByNone($order = Criteria::ASC) Order by the none column + * @method ChildTaxRuleCountryQuery orderByPosition($order = Criteria::ASC) Order by the position column * @method ChildTaxRuleCountryQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildTaxRuleCountryQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * - * @method ChildTaxRuleCountryQuery groupById() Group by the id column * @method ChildTaxRuleCountryQuery groupByTaxRuleId() Group by the tax_rule_id column * @method ChildTaxRuleCountryQuery groupByCountryId() Group by the country_id column * @method ChildTaxRuleCountryQuery groupByTaxId() Group by the tax_id column - * @method ChildTaxRuleCountryQuery groupByNone() Group by the none column + * @method ChildTaxRuleCountryQuery groupByPosition() Group by the position column * @method ChildTaxRuleCountryQuery groupByCreatedAt() Group by the created_at column * @method ChildTaxRuleCountryQuery groupByUpdatedAt() Group by the updated_at column * @@ -56,19 +54,17 @@ use Thelia\Model\Map\TaxRuleCountryTableMap; * @method ChildTaxRuleCountry findOne(ConnectionInterface $con = null) Return the first ChildTaxRuleCountry matching the query * @method ChildTaxRuleCountry findOneOrCreate(ConnectionInterface $con = null) Return the first ChildTaxRuleCountry matching the query, or a new ChildTaxRuleCountry object populated from the query conditions when no match is found * - * @method ChildTaxRuleCountry findOneById(int $id) Return the first ChildTaxRuleCountry filtered by the id column * @method ChildTaxRuleCountry findOneByTaxRuleId(int $tax_rule_id) Return the first ChildTaxRuleCountry filtered by the tax_rule_id column * @method ChildTaxRuleCountry findOneByCountryId(int $country_id) Return the first ChildTaxRuleCountry filtered by the country_id column * @method ChildTaxRuleCountry findOneByTaxId(int $tax_id) Return the first ChildTaxRuleCountry filtered by the tax_id column - * @method ChildTaxRuleCountry findOneByNone(int $none) Return the first ChildTaxRuleCountry filtered by the none column + * @method ChildTaxRuleCountry findOneByPosition(int $position) Return the first ChildTaxRuleCountry filtered by the position column * @method ChildTaxRuleCountry findOneByCreatedAt(string $created_at) Return the first ChildTaxRuleCountry filtered by the created_at column * @method ChildTaxRuleCountry findOneByUpdatedAt(string $updated_at) Return the first ChildTaxRuleCountry filtered by the updated_at column * - * @method array findById(int $id) Return ChildTaxRuleCountry objects filtered by the id column * @method array findByTaxRuleId(int $tax_rule_id) Return ChildTaxRuleCountry objects filtered by the tax_rule_id column * @method array findByCountryId(int $country_id) Return ChildTaxRuleCountry objects filtered by the country_id column * @method array findByTaxId(int $tax_id) Return ChildTaxRuleCountry objects filtered by the tax_id column - * @method array findByNone(int $none) Return ChildTaxRuleCountry objects filtered by the none column + * @method array findByPosition(int $position) Return ChildTaxRuleCountry objects filtered by the position column * @method array findByCreatedAt(string $created_at) Return ChildTaxRuleCountry objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildTaxRuleCountry objects filtered by the updated_at column * @@ -118,10 +114,10 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * Go fast if the query is untouched. * * - * $obj = $c->findPk(12, $con); + * $obj = $c->findPk(array(12, 34, 56), $con); * * - * @param mixed $key Primary key to use for the query + * @param array[$tax_rule_id, $country_id, $tax_id] $key Primary key to use for the query * @param ConnectionInterface $con an optional connection object * * @return ChildTaxRuleCountry|array|mixed the result, formatted by the current formatter @@ -131,7 +127,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria if ($key === null) { return null; } - if ((null !== ($obj = TaxRuleCountryTableMap::getInstanceFromPool((string) $key))) && !$this->formatter) { + if ((null !== ($obj = TaxRuleCountryTableMap::getInstanceFromPool(serialize(array((string) $key[0], (string) $key[1], (string) $key[2]))))) && !$this->formatter) { // the object is already in the instance pool return $obj; } @@ -159,10 +155,12 @@ abstract class TaxRuleCountryQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, TAX_RULE_ID, COUNTRY_ID, TAX_ID, NONE, CREATED_AT, UPDATED_AT FROM tax_rule_country WHERE ID = :p0'; + $sql = 'SELECT TAX_RULE_ID, COUNTRY_ID, TAX_ID, POSITION, CREATED_AT, UPDATED_AT FROM tax_rule_country WHERE TAX_RULE_ID = :p0 AND COUNTRY_ID = :p1 AND TAX_ID = :p2'; try { $stmt = $con->prepare($sql); - $stmt->bindValue(':p0', $key, PDO::PARAM_INT); + $stmt->bindValue(':p0', $key[0], PDO::PARAM_INT); + $stmt->bindValue(':p1', $key[1], PDO::PARAM_INT); + $stmt->bindValue(':p2', $key[2], PDO::PARAM_INT); $stmt->execute(); } catch (Exception $e) { Propel::log($e->getMessage(), Propel::LOG_ERR); @@ -172,7 +170,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria if ($row = $stmt->fetch(\PDO::FETCH_NUM)) { $obj = new ChildTaxRuleCountry(); $obj->hydrate($row); - TaxRuleCountryTableMap::addInstanceToPool($obj, (string) $key); + TaxRuleCountryTableMap::addInstanceToPool($obj, serialize(array((string) $key[0], (string) $key[1], (string) $key[2]))); } $stmt->closeCursor(); @@ -201,7 +199,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria /** * Find objects by primary key * - * $objs = $c->findPks(array(12, 56, 832), $con); + * $objs = $c->findPks(array(array(12, 56), array(832, 123), array(123, 456)), $con); * * @param array $keys Primary keys to use for the query * @param ConnectionInterface $con an optional connection object @@ -231,8 +229,11 @@ abstract class TaxRuleCountryQuery extends ModelCriteria */ public function filterByPrimaryKey($key) { + $this->addUsingAlias(TaxRuleCountryTableMap::TAX_RULE_ID, $key[0], Criteria::EQUAL); + $this->addUsingAlias(TaxRuleCountryTableMap::COUNTRY_ID, $key[1], Criteria::EQUAL); + $this->addUsingAlias(TaxRuleCountryTableMap::TAX_ID, $key[2], Criteria::EQUAL); - return $this->addUsingAlias(TaxRuleCountryTableMap::ID, $key, Criteria::EQUAL); + return $this; } /** @@ -244,49 +245,19 @@ abstract class TaxRuleCountryQuery extends ModelCriteria */ public function filterByPrimaryKeys($keys) { - - return $this->addUsingAlias(TaxRuleCountryTableMap::ID, $keys, Criteria::IN); - } - - /** - * Filter the query on the id column - * - * Example usage: - * - * $query->filterById(1234); // WHERE id = 1234 - * $query->filterById(array(12, 34)); // WHERE id IN (12, 34) - * $query->filterById(array('min' => 12)); // WHERE id > 12 - * - * - * @param mixed $id The value to use as filter. - * Use scalar values for equality. - * Use array values for in_array() equivalent. - * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildTaxRuleCountryQuery The current query, for fluid interface - */ - public function filterById($id = null, $comparison = null) - { - if (is_array($id)) { - $useMinMax = false; - if (isset($id['min'])) { - $this->addUsingAlias(TaxRuleCountryTableMap::ID, $id['min'], Criteria::GREATER_EQUAL); - $useMinMax = true; - } - if (isset($id['max'])) { - $this->addUsingAlias(TaxRuleCountryTableMap::ID, $id['max'], Criteria::LESS_EQUAL); - $useMinMax = true; - } - if ($useMinMax) { - return $this; - } - if (null === $comparison) { - $comparison = Criteria::IN; - } + if (empty($keys)) { + return $this->add(null, '1<>1', Criteria::CUSTOM); + } + foreach ($keys as $key) { + $cton0 = $this->getNewCriterion(TaxRuleCountryTableMap::TAX_RULE_ID, $key[0], Criteria::EQUAL); + $cton1 = $this->getNewCriterion(TaxRuleCountryTableMap::COUNTRY_ID, $key[1], Criteria::EQUAL); + $cton0->addAnd($cton1); + $cton2 = $this->getNewCriterion(TaxRuleCountryTableMap::TAX_ID, $key[2], Criteria::EQUAL); + $cton0->addAnd($cton2); + $this->addOr($cton0); } - return $this->addUsingAlias(TaxRuleCountryTableMap::ID, $id, $comparison); + return $this; } /** @@ -419,16 +390,16 @@ abstract class TaxRuleCountryQuery extends ModelCriteria } /** - * Filter the query on the none column + * Filter the query on the position column * * Example usage: * - * $query->filterByNone(1234); // WHERE none = 1234 - * $query->filterByNone(array(12, 34)); // WHERE none IN (12, 34) - * $query->filterByNone(array('min' => 12)); // WHERE none > 12 + * $query->filterByPosition(1234); // WHERE position = 1234 + * $query->filterByPosition(array(12, 34)); // WHERE position IN (12, 34) + * $query->filterByPosition(array('min' => 12)); // WHERE position > 12 * * - * @param mixed $none The value to use as filter. + * @param mixed $position The value to use as filter. * Use scalar values for equality. * Use array values for in_array() equivalent. * Use associative array('min' => $minValue, 'max' => $maxValue) for intervals. @@ -436,16 +407,16 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return ChildTaxRuleCountryQuery The current query, for fluid interface */ - public function filterByNone($none = null, $comparison = null) + public function filterByPosition($position = null, $comparison = null) { - if (is_array($none)) { + if (is_array($position)) { $useMinMax = false; - if (isset($none['min'])) { - $this->addUsingAlias(TaxRuleCountryTableMap::NONE, $none['min'], Criteria::GREATER_EQUAL); + if (isset($position['min'])) { + $this->addUsingAlias(TaxRuleCountryTableMap::POSITION, $position['min'], Criteria::GREATER_EQUAL); $useMinMax = true; } - if (isset($none['max'])) { - $this->addUsingAlias(TaxRuleCountryTableMap::NONE, $none['max'], Criteria::LESS_EQUAL); + if (isset($position['max'])) { + $this->addUsingAlias(TaxRuleCountryTableMap::POSITION, $position['max'], Criteria::LESS_EQUAL); $useMinMax = true; } if ($useMinMax) { @@ -456,7 +427,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria } } - return $this->addUsingAlias(TaxRuleCountryTableMap::NONE, $none, $comparison); + return $this->addUsingAlias(TaxRuleCountryTableMap::POSITION, $position, $comparison); } /** @@ -578,7 +549,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return ChildTaxRuleCountryQuery The current query, for fluid interface */ - public function joinTax($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinTax($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('Tax'); @@ -613,7 +584,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return \Thelia\Model\TaxQuery A secondary query class using the current class as primary query */ - public function useTaxQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useTaxQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinTax($relationAlias, $joinType) @@ -653,7 +624,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return ChildTaxRuleCountryQuery The current query, for fluid interface */ - public function joinTaxRule($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinTaxRule($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('TaxRule'); @@ -688,7 +659,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return \Thelia\Model\TaxRuleQuery A secondary query class using the current class as primary query */ - public function useTaxRuleQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useTaxRuleQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinTaxRule($relationAlias, $joinType) @@ -728,7 +699,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return ChildTaxRuleCountryQuery The current query, for fluid interface */ - public function joinCountry($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinCountry($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('Country'); @@ -763,7 +734,7 @@ abstract class TaxRuleCountryQuery extends ModelCriteria * * @return \Thelia\Model\CountryQuery A secondary query class using the current class as primary query */ - public function useCountryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useCountryQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinCountry($relationAlias, $joinType) @@ -780,7 +751,10 @@ abstract class TaxRuleCountryQuery extends ModelCriteria public function prune($taxRuleCountry = null) { if ($taxRuleCountry) { - $this->addUsingAlias(TaxRuleCountryTableMap::ID, $taxRuleCountry->getId(), Criteria::NOT_EQUAL); + $this->addCond('pruneCond0', $this->getAliasedColName(TaxRuleCountryTableMap::TAX_RULE_ID), $taxRuleCountry->getTaxRuleId(), Criteria::NOT_EQUAL); + $this->addCond('pruneCond1', $this->getAliasedColName(TaxRuleCountryTableMap::COUNTRY_ID), $taxRuleCountry->getCountryId(), Criteria::NOT_EQUAL); + $this->addCond('pruneCond2', $this->getAliasedColName(TaxRuleCountryTableMap::TAX_ID), $taxRuleCountry->getTaxId(), Criteria::NOT_EQUAL); + $this->combine(array('pruneCond0', 'pruneCond1', 'pruneCond2'), Criteria::LOGICAL_OR); } return $this; diff --git a/core/lib/Thelia/Model/Base/TaxRuleI18n.php b/core/lib/Thelia/Model/Base/TaxRuleI18n.php old mode 100755 new mode 100644 index b1efadd6a..711dba307 --- a/core/lib/Thelia/Model/Base/TaxRuleI18n.php +++ b/core/lib/Thelia/Model/Base/TaxRuleI18n.php @@ -66,6 +66,18 @@ abstract class TaxRuleI18n implements ActiveRecordInterface */ protected $locale; + /** + * The value for the title field. + * @var string + */ + protected $title; + + /** + * The value for the description field. + * @var string + */ + protected $description; + /** * @var TaxRule */ @@ -368,6 +380,28 @@ abstract class TaxRuleI18n implements ActiveRecordInterface return $this->locale; } + /** + * Get the [title] column value. + * + * @return string + */ + public function getTitle() + { + + return $this->title; + } + + /** + * Get the [description] column value. + * + * @return string + */ + public function getDescription() + { + + return $this->description; + } + /** * Set the value of [id] column. * @@ -414,6 +448,48 @@ abstract class TaxRuleI18n implements ActiveRecordInterface return $this; } // setLocale() + /** + * Set the value of [title] column. + * + * @param string $v new value + * @return \Thelia\Model\TaxRuleI18n The current object (for fluent API support) + */ + public function setTitle($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->title !== $v) { + $this->title = $v; + $this->modifiedColumns[] = TaxRuleI18nTableMap::TITLE; + } + + + return $this; + } // setTitle() + + /** + * Set the value of [description] column. + * + * @param string $v new value + * @return \Thelia\Model\TaxRuleI18n The current object (for fluent API support) + */ + public function setDescription($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->description !== $v) { + $this->description = $v; + $this->modifiedColumns[] = TaxRuleI18nTableMap::DESCRIPTION; + } + + + return $this; + } // setDescription() + /** * Indicates whether the columns in this object are only set to default values. * @@ -460,6 +536,12 @@ abstract class TaxRuleI18n implements ActiveRecordInterface $col = $row[TableMap::TYPE_NUM == $indexType ? 1 + $startcol : TaxRuleI18nTableMap::translateFieldName('Locale', TableMap::TYPE_PHPNAME, $indexType)]; $this->locale = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 2 + $startcol : TaxRuleI18nTableMap::translateFieldName('Title', TableMap::TYPE_PHPNAME, $indexType)]; + $this->title = (null !== $col) ? (string) $col : null; + + $col = $row[TableMap::TYPE_NUM == $indexType ? 3 + $startcol : TaxRuleI18nTableMap::translateFieldName('Description', TableMap::TYPE_PHPNAME, $indexType)]; + $this->description = (null !== $col) ? (string) $col : null; $this->resetModified(); $this->setNew(false); @@ -468,7 +550,7 @@ abstract class TaxRuleI18n implements ActiveRecordInterface $this->ensureConsistency(); } - return $startcol + 2; // 2 = TaxRuleI18nTableMap::NUM_HYDRATE_COLUMNS. + return $startcol + 4; // 4 = TaxRuleI18nTableMap::NUM_HYDRATE_COLUMNS. } catch (Exception $e) { throw new PropelException("Error populating \Thelia\Model\TaxRuleI18n object", 0, $e); @@ -695,6 +777,12 @@ abstract class TaxRuleI18n implements ActiveRecordInterface if ($this->isColumnModified(TaxRuleI18nTableMap::LOCALE)) { $modifiedColumns[':p' . $index++] = 'LOCALE'; } + if ($this->isColumnModified(TaxRuleI18nTableMap::TITLE)) { + $modifiedColumns[':p' . $index++] = 'TITLE'; + } + if ($this->isColumnModified(TaxRuleI18nTableMap::DESCRIPTION)) { + $modifiedColumns[':p' . $index++] = 'DESCRIPTION'; + } $sql = sprintf( 'INSERT INTO tax_rule_i18n (%s) VALUES (%s)', @@ -712,6 +800,12 @@ abstract class TaxRuleI18n implements ActiveRecordInterface case 'LOCALE': $stmt->bindValue($identifier, $this->locale, PDO::PARAM_STR); break; + case 'TITLE': + $stmt->bindValue($identifier, $this->title, PDO::PARAM_STR); + break; + case 'DESCRIPTION': + $stmt->bindValue($identifier, $this->description, PDO::PARAM_STR); + break; } } $stmt->execute(); @@ -773,6 +867,12 @@ abstract class TaxRuleI18n implements ActiveRecordInterface case 1: return $this->getLocale(); break; + case 2: + return $this->getTitle(); + break; + case 3: + return $this->getDescription(); + break; default: return null; break; @@ -804,6 +904,8 @@ abstract class TaxRuleI18n implements ActiveRecordInterface $result = array( $keys[0] => $this->getId(), $keys[1] => $this->getLocale(), + $keys[2] => $this->getTitle(), + $keys[3] => $this->getDescription(), ); $virtualColumns = $this->virtualColumns; foreach($virtualColumns as $key => $virtualColumn) @@ -855,6 +957,12 @@ abstract class TaxRuleI18n implements ActiveRecordInterface case 1: $this->setLocale($value); break; + case 2: + $this->setTitle($value); + break; + case 3: + $this->setDescription($value); + break; } // switch() } @@ -881,6 +989,8 @@ abstract class TaxRuleI18n implements ActiveRecordInterface if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); if (array_key_exists($keys[1], $arr)) $this->setLocale($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setTitle($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setDescription($arr[$keys[3]]); } /** @@ -894,6 +1004,8 @@ abstract class TaxRuleI18n implements ActiveRecordInterface if ($this->isColumnModified(TaxRuleI18nTableMap::ID)) $criteria->add(TaxRuleI18nTableMap::ID, $this->id); if ($this->isColumnModified(TaxRuleI18nTableMap::LOCALE)) $criteria->add(TaxRuleI18nTableMap::LOCALE, $this->locale); + if ($this->isColumnModified(TaxRuleI18nTableMap::TITLE)) $criteria->add(TaxRuleI18nTableMap::TITLE, $this->title); + if ($this->isColumnModified(TaxRuleI18nTableMap::DESCRIPTION)) $criteria->add(TaxRuleI18nTableMap::DESCRIPTION, $this->description); return $criteria; } @@ -966,6 +1078,8 @@ abstract class TaxRuleI18n implements ActiveRecordInterface { $copyObj->setId($this->getId()); $copyObj->setLocale($this->getLocale()); + $copyObj->setTitle($this->getTitle()); + $copyObj->setDescription($this->getDescription()); if ($makeNew) { $copyObj->setNew(true); } @@ -1051,6 +1165,8 @@ abstract class TaxRuleI18n implements ActiveRecordInterface { $this->id = null; $this->locale = null; + $this->title = null; + $this->description = null; $this->alreadyInSave = false; $this->clearAllReferences(); $this->applyDefaultValues(); diff --git a/core/lib/Thelia/Model/Base/TaxRuleI18nQuery.php b/core/lib/Thelia/Model/Base/TaxRuleI18nQuery.php old mode 100755 new mode 100644 index 02667f4ac..dfb3e100c --- a/core/lib/Thelia/Model/Base/TaxRuleI18nQuery.php +++ b/core/lib/Thelia/Model/Base/TaxRuleI18nQuery.php @@ -23,9 +23,13 @@ use Thelia\Model\Map\TaxRuleI18nTableMap; * * @method ChildTaxRuleI18nQuery orderById($order = Criteria::ASC) Order by the id column * @method ChildTaxRuleI18nQuery orderByLocale($order = Criteria::ASC) Order by the locale column + * @method ChildTaxRuleI18nQuery orderByTitle($order = Criteria::ASC) Order by the title column + * @method ChildTaxRuleI18nQuery orderByDescription($order = Criteria::ASC) Order by the description column * * @method ChildTaxRuleI18nQuery groupById() Group by the id column * @method ChildTaxRuleI18nQuery groupByLocale() Group by the locale column + * @method ChildTaxRuleI18nQuery groupByTitle() Group by the title column + * @method ChildTaxRuleI18nQuery groupByDescription() Group by the description column * * @method ChildTaxRuleI18nQuery leftJoin($relation) Adds a LEFT JOIN clause to the query * @method ChildTaxRuleI18nQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query @@ -40,9 +44,13 @@ use Thelia\Model\Map\TaxRuleI18nTableMap; * * @method ChildTaxRuleI18n findOneById(int $id) Return the first ChildTaxRuleI18n filtered by the id column * @method ChildTaxRuleI18n findOneByLocale(string $locale) Return the first ChildTaxRuleI18n filtered by the locale column + * @method ChildTaxRuleI18n findOneByTitle(string $title) Return the first ChildTaxRuleI18n filtered by the title column + * @method ChildTaxRuleI18n findOneByDescription(string $description) Return the first ChildTaxRuleI18n filtered by the description column * * @method array findById(int $id) Return ChildTaxRuleI18n objects filtered by the id column * @method array findByLocale(string $locale) Return ChildTaxRuleI18n objects filtered by the locale column + * @method array findByTitle(string $title) Return ChildTaxRuleI18n objects filtered by the title column + * @method array findByDescription(string $description) Return ChildTaxRuleI18n objects filtered by the description column * */ abstract class TaxRuleI18nQuery extends ModelCriteria @@ -131,7 +139,7 @@ abstract class TaxRuleI18nQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, LOCALE FROM tax_rule_i18n WHERE ID = :p0 AND LOCALE = :p1'; + $sql = 'SELECT ID, LOCALE, TITLE, DESCRIPTION FROM tax_rule_i18n WHERE ID = :p0 AND LOCALE = :p1'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key[0], PDO::PARAM_INT); @@ -304,6 +312,64 @@ abstract class TaxRuleI18nQuery extends ModelCriteria return $this->addUsingAlias(TaxRuleI18nTableMap::LOCALE, $locale, $comparison); } + /** + * Filter the query on the title column + * + * Example usage: + * + * $query->filterByTitle('fooValue'); // WHERE title = 'fooValue' + * $query->filterByTitle('%fooValue%'); // WHERE title LIKE '%fooValue%' + * + * + * @param string $title The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildTaxRuleI18nQuery The current query, for fluid interface + */ + public function filterByTitle($title = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($title)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $title)) { + $title = str_replace('*', '%', $title); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(TaxRuleI18nTableMap::TITLE, $title, $comparison); + } + + /** + * Filter the query on the description column + * + * Example usage: + * + * $query->filterByDescription('fooValue'); // WHERE description = 'fooValue' + * $query->filterByDescription('%fooValue%'); // WHERE description LIKE '%fooValue%' + * + * + * @param string $description The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return ChildTaxRuleI18nQuery The current query, for fluid interface + */ + public function filterByDescription($description = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($description)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $description)) { + $description = str_replace('*', '%', $description); + $comparison = Criteria::LIKE; + } + } + + return $this->addUsingAlias(TaxRuleI18nTableMap::DESCRIPTION, $description, $comparison); + } + /** * Filter the query by a related \Thelia\Model\TaxRule object * diff --git a/core/lib/Thelia/Model/Base/TaxRuleQuery.php b/core/lib/Thelia/Model/Base/TaxRuleQuery.php old mode 100755 new mode 100644 index 2fb478b7a..8ee264415 --- a/core/lib/Thelia/Model/Base/TaxRuleQuery.php +++ b/core/lib/Thelia/Model/Base/TaxRuleQuery.php @@ -23,16 +23,10 @@ use Thelia\Model\Map\TaxRuleTableMap; * * * @method ChildTaxRuleQuery orderById($order = Criteria::ASC) Order by the id column - * @method ChildTaxRuleQuery orderByCode($order = Criteria::ASC) Order by the code column - * @method ChildTaxRuleQuery orderByTitle($order = Criteria::ASC) Order by the title column - * @method ChildTaxRuleQuery orderByDescription($order = Criteria::ASC) Order by the description column * @method ChildTaxRuleQuery orderByCreatedAt($order = Criteria::ASC) Order by the created_at column * @method ChildTaxRuleQuery orderByUpdatedAt($order = Criteria::ASC) Order by the updated_at column * * @method ChildTaxRuleQuery groupById() Group by the id column - * @method ChildTaxRuleQuery groupByCode() Group by the code column - * @method ChildTaxRuleQuery groupByTitle() Group by the title column - * @method ChildTaxRuleQuery groupByDescription() Group by the description column * @method ChildTaxRuleQuery groupByCreatedAt() Group by the created_at column * @method ChildTaxRuleQuery groupByUpdatedAt() Group by the updated_at column * @@ -56,16 +50,10 @@ use Thelia\Model\Map\TaxRuleTableMap; * @method ChildTaxRule findOneOrCreate(ConnectionInterface $con = null) Return the first ChildTaxRule matching the query, or a new ChildTaxRule object populated from the query conditions when no match is found * * @method ChildTaxRule findOneById(int $id) Return the first ChildTaxRule filtered by the id column - * @method ChildTaxRule findOneByCode(string $code) Return the first ChildTaxRule filtered by the code column - * @method ChildTaxRule findOneByTitle(string $title) Return the first ChildTaxRule filtered by the title column - * @method ChildTaxRule findOneByDescription(string $description) Return the first ChildTaxRule filtered by the description column * @method ChildTaxRule findOneByCreatedAt(string $created_at) Return the first ChildTaxRule filtered by the created_at column * @method ChildTaxRule findOneByUpdatedAt(string $updated_at) Return the first ChildTaxRule filtered by the updated_at column * * @method array findById(int $id) Return ChildTaxRule objects filtered by the id column - * @method array findByCode(string $code) Return ChildTaxRule objects filtered by the code column - * @method array findByTitle(string $title) Return ChildTaxRule objects filtered by the title column - * @method array findByDescription(string $description) Return ChildTaxRule objects filtered by the description column * @method array findByCreatedAt(string $created_at) Return ChildTaxRule objects filtered by the created_at column * @method array findByUpdatedAt(string $updated_at) Return ChildTaxRule objects filtered by the updated_at column * @@ -156,7 +144,7 @@ abstract class TaxRuleQuery extends ModelCriteria */ protected function findPkSimple($key, $con) { - $sql = 'SELECT ID, CODE, TITLE, DESCRIPTION, CREATED_AT, UPDATED_AT FROM tax_rule WHERE ID = :p0'; + $sql = 'SELECT ID, CREATED_AT, UPDATED_AT FROM tax_rule WHERE ID = :p0'; try { $stmt = $con->prepare($sql); $stmt->bindValue(':p0', $key, PDO::PARAM_INT); @@ -286,93 +274,6 @@ abstract class TaxRuleQuery extends ModelCriteria return $this->addUsingAlias(TaxRuleTableMap::ID, $id, $comparison); } - /** - * Filter the query on the code column - * - * Example usage: - * - * $query->filterByCode('fooValue'); // WHERE code = 'fooValue' - * $query->filterByCode('%fooValue%'); // WHERE code LIKE '%fooValue%' - * - * - * @param string $code The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildTaxRuleQuery The current query, for fluid interface - */ - public function filterByCode($code = null, $comparison = null) - { - if (null === $comparison) { - if (is_array($code)) { - $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $code)) { - $code = str_replace('*', '%', $code); - $comparison = Criteria::LIKE; - } - } - - return $this->addUsingAlias(TaxRuleTableMap::CODE, $code, $comparison); - } - - /** - * Filter the query on the title column - * - * Example usage: - * - * $query->filterByTitle('fooValue'); // WHERE title = 'fooValue' - * $query->filterByTitle('%fooValue%'); // WHERE title LIKE '%fooValue%' - * - * - * @param string $title The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildTaxRuleQuery The current query, for fluid interface - */ - public function filterByTitle($title = null, $comparison = null) - { - if (null === $comparison) { - if (is_array($title)) { - $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $title)) { - $title = str_replace('*', '%', $title); - $comparison = Criteria::LIKE; - } - } - - return $this->addUsingAlias(TaxRuleTableMap::TITLE, $title, $comparison); - } - - /** - * Filter the query on the description column - * - * Example usage: - * - * $query->filterByDescription('fooValue'); // WHERE description = 'fooValue' - * $query->filterByDescription('%fooValue%'); // WHERE description LIKE '%fooValue%' - * - * - * @param string $description The value to use as filter. - * Accepts wildcards (* and % trigger a LIKE) - * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL - * - * @return ChildTaxRuleQuery The current query, for fluid interface - */ - public function filterByDescription($description = null, $comparison = null) - { - if (null === $comparison) { - if (is_array($description)) { - $comparison = Criteria::IN; - } elseif (preg_match('/[\%\*]/', $description)) { - $description = str_replace('*', '%', $description); - $comparison = Criteria::LIKE; - } - } - - return $this->addUsingAlias(TaxRuleTableMap::DESCRIPTION, $description, $comparison); - } - /** * Filter the query on the created_at column * @@ -563,7 +464,7 @@ abstract class TaxRuleQuery extends ModelCriteria * * @return ChildTaxRuleQuery The current query, for fluid interface */ - public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function joinTaxRuleCountry($relationAlias = null, $joinType = Criteria::INNER_JOIN) { $tableMap = $this->getTableMap(); $relationMap = $tableMap->getRelation('TaxRuleCountry'); @@ -598,7 +499,7 @@ abstract class TaxRuleQuery extends ModelCriteria * * @return \Thelia\Model\TaxRuleCountryQuery A secondary query class using the current class as primary query */ - public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN) + public function useTaxRuleCountryQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN) { return $this ->joinTaxRuleCountry($relationAlias, $joinType) diff --git a/core/lib/Thelia/Model/Cart.php b/core/lib/Thelia/Model/Cart.php index 7493546ae..55b697379 100755 --- a/core/lib/Thelia/Model/Cart.php +++ b/core/lib/Thelia/Model/Cart.php @@ -71,4 +71,9 @@ class Cart extends BaseCart ->findOne() ; } + + public function getTaxedAmount() + { + + } } diff --git a/core/lib/Thelia/Model/Coupon.php b/core/lib/Thelia/Model/Coupon.php index d135ccbb0..f5788ff4f 100755 --- a/core/lib/Thelia/Model/Coupon.php +++ b/core/lib/Thelia/Model/Coupon.php @@ -1,9 +1,132 @@ . */ +/* */ +/**********************************************************************************/ 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; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Used to provide an effect (mostly a discount) + * at the end of the Customer checkout tunnel + * It will be usable for a Customer only if it matches the Coupon criteria (Rules) + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class Coupon extends BaseCoupon +{ + + use \Thelia\Model\Tools\ModelEventDispatcherTrait; + + + /** + * Constructor + * + * @param string $code Coupon Code + * @param string $title Coupon title + * @param float $amount Amount removed from the Total Checkout + * @param string $effect Coupon effect + * @param string $shortDescription Coupon short description + * @param string $description Coupon description + * @param boolean $isEnabled Enable/Disable + * @param \DateTime $expirationDate Coupon expiration date + * @param boolean $isAvailableOnSpecialOffers Is available on special offers + * @param boolean $isCumulative Is cumulative + * @param boolean $isRemovingPostage Is removing Postage + * @param int $maxUsage Coupon quantity + * @param CouponRuleCollection $rules CouponRuleInterface to add + * @param string $locale Coupon Language code ISO (ex: fr_FR) + */ + function createOrUpdate($code, $title, $amount, $effect, $shortDescription, $description, $isEnabled, $expirationDate, $isAvailableOnSpecialOffers, $isCumulative, $maxUsage, $rules, $locale = null) + { + $this->setCode($code) + ->setTitle($title) + ->setShortDescription($shortDescription) + ->setDescription($description) + ->setType($effect) + ->setAmount($amount) + ->setType($amount) + ->setIsEnabled($isEnabled) + ->setExpirationDate($expirationDate) + ->setIsAvailableOnSpecialOffers($isAvailableOnSpecialOffers) + ->setIsCumulative($isCumulative) + ->setMaxUsage($maxUsage) + ->setRules($rules); + + // Set object language (i18n) + if (!is_null($locale)) { + $this->setLocale($locale); + } + + $con = Propel::getWriteConnection(CouponTableMap::DATABASE_NAME); + $con->beginTransaction(); + try { + $this->save($con); + $con->commit(); + + } catch(\Exception $e) { + $con->rollback(); + throw $e; + } + } + +// /** +// * 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; +// } + -class Coupon extends BaseCoupon { } diff --git a/core/lib/Thelia/Model/Currency.php b/core/lib/Thelia/Model/Currency.php index ef8d73735..843211d5a 100755 --- a/core/lib/Thelia/Model/Currency.php +++ b/core/lib/Thelia/Model/Currency.php @@ -13,6 +13,17 @@ class Currency extends BaseCurrency { use \Thelia\Model\Tools\PositionManagementTrait; + public static function getDefaultCurrency() + { + $currency = CurrencyQuery::create()->findOneByByDefault(1); + + if (null === $currency) { + throw new \RuntimeException("No default currency is defined. Please define one."); + } + + return $currency; + } + /** * {@inheritDoc} */ diff --git a/core/lib/Thelia/Model/Map/AccessoryTableMap.php b/core/lib/Thelia/Model/Map/AccessoryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AddressTableMap.php b/core/lib/Thelia/Model/Map/AddressTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AdminGroupTableMap.php b/core/lib/Thelia/Model/Map/AdminGroupTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AdminLogTableMap.php b/core/lib/Thelia/Model/Map/AdminLogTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AdminTableMap.php b/core/lib/Thelia/Model/Map/AdminTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AreaTableMap.php b/core/lib/Thelia/Model/Map/AreaTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeAvI18nTableMap.php b/core/lib/Thelia/Model/Map/AttributeAvI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeAvTableMap.php b/core/lib/Thelia/Model/Map/AttributeAvTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeCategoryTableMap.php b/core/lib/Thelia/Model/Map/AttributeCategoryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeCombinationTableMap.php b/core/lib/Thelia/Model/Map/AttributeCombinationTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeI18nTableMap.php b/core/lib/Thelia/Model/Map/AttributeI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/AttributeTableMap.php b/core/lib/Thelia/Model/Map/AttributeTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CartItemTableMap.php b/core/lib/Thelia/Model/Map/CartItemTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CartTableMap.php b/core/lib/Thelia/Model/Map/CartTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryDocumentI18nTableMap.php b/core/lib/Thelia/Model/Map/CategoryDocumentI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryDocumentTableMap.php b/core/lib/Thelia/Model/Map/CategoryDocumentTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryI18nTableMap.php b/core/lib/Thelia/Model/Map/CategoryI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryImageI18nTableMap.php b/core/lib/Thelia/Model/Map/CategoryImageI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryImageTableMap.php b/core/lib/Thelia/Model/Map/CategoryImageTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryTableMap.php b/core/lib/Thelia/Model/Map/CategoryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CategoryVersionTableMap.php b/core/lib/Thelia/Model/Map/CategoryVersionTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ConfigI18nTableMap.php b/core/lib/Thelia/Model/Map/ConfigI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ConfigTableMap.php b/core/lib/Thelia/Model/Map/ConfigTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentDocumentI18nTableMap.php b/core/lib/Thelia/Model/Map/ContentDocumentI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentDocumentTableMap.php b/core/lib/Thelia/Model/Map/ContentDocumentTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentFolderTableMap.php b/core/lib/Thelia/Model/Map/ContentFolderTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentI18nTableMap.php b/core/lib/Thelia/Model/Map/ContentI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentImageI18nTableMap.php b/core/lib/Thelia/Model/Map/ContentImageI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentImageTableMap.php b/core/lib/Thelia/Model/Map/ContentImageTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentTableMap.php b/core/lib/Thelia/Model/Map/ContentTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ContentVersionTableMap.php b/core/lib/Thelia/Model/Map/ContentVersionTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CountryI18nTableMap.php b/core/lib/Thelia/Model/Map/CountryI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CountryTableMap.php b/core/lib/Thelia/Model/Map/CountryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CouponOrderTableMap.php b/core/lib/Thelia/Model/Map/CouponOrderTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CouponRuleTableMap.php b/core/lib/Thelia/Model/Map/CouponRuleTableMap.php deleted file mode 100755 index 99faeac59..000000000 --- a/core/lib/Thelia/Model/Map/CouponRuleTableMap.php +++ /dev/null @@ -1,463 +0,0 @@ - array('Id', 'CouponId', 'Controller', 'Operation', 'Value', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'couponId', 'controller', 'operation', 'value', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(CouponRuleTableMap::ID, CouponRuleTableMap::COUPON_ID, CouponRuleTableMap::CONTROLLER, CouponRuleTableMap::OPERATION, CouponRuleTableMap::VALUE, CouponRuleTableMap::CREATED_AT, CouponRuleTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'COUPON_ID', 'CONTROLLER', 'OPERATION', 'VALUE', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'coupon_id', 'controller', 'operation', 'value', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) - ); - - /** - * holds an array of keys for quick access to the fieldnames array - * - * first dimension keys are the type constants - * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 - */ - protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'CouponId' => 1, 'Controller' => 2, 'Operation' => 3, 'Value' => 4, 'CreatedAt' => 5, 'UpdatedAt' => 6, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'couponId' => 1, 'controller' => 2, 'operation' => 3, 'value' => 4, 'createdAt' => 5, 'updatedAt' => 6, ), - self::TYPE_COLNAME => array(CouponRuleTableMap::ID => 0, CouponRuleTableMap::COUPON_ID => 1, CouponRuleTableMap::CONTROLLER => 2, CouponRuleTableMap::OPERATION => 3, CouponRuleTableMap::VALUE => 4, CouponRuleTableMap::CREATED_AT => 5, CouponRuleTableMap::UPDATED_AT => 6, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'COUPON_ID' => 1, 'CONTROLLER' => 2, 'OPERATION' => 3, 'VALUE' => 4, 'CREATED_AT' => 5, 'UPDATED_AT' => 6, ), - self::TYPE_FIELDNAME => array('id' => 0, 'coupon_id' => 1, 'controller' => 2, 'operation' => 3, 'value' => 4, 'created_at' => 5, 'updated_at' => 6, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) - ); - - /** - * Initialize the table attributes and columns - * Relations are not initialized by this method since they are lazy loaded - * - * @return void - * @throws PropelException - */ - public function initialize() - { - // attributes - $this->setName('coupon_rule'); - $this->setPhpName('CouponRule'); - $this->setClassName('\\Thelia\\Model\\CouponRule'); - $this->setPackage('Thelia.Model'); - $this->setUseIdGenerator(true); - // columns - $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null); - $this->addForeignKey('COUPON_ID', 'CouponId', 'INTEGER', 'coupon', 'ID', true, null, null); - $this->addColumn('CONTROLLER', 'Controller', 'VARCHAR', false, 255, null); - $this->addColumn('OPERATION', 'Operation', 'VARCHAR', false, 255, null); - $this->addColumn('VALUE', 'Value', 'FLOAT', false, null, null); - $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); - $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); - } // initialize() - - /** - * Build the RelationMap objects for this table relationships - */ - public function buildRelations() - { - $this->addRelation('Coupon', '\\Thelia\\Model\\Coupon', RelationMap::MANY_TO_ONE, array('coupon_id' => 'id', ), 'CASCADE', 'RESTRICT'); - } // buildRelations() - - /** - * - * Gets the list of behaviors registered for this table - * - * @return array Associative array (name => parameters) of behaviors - */ - public function getBehaviors() - { - return array( - 'timestampable' => array('create_column' => 'created_at', 'update_column' => 'updated_at', ), - ); - } // getBehaviors() - - /** - * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. - * - * For tables with a single-column primary key, that simple pkey value will be returned. For tables with - * a multi-column primary key, a serialize()d version of the primary key will be returned. - * - * @param array $row resultset row. - * @param int $offset The 0-based offset for reading from the resultset row. - * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM - */ - public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) - { - // If the PK cannot be derived from the row, return NULL. - if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { - return null; - } - - return (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; - } - - /** - * Retrieves the primary key from the DB resultset row - * For tables with a single-column primary key, that simple pkey value will be returned. For tables with - * a multi-column primary key, an array of the primary key columns will be returned. - * - * @param array $row resultset row. - * @param int $offset The 0-based offset for reading from the resultset row. - * @param string $indexType One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM - * - * @return mixed The primary key of the row - */ - public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) - { - - return (int) $row[ - $indexType == TableMap::TYPE_NUM - ? 0 + $offset - : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) - ]; - } - - /** - * The class that the tableMap will make instances of. - * - * If $withPrefix is true, the returned path - * uses a dot-path notation which is translated into a path - * relative to a location on the PHP include_path. - * (e.g. path.to.MyClass -> 'path/to/MyClass.php') - * - * @param boolean $withPrefix Whether or not to return the path with the class name - * @return string path.to.ClassName - */ - public static function getOMClass($withPrefix = true) - { - return $withPrefix ? CouponRuleTableMap::CLASS_DEFAULT : CouponRuleTableMap::OM_CLASS; - } - - /** - * Populates an object of the default type or an object that inherit from the default. - * - * @param array $row row returned by DataFetcher->fetch(). - * @param int $offset The 0-based offset for reading from the resultset row. - * @param string $indexType The index type of $row. Mostly DataFetcher->getIndexType(). - One of the class type constants TableMap::TYPE_PHPNAME, TableMap::TYPE_STUDLYPHPNAME - * TableMap::TYPE_COLNAME, TableMap::TYPE_FIELDNAME, TableMap::TYPE_NUM. - * - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - * @return array (CouponRule object, last column rank) - */ - public static function populateObject($row, $offset = 0, $indexType = TableMap::TYPE_NUM) - { - $key = CouponRuleTableMap::getPrimaryKeyHashFromRow($row, $offset, $indexType); - if (null !== ($obj = CouponRuleTableMap::getInstanceFromPool($key))) { - // We no longer rehydrate the object, since this can cause data loss. - // See http://www.propelorm.org/ticket/509 - // $obj->hydrate($row, $offset, true); // rehydrate - $col = $offset + CouponRuleTableMap::NUM_HYDRATE_COLUMNS; - } else { - $cls = CouponRuleTableMap::OM_CLASS; - $obj = new $cls(); - $col = $obj->hydrate($row, $offset, false, $indexType); - CouponRuleTableMap::addInstanceToPool($obj, $key); - } - - return array($obj, $col); - } - - /** - * The returned array will contain objects of the default type or - * objects that inherit from the default. - * - * @param DataFetcherInterface $dataFetcher - * @return array - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public static function populateObjects(DataFetcherInterface $dataFetcher) - { - $results = array(); - - // set the class once to avoid overhead in the loop - $cls = static::getOMClass(false); - // populate the object(s) - while ($row = $dataFetcher->fetch()) { - $key = CouponRuleTableMap::getPrimaryKeyHashFromRow($row, 0, $dataFetcher->getIndexType()); - if (null !== ($obj = CouponRuleTableMap::getInstanceFromPool($key))) { - // We no longer rehydrate the object, since this can cause data loss. - // See http://www.propelorm.org/ticket/509 - // $obj->hydrate($row, 0, true); // rehydrate - $results[] = $obj; - } else { - $obj = new $cls(); - $obj->hydrate($row); - $results[] = $obj; - CouponRuleTableMap::addInstanceToPool($obj, $key); - } // if key exists - } - - return $results; - } - /** - * Add all the columns needed to create a new object. - * - * Note: any columns that were marked with lazyLoad="true" in the - * XML schema will not be added to the select list and only loaded - * on demand. - * - * @param Criteria $criteria object containing the columns to add. - * @param string $alias optional table alias - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public static function addSelectColumns(Criteria $criteria, $alias = null) - { - if (null === $alias) { - $criteria->addSelectColumn(CouponRuleTableMap::ID); - $criteria->addSelectColumn(CouponRuleTableMap::COUPON_ID); - $criteria->addSelectColumn(CouponRuleTableMap::CONTROLLER); - $criteria->addSelectColumn(CouponRuleTableMap::OPERATION); - $criteria->addSelectColumn(CouponRuleTableMap::VALUE); - $criteria->addSelectColumn(CouponRuleTableMap::CREATED_AT); - $criteria->addSelectColumn(CouponRuleTableMap::UPDATED_AT); - } else { - $criteria->addSelectColumn($alias . '.ID'); - $criteria->addSelectColumn($alias . '.COUPON_ID'); - $criteria->addSelectColumn($alias . '.CONTROLLER'); - $criteria->addSelectColumn($alias . '.OPERATION'); - $criteria->addSelectColumn($alias . '.VALUE'); - $criteria->addSelectColumn($alias . '.CREATED_AT'); - $criteria->addSelectColumn($alias . '.UPDATED_AT'); - } - } - - /** - * Returns the TableMap related to this object. - * This method is not needed for general use but a specific application could have a need. - * @return TableMap - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public static function getTableMap() - { - return Propel::getServiceContainer()->getDatabaseMap(CouponRuleTableMap::DATABASE_NAME)->getTable(CouponRuleTableMap::TABLE_NAME); - } - - /** - * Add a TableMap instance to the database for this tableMap class. - */ - public static function buildTableMap() - { - $dbMap = Propel::getServiceContainer()->getDatabaseMap(CouponRuleTableMap::DATABASE_NAME); - if (!$dbMap->hasTable(CouponRuleTableMap::TABLE_NAME)) { - $dbMap->addTableObject(new CouponRuleTableMap()); - } - } - - /** - * Performs a DELETE on the database, given a CouponRule or Criteria object OR a primary key value. - * - * @param mixed $values Criteria or CouponRule object or primary key or array of primary keys - * which is used to create the DELETE statement - * @param ConnectionInterface $con the connection to use - * @return int The number of affected rows (if supported by underlying database driver). This includes CASCADE-related rows - * if supported by native driver or if emulated using Propel. - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public static function doDelete($values, ConnectionInterface $con = null) - { - if (null === $con) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - - if ($values instanceof Criteria) { - // rename for clarity - $criteria = $values; - } elseif ($values instanceof \Thelia\Model\CouponRule) { // it's a model object - // create criteria based on pk values - $criteria = $values->buildPkeyCriteria(); - } else { // it's a primary key, or an array of pks - $criteria = new Criteria(CouponRuleTableMap::DATABASE_NAME); - $criteria->add(CouponRuleTableMap::ID, (array) $values, Criteria::IN); - } - - $query = CouponRuleQuery::create()->mergeWith($criteria); - - if ($values instanceof Criteria) { CouponRuleTableMap::clearInstancePool(); - } elseif (!is_object($values)) { // it's a primary key, or an array of pks - foreach ((array) $values as $singleval) { CouponRuleTableMap::removeInstanceFromPool($singleval); - } - } - - return $query->delete($con); - } - - /** - * Deletes all rows from the coupon_rule table. - * - * @param ConnectionInterface $con the connection to use - * @return int The number of affected rows (if supported by underlying database driver). - */ - public static function doDeleteAll(ConnectionInterface $con = null) - { - return CouponRuleQuery::create()->doDeleteAll($con); - } - - /** - * Performs an INSERT on the database, given a CouponRule or Criteria object. - * - * @param mixed $criteria Criteria or CouponRule object containing data that is used to create the INSERT statement. - * @param ConnectionInterface $con the ConnectionInterface connection to use - * @return mixed The new primary key. - * @throws PropelException Any exceptions caught during processing will be - * rethrown wrapped into a PropelException. - */ - public static function doInsert($criteria, ConnectionInterface $con = null) - { - if (null === $con) { - $con = Propel::getServiceContainer()->getWriteConnection(CouponRuleTableMap::DATABASE_NAME); - } - - if ($criteria instanceof Criteria) { - $criteria = clone $criteria; // rename for clarity - } else { - $criteria = $criteria->buildCriteria(); // build Criteria from CouponRule object - } - - if ($criteria->containsKey(CouponRuleTableMap::ID) && $criteria->keyContainsValue(CouponRuleTableMap::ID) ) { - throw new PropelException('Cannot insert a value for auto-increment primary key ('.CouponRuleTableMap::ID.')'); - } - - - // Set the correct dbName - $query = CouponRuleQuery::create()->mergeWith($criteria); - - try { - // use transaction because $criteria could contain info - // for more than one table (I guess, conceivably) - $con->beginTransaction(); - $pk = $query->doInsert($con); - $con->commit(); - } catch (PropelException $e) { - $con->rollBack(); - throw $e; - } - - return $pk; - } - -} // CouponRuleTableMap -// This is the static code needed to register the TableMap for this table with the main Propel class. -// -CouponRuleTableMap::buildTableMap(); diff --git a/core/lib/Thelia/Model/Map/CouponTableMap.php b/core/lib/Thelia/Model/Map/CouponTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CurrencyI18nTableMap.php b/core/lib/Thelia/Model/Map/CurrencyI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CurrencyTableMap.php b/core/lib/Thelia/Model/Map/CurrencyTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CustomerTableMap.php b/core/lib/Thelia/Model/Map/CustomerTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CustomerTitleI18nTableMap.php b/core/lib/Thelia/Model/Map/CustomerTitleI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/CustomerTitleTableMap.php b/core/lib/Thelia/Model/Map/CustomerTitleTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/DelivzoneTableMap.php b/core/lib/Thelia/Model/Map/DelivzoneTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureAvI18nTableMap.php b/core/lib/Thelia/Model/Map/FeatureAvI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureAvTableMap.php b/core/lib/Thelia/Model/Map/FeatureAvTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureCategoryTableMap.php b/core/lib/Thelia/Model/Map/FeatureCategoryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureI18nTableMap.php b/core/lib/Thelia/Model/Map/FeatureI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureProductTableMap.php b/core/lib/Thelia/Model/Map/FeatureProductTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FeatureTableMap.php b/core/lib/Thelia/Model/Map/FeatureTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderDocumentI18nTableMap.php b/core/lib/Thelia/Model/Map/FolderDocumentI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderDocumentTableMap.php b/core/lib/Thelia/Model/Map/FolderDocumentTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderI18nTableMap.php b/core/lib/Thelia/Model/Map/FolderI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderImageI18nTableMap.php b/core/lib/Thelia/Model/Map/FolderImageI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderImageTableMap.php b/core/lib/Thelia/Model/Map/FolderImageTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderTableMap.php b/core/lib/Thelia/Model/Map/FolderTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/FolderVersionTableMap.php b/core/lib/Thelia/Model/Map/FolderVersionTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/GroupI18nTableMap.php b/core/lib/Thelia/Model/Map/GroupI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/GroupModuleTableMap.php b/core/lib/Thelia/Model/Map/GroupModuleTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/GroupResourceTableMap.php b/core/lib/Thelia/Model/Map/GroupResourceTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/GroupTableMap.php b/core/lib/Thelia/Model/Map/GroupTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/LangTableMap.php b/core/lib/Thelia/Model/Map/LangTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/MessageI18nTableMap.php b/core/lib/Thelia/Model/Map/MessageI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/MessageTableMap.php b/core/lib/Thelia/Model/Map/MessageTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/MessageVersionTableMap.php b/core/lib/Thelia/Model/Map/MessageVersionTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ModuleI18nTableMap.php b/core/lib/Thelia/Model/Map/ModuleI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ModuleTableMap.php b/core/lib/Thelia/Model/Map/ModuleTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderAddressTableMap.php b/core/lib/Thelia/Model/Map/OrderAddressTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderFeatureTableMap.php b/core/lib/Thelia/Model/Map/OrderFeatureTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderProductTableMap.php b/core/lib/Thelia/Model/Map/OrderProductTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderStatusI18nTableMap.php b/core/lib/Thelia/Model/Map/OrderStatusI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderStatusTableMap.php b/core/lib/Thelia/Model/Map/OrderStatusTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/OrderTableMap.php b/core/lib/Thelia/Model/Map/OrderTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductCategoryTableMap.php b/core/lib/Thelia/Model/Map/ProductCategoryTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductDocumentI18nTableMap.php b/core/lib/Thelia/Model/Map/ProductDocumentI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductDocumentTableMap.php b/core/lib/Thelia/Model/Map/ProductDocumentTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductI18nTableMap.php b/core/lib/Thelia/Model/Map/ProductI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductImageI18nTableMap.php b/core/lib/Thelia/Model/Map/ProductImageI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductImageTableMap.php b/core/lib/Thelia/Model/Map/ProductImageTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductPriceTableMap.php b/core/lib/Thelia/Model/Map/ProductPriceTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductSaleElementsTableMap.php b/core/lib/Thelia/Model/Map/ProductSaleElementsTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductTableMap.php b/core/lib/Thelia/Model/Map/ProductTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ProductVersionTableMap.php b/core/lib/Thelia/Model/Map/ProductVersionTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ResourceI18nTableMap.php b/core/lib/Thelia/Model/Map/ResourceI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/ResourceTableMap.php b/core/lib/Thelia/Model/Map/ResourceTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/TaxI18nTableMap.php b/core/lib/Thelia/Model/Map/TaxI18nTableMap.php old mode 100755 new mode 100644 diff --git a/core/lib/Thelia/Model/Map/TaxRuleCountryTableMap.php b/core/lib/Thelia/Model/Map/TaxRuleCountryTableMap.php old mode 100755 new mode 100644 index 42b4e6f59..5282d67fa --- a/core/lib/Thelia/Model/Map/TaxRuleCountryTableMap.php +++ b/core/lib/Thelia/Model/Map/TaxRuleCountryTableMap.php @@ -57,7 +57,7 @@ class TaxRuleCountryTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 7; + const NUM_COLUMNS = 6; /** * The number of lazy-loaded columns @@ -67,12 +67,7 @@ class TaxRuleCountryTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 7; - - /** - * the column name for the ID field - */ - const ID = 'tax_rule_country.ID'; + const NUM_HYDRATE_COLUMNS = 6; /** * the column name for the TAX_RULE_ID field @@ -90,9 +85,9 @@ class TaxRuleCountryTableMap extends TableMap const TAX_ID = 'tax_rule_country.TAX_ID'; /** - * the column name for the NONE field + * the column name for the POSITION field */ - const NONE = 'tax_rule_country.NONE'; + const POSITION = 'tax_rule_country.POSITION'; /** * the column name for the CREATED_AT field @@ -116,12 +111,12 @@ class TaxRuleCountryTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'TaxRuleId', 'CountryId', 'TaxId', 'None', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'taxRuleId', 'countryId', 'taxId', 'none', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(TaxRuleCountryTableMap::ID, TaxRuleCountryTableMap::TAX_RULE_ID, TaxRuleCountryTableMap::COUNTRY_ID, TaxRuleCountryTableMap::TAX_ID, TaxRuleCountryTableMap::NONE, TaxRuleCountryTableMap::CREATED_AT, TaxRuleCountryTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'TAX_RULE_ID', 'COUNTRY_ID', 'TAX_ID', 'NONE', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'tax_rule_id', 'country_id', 'tax_id', 'none', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + self::TYPE_PHPNAME => array('TaxRuleId', 'CountryId', 'TaxId', 'Position', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('taxRuleId', 'countryId', 'taxId', 'position', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(TaxRuleCountryTableMap::TAX_RULE_ID, TaxRuleCountryTableMap::COUNTRY_ID, TaxRuleCountryTableMap::TAX_ID, TaxRuleCountryTableMap::POSITION, TaxRuleCountryTableMap::CREATED_AT, TaxRuleCountryTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('TAX_RULE_ID', 'COUNTRY_ID', 'TAX_ID', 'POSITION', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('tax_rule_id', 'country_id', 'tax_id', 'position', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, ) ); /** @@ -131,12 +126,12 @@ class TaxRuleCountryTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'TaxRuleId' => 1, 'CountryId' => 2, 'TaxId' => 3, 'None' => 4, 'CreatedAt' => 5, 'UpdatedAt' => 6, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'taxRuleId' => 1, 'countryId' => 2, 'taxId' => 3, 'none' => 4, 'createdAt' => 5, 'updatedAt' => 6, ), - self::TYPE_COLNAME => array(TaxRuleCountryTableMap::ID => 0, TaxRuleCountryTableMap::TAX_RULE_ID => 1, TaxRuleCountryTableMap::COUNTRY_ID => 2, TaxRuleCountryTableMap::TAX_ID => 3, TaxRuleCountryTableMap::NONE => 4, TaxRuleCountryTableMap::CREATED_AT => 5, TaxRuleCountryTableMap::UPDATED_AT => 6, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'TAX_RULE_ID' => 1, 'COUNTRY_ID' => 2, 'TAX_ID' => 3, 'NONE' => 4, 'CREATED_AT' => 5, 'UPDATED_AT' => 6, ), - self::TYPE_FIELDNAME => array('id' => 0, 'tax_rule_id' => 1, 'country_id' => 2, 'tax_id' => 3, 'none' => 4, 'created_at' => 5, 'updated_at' => 6, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, 6, ) + self::TYPE_PHPNAME => array('TaxRuleId' => 0, 'CountryId' => 1, 'TaxId' => 2, 'Position' => 3, 'CreatedAt' => 4, 'UpdatedAt' => 5, ), + self::TYPE_STUDLYPHPNAME => array('taxRuleId' => 0, 'countryId' => 1, 'taxId' => 2, 'position' => 3, 'createdAt' => 4, 'updatedAt' => 5, ), + self::TYPE_COLNAME => array(TaxRuleCountryTableMap::TAX_RULE_ID => 0, TaxRuleCountryTableMap::COUNTRY_ID => 1, TaxRuleCountryTableMap::TAX_ID => 2, TaxRuleCountryTableMap::POSITION => 3, TaxRuleCountryTableMap::CREATED_AT => 4, TaxRuleCountryTableMap::UPDATED_AT => 5, ), + self::TYPE_RAW_COLNAME => array('TAX_RULE_ID' => 0, 'COUNTRY_ID' => 1, 'TAX_ID' => 2, 'POSITION' => 3, 'CREATED_AT' => 4, 'UPDATED_AT' => 5, ), + self::TYPE_FIELDNAME => array('tax_rule_id' => 0, 'country_id' => 1, 'tax_id' => 2, 'position' => 3, 'created_at' => 4, 'updated_at' => 5, ), + self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, ) ); /** @@ -155,11 +150,10 @@ class TaxRuleCountryTableMap extends TableMap $this->setPackage('Thelia.Model'); $this->setUseIdGenerator(false); // columns - $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null); - $this->addForeignKey('TAX_RULE_ID', 'TaxRuleId', 'INTEGER', 'tax_rule', 'ID', false, null, null); - $this->addForeignKey('COUNTRY_ID', 'CountryId', 'INTEGER', 'country', 'ID', false, null, null); - $this->addForeignKey('TAX_ID', 'TaxId', 'INTEGER', 'tax', 'ID', false, null, null); - $this->addColumn('NONE', 'None', 'TINYINT', false, null, null); + $this->addForeignPrimaryKey('TAX_RULE_ID', 'TaxRuleId', 'INTEGER' , 'tax_rule', 'ID', true, null, null); + $this->addForeignPrimaryKey('COUNTRY_ID', 'CountryId', 'INTEGER' , 'country', 'ID', true, null, null); + $this->addForeignPrimaryKey('TAX_ID', 'TaxId', 'INTEGER' , 'tax', 'ID', true, null, null); + $this->addColumn('POSITION', 'Position', 'INTEGER', true, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -169,7 +163,7 @@ class TaxRuleCountryTableMap extends TableMap */ public function buildRelations() { - $this->addRelation('Tax', '\\Thelia\\Model\\Tax', RelationMap::MANY_TO_ONE, array('tax_id' => 'id', ), 'SET NULL', 'RESTRICT'); + $this->addRelation('Tax', '\\Thelia\\Model\\Tax', RelationMap::MANY_TO_ONE, array('tax_id' => 'id', ), 'CASCADE', 'RESTRICT'); $this->addRelation('TaxRule', '\\Thelia\\Model\\TaxRule', RelationMap::MANY_TO_ONE, array('tax_rule_id' => 'id', ), 'CASCADE', 'RESTRICT'); $this->addRelation('Country', '\\Thelia\\Model\\Country', RelationMap::MANY_TO_ONE, array('country_id' => 'id', ), 'CASCADE', 'RESTRICT'); } // buildRelations() @@ -187,6 +181,59 @@ class TaxRuleCountryTableMap extends TableMap ); } // getBehaviors() + /** + * Adds an object to the instance pool. + * + * Propel keeps cached copies of objects in an instance pool when they are retrieved + * from the database. In some cases you may need to explicitly add objects + * to the cache in order to ensure that the same objects are always returned by find*() + * and findPk*() calls. + * + * @param \Thelia\Model\TaxRuleCountry $obj A \Thelia\Model\TaxRuleCountry object. + * @param string $key (optional) key to use for instance map (for performance boost if key was already calculated externally). + */ + public static function addInstanceToPool($obj, $key = null) + { + if (Propel::isInstancePoolingEnabled()) { + if (null === $key) { + $key = serialize(array((string) $obj->getTaxRuleId(), (string) $obj->getCountryId(), (string) $obj->getTaxId())); + } // if key === null + self::$instances[$key] = $obj; + } + } + + /** + * Removes an object from the instance pool. + * + * Propel keeps cached copies of objects in an instance pool when they are retrieved + * from the database. In some cases -- especially when you override doDelete + * methods in your stub classes -- you may need to explicitly remove objects + * from the cache in order to prevent returning objects that no longer exist. + * + * @param mixed $value A \Thelia\Model\TaxRuleCountry object or a primary key value. + */ + public static function removeInstanceFromPool($value) + { + if (Propel::isInstancePoolingEnabled() && null !== $value) { + if (is_object($value) && $value instanceof \Thelia\Model\TaxRuleCountry) { + $key = serialize(array((string) $value->getTaxRuleId(), (string) $value->getCountryId(), (string) $value->getTaxId())); + + } elseif (is_array($value) && count($value) === 3) { + // assume we've been passed a primary key"; + $key = serialize(array((string) $value[0], (string) $value[1], (string) $value[2])); + } elseif ($value instanceof Criteria) { + self::$instances = []; + + return; + } else { + $e = new PropelException("Invalid value passed to removeInstanceFromPool(). Expected primary key or \Thelia\Model\TaxRuleCountry object; got " . (is_object($value) ? get_class($value) . ' object.' : var_export($value, true))); + throw $e; + } + + unset(self::$instances[$key]); + } + } + /** * Retrieves a string version of the primary key from the DB resultset row that can be used to uniquely identify a row in this table. * @@ -201,11 +248,11 @@ class TaxRuleCountryTableMap extends TableMap public static function getPrimaryKeyHashFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) { // If the PK cannot be derived from the row, return NULL. - if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)] === null) { + if ($row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('TaxRuleId', TableMap::TYPE_PHPNAME, $indexType)] === null && $row[TableMap::TYPE_NUM == $indexType ? 1 + $offset : static::translateFieldName('CountryId', TableMap::TYPE_PHPNAME, $indexType)] === null && $row[TableMap::TYPE_NUM == $indexType ? 2 + $offset : static::translateFieldName('TaxId', TableMap::TYPE_PHPNAME, $indexType)] === null) { return null; } - return (string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType)]; + return serialize(array((string) $row[TableMap::TYPE_NUM == $indexType ? 0 + $offset : static::translateFieldName('TaxRuleId', TableMap::TYPE_PHPNAME, $indexType)], (string) $row[TableMap::TYPE_NUM == $indexType ? 1 + $offset : static::translateFieldName('CountryId', TableMap::TYPE_PHPNAME, $indexType)], (string) $row[TableMap::TYPE_NUM == $indexType ? 2 + $offset : static::translateFieldName('TaxId', TableMap::TYPE_PHPNAME, $indexType)])); } /** @@ -223,11 +270,7 @@ class TaxRuleCountryTableMap extends TableMap public static function getPrimaryKeyFromRow($row, $offset = 0, $indexType = TableMap::TYPE_NUM) { - return (int) $row[ - $indexType == TableMap::TYPE_NUM - ? 0 + $offset - : self::translateFieldName('Id', TableMap::TYPE_PHPNAME, $indexType) - ]; + return $pks; } /** @@ -325,19 +368,17 @@ class TaxRuleCountryTableMap extends TableMap public static function addSelectColumns(Criteria $criteria, $alias = null) { if (null === $alias) { - $criteria->addSelectColumn(TaxRuleCountryTableMap::ID); $criteria->addSelectColumn(TaxRuleCountryTableMap::TAX_RULE_ID); $criteria->addSelectColumn(TaxRuleCountryTableMap::COUNTRY_ID); $criteria->addSelectColumn(TaxRuleCountryTableMap::TAX_ID); - $criteria->addSelectColumn(TaxRuleCountryTableMap::NONE); + $criteria->addSelectColumn(TaxRuleCountryTableMap::POSITION); $criteria->addSelectColumn(TaxRuleCountryTableMap::CREATED_AT); $criteria->addSelectColumn(TaxRuleCountryTableMap::UPDATED_AT); } else { - $criteria->addSelectColumn($alias . '.ID'); $criteria->addSelectColumn($alias . '.TAX_RULE_ID'); $criteria->addSelectColumn($alias . '.COUNTRY_ID'); $criteria->addSelectColumn($alias . '.TAX_ID'); - $criteria->addSelectColumn($alias . '.NONE'); + $criteria->addSelectColumn($alias . '.POSITION'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } @@ -391,7 +432,18 @@ class TaxRuleCountryTableMap extends TableMap $criteria = $values->buildPkeyCriteria(); } else { // it's a primary key, or an array of pks $criteria = new Criteria(TaxRuleCountryTableMap::DATABASE_NAME); - $criteria->add(TaxRuleCountryTableMap::ID, (array) $values, Criteria::IN); + // primary key is composite; we therefore, expect + // the primary key passed to be an array of pkey values + if (count($values) == count($values, COUNT_RECURSIVE)) { + // array is not multi-dimensional + $values = array($values); + } + foreach ($values as $value) { + $criterion = $criteria->getNewCriterion(TaxRuleCountryTableMap::TAX_RULE_ID, $value[0]); + $criterion->addAnd($criteria->getNewCriterion(TaxRuleCountryTableMap::COUNTRY_ID, $value[1])); + $criterion->addAnd($criteria->getNewCriterion(TaxRuleCountryTableMap::TAX_ID, $value[2])); + $criteria->addOr($criterion); + } } $query = TaxRuleCountryQuery::create()->mergeWith($criteria); diff --git a/core/lib/Thelia/Model/Map/TaxRuleI18nTableMap.php b/core/lib/Thelia/Model/Map/TaxRuleI18nTableMap.php old mode 100755 new mode 100644 index 1f0ed1e96..012ad2e72 --- a/core/lib/Thelia/Model/Map/TaxRuleI18nTableMap.php +++ b/core/lib/Thelia/Model/Map/TaxRuleI18nTableMap.php @@ -57,7 +57,7 @@ class TaxRuleI18nTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 2; + const NUM_COLUMNS = 4; /** * The number of lazy-loaded columns @@ -67,7 +67,7 @@ class TaxRuleI18nTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 2; + const NUM_HYDRATE_COLUMNS = 4; /** * the column name for the ID field @@ -79,6 +79,16 @@ class TaxRuleI18nTableMap extends TableMap */ const LOCALE = 'tax_rule_i18n.LOCALE'; + /** + * the column name for the TITLE field + */ + const TITLE = 'tax_rule_i18n.TITLE'; + + /** + * the column name for the DESCRIPTION field + */ + const DESCRIPTION = 'tax_rule_i18n.DESCRIPTION'; + /** * The default string format for model objects of the related table */ @@ -91,12 +101,12 @@ class TaxRuleI18nTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'Locale', ), - self::TYPE_STUDLYPHPNAME => array('id', 'locale', ), - self::TYPE_COLNAME => array(TaxRuleI18nTableMap::ID, TaxRuleI18nTableMap::LOCALE, ), - self::TYPE_RAW_COLNAME => array('ID', 'LOCALE', ), - self::TYPE_FIELDNAME => array('id', 'locale', ), - self::TYPE_NUM => array(0, 1, ) + self::TYPE_PHPNAME => array('Id', 'Locale', 'Title', 'Description', ), + self::TYPE_STUDLYPHPNAME => array('id', 'locale', 'title', 'description', ), + self::TYPE_COLNAME => array(TaxRuleI18nTableMap::ID, TaxRuleI18nTableMap::LOCALE, TaxRuleI18nTableMap::TITLE, TaxRuleI18nTableMap::DESCRIPTION, ), + self::TYPE_RAW_COLNAME => array('ID', 'LOCALE', 'TITLE', 'DESCRIPTION', ), + self::TYPE_FIELDNAME => array('id', 'locale', 'title', 'description', ), + self::TYPE_NUM => array(0, 1, 2, 3, ) ); /** @@ -106,12 +116,12 @@ class TaxRuleI18nTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'Locale' => 1, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'locale' => 1, ), - self::TYPE_COLNAME => array(TaxRuleI18nTableMap::ID => 0, TaxRuleI18nTableMap::LOCALE => 1, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'LOCALE' => 1, ), - self::TYPE_FIELDNAME => array('id' => 0, 'locale' => 1, ), - self::TYPE_NUM => array(0, 1, ) + self::TYPE_PHPNAME => array('Id' => 0, 'Locale' => 1, 'Title' => 2, 'Description' => 3, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'locale' => 1, 'title' => 2, 'description' => 3, ), + self::TYPE_COLNAME => array(TaxRuleI18nTableMap::ID => 0, TaxRuleI18nTableMap::LOCALE => 1, TaxRuleI18nTableMap::TITLE => 2, TaxRuleI18nTableMap::DESCRIPTION => 3, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'LOCALE' => 1, 'TITLE' => 2, 'DESCRIPTION' => 3, ), + self::TYPE_FIELDNAME => array('id' => 0, 'locale' => 1, 'title' => 2, 'description' => 3, ), + self::TYPE_NUM => array(0, 1, 2, 3, ) ); /** @@ -132,6 +142,8 @@ class TaxRuleI18nTableMap extends TableMap // columns $this->addForeignPrimaryKey('ID', 'Id', 'INTEGER' , 'tax_rule', 'ID', true, null, null); $this->addPrimaryKey('LOCALE', 'Locale', 'VARCHAR', true, 5, 'en_US'); + $this->addColumn('TITLE', 'Title', 'VARCHAR', false, 255, null); + $this->addColumn('DESCRIPTION', 'Description', 'LONGVARCHAR', false, null, null); } // initialize() /** @@ -331,9 +343,13 @@ class TaxRuleI18nTableMap extends TableMap if (null === $alias) { $criteria->addSelectColumn(TaxRuleI18nTableMap::ID); $criteria->addSelectColumn(TaxRuleI18nTableMap::LOCALE); + $criteria->addSelectColumn(TaxRuleI18nTableMap::TITLE); + $criteria->addSelectColumn(TaxRuleI18nTableMap::DESCRIPTION); } else { $criteria->addSelectColumn($alias . '.ID'); $criteria->addSelectColumn($alias . '.LOCALE'); + $criteria->addSelectColumn($alias . '.TITLE'); + $criteria->addSelectColumn($alias . '.DESCRIPTION'); } } diff --git a/core/lib/Thelia/Model/Map/TaxRuleTableMap.php b/core/lib/Thelia/Model/Map/TaxRuleTableMap.php old mode 100755 new mode 100644 index cc5f628b9..391e23b6d --- a/core/lib/Thelia/Model/Map/TaxRuleTableMap.php +++ b/core/lib/Thelia/Model/Map/TaxRuleTableMap.php @@ -57,7 +57,7 @@ class TaxRuleTableMap extends TableMap /** * The total number of columns */ - const NUM_COLUMNS = 6; + const NUM_COLUMNS = 3; /** * The number of lazy-loaded columns @@ -67,28 +67,13 @@ class TaxRuleTableMap extends TableMap /** * The number of columns to hydrate (NUM_COLUMNS - NUM_LAZY_LOAD_COLUMNS) */ - const NUM_HYDRATE_COLUMNS = 6; + const NUM_HYDRATE_COLUMNS = 3; /** * the column name for the ID field */ const ID = 'tax_rule.ID'; - /** - * the column name for the CODE field - */ - const CODE = 'tax_rule.CODE'; - - /** - * the column name for the TITLE field - */ - const TITLE = 'tax_rule.TITLE'; - - /** - * the column name for the DESCRIPTION field - */ - const DESCRIPTION = 'tax_rule.DESCRIPTION'; - /** * the column name for the CREATED_AT field */ @@ -120,12 +105,12 @@ class TaxRuleTableMap extends TableMap * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ protected static $fieldNames = array ( - self::TYPE_PHPNAME => array('Id', 'Code', 'Title', 'Description', 'CreatedAt', 'UpdatedAt', ), - self::TYPE_STUDLYPHPNAME => array('id', 'code', 'title', 'description', 'createdAt', 'updatedAt', ), - self::TYPE_COLNAME => array(TaxRuleTableMap::ID, TaxRuleTableMap::CODE, TaxRuleTableMap::TITLE, TaxRuleTableMap::DESCRIPTION, TaxRuleTableMap::CREATED_AT, TaxRuleTableMap::UPDATED_AT, ), - self::TYPE_RAW_COLNAME => array('ID', 'CODE', 'TITLE', 'DESCRIPTION', 'CREATED_AT', 'UPDATED_AT', ), - self::TYPE_FIELDNAME => array('id', 'code', 'title', 'description', 'created_at', 'updated_at', ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, ) + self::TYPE_PHPNAME => array('Id', 'CreatedAt', 'UpdatedAt', ), + self::TYPE_STUDLYPHPNAME => array('id', 'createdAt', 'updatedAt', ), + self::TYPE_COLNAME => array(TaxRuleTableMap::ID, TaxRuleTableMap::CREATED_AT, TaxRuleTableMap::UPDATED_AT, ), + self::TYPE_RAW_COLNAME => array('ID', 'CREATED_AT', 'UPDATED_AT', ), + self::TYPE_FIELDNAME => array('id', 'created_at', 'updated_at', ), + self::TYPE_NUM => array(0, 1, 2, ) ); /** @@ -135,12 +120,12 @@ class TaxRuleTableMap extends TableMap * e.g. self::$fieldKeys[self::TYPE_PHPNAME]['Id'] = 0 */ protected static $fieldKeys = array ( - self::TYPE_PHPNAME => array('Id' => 0, 'Code' => 1, 'Title' => 2, 'Description' => 3, 'CreatedAt' => 4, 'UpdatedAt' => 5, ), - self::TYPE_STUDLYPHPNAME => array('id' => 0, 'code' => 1, 'title' => 2, 'description' => 3, 'createdAt' => 4, 'updatedAt' => 5, ), - self::TYPE_COLNAME => array(TaxRuleTableMap::ID => 0, TaxRuleTableMap::CODE => 1, TaxRuleTableMap::TITLE => 2, TaxRuleTableMap::DESCRIPTION => 3, TaxRuleTableMap::CREATED_AT => 4, TaxRuleTableMap::UPDATED_AT => 5, ), - self::TYPE_RAW_COLNAME => array('ID' => 0, 'CODE' => 1, 'TITLE' => 2, 'DESCRIPTION' => 3, 'CREATED_AT' => 4, 'UPDATED_AT' => 5, ), - self::TYPE_FIELDNAME => array('id' => 0, 'code' => 1, 'title' => 2, 'description' => 3, 'created_at' => 4, 'updated_at' => 5, ), - self::TYPE_NUM => array(0, 1, 2, 3, 4, 5, ) + self::TYPE_PHPNAME => array('Id' => 0, 'CreatedAt' => 1, 'UpdatedAt' => 2, ), + self::TYPE_STUDLYPHPNAME => array('id' => 0, 'createdAt' => 1, 'updatedAt' => 2, ), + self::TYPE_COLNAME => array(TaxRuleTableMap::ID => 0, TaxRuleTableMap::CREATED_AT => 1, TaxRuleTableMap::UPDATED_AT => 2, ), + self::TYPE_RAW_COLNAME => array('ID' => 0, 'CREATED_AT' => 1, 'UPDATED_AT' => 2, ), + self::TYPE_FIELDNAME => array('id' => 0, 'created_at' => 1, 'updated_at' => 2, ), + self::TYPE_NUM => array(0, 1, 2, ) ); /** @@ -160,9 +145,6 @@ class TaxRuleTableMap extends TableMap $this->setUseIdGenerator(true); // columns $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null); - $this->addColumn('CODE', 'Code', 'VARCHAR', false, 45, null); - $this->addColumn('TITLE', 'Title', 'VARCHAR', false, 255, null); - $this->addColumn('DESCRIPTION', 'Description', 'LONGVARCHAR', false, null, null); $this->addColumn('CREATED_AT', 'CreatedAt', 'TIMESTAMP', false, null, null); $this->addColumn('UPDATED_AT', 'UpdatedAt', 'TIMESTAMP', false, null, null); } // initialize() @@ -187,7 +169,7 @@ class TaxRuleTableMap extends TableMap { return array( 'timestampable' => array('create_column' => 'created_at', 'update_column' => 'updated_at', ), - 'i18n' => array('i18n_table' => '%TABLE%_i18n', 'i18n_phpname' => '%PHPNAME%I18n', 'i18n_columns' => '', 'locale_column' => 'locale', 'locale_length' => '5', 'default_locale' => '', 'locale_alias' => '', ), + 'i18n' => array('i18n_table' => '%TABLE%_i18n', 'i18n_phpname' => '%PHPNAME%I18n', 'i18n_columns' => 'title, description', 'locale_column' => 'locale', 'locale_length' => '5', 'default_locale' => '', 'locale_alias' => '', ), ); } // getBehaviors() /** @@ -341,16 +323,10 @@ class TaxRuleTableMap extends TableMap { if (null === $alias) { $criteria->addSelectColumn(TaxRuleTableMap::ID); - $criteria->addSelectColumn(TaxRuleTableMap::CODE); - $criteria->addSelectColumn(TaxRuleTableMap::TITLE); - $criteria->addSelectColumn(TaxRuleTableMap::DESCRIPTION); $criteria->addSelectColumn(TaxRuleTableMap::CREATED_AT); $criteria->addSelectColumn(TaxRuleTableMap::UPDATED_AT); } else { $criteria->addSelectColumn($alias . '.ID'); - $criteria->addSelectColumn($alias . '.CODE'); - $criteria->addSelectColumn($alias . '.TITLE'); - $criteria->addSelectColumn($alias . '.DESCRIPTION'); $criteria->addSelectColumn($alias . '.CREATED_AT'); $criteria->addSelectColumn($alias . '.UPDATED_AT'); } diff --git a/core/lib/Thelia/Model/Map/TaxTableMap.php b/core/lib/Thelia/Model/Map/TaxTableMap.php old mode 100755 new mode 100644 index 6d43f20e9..11e5047ce --- a/core/lib/Thelia/Model/Map/TaxTableMap.php +++ b/core/lib/Thelia/Model/Map/TaxTableMap.php @@ -160,7 +160,7 @@ class TaxTableMap extends TableMap */ public function buildRelations() { - $this->addRelation('TaxRuleCountry', '\\Thelia\\Model\\TaxRuleCountry', RelationMap::ONE_TO_MANY, array('id' => 'tax_id', ), 'SET NULL', 'RESTRICT', 'TaxRuleCountries'); + $this->addRelation('TaxRuleCountry', '\\Thelia\\Model\\TaxRuleCountry', RelationMap::ONE_TO_MANY, array('id' => 'tax_id', ), 'CASCADE', 'RESTRICT', 'TaxRuleCountries'); $this->addRelation('TaxI18n', '\\Thelia\\Model\\TaxI18n', RelationMap::ONE_TO_MANY, array('id' => 'id', ), 'CASCADE', null, 'TaxI18ns'); } // buildRelations() diff --git a/core/lib/Thelia/Model/Order.php b/core/lib/Thelia/Model/Order.php index 91582750a..f8e6db193 100755 --- a/core/lib/Thelia/Model/Order.php +++ b/core/lib/Thelia/Model/Order.php @@ -6,4 +6,15 @@ use Thelia\Model\Base\Order as BaseOrder; class Order extends BaseOrder { + /** + * calculate the total amount + * + * @TODO create body method + * + * @return int + */ + public function getTotalAmount() + { + return 2; + } } diff --git a/core/lib/Thelia/Model/Product.php b/core/lib/Thelia/Model/Product.php index 6c7ffbe44..06c4640d0 100755 --- a/core/lib/Thelia/Model/Product.php +++ b/core/lib/Thelia/Model/Product.php @@ -2,8 +2,10 @@ namespace Thelia\Model; +use Propel\Runtime\Exception\PropelException; use Thelia\Model\Base\Product as BaseProduct; use Thelia\Tools\URL; +use Thelia\TaxEngine\Calculator; class Product extends BaseProduct { @@ -11,4 +13,21 @@ class Product extends BaseProduct { return URL::getInstance()->retrieve('product', $this->getId(), $locale)->toString(); } + + public function getRealLowestPrice($virtualColumnName = 'real_lowest_price') + { + try { + $amount = $this->getVirtualColumn($virtualColumnName); + } catch(PropelException $e) { + throw new PropelException("Virtual column `$virtualColumnName` does not exist in Product::getRealLowestPrice"); + } + + return $amount; + } + + public function getTaxedPrice(Country $country) + { + $taxCalculator = new Calculator(); + return $taxCalculator->load($this, $country)->getTaxedPrice($this->getRealLowestPrice()); + } } diff --git a/core/lib/Thelia/Model/ProductSaleElements.php b/core/lib/Thelia/Model/ProductSaleElements.php index cec9c49a7..184e37d0a 100755 --- a/core/lib/Thelia/Model/ProductSaleElements.php +++ b/core/lib/Thelia/Model/ProductSaleElements.php @@ -3,8 +3,41 @@ namespace Thelia\Model; use Thelia\Model\Base\ProductSaleElements as BaseProductSaleElements; +use Thelia\TaxEngine\Calculator; - class ProductSaleElements extends BaseProductSaleElements +class ProductSaleElements extends BaseProductSaleElements { + public function getPrice($virtualColumnName = 'price_PRICE') + { + try { + $amount = $this->getVirtualColumn($virtualColumnName); + } catch(PropelException $e) { + throw new PropelException("Virtual column `$virtualColumnName` does not exist in ProductSaleElements::getPrice"); + } + return $amount; + } + + public function getPromoPrice($virtualColumnName = 'price_PROMO_PRICE') + { + try { + $amount = $this->getVirtualColumn($virtualColumnName); + } catch(PropelException $e) { + throw new PropelException("Virtual column `$virtualColumnName` does not exist in ProductSaleElements::getPromoPrice"); + } + + return $amount; + } + + public function getTaxedPrice(Country $country) + { + $taxCalculator = new Calculator(); + return $taxCalculator->load($this->getProduct(), $country)->getTaxedPrice($this->getPrice()); + } + + public function getTaxedPromoPrice(Country $country) + { + $taxCalculator = new Calculator(); + return $taxCalculator->load($this->getProduct(), $country)->getTaxedPrice($this->getPromoPrice()); + } } diff --git a/core/lib/Thelia/Model/Rewriting.php b/core/lib/Thelia/Model/Rewriting.php new file mode 100644 index 000000000..8d6f75fab --- /dev/null +++ b/core/lib/Thelia/Model/Rewriting.php @@ -0,0 +1,9 @@ +getRate(); + + if($rate === null) { + return 0; + } + + return $amount * $rate * 0.01; + } + + public function getTaxRuleCountryPosition() + { + try { + $taxRuleCountryPosition = $this->getVirtualColumn(TaxRuleQuery::ALIAS_FOR_TAX_RULE_COUNTRY_POSITION); + } catch(PropelException $e) { + throw new PropelException("Virtual column `" . TaxRuleQuery::ALIAS_FOR_TAX_RULE_COUNTRY_POSITION . "` does not exist in Tax::getTaxRuleCountryPosition"); + } + + return $taxRuleCountryPosition; + } + + public function getTaxRuleRateSum() + { + try { + $taxRuleRateSum = $this->getVirtualColumn(TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM); + } catch(PropelException $e) { + throw new PropelException("Virtual column `" . TaxRuleQuery::ALIAS_FOR_TAX_RATE_SUM . "` does not exist in Tax::getTaxRuleRateSum"); + } + + return $taxRuleRateSum; + } } diff --git a/core/lib/Thelia/Model/TaxRuleQuery.php b/core/lib/Thelia/Model/TaxRuleQuery.php index 8cb79562d..f9c6cf1e5 100755 --- a/core/lib/Thelia/Model/TaxRuleQuery.php +++ b/core/lib/Thelia/Model/TaxRuleQuery.php @@ -2,8 +2,10 @@ namespace Thelia\Model; +use Propel\Runtime\ActiveQuery\Criteria; use Thelia\Model\Base\TaxRuleQuery as BaseTaxRuleQuery; - +use Thelia\Model\Map\TaxRuleCountryTableMap; +use Thelia\Model\Map\TaxTableMap; /** * Skeleton subclass for performing query and update operations on the 'tax_rule' table. @@ -15,6 +17,26 @@ use Thelia\Model\Base\TaxRuleQuery as BaseTaxRuleQuery; * long as it does not already exist in the output directory. * */ -class TaxRuleQuery extends BaseTaxRuleQuery { +class TaxRuleQuery extends BaseTaxRuleQuery +{ + const ALIAS_FOR_TAX_RULE_COUNTRY_POSITION = 'taxRuleCountryPosition'; + const ALIAS_FOR_TAX_RATE_SUM = 'taxRateSum'; + public function getTaxCalculatorGroupedCollection(Product $product, Country $country) + { + $search = TaxQuery::create() + ->filterByTaxRuleCountry( + TaxRuleCountryQuery::create() + ->filterByCountry($country, Criteria::EQUAL) + ->filterByTaxRuleId($product->getTaxRuleId()) + ->groupByPosition() + ->orderByPosition() + ->find() + ) + ->withColumn(TaxRuleCountryTableMap::POSITION, self::ALIAS_FOR_TAX_RULE_COUNTRY_POSITION) + ->withColumn('ROUND(SUM(' . TaxTableMap::RATE . '), 2)', self::ALIAS_FOR_TAX_RATE_SUM) + ; + + return $search->find(); + } } // TaxRuleQuery diff --git a/core/lib/Thelia/TaxEngine/Calculator.php b/core/lib/Thelia/TaxEngine/Calculator.php new file mode 100755 index 000000000..66c4fcbbf --- /dev/null +++ b/core/lib/Thelia/TaxEngine/Calculator.php @@ -0,0 +1,95 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\TaxEngine; + +use Thelia\Exception\TaxEngineException; +use Thelia\Model\Country; +use Thelia\Model\Product; +use Thelia\Model\TaxRuleQuery; + +/** + * Class Calculator + * @package Thelia\TaxEngine + * @author Etienne Roudeix + */ +class Calculator +{ + protected $taxRuleQuery = null; + + protected $taxRulesGroupedCollection = null; + + protected $product = null; + protected $country = null; + + public function __construct() + { + $this->taxRuleQuery = new TaxRuleQuery(); + } + + public function load(Product $product, Country $country) + { + $this->product = null; + $this->country = null; + $this->taxRulesGroupedCollection = null; + + if($product->getId() === null) { + throw new TaxEngineException('Product id is empty in Calculator::load', TaxEngineException::UNDEFINED_PRODUCT); + } + if($country->getId() === null) { + throw new TaxEngineException('Country id is empty in Calculator::load', TaxEngineException::UNDEFINED_COUNTRY); + } + + $this->product = $product; + $this->country = $country; + + $this->taxRulesGroupedCollection = $this->taxRuleQuery->getTaxCalculatorGroupedCollection($product, $country); + + return $this; + } + + public function getTaxAmount($amount) + { + if(null === $this->taxRulesGroupedCollection) { + throw new TaxEngineException('Tax rules collection is empty in Calculator::getTaxAmount', TaxEngineException::UNDEFINED_TAX_RULES_COLLECTION); + } + + if(false === filter_var($amount, FILTER_VALIDATE_FLOAT)) { + throw new TaxEngineException('BAD AMOUNT FORMAT', TaxEngineException::BAD_AMOUNT_FORMAT); + } + + $totalTaxAmount = 0; + foreach($this->taxRulesGroupedCollection as $taxRule) { + $rateSum = $taxRule->getTaxRuleRateSum(); + $taxAmount = $amount * $rateSum * 0.01; + $totalTaxAmount += $taxAmount; + $amount += $taxAmount; + } + + return $totalTaxAmount; + } + + public function getTaxedPrice($amount) + { + return $amount + $this->getTaxAmount($amount); + } +} diff --git a/core/lib/Thelia/Tests/Constraint/ConstraintFactoryTest.php b/core/lib/Thelia/Tests/Constraint/ConstraintFactoryTest.php new file mode 100644 index 000000000..70d6e498c --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/ConstraintFactoryTest.php @@ -0,0 +1,229 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\AvailableForXArticlesManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\CouponBaseAdapter; +use Thelia\Coupon\CouponRuleCollection; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test ConstraintManager Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class ConstraintFactoryTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + public function setUp() + { + } + + /** + * Check the Rules serialization module + */ + public function testBuild() + { + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 40.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule1->setValidatorsFromForm($operators, $values); + + /** @var ConstraintManager $constraintManager */ + $constraintFactory = new ConstraintFactory($this->getContainer()); + $ruleManager1 = $constraintFactory->build($rule1->getServiceId(), $operators, $values); + + $expected = $rule1; + $actual = $ruleManager1; + + $this->assertEquals($expected, $actual); + $this->assertEquals($rule1->getServiceId(), $ruleManager1->getServiceId()); + $this->assertEquals($rule1->getValidators(), $ruleManager1->getValidators()); + } + + /** + * Check the Rules serialization module + */ + public function testBuildFail() + { + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 40.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule1->setValidatorsFromForm($operators, $values); + + /** @var ConstraintManager $constraintManager */ + $constraintFactory = new ConstraintFactory($this->getContainer()); + $ruleManager1 = $constraintFactory->build('unset.service', $operators, $values); + + $expected = false; + $actual = $ruleManager1; + + $this->assertEquals($expected, $actual); + } + + + /** + * Check the Rules serialization module + */ + public function testRuleSerialisation() + { + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 40.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule1->setValidatorsFromForm($operators, $values); + + $rule2 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule2->setValidatorsFromForm($operators, $values); + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + $rules->add($rule2); + + /** @var ConstraintManager $constraintManager */ + $constraintFactory = new ConstraintFactory($this->getContainer()); + + $serializedRules = $constraintFactory->serializeCouponRuleCollection($rules); + $unserializedRules = $constraintFactory->unserializeCouponRuleCollection($serializedRules); + + $expected = (string)$rules; + $actual = (string)$unserializedRules; + + $this->assertEquals($expected, $actual); + } + + /** + * Get Mocked Container with 2 Rules + * + * @return ContainerBuilder + */ + public function getContainer() + { + $container = new ContainerBuilder(); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $rule2 = new AvailableForXArticlesManager($stubAdapter); + + $adapter = new CouponBaseAdapter($container); + + $container->set('thelia.constraint.rule.available_for_total_amount', $rule1); + $container->set('thelia.constraint.rule.available_for_x_articles', $rule2); + $container->set('thelia.adapter', $adapter); + + return $container; + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php b/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php new file mode 100644 index 000000000..28ac4b952 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/ConstraintValidatorTest.php @@ -0,0 +1,337 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Constraint; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\AvailableForXArticlesManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\CouponBaseAdapter; +use Thelia\Coupon\CouponRuleCollection; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test ConstraintValidator Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class ConstraintValidatorTest extends \PHPUnit_Framework_TestCase +{ + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + public function setUp() + { + } + + public function testTestSuccess1Rules() + { + $ConstraintValidator = new ConstraintValidator(); + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(401)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => '>', + AvailableForTotalAmountManager::INPUT2 => '==' + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + + $isValid = $ConstraintValidator->test($rules); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testTestFail1Rules() + { + $ConstraintValidator = new ConstraintValidator(); + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => '>', + AvailableForTotalAmountManager::INPUT2 => '==' + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + + $isValid = $ConstraintValidator->test($rules); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual, 'Constraints validator always think Customer is matching rules'); + } + + public function testTestSuccess2Rules() + { + $ConstraintValidator = new ConstraintValidator(); + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(401)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(5)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => '>', + AvailableForTotalAmountManager::INPUT2 => '==' + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $rule2 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => '>' + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule2->setValidatorsFromForm($operators, $values); + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + $rules->add($rule2); + + $isValid = $ConstraintValidator->test($rules); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testTestFail2Rules() + { + $ConstraintValidator = new ConstraintValidator(); + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(5)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => '>', + AvailableForTotalAmountManager::INPUT2 => '==' + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $rule2 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => '>' + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule2->setValidatorsFromForm($operators, $values); + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + $rules->add($rule2); + + $isValid = $ConstraintValidator->test($rules); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual, 'Constraints validator always think Customer is matching rules'); + } + + + public function testVariableOpComparisonSuccess() + { + $ConstraintValidator = new ConstraintValidator(); + $expected = true; + $actual = $ConstraintValidator->variableOpComparison(1, Operators::EQUAL, 1); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::DIFFERENT, 2); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::SUPERIOR, 0); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::INFERIOR, 2); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::INFERIOR_OR_EQUAL, 1); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::INFERIOR_OR_EQUAL, 2); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::SUPERIOR_OR_EQUAL, 1); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::SUPERIOR_OR_EQUAL, 0); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::IN, array(1, 2, 3)); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(1, Operators::OUT, array(0, 2, 3)); + $this->assertEquals($expected, $actual); + + } + + public function testVariableOpComparisonFail() + { + $ConstraintValidator = new ConstraintValidator(); + $expected = false; + $actual = $ConstraintValidator->variableOpComparison(2, Operators::EQUAL, 1); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(2, Operators::DIFFERENT, 2); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(0, Operators::SUPERIOR, 0); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(3, Operators::INFERIOR, 2); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(2, Operators::INFERIOR_OR_EQUAL, 1); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(3, Operators::SUPERIOR_OR_EQUAL, 4); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(0, Operators::IN, array(1, 2, 3)); + $this->assertEquals($expected, $actual); + + $actual = $ConstraintValidator->variableOpComparison(2, Operators::OUT, array(0, 2, 3)); + $this->assertEquals($expected, $actual); + + } + + /** + * @expectedException \Exception + */ + public function testVariableOpComparisonException() + { + $ConstraintValidator = new ConstraintValidator(); + $expected = true; + $actual = $ConstraintValidator->variableOpComparison(1, 'bad', 1); + $this->assertEquals($expected, $actual); + } + + /** + * Get Mocked Container with 2 Rules + * + * @return ContainerBuilder + */ + public function getContainer() + { + $container = new ContainerBuilder(); + + $stubTranslator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator)); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $rule2 = new AvailableForXArticlesManager($stubAdapter); + + $adapter = new CouponBaseAdapter($container); + + $container->set('thelia.constraint.rule.available_for_total_amount', $rule1); + $container->set('thelia.constraint.rule.available_for_x_articles', $rule2); + $container->set('thelia.adapter', $adapter); + + return $container; + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } +} diff --git a/core/lib/Thelia/Tests/Constraint/Rule/AvailableForTotalAmountTest.php b/core/lib/Thelia/Tests/Constraint/Rule/AvailableForTotalAmountTest.php new file mode 100644 index 000000000..bfcde8a21 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Rule/AvailableForTotalAmountTest.php @@ -0,0 +1,670 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\Operators; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test AvailableForTotalAmount Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForTotalAmountTest extends \PHPUnit_Framework_TestCase +{ + /** @var CouponAdapterInterface $stubTheliaAdapter */ + protected $stubTheliaAdapter = null; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $this->stubTheliaAdapter = $this->generateValidCouponBaseAdapterMock(); + } + +// /** +// * Generate valid CouponBaseAdapter +// * +// * @param float $cartTotalPrice Total amount of the current Cart +// * +// * @return CouponAdapterInterface +// */ +// protected function generateValidCouponBaseAdapterMock($cartTotalPrice = 421.23) +// { +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $stubTheliaAdapter = $this->getMock( +// 'Thelia\Coupon\CouponBaseAdapter', +// array('getCartTotalPrice'), +// array() +// ); +// $stubTheliaAdapter->expects($this->any()) +// ->method('getCartTotalPrice') +// ->will($this->returnValue($cartTotalPrice)); +// +// return $stubTheliaAdapter; +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForTotalAmount::checkBackOfficeInput +// * +// */ +// public function testValidBackOfficeInput() +// { +// $adapter = new CouponBaseAdapter(); +// +// $validators = array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// new PriceParam( +// $adapter, 421.23, 'EUR' +// ) +// ) +// ); +// $rule = new AvailableForTotalAmount($adapter, $validators); +// +// $expected = true; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForTotalAmount::checkBackOfficeInput +// * @expectedException \Thelia\Exception\InvalidRuleOperatorException +// * +// */ +// public function testInValidBackOfficeInputOperator() +// { +// $adapter = new CouponBaseAdapter(); +// +// $validators = array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// 'X', +// new PriceParam( +// $adapter, 421.23, 'EUR' +// ) +// ) +// ); +// +// $rule = new AvailableForTotalAmount($adapter, $validators); +// +// $expected = false; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForTotalAmount::checkBackOfficeInput +// * @expectedException \ErrorException +// * +// */ +// public function testInValidBackOfficeInputValue() +// { +// $adapter = $this->generateValidCouponBaseAdapterMock(); +// +// $validators = array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// 421 +// ) +// ); +// +// $rule = new AvailableForTotalAmount($adapter, $validators); +// +// $expected = false; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleInferior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(399)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleInferior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleInferiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleInferiorEquals2() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(399)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleInferiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(401)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test equals operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleEqual() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test equals operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleEqual() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(399)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleSuperiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(401)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleSuperiorEquals2() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleSuperiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(399.00)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleSuperior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(401)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleSuperior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(399.00)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + + /** + * Check currency is checked + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testMatchingRuleCurrency() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400.00)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check currency is checked + * + * @covers Thelia\Constraint\Rule\AvailableForTotalAmountManager::isMatching + * + */ + public function testNotMatchingRuleCurrency() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getCartTotalPrice') + ->will($this->returnValue(400.00)); + $stubAdapter->expects($this->any()) + ->method('getCheckoutCurrency') + ->will($this->returnValue('EUR')); + + $rule1 = new AvailableForTotalAmountManager($stubAdapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::EQUAL, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'USD'); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Rule/AvailableForXArticlesTest.php b/core/lib/Thelia/Tests/Constraint/Rule/AvailableForXArticlesTest.php new file mode 100644 index 000000000..cc5caee2a --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Rule/AvailableForXArticlesTest.php @@ -0,0 +1,673 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Rule\AvailableForXArticlesManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Constraint\Rule\SerializableRule; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test AvailableForXArticles Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class AvailableForXArticlesTest extends \PHPUnit_Framework_TestCase +{ + +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// protected $stubTheliaAdapter = null; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $this->stubTheliaAdapter = $this->generateValidCouponBaseAdapterMock(); + } + +// /** +// * Generate valid CouponBaseAdapter +// * +// * @param int $nbArticlesInCart Total articles in the current Cart +// * +// * @return CouponAdapterInterface +// */ +// protected function generateValidCouponBaseAdapterMock($nbArticlesInCart = 4) +// { +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $stubTheliaAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') +// ->disableOriginalConstructor() +// ->setMethods(array('getNbArticlesInCart')) +// ->getMock(); +// $stubTheliaAdapter->expects($this->any()) +// ->method('getNbArticlesInCart') +// ->will($this->returnValue($nbArticlesInCart)); +// +// return $stubTheliaAdapter; +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForXArticles::checkBackOfficeInput +// * +// */ +// public function testValidBackOfficeInput() +// { +// $translator = $this->getMockBuilder('\Thelia\Core\Translation\Translator') +// ->disableOriginalConstructor() +// ->getMock(); +// +// $rule = new AvailableForXArticles($translator); +// $operators = array(AvailableForXArticles::PARAM1_QUANTITY => Operators::SUPERIOR); +// $values = array( +// AvailableForXArticles::PARAM1_QUANTITY => 4 +// ); +// $rule->populateFromForm($operators, $values); +// +// $expected = true; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForXArticles::checkBackOfficeInput +// * @expectedException \Thelia\Exception\InvalidRuleValueException +// */ +// public function testInValidBackOfficeInputFloat() +// { +// $adapter = $this->stubTheliaAdapter; +// +// $validators = array( +// AvailableForXArticles::PARAM1_QUANTITY => new RuleValidator( +// Operators::SUPERIOR, +// new QuantityParam( +// $adapter, +// 4.5 +// ) +// ) +// ); +// $rule = new AvailableForXArticles($adapter, $validators); +// +// $expected = false; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForXArticles::checkBackOfficeInput +// * @expectedException \Thelia\Exception\InvalidRuleValueException +// */ +// public function testInValidBackOfficeInputNegative() +// { +// $adapter = $this->stubTheliaAdapter; +// +// $validators = array( +// AvailableForXArticles::PARAM1_QUANTITY => new RuleValidator( +// Operators::SUPERIOR, +// new QuantityParam( +// $adapter, +// -1 +// ) +// ) +// ); +// $rule = new AvailableForXArticles($adapter, $validators); +// +// $expected = false; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + +// /** +// * Check if validity test on BackOffice inputs are working +// * +// * @covers Thelia\Coupon\Rule\AvailableForXArticles::checkBackOfficeInput +// * @expectedException \Thelia\Exception\InvalidRuleValueException +// */ +// public function testInValidBackOfficeInputString() +// { +// $adapter = $this->stubTheliaAdapter; +// +// $validators = array( +// AvailableForXArticles::PARAM1_QUANTITY => new RuleValidator( +// Operators::SUPERIOR, +// new QuantityParam( +// $adapter, +// 'bad' +// ) +// ) +// ); +// $rule = new AvailableForXArticles($adapter, $validators); +// +// $expected = false; +// $actual = $rule->checkBackOfficeInput(); +// $this->assertEquals($expected, $actual); +// } + + + + + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleInferior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::INFERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 5 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testNotMatchingRuleInferior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::INFERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4, + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleInferiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::INFERIOR_OR_EQUAL, + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 5, + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleInferiorEquals2() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test inferior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testNotMatchingRuleInferiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::INFERIOR_OR_EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 3 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test equals operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleEqual() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test equals operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testNotMatchingRuleEqual() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 5 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleSuperiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleSuperiorEquals2() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 3 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testNotMatchingRuleSuperiorEquals() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR_OR_EQUAL + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 5 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testMatchingRuleSuperior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 3 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = true; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + /** + * Check if test superior operator is working + * + * @covers Thelia\Constraint\Rule\AvailableForXArticlesManager::isMatching + * + */ + public function testNotMatchingRuleSuperior() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $isValid = $rule1->isMatching(); + + $expected = false; + $actual =$isValid; + $this->assertEquals($expected, $actual); + } + + public function testGetSerializableRule() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $serializableRule = $rule1->getSerializableRule(); + + $expected = new SerializableRule(); + $expected->ruleServiceId = $rule1->getServiceId(); + $expected->operators = $operators; + $expected->values = $values; + + $actual = $serializableRule; + + $this->assertEquals($expected, $actual); + + } + + public function testGetAvailableOperators() + { + $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') + ->disableOriginalConstructor() + ->getMock(); + + $stubAdapter->expects($this->any()) + ->method('getNbArticlesInCart') + ->will($this->returnValue(4)); + + $rule1 = new AvailableForXArticlesManager($stubAdapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4 + ); + $rule1->setValidatorsFromForm($operators, $values); + + $expected = array( + AvailableForXArticlesManager::INPUT1 => array( + Operators::INFERIOR, + Operators::INFERIOR_OR_EQUAL, + Operators::EQUAL, + Operators::SUPERIOR_OR_EQUAL, + Operators::SUPERIOR + ) + ); + $actual = $rule1->getAvailableOperators(); + + $this->assertEquals($expected, $actual); + + } + +// public function testGetValidators() +// { +// $stubAdapter = $this->getMockBuilder('\Thelia\Coupon\CouponBaseAdapter') +// ->disableOriginalConstructor() +// ->getMock(); +// +// $stubAdapter->expects($this->any()) +// ->method('getNbArticlesInCart') +// ->will($this->returnValue(4)); +// +// $rule1 = new AvailableForXArticlesManager($stubAdapter); +// $operators = array( +// AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR +// ); +// $values = array( +// AvailableForXArticlesManager::INPUT1 => 4 +// ); +// $rule1->setValidatorsFromForm($operators, $values); +// +// $expected = array( +// $operators, +// $values +// ); +// $actual = $rule1->getValidators(); +// +// $this->assertEquals($expected, $actual); +// +// } + + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Rule/OperatorsTest.php b/core/lib/Thelia/Tests/Constraint/Rule/OperatorsTest.php new file mode 100644 index 000000000..c86e827b6 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Rule/OperatorsTest.php @@ -0,0 +1,429 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Validator\QuantityParam; +use Thelia\Constraint\Rule\Operators; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test Operators Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class OperatorsTest 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 testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorValidBefore() +// { +// $adapter = new CouponBaseAdapter(); +// // Given +// $a = 11; +// $operator = Operators::INFERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorInvalidEquals() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::INFERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorInvalidAfter() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 13; +// $operator = Operators::INFERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorOrEqualValidEqual() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 11; +// $operator = Operators::INFERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorOrEqualValidBefore() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 10; +// $operator = Operators::INFERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInferiorOrEqualInValidAfter() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::INFERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorEqualValidEqual() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::EQUAL; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorEqualInValidBefore() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 11; +// $operator = Operators::EQUAL; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorEqualInValidAfter() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 13; +// $operator = Operators::EQUAL; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorOrEqualValidEqual() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 13; +// $operator = Operators::SUPERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 13); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorOrEqualAfter() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 14; +// $operator = Operators::SUPERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 13); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorOrEqualInvalidBefore() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::SUPERIOR_OR_EQUAL; +// $b = new QuantityParam($adapter, 13); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorValidAfter() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 13; +// $operator = Operators::SUPERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorInvalidEqual() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::SUPERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorSuperiorInvalidBefore() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 11; +// $operator = Operators::SUPERIOR; +// $b = new QuantityParam($adapter, 12); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorDifferentValid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = Operators::DIFFERENT; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertTrue($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorDifferentInvalidEquals() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 11; +// $operator = Operators::DIFFERENT; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Rule\Operator::isValidAccordingToOperator +// * +// */ +// public function testOperatorInValid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $a = 12; +// $operator = 'X'; +// $b = new QuantityParam($adapter, 11); +// +// // When +// $actual = Operators::isValid($a, $operator, $b); +// +// // Then +// $this->assertFalse($actual); +// } + + + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/CustomerParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/CustomerParamTest.php new file mode 100644 index 000000000..afb7b8c80 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/CustomerParamTest.php @@ -0,0 +1,169 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\CustomerParam; +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\QuantityParam; +use Thelia\Model\Customer; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test CustomerParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class CustomerParamTest extends \PHPUnit_Framework_TestCase +{ + + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// protected $stubTheliaAdapter = null; +// +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $this->stubTheliaAdapter = $this->generateValidCouponBaseAdapterMock(); +// } +// +// /** +// * Generate valid CouponBaseAdapter +// * +// * @param int $customerId Customer id +// * +// * @return CouponAdapterInterface +// */ +// protected function generateValidCouponBaseAdapterMock($customerId = 4521) +// { +// $customer = new Customer(); +// $customer->setId($customerId); +// $customer->setFirstname('Firstname'); +// $customer->setLastname('Lastname'); +// $customer->setEmail('em@il.com'); +// +// /** @var CouponAdapterInterface $stubTheliaAdapter */ +// $stubTheliaAdapter = $this->getMock( +// 'Thelia\Coupon\CouponBaseAdapter', +// array('getCustomer'), +// array() +// ); +// $stubTheliaAdapter->expects($this->any()) +// ->method('getCustomer') +// ->will($this->returnValue($customer)); +// +// return $stubTheliaAdapter; +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * +// */ +// public function testCanUseCoupon() +// { +// $customerId = 4521; +// $couponValidForCustomerId = 4521; +// +// $adapter = $this->generateValidCouponBaseAdapterMock($customerId); +// +// $customerParam = new CustomerParam($adapter, $couponValidForCustomerId); +// +// $expected = 0; +// $actual = $customerParam->compareTo($customerId); +// $this->assertEquals($expected, $actual); +// } +// +//// /** +//// * +//// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +//// * +//// */ +//// public function testCanNotUseCouponTest() +//// { +//// +//// } +//// +//// /** +//// * +//// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +//// * @expectedException InvalidArgumentException +//// * +//// */ +//// public function testCanNotUseCouponCustomerNotFoundTest() +//// { +//// +//// } +// +// +// +// +//// /** +//// * Test is the object is serializable +//// * If no data is lost during the process +//// */ +//// public function isSerializableTest() +//// { +//// $adapter = new CouponBaseAdapter(); +//// $intValidator = 42; +//// $intToValidate = -1; +//// +//// $param = new QuantityParam($adapter, $intValidator); +//// +//// $serialized = base64_encode(serialize($param)); +//// /** @var QuantityParam $unserialized */ +//// $unserialized = base64_decode(serialize($serialized)); +//// +//// $this->assertEquals($param->getValue(), $unserialized->getValue()); +//// $this->assertEquals($param->getInteger(), $unserialized->getInteger()); +//// +//// $new = new QuantityParam($adapter, $unserialized->getInteger()); +//// $this->assertEquals($param->getInteger(), $new->getInteger()); +//// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/DateParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/DateParamTest.php new file mode 100644 index 000000000..53a5c70eb --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/DateParamTest.php @@ -0,0 +1,158 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\DateParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test DateParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class DateParamTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * +// */ +// public function testInferiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-07"); +// +// $dateParam = new DateParam($adapter, $dateValidator); +// +// $expected = 1; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * +// */ +// public function testEqualsDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-08"); +// +// $dateParam = new DateParam($adapter, $dateValidator); +// +// $expected = 0; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * +// */ +// public function testSuperiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-09"); +// +// $dateParam = new DateParam($adapter, $dateValidator); +// +// $expected = -1; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = 1377012588; +// +// $dateParam = new DateParam($adapter, $dateValidator); +// +// $dateParam->compareTo($dateToValidate); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidator = new \DateTime("2012-07-08"); +// +// $param = new DateParam($adapter, $dateValidator); +// +// $serialized = base64_encode(serialize($param)); +// /** @var DateParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getDateTime(), $unserialized->getDateTime()); +// +// $new = new DateParam($adapter, $unserialized->getDateTime()); +// $this->assertEquals($param->getDateTime(), $new->getDateTime()); +// } +// +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/IntegerParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/IntegerParamTest.php new file mode 100644 index 000000000..edf71b138 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/IntegerParamTest.php @@ -0,0 +1,159 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\IntegerParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test IntegerParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class IntegerParamTest extends \PHPUnit_Framework_TestCase +{ + + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntegerParam::compareTo +// * +// */ +// public function testInferiorInteger() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 41; +// +// $integerParam = new IntegerParam($adapter, $intValidator); +// +// $expected = 1; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntegerParam::compareTo +// * +// */ +// public function testEqualsInteger() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 42; +// +// $integerParam = new IntegerParam($adapter, $intValidator); +// +// $expected = 0; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntegerParam::compareTo +// * +// */ +// public function testSuperiorInteger() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 43; +// +// $integerParam = new IntegerParam($adapter, $intValidator); +// +// $expected = -1; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\IntegerParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = '42'; +// +// $integerParam = new IntegerParam($adapter, $intValidator); +// +// $expected = 0; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// +// $param = new IntegerParam($adapter, $intValidator); +// +// $serialized = base64_encode(serialize($param)); +// /** @var IntegerParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getInteger(), $unserialized->getInteger()); +// +// $new = new IntegerParam($adapter, $unserialized->getInteger()); +// $this->assertEquals($param->getInteger(), $new->getInteger()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/IntervalParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/IntervalParamTest.php new file mode 100644 index 000000000..e98c5f719 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/IntervalParamTest.php @@ -0,0 +1,184 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\IntervalParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test IntervalParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class IntervalParamTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntervalParam::compareTo +// * +// */ +// public function testInferiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// $dateToValidate = new \DateTime("2012-07-07"); +// +// $dateParam = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $expected = 1; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntervalParam::compareTo +// * +// */ +// public function testEqualsDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// $dateToValidate = new \DateTime("2012-07-08"); +// +// echo '1 ' . date_format($dateValidatorStart, 'g:ia \o\n l jS F Y') . "\n"; +// echo '2 ' . date_format($dateToValidate, 'g:ia \o\n l jS F Y') . "\n"; +// +// $dateParam = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $expected = 0; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntervalParam::compareTo +// * +// */ +// public function testEqualsDate2() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// $dateToValidate = new \DateTime("2012-08-08"); +// +// $dateParam = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $expected = 0; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\IntervalParam::compareTo +// * +// */ +// public function testSuperiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// $dateToValidate = new \DateTime("2012-08-09"); +// +// $dateParam = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $expected = -1; +// $actual = $dateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// $dateToValidate = 1377012588; +// +// $dateParam = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $dateParam->compareTo($dateToValidate); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $dateValidatorStart = new \DateTime("2012-07-08"); +// $dateValidatorInterval = new \DateInterval("P1M"); //1month +// +// $param = new IntervalParam($adapter, $dateValidatorStart, $dateValidatorInterval); +// +// $serialized = base64_encode(serialize($param)); +// /** @var IntervalParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getDatePeriod(), $unserialized->getDatePeriod()); +// +// $new = new IntervalParam($adapter, $unserialized->getStart(), $unserialized->getInterval()); +// $this->assertEquals($param->getDatePeriod(), $new->getDatePeriod()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/PriceParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/PriceParamTest.php new file mode 100644 index 000000000..4eb04a77e --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/PriceParamTest.php @@ -0,0 +1,237 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\PriceParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test PriceParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class PriceParamTest extends \PHPUnit_Framework_TestCase +{ + + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * +// */ +// public function testInferiorPrice() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = 1.00; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 1; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * +// */ +// public function testInferiorPrice2() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = 42.49; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 1; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * +// */ +// public function testEqualsPrice() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = 42.50; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 0; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * +// */ +// public function testSuperiorPrice() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = 42.51; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = -1; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = '42.50'; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 0; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException2() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = -1; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 0; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException3() +// { +// $adapter = new CouponBaseAdapter(); +// +// $priceValidator = 42.50; +// $priceToValidate = 0; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'EUR'); +// +// $expected = 0; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\PriceParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException4() +// { +// $adapter = new CouponBaseAdapter(); +// $priceValidator = 42.50; +// $priceToValidate = 1; +// +// $integerParam = new PriceParam($adapter, $priceValidator, 'GBP'); +// +// $expected = 0; +// $actual = $integerParam->compareTo($priceToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $priceValidator = 42.50; +// +// $param = new PriceParam($adapter, $priceValidator, 'GBP'); +// +// $serialized = base64_encode(serialize($param)); +// /** @var PriceParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getPrice(), $unserialized->getPrice()); +// $this->assertEquals($param->getCurrency(), $unserialized->getCurrency()); +// +// $new = new PriceParam($adapter, $unserialized->getPrice(), $unserialized->getCurrency()); +// $this->assertEquals($param->getPrice(), $new->getPrice()); +// $this->assertEquals($param->getCurrency(), $new->getCurrency()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/QuantityParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/QuantityParamTest.php new file mode 100644 index 000000000..afcc62f6e --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/QuantityParamTest.php @@ -0,0 +1,196 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\QuantityParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test QuantityParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class QuantityParamTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * +// */ +// public function testInferiorQuantity() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 0; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = 1; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * +// */ +// public function testInferiorQuantity2() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 41; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = 1; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * +// */ +// public function testEqualsQuantity() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 42; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = 0; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * +// */ +// public function testSuperiorQuantity() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = 43; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = -1; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = '42'; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = 0; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\QuantityParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException2() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = -1; +// +// $integerParam = new QuantityParam($adapter, $intValidator); +// +// $expected = 0; +// $actual = $integerParam->compareTo($intToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $intValidator = 42; +// $intToValidate = -1; +// +// $param = new QuantityParam($adapter, $intValidator); +// +// $serialized = base64_encode(serialize($param)); +// /** @var QuantityParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getInteger(), $unserialized->getInteger()); +// +// $new = new QuantityParam($adapter, $unserialized->getInteger()); +// $this->assertEquals($param->getInteger(), $new->getInteger()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/RepeatedDateParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/RepeatedDateParamTest.php new file mode 100644 index 000000000..677117348 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/RepeatedDateParamTest.php @@ -0,0 +1,310 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use InvalidArgumentException; +use Symfony\Component\Intl\Exception\NotImplementedException; +use Thelia\Constraint\Validator\RepeatedDateParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RepeatedDateParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class RepeatedDateParamTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testInferiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-07"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(); +// +// $expected = -1; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeFirstPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeSecondPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-08-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(1, 1); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthTenTimesThirdPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-09-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(1, 10); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthTenTimesTensPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2013-05-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(1, 10); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryFourMonthTwoTimesSecondPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-11-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryFourMonthTwoTimesLastPeriod() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2013-03-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $expected = 0; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testNotEqualsDateRepeatEveryFourMonthTwoTimes1() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-08-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $expected = -1; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testNotEqualsDateRepeatEveryFourMonthTwoTimes2() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-12-08"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $expected = -1; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedDateParam::compareTo +// * +// */ +// public function testSuperiorDateRepeatEveryFourMonthTwoTimes() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2013-03-09"); +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $expected = -1; +// $actual = $repeatedDateParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * @expectedException InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = 1377012588; +// +// $repeatedDateParam = new RepeatedDateParam($adapter); +// $repeatedDateParam->setFrom($startDateValidator); +// $repeatedDateParam->repeatEveryMonth(4, 2); +// +// $repeatedDateParam->compareTo($dateToValidate); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// +// $param = new RepeatedDateParam($adapter); +// $param->setFrom($startDateValidator); +// $param->repeatEveryMonth(4, 2); +// +// $serialized = base64_encode(serialize($param)); +// /** @var RepeatedDateParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getDatePeriod(), $unserialized->getDatePeriod()); +// +// $new = new RepeatedDateParam($adapter); +// $new->setFrom($unserialized->getFrom()); +// $new->repeatEveryMonth($unserialized->getFrequency(), $unserialized->getNbRepetition()); +// $this->assertEquals($param->getDatePeriod(), $new->getDatePeriod()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Constraint/Validator/RepeatedIntervalParamTest.php b/core/lib/Thelia/Tests/Constraint/Validator/RepeatedIntervalParamTest.php new file mode 100644 index 000000000..513e85836 --- /dev/null +++ b/core/lib/Thelia/Tests/Constraint/Validator/RepeatedIntervalParamTest.php @@ -0,0 +1,427 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Symfony\Component\Intl\Exception\NotImplementedException; +use Thelia\Constraint\Validator\RepeatedIntervalParam; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RepeatedIntervalParam Class + * + * @package Constraint + * @author Guillaume MOREL + * + */ +class RepeatedIntervalParamTest extends \PHPUnit_Framework_TestCase +{ + + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testInferiorDate() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-07"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = -1; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeFirstPeriodBeginning() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-08"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeFirstPeriodMiddle() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-13"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeFirstPeriodEnding() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-07-18"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeSecondPeriodBeginning() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-08-08"); +// $dateToValidate = new \DateTime("2012-08-08"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeSecondPeriodMiddle() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-08-08"); +// $dateToValidate = new \DateTime("2012-08-13"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthOneTimeSecondPeriodEnding() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-08-08"); +// $dateToValidate = new \DateTime("2012-08-18"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthFourTimeLastPeriodBeginning() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-10-08"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthFourTimeLastPeriodMiddle() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-10-13"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testEqualsDateRepeatEveryMonthFourTimeLastPeriodEnding() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-10-18"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = 0; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testNotEqualsDateRepeatEveryMonthFourTimeInTheBeginning() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-07-19"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = -1; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testNotEqualsDateRepeatEveryMonthFourTimeInTheMiddle() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-08-01"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = -1; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testNotEqualsDateRepeatEveryMonthFourTimeInTheEnd() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-10-08"); +// $dateToValidate = new \DateTime("2012-08-07"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $expected = -1; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// +// +// /** +// * +// * @covers Thelia\Coupon\Parameter\RepeatedIntervalParam::compareTo +// * +// */ +// public function testSuperiorDateRepeatEveryMonthFourTime() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = new \DateTime("2012-10-19"); +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 0); +// +// $expected = -1; +// $actual = $RepeatedIntervalParam->compareTo($dateToValidate); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * @covers Thelia\Coupon\Parameter\DateParam::compareTo +// * @expectedException \InvalidArgumentException +// */ +// public function testInvalidArgumentException() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = 1377012588; +// $duration = 10; +// +// $RepeatedIntervalParam = new RepeatedIntervalParam($adapter); +// $RepeatedIntervalParam->setFrom($startDateValidator); +// $RepeatedIntervalParam->setDurationInDays($duration); +// $RepeatedIntervalParam->repeatEveryMonth(1, 4); +// +// $RepeatedIntervalParam->compareTo($dateToValidate); +// } +// +// /** +// * Test is the object is serializable +// * If no data is lost during the process +// */ +// public function isSerializableTest() +// { +// $adapter = new CouponBaseAdapter(); +// $startDateValidator = new \DateTime("2012-07-08"); +// $dateToValidate = 1377012588; +// $duration = 10; +// +// $param = new RepeatedIntervalParam($adapter); +// $param->setFrom($startDateValidator); +// $param->setDurationInDays($duration); +// $param->repeatEveryMonth(1, 4); +// +// $serialized = base64_encode(serialize($param)); +// /** @var RepeatedIntervalParam $unserialized */ +// $unserialized = base64_decode(serialize($serialized)); +// +// $this->assertEquals($param->getValue(), $unserialized->getValue()); +// $this->assertEquals($param->getDatePeriod(), $unserialized->getDatePeriod()); +// +// $new = new RepeatedIntervalParam($adapter); +// $new->setFrom($unserialized->getFrom()); +// $new->repeatEveryMonth($unserialized->getFrequency(), $unserialized->getNbRepetition()); +// $new->setDurationInDays($unserialized->getDurationInDays()); +// $this->assertEquals($param->getDatePeriod(), $new->getDatePeriod()); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php b/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php index 7d14fbbc5..4a9cb4158 100755 --- a/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php +++ b/core/lib/Thelia/Tests/Core/Template/Element/BaseLoopTestor.php @@ -23,6 +23,7 @@ namespace Thelia\Tests\Core\Template\Element; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\EventDispatcher\EventDispatcher; use Thelia\Core\HttpFoundation\Request; use Thelia\Core\Security\SecurityContext; @@ -34,11 +35,9 @@ use Thelia\Core\HttpFoundation\Session\Session; * @author Etienne Roudeix * */ -abstract class BaseLoopTestor extends \Thelia\Tests\TestCaseWithURLToolSetup +abstract class BaseLoopTestor extends \PHPUnit_Framework_TestCase { - protected $request; - protected $dispatcher; - protected $securityContext; + protected $container; protected $instance; @@ -57,12 +56,35 @@ abstract class BaseLoopTestor extends \Thelia\Tests\TestCaseWithURLToolSetup public function setUp() { - $this->request = new Request(); + $this->container = new ContainerBuilder(); + + $session = new Session(new MockArraySessionStorage()); + $request = new Request(); + + $request->setSession($session); + + /*$stubEventdispatcher = $this->getMockBuilder('\Symfony\Component\EventDispatcher\EventDispatcher') + ->disableOriginalConstructor() + ->getMock(); + + $stubSecurityContext = $this->getMockBuilder('\Thelia\Core\Security\SecurityContext') + ->disableOriginalConstructor() + ->getMock();*/ + + /*$stubAdapter->expects($this->any()) + ->method('getTranslator') + ->will($this->returnValue($stubTranslator));*/ + + /*$this->request = new Request(); $this->request->setSession(new Session(new MockArraySessionStorage())); $this->dispatcher = new EventDispatcher(); - $this->securityContext = new SecurityContext($this->request); + $this->securityContext = new SecurityContext($this->request);*/ + + $this->container->set('request', $request); + $this->container->set('event_dispatcher', new EventDispatcher()); + $this->container->set('thelia.securityContext', new SecurityContext($request)); $this->instance = $this->getTestedInstance(); $this->instance->initializeArgs($this->getMandatoryArguments()); diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php index 99f5a0310..64bd4b5b6 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AccessoryTest.php @@ -41,7 +41,7 @@ class AccessoryTest extends BaseLoopTestor public function getTestedInstance() { - return new Accessory($this->request, $this->dispatcher, $this->securityContext); + return new Accessory($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php index 7ca5c094b..447646b8b 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AddressTest.php @@ -41,7 +41,7 @@ class AddressTest extends BaseLoopTestor public function getTestedInstance() { - return new Address($this->request, $this->dispatcher, $this->securityContext); + return new Address($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AssociatedContentTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AssociatedContentTest.php index 0a12ad076..5d6c2579c 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AssociatedContentTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AssociatedContentTest.php @@ -41,7 +41,7 @@ class AssociatedContentTest extends BaseLoopTestor public function getTestedInstance() { - return new AssociatedContent($this->request, $this->dispatcher, $this->securityContext); + return new AssociatedContent($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeAvailabilityTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeAvailabilityTest.php index c870f32ef..ca880daa8 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeAvailabilityTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeAvailabilityTest.php @@ -41,7 +41,7 @@ class AttributeAvailabilityTest extends BaseLoopTestor public function getTestedInstance() { - return new AttributeAvailability($this->request, $this->dispatcher, $this->securityContext); + return new AttributeAvailability($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeCombinationTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeCombinationTest.php index 98d0575eb..f811c7de9 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeCombinationTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeCombinationTest.php @@ -41,7 +41,7 @@ class AttributeCombinationTest extends BaseLoopTestor public function getTestedInstance() { - return new AttributeCombination($this->request, $this->dispatcher, $this->securityContext); + return new AttributeCombination($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeTest.php index 653de34e9..46b19e3ac 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/AttributeTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/AttributeTest.php @@ -41,7 +41,7 @@ class AttributeTest extends BaseLoopTestor public function getTestedInstance() { - return new Attribute($this->request, $this->dispatcher, $this->securityContext); + return new Attribute($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php index f33d07868..a2a320693 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CategoryTest.php @@ -41,7 +41,7 @@ class CategoryTest extends BaseLoopTestor public function getTestedInstance() { - return new Category($this->request, $this->dispatcher, $this->securityContext); + return new Category($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/ContentTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/ContentTest.php index 71922dbab..b6f9d0e3d 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/ContentTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/ContentTest.php @@ -41,7 +41,7 @@ class ContentTest extends BaseLoopTestor public function getTestedInstance() { - return new Content($this->request, $this->dispatcher, $this->securityContext); + return new Content($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php index 389d0bc5d..0eb37a6fd 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CountryTest.php @@ -41,7 +41,7 @@ class CountryTest extends BaseLoopTestor public function getTestedInstance() { - return new Country($this->request, $this->dispatcher, $this->securityContext); + return new Country($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CurrencyTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CurrencyTest.php index 95dd5a5c6..a866fae0c 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/CurrencyTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CurrencyTest.php @@ -41,7 +41,7 @@ class CurrencyTest extends BaseLoopTestor public function getTestedInstance() { - return new Currency($this->request, $this->dispatcher, $this->securityContext); + return new Currency($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php index 62bcaa3be..4239414fa 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/CustomerTest.php @@ -41,7 +41,7 @@ class CustomerTest extends BaseLoopTestor public function getTestedInstance() { - return new Customer($this->request, $this->dispatcher, $this->securityContext); + return new Customer($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailabilityTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailabilityTest.php index d3a045f33..aae4ec254 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailabilityTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureAvailabilityTest.php @@ -41,7 +41,7 @@ class FeatureAvailabilityTest extends BaseLoopTestor public function getTestedInstance() { - return new FeatureAvailability($this->request, $this->dispatcher, $this->securityContext); + return new FeatureAvailability($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php index 155088173..7324856f6 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureTest.php @@ -41,7 +41,7 @@ class FeatureTest extends BaseLoopTestor public function getTestedInstance() { - return new Feature($this->request, $this->dispatcher, $this->securityContext); + return new Feature($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php index 3f6a14a16..19966ba71 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FeatureValueTest.php @@ -41,7 +41,7 @@ class FeatureValueTest extends BaseLoopTestor public function getTestedInstance() { - return new FeatureValue($this->request, $this->dispatcher, $this->securityContext); + return new FeatureValue($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/FolderTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/FolderTest.php index 2505c2fc2..2388a86c0 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/FolderTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/FolderTest.php @@ -41,7 +41,7 @@ class FolderTest extends BaseLoopTestor public function getTestedInstance() { - return new Folder($this->request, $this->dispatcher, $this->securityContext); + return new Folder($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/ProductSaleElementTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/ProductSaleElementTest.php index 612519e04..d8ed243ca 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/ProductSaleElementTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/ProductSaleElementTest.php @@ -41,7 +41,7 @@ class ProductSaleElementsTest extends BaseLoopTestor public function getTestedInstance() { - return new ProductSaleElements($this->request, $this->dispatcher, $this->securityContext); + return new ProductSaleElements($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php index 1ac5cb3b3..8fc7d5ae5 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/ProductTest.php @@ -32,7 +32,7 @@ use Thelia\Core\Template\Loop\Product; * @author Etienne Roudeix * */ -/*class ProductTest extends BaseLoopTestor +class ProductTest extends BaseLoopTestor { public function getTestedClassName() { @@ -41,11 +41,11 @@ use Thelia\Core\Template\Loop\Product; public function getTestedInstance() { - return new Product($this->request, $this->dispatcher, $this->securityContext); + return new Product($this->container); } public function getMandatoryArguments() { return array(); } -}*/ +} diff --git a/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php b/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php index 392e97930..63e4a7a9a 100755 --- a/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php +++ b/core/lib/Thelia/Tests/Core/Template/Loop/TitleTest.php @@ -41,7 +41,7 @@ class TitleTest extends BaseLoopTestor public function getTestedInstance() { - return new Title($this->request, $this->dispatcher, $this->securityContext); + return new Title($this->container); } public function getMandatoryArguments() diff --git a/core/lib/Thelia/Tests/Coupon/CouponBaseAdapterTest.php b/core/lib/Thelia/Tests/Coupon/CouponBaseAdapterTest.php new file mode 100644 index 000000000..45f097a77 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/CouponBaseAdapterTest.php @@ -0,0 +1,103 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test CouponBaseAdapter Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponBaseAdapterTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * @var CouponBaseAdapter +// */ +// protected $object; +// +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// $this->object = new CouponBaseAdapter; +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } +// +// /** +// * @covers Thelia\Coupon\CouponBaseAdapter::getCart +// * @todo Implement testGetCart(). +// */ +// public function testGetCart() +// { +// // Remove the following lines when you implement this test. +// $this->markTestIncomplete( +// 'This test has not been implemented yet.' +// ); +// } +// +// /** +// * @covers Thelia\Coupon\CouponBaseAdapter::getDeliveryAddress +// * @todo Implement testGetDeliveryAddress(). +// */ +// public function testGetDeliveryAddress() +// { +// // Remove the following lines when you implement this test. +// $this->markTestIncomplete( +// 'This test has not been implemented yet.' +// ); +// } +// +// /** +// * @covers Thelia\Coupon\CouponBaseAdapter::getCustomer +// * @todo Implement testGetCustomer(). +// */ +// public function testGetCustomer() +// { +// // Remove the following lines when you implement this test. +// $this->markTestIncomplete( +// 'This test has not been implemented yet.' +// ); +// } +} diff --git a/core/lib/Thelia/Tests/Coupon/CouponFactoryTest.php b/core/lib/Thelia/Tests/Coupon/CouponFactoryTest.php new file mode 100644 index 000000000..261f0e100 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/CouponFactoryTest.php @@ -0,0 +1,345 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Constraint\Rule\AvailableForTotalAmount; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Exception\CouponExpiredException; +use Thelia\Model\Coupon; + +require_once 'CouponManagerTest.php'; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test CouponFactory Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponFactoryTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * Fake CouponQuery->findByCode +// * +// * @param string $code Coupon code +// * @param string $type Coupon type (object) +// * @param string $title Coupon title +// * @param string $shortDescription Coupon short description +// * @param string $description Coupon description +// * @param float $amount Coupon amount +// * @param bool $isUsed If Coupon has been used yet +// * @param bool $isEnabled If Coupon is enabled +// * @param \DateTime $expirationDate When Coupon expires +// * @param CouponRuleCollection $rules Coupon rules +// * @param bool $isCumulative If Coupon is cumulative +// * @param bool $isRemovingPostage If Coupon is removing postage +// * +// * @return Coupon +// */ +// public function generateCouponModelMock( +// $code = null, +// $type = null, +// $title = null, +// $shortDescription = null, +// $description = null, +// $amount = null, +// $isUsed = null, +// $isEnabled = null, +// $expirationDate = null, +// $rules = null, +// $isCumulative = null, +// $isRemovingPostage = null +// ) { +// $coupon = $this->generateValidCoupon( +// $code, +// $type, +// $title, +// $shortDescription, +// $description, +// $amount, +// $isUsed, +// $isEnabled, +// $expirationDate, +// $rules, +// $isCumulative, +// $isRemovingPostage +// ); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->getMock( +// 'Thelia\Coupon\CouponBaseAdapter', +// array('findOneCouponByCode'), +// array() +// ); +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('findOneCouponByCode') +// ->will($this->returnValue($coupon)); +// +// return $stubCouponBaseAdapter; +// } +// +// +// +// /** +// * Test if an expired Coupon is build or not (superior) +// * +// * @covers Thelia\Coupon\CouponFactory::buildCouponFromCode +// * @expectedException \Thelia\Exception\CouponExpiredException +// */ +// public function testBuildCouponFromCodeExpiredDateBefore() +// { +// $date = new \DateTime(); +// $date->setTimestamp(strtotime("today - 2 months")); +// +// /** @var CouponAdapterInterface $mockAdapter */ +// $mockAdapter = $this->generateCouponModelMock(null, null, null, null, null, null, null, null, $date); +// $couponFactory = new CouponFactory($mockAdapter); +// $coupon = $couponFactory->buildCouponFromCode('XMAS1'); +// } +// +// /** +// * Test if an expired Coupon is build or not (equal) +// * +// * @covers Thelia\Coupon\CouponFactory::buildCouponFromCode +// * @expectedException \Thelia\Exception\CouponExpiredException +// */ +// public function testBuildCouponFromCodeExpiredDateEquals() +// { +// $date = new \DateTime(); +// +// /** @var CouponAdapterInterface $mockAdapter */ +// $mockAdapter = $this->generateCouponModelMock(null, null, null, null, null, null, null, null, $date); +// $couponFactory = new CouponFactory($mockAdapter); +// $coupon = $couponFactory->buildCouponFromCode('XMAS1'); +// } +// +// /** +// * Test if an expired Coupon is build or not (equal) +// * +// * @covers Thelia\Coupon\CouponFactory::buildCouponFromCode +// * @expectedException \Thelia\Exception\InvalidRuleException +// */ +// public function testBuildCouponFromCodeWithoutRule() +// { +// /** @var CouponAdapterInterface $mockAdapter */ +// $mockAdapter = $this->generateCouponModelMock(null, null, null, null, null, null, null, null, null, new CouponRuleCollection(array())); +// $couponFactory = new CouponFactory($mockAdapter); +// $coupon = $couponFactory->buildCouponFromCode('XMAS1'); +// } +// +// /** +// * Test if a CouponInterface can be built from database +// * +// * @covers Thelia\Coupon\CouponFactory::buildCouponFromCode +// */ +// public function testBuildCouponFromCode() +// { +// /** @var CouponAdapterInterface $mockAdapter */ +// $mockAdapter = $this->generateCouponModelMock(); +// $couponFactory = new CouponFactory($mockAdapter); +// /** @var CouponInterface $coupon */ +// $coupon = $couponFactory->buildCouponFromCode('XMAS1'); +// +// $this->assertEquals('XMAS1', $coupon->getCode()); +// $this->assertEquals('Thelia\Coupon\Type\RemoveXAmount', get_class($coupon)); +// $this->assertEquals(CouponManagerTest::VALID_TITLE, $coupon->getTitle()); +// $this->assertEquals(CouponManagerTest::VALID_SHORT_DESCRIPTION, $coupon->getShortDescription()); +// $this->assertEquals(CouponManagerTest::VALID_DESCRIPTION, $coupon->getDescription()); +// $this->assertEquals(10.00, $coupon->getDiscount()); +// $this->assertEquals(1, $coupon->isEnabled()); +// +// $date = new \DateTime(); +// $date->setTimestamp(strtotime("today + 2 months")); +// $this->assertEquals($date, $coupon->getExpirationDate()); +// +// $rules = $this->generateValidRules(); +// $this->assertEquals($rules, $coupon->getRules()); +// +// $this->assertEquals(1, $coupon->isCumulative()); +// $this->assertEquals(0, $coupon->isRemovingPostage()); +// } +// +// /** +// * Generate valid CouponRuleInterfaces +// * +// * @return CouponRuleCollection Set of CouponRuleInterface +// */ +// protected function generateValidRules() +// { +//// $rule1 = new AvailableForTotalAmount( +//// , array( +//// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +//// Operators::SUPERIOR, +//// new PriceParam( +//// , 40.00, 'EUR' +//// ) +//// ) +//// ) +//// ); +//// $rule2 = new AvailableForTotalAmount( +//// , array( +//// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +//// Operators::INFERIOR, +//// new PriceParam( +//// , 400.00, 'EUR' +//// ) +//// ) +//// ) +//// ); +//// $rules = new CouponRuleCollection(array($rule1, $rule2)); +//// +//// return $rules; +// } +// +// /** +// * Generate valid CouponInterface +// * +// * @param string $code Coupon code +// * @param string $type Coupon type (object) +// * @param string $title Coupon title +// * @param string $shortDescription Coupon short description +// * @param string $description Coupon description +// * @param float $amount Coupon amount +// * @param bool $isUsed If Coupon has been used yet +// * @param bool $isEnabled If Coupon is enabled +// * @param \DateTime $expirationDate When Coupon expires +// * @param CouponRuleCollection $rules Coupon rules +// * @param bool $isCumulative If Coupon is cumulative +// * @param bool $isRemovingPostage If Coupon is removing postage +// * +// * @return Coupon +// */ +// public function generateValidCoupon( +// $code = null, +// $type = null, +// $title = null, +// $shortDescription = null, +// $description = null, +// $amount = null, +// $isUsed = null, +// $isEnabled = null, +// $expirationDate = null, +// $rules = null, +// $isCumulative = null, +// $isRemovingPostage = null +// ) { +// $coupon = new Coupon(); +// +// if ($code === null) { +// $code = 'XMAS1'; +// } +// $coupon->setCode($code); +// +// if ($type === null) { +// $type = 'Thelia\Coupon\Type\RemoveXAmount'; +// } +// $coupon->setType($type); +// +// if ($title === null) { +// $title = CouponManagerTest::VALID_TITLE; +// } +// $coupon->setTitle($title); +// +// if ($shortDescription === null) { +// $shortDescription = CouponManagerTest::VALID_SHORT_DESCRIPTION; +// } +// $coupon->setShortDescription($shortDescription); +// +// if ($description === null) { +// $description = CouponManagerTest::VALID_DESCRIPTION; +// } +// $coupon->setDescription($description); +// +// if ($amount === null) { +// $amount = 10.00; +// } +// $coupon->setAmount($amount); +// +// if ($isUsed === null) { +// $isUsed = 1; +// } +// $coupon->setIsUsed($isUsed); +// +// if ($isEnabled === null) { +// $isEnabled = 1; +// } +// $coupon->setIsEnabled($isEnabled); +// +// if ($isCumulative === null) { +// $isCumulative = 1; +// } +// if ($isRemovingPostage === null) { +// $isRemovingPostage = 0; +// } +// +// if ($expirationDate === null) { +// $date = new \DateTime(); +// $coupon->setExpirationDate( +// $date->setTimestamp(strtotime("today + 2 months")) +// ); +// } +// +// if ($rules === null) { +// $rules = $this->generateValidRules(); +// } +// +// $coupon->setSerializedRules(base64_encode(serialize($rules))); +// +// $coupon->setIsCumulative($isCumulative); +// $coupon->setIsRemovingPostage($isRemovingPostage); +// +// return $coupon; +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } +} diff --git a/core/lib/Thelia/Tests/Coupon/CouponManagerTest.php b/core/lib/Thelia/Tests/Coupon/CouponManagerTest.php new file mode 100644 index 000000000..5a3d7881f --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/CouponManagerTest.php @@ -0,0 +1,811 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Coupon\Type\RemoveXAmountManager; +use Thelia\Tools\PhpUnitUtils; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test CouponManager Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponManagerTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// CONST VALID_CODE = 'XMAS'; +// CONST VALID_TITLE = 'XMAS coupon'; +// CONST VALID_SHORT_DESCRIPTION = 'Coupon for Christmas removing 10€ if your total checkout is more than 40€'; +// CONST VALID_DESCRIPTION = '

Lorem ipsum dolor sit amet

Consectetur adipiscing elit. Cras at luctus tellus. Integer turpis mauris, aliquet vitae risus tristique, pellentesque vestibulum urna. Vestibulum sodales laoreet lectus dictum suscipit. Praesent vulputate, sem id varius condimentum, quam magna tempor elit, quis venenatis ligula nulla eget libero. Cras egestas euismod tellus, id pharetra leo suscipit quis. Donec lacinia ac lacus et ultricies. Nunc in porttitor neque. Proin at quam congue, consectetur orci sed, congue nulla. Nulla eleifend nunc ligula, nec pharetra elit tempus quis. Vivamus vel mauris sed est dictum blandit. Maecenas blandit dapibus velit ut sollicitudin. In in euismod mauris, consequat viverra magna. Cras velit velit, sollicitudin commodo tortor gravida, tempus varius nulla. +// +//Donec rhoncus leo mauris, id porttitor ante luctus tempus. +// +//Curabitur quis augue feugiat, ullamcorper mauris ac, interdum mi. Quisque aliquam lorem vitae felis lobortis, id interdum turpis mattis. Vestibulum diam massa, ornare congue blandit quis, facilisis at nisl. In tortor metus, venenatis non arcu nec, sollicitudin ornare nisl. Nunc erat risus, varius nec urna at, iaculis lacinia elit. Aenean ut felis tempus, tincidunt odio non, sagittis nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec vitae hendrerit elit. Nunc sit amet gravida risus, euismod lobortis massa. Nam a erat mauris. Nam a malesuada lorem. Nulla id accumsan dolor, sed rhoncus tellus. Quisque dictum felis sed leo auctor, at volutpat lectus viverra. Morbi rutrum, est ac aliquam imperdiet, nibh sem sagittis justo, ac mattis magna lacus eu nulla. +// +//Duis interdum lectus nulla, nec pellentesque sapien condimentum at. Suspendisse potenti. Sed eu purus tellus. Nunc quis rhoncus metus. Fusce vitae tellus enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam tempor porttitor erat vitae iaculis. Sed est elit, consequat non ornare vitae, vehicula eget lectus. Etiam consequat sapien mauris, eget consectetur magna imperdiet eget. Nunc sollicitudin luctus velit, in commodo nulla adipiscing fermentum. Fusce nisi sapien, posuere vitae metus sit amet, facilisis sollicitudin dui. Fusce ultricies auctor enim sit amet iaculis. Morbi at vestibulum enim, eget adipiscing eros. +// +//Praesent ligula lorem, faucibus ut metus quis, fermentum iaculis erat. Pellentesque elit erat, lacinia sed semper ac, sagittis vel elit. Nam eu convallis est. Curabitur rhoncus odio vitae consectetur pellentesque. Nam vitae arcu nec ante scelerisque dignissim vel nec neque. Suspendisse augue nulla, mollis eget dui et, tempor facilisis erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ac diam ipsum. Donec convallis dui ultricies velit auctor, non lobortis nulla ultrices. Morbi vitae dignissim ante, sit amet lobortis tortor. Nunc dapibus condimentum augue, in molestie neque congue non. +// +//Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.'; +// +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * Test getDiscount() behaviour +// * Entering : 1 valid Coupon (If 40 < total amount 400) - 10euros +// * +// * @covers Thelia\Coupon\CouponManager::getDiscount +// */ +// public function testGetDiscountOneCoupon() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// /** @var CouponInterface $coupon */ +// $coupon = self::generateValidCoupon(); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter(array($coupon), $cartTotalPrice, $checkoutTotalPrice); +// +// $couponManager = new CouponManager($stubCouponBaseAdapter); +// $discount = $couponManager->getDiscount(); +// +// $expected = 10.00; +// $actual = $discount; +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test getDiscount() behaviour +// * Entering : 1 valid Coupon (If 40 < total amount 400) - 10euros +// * 1 valid Coupon (If total amount > 20) - 15euros +// * +// * @covers Thelia\Coupon\CouponManager::getDiscount +// */ +// public function testGetDiscountTwoCoupon() +// { +// $adapter = new CouponBaseAdapter(); +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// /** @var CouponInterface $coupon1 */ +// $coupon1 = self::generateValidCoupon(); +// $rule1 = new AvailableForTotalAmount( +// $adapter, array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// new PriceParam( +// $adapter, 40.00, 'EUR' +// ) +// ) +// ) +// ); +// $rules = new CouponRuleCollection(array($rule1)); +// /** @var CouponInterface $coupon2 */ +// $coupon2 = $this->generateValidCoupon('XMAS2', null, null, null, 15.00, null, null, $rules); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter(array($coupon1, $coupon2), $cartTotalPrice, $checkoutTotalPrice); +// +// $couponManager = new CouponManager($stubCouponBaseAdapter); +// $discount = $couponManager->getDiscount(); +// +// $expected = 25.00; +// $actual = $discount; +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test getDiscount() behaviour +// * For a Cart of 21euros +// * Entering : 1 valid Coupon (If total amount > 20) - 30euros +// * +// * @covers Thelia\Coupon\CouponManager::getDiscount +// */ +// public function testGetDiscountAlwaysInferiorToPrice() +// { +// $adapter = new CouponBaseAdapter(); +// $cartTotalPrice = 21.00; +// $checkoutTotalPrice = 26.00; +// +// $rule1 = new AvailableForTotalAmount( +// $adapter, array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// new PriceParam( +// $adapter, 20.00, 'EUR' +// ) +// ) +// ) +// ); +// $rules = new CouponRuleCollection(array($rule1)); +// /** @var CouponInterface $coupon */ +// $coupon = $this->generateValidCoupon('XMAS2', null, null, null, 30.00, null, null, $rules); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter(array($coupon), $cartTotalPrice, $checkoutTotalPrice); +// +// $couponManager = new CouponManager($stubCouponBaseAdapter); +// $discount = $couponManager->getDiscount(); +// +// $expected = 21.00; +// $actual = $discount; +// $this->assertEquals($expected, $actual); +// } +// +// +// /** +// * Check if removing postage on discout is working +// * @covers Thelia\Coupon\CouponManager::isCouponRemovingPostage +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testIsCouponRemovingPostage() +// { +// $adapter = new CouponBaseAdapter(); +// $cartTotalPrice = 21.00; +// $checkoutTotalPrice = 27.00; +// +// $rule1 = new AvailableForTotalAmount( +// $adapter, array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// new PriceParam( +// $adapter, 20.00, 'EUR' +// ) +// ) +// ) +// ); +// $rules = new CouponRuleCollection(array($rule1)); +// /** @var CouponInterface $coupon */ +// $coupon = $this->generateValidCoupon('XMAS2', null, null, null, 30.00, null, null, $rules, null, true); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter(array($coupon), $cartTotalPrice, $checkoutTotalPrice); +// +// $couponManager = new CouponManager($stubCouponBaseAdapter); +// $discount = $couponManager->getDiscount(); +// +// $expected = 21.00; +// $actual = $discount; +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon not cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponNotCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false); +// +// $coupons = array($couponCumulative1); +// +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = $coupons; +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite there is only once'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon(null, null, null, null, null, null, null, null, true); +// +// $coupons = array($couponCumulative1); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = $coupons; +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite there is only once'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative +// * 1 Coupon cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationTwoCouponCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = $coupons; +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite both Coupon can be accumulated'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative +// * 1 Coupon non cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponCumulativeOneNonCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, false); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative2); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite both Coupon can be accumulated'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon non cumulative +// * 1 Coupon cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponNonCumulativeOneCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, false); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative2); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite both Coupon can be accumulated'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon non cumulative +// * 1 Coupon non cumulative +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationTwoCouponNonCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, false); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, false); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative2); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Array Sorted despite both Coupon can be accumulated'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative expired +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponCumulativeExpired() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, new \DateTime(), null, true); +// +// $coupons = array($couponCumulative1); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array(); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon expired ignored'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative expired +// * 1 Coupon cumulative expired +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationTwoCouponCumulativeExpired() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, new \DateTime(), null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, new \DateTime(), null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array(); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon expired ignored'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative expired +// * 1 Coupon cumulative valid +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponCumulativeExpiredOneNonExpired() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, new \DateTime(), null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative2); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon expired ignored'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative valid +// * 1 Coupon cumulative expired +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationOneCouponCumulativeNonExpiredOneExpired() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, new \DateTime(), null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative1); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon expired ignored'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative valid +// * 1 Coupon cumulative valid +// * 1 Coupon cumulative valid +// * 1 Coupon cumulative valid +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationFourCouponCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, true); +// $couponCumulative3 = $this->generateValidCoupon('XMAS3', null, null, null, null, null, null, null, true); +// $couponCumulative4 = $this->generateValidCoupon('XMAS4', null, null, null, null, null, null, null, true); +// +// $coupons = array($couponCumulative1, $couponCumulative2, $couponCumulative3, $couponCumulative4); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = $coupons; +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon cumulative ignored'); +// } +// +// /** +// * Testing how multiple Coupon behaviour +// * Entering 1 Coupon cumulative valid +// * 1 Coupon cumulative valid +// * 1 Coupon cumulative valid +// * 1 Coupon non cumulative valid +// * +// * @covers Thelia\Coupon\CouponManager::sortCoupons +// */ +// public function testCouponCumulationThreeCouponCumulativeOneNonCumulative() +// { +// $cartTotalPrice = 100.00; +// $checkoutTotalPrice = 120.00; +// +// // Given +// /** @var CouponInterface $coupon */ +// $couponCumulative1 = $this->generateValidCoupon('XMAS1', null, null, null, null, null, null, null, true); +// $couponCumulative2 = $this->generateValidCoupon('XMAS2', null, null, null, null, null, null, null, true); +// $couponCumulative3 = $this->generateValidCoupon('XMAS3', null, null, null, null, null, null, null, true); +// $couponCumulative4 = $this->generateValidCoupon('XMAS4', null, null, null, null, null, null, null, false); +// +// $coupons = array($couponCumulative1, $couponCumulative2, $couponCumulative3, $couponCumulative4); +// /** @var CouponAdapterInterface $stubCouponBaseAdapter */ +// $stubCouponBaseAdapter = $this->generateFakeAdapter($coupons, $cartTotalPrice, $checkoutTotalPrice); +// +// // When +// $sortedCoupons = PhpUnitUtils::callMethod( +// new CouponManager($stubCouponBaseAdapter), +// 'sortCoupons', +// array($coupons) +// ); +// +// // Then +// $expected = array($couponCumulative4); +// $actual = $sortedCoupons; +// +// $this->assertSame($expected, $actual, 'Coupon cumulative ignored'); +// } +// +// +// /** +// * Generate valid CouponRuleInterfaces +// * +// * @return array Array of CouponRuleInterface +// */ +// public static function generateValidRules() +// { +// $adapter = new CouponBaseAdapter(); +// $rule1 = new AvailableForTotalAmount( +// $adapter, array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::SUPERIOR, +// new PriceParam( +// $adapter, 40.00, 'EUR' +// ) +// ) +// ) +// ); +// $rule2 = new AvailableForTotalAmount( +// $adapter, array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// Operators::INFERIOR, +// new PriceParam( +// $adapter, 400.00, 'EUR' +// ) +// ) +// ) +// ); +// $rules = new CouponRuleCollection(array($rule1, $rule2)); +// +// return $rules; +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } +// +// /** +// * Generate a fake Adapter +// * +// * @param array $coupons Coupons +// * @param float $cartTotalPrice Cart total price +// * @param float $checkoutTotalPrice Checkout total price +// * @param float $postagePrice Checkout postage price +// * +// * @return \PHPUnit_Framework_MockObject_MockObject +// */ +// public function generateFakeAdapter(array $coupons, $cartTotalPrice, $checkoutTotalPrice, $postagePrice = 6.00) +// { +// $stubCouponBaseAdapter = $this->getMock( +// 'Thelia\Coupon\CouponBaseAdapter', +// array( +// 'getCurrentCoupons', +// 'getCartTotalPrice', +// 'getCheckoutTotalPrice', +// 'getCheckoutPostagePrice' +// ), +// array() +// ); +// +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('getCurrentCoupons') +// ->will($this->returnValue(($coupons))); +// +// // Return Cart product amount = $cartTotalPrice euros +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('getCartTotalPrice') +// ->will($this->returnValue($cartTotalPrice)); +// +// // Return Checkout amount = $checkoutTotalPrice euros +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('getCheckoutTotalPrice') +// ->will($this->returnValue($checkoutTotalPrice)); +// +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('getCheckoutPostagePrice') +// ->will($this->returnValue($postagePrice)); +// +// return $stubCouponBaseAdapter; +// } +// +// /** +// * Generate valid CouponInterface +// * +// * @param string $code Coupon Code +// * @param string $title Coupon Title +// * @param string $shortDescription Coupon short +// * description +// * @param string $description Coupon description +// * @param float $amount Coupon discount +// * @param bool $isEnabled Is Coupon enabled +// * @param \DateTime $expirationDate Coupon expiration date +// * @param CouponRuleCollection $rules Coupon rules +// * @param bool $isCumulative If is cumulative +// * @param bool $isRemovingPostage If is removing postage +// * @param bool $isAvailableOnSpecialOffers If is available on +// * special offers or not +// * @param int $maxUsage How many time a Coupon +// * can be used +// * +// * @return CouponInterface +// */ +// public static function generateValidCoupon( +// $code = null, +// $title = null, +// $shortDescription = null, +// $description = null, +// $amount = null, +// $isEnabled = null, +// $expirationDate = null, +// $rules = null, +// $isCumulative = null, +// $isRemovingPostage = null, +// $isAvailableOnSpecialOffers = null, +// $maxUsage = null +// ) { +// $adapter = new CouponBaseAdapter(); +// if ($code === null) { +// $code = self::VALID_CODE; +// } +// if ($title === null) { +// $title = self::VALID_TITLE; +// } +// if ($shortDescription === null) { +// $shortDescription = self::VALID_SHORT_DESCRIPTION; +// } +// if ($description === null) { +// $description = self::VALID_DESCRIPTION; +// } +// if ($amount === null) { +// $amount = 10.00; +// } +// if ($isEnabled === null) { +// $isEnabled = true; +// } +// if ($isCumulative === null) { +// $isCumulative = true; +// } +// if ($isRemovingPostage === null) { +// $isRemovingPostage = false; +// } +// if ($isAvailableOnSpecialOffers === null) { +// $isAvailableOnSpecialOffers = true; +// } +// if ($maxUsage === null) { +// $maxUsage = 40; +// } +// +// if ($expirationDate === null) { +// $expirationDate = new \DateTime(); +// $expirationDate->setTimestamp(strtotime("today + 2 months")); +// } +// +// $coupon = new RemoveXAmount($adapter, $code, $title, $shortDescription, $description, $amount, $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate); +// +// if ($rules === null) { +// $rules = self::generateValidRules(); +// } +// +// $coupon->setRules($rules); +// +// return $coupon; +// } + +} diff --git a/core/lib/Thelia/Tests/Coupon/CouponRuleCollectionTest.php b/core/lib/Thelia/Tests/Coupon/CouponRuleCollectionTest.php new file mode 100644 index 000000000..803000779 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/CouponRuleCollectionTest.php @@ -0,0 +1,86 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Constraint\Rule\AvailableForTotalAmount; +use Thelia\Constraint\Rule\Operators; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test CouponRuleCollection Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class CouponRuleCollectionTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * +// */ +// public function testRuleSerialisation() +// { +//// $rule1 = new AvailableForTotalAmount( +//// , array( +//// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +//// Operators::SUPERIOR, +//// new PriceParam( +//// , 40.00, 'EUR' +//// ) +//// ) +//// ) +//// ); +//// $rule2 = new AvailableForTotalAmount( +//// , array( +//// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +//// Operators::INFERIOR, +//// new PriceParam( +//// , 400.00, 'EUR' +//// ) +//// ) +//// ) +//// ); +//// $rules = new CouponRuleCollection(array($rule1, $rule2)); +//// +//// $serializedRules = base64_encode(serialize($rules)); +//// $unserializedRules = unserialize(base64_decode($serializedRules)); +//// +//// $expected = $rules; +//// $actual = $unserializedRules; +//// +//// $this->assertEquals($expected, $actual); +// } +} diff --git a/core/lib/Thelia/Tests/Coupon/RuleOrganizerTest.php b/core/lib/Thelia/Tests/Coupon/RuleOrganizerTest.php new file mode 100644 index 000000000..3300cb19b --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/RuleOrganizerTest.php @@ -0,0 +1,72 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RuleOrganizer Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RuleOrganizerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var RuleOrganizer + */ + protected $object; + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() + { + $this->object = new RuleOrganizer; + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown() + { + } + + /** + * @covers Thelia\Coupon\RuleOrganizer::organize + * @todo Implement testOrganize(). + */ + public function testOrganize() + { + // Remove the following lines when you implement this test. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php new file mode 100644 index 000000000..8467852ac --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveXAmountTest.php @@ -0,0 +1,384 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Coupon\Type\RemoveXAmountManager; + +//require_once '../CouponManagerTest.php'; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RemoveXAmount Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXAmountTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// +// } +// +// /** +// * Test if a Coupon is well displayed +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getCode +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getTitle +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getShortDescription +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getDescription +// * +// */ +// public function testDisplay() +// { +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, true, true); +// +// $expected = CouponManagerTest::VALID_CODE; +// $actual = $coupon->getCode(); +// $this->assertEquals($expected, $actual); +// +// $expected = CouponManagerTest::VALID_TITLE; +// $actual = $coupon->getTitle(); +// $this->assertEquals($expected, $actual); +// +// $expected = CouponManagerTest::VALID_SHORT_DESCRIPTION; +// $actual = $coupon->getShortDescription(); +// $this->assertEquals($expected, $actual); +// +// $expected = CouponManagerTest::VALID_DESCRIPTION; +// $actual = $coupon->getDescription(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test if a Coupon can be Cumulative +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::isCumulative +// * +// */ +// public function testIsCumulative() +// { +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, true, true); +// +// $actual = $coupon->isCumulative(); +// $this->assertTrue($actual); +// } +// +// /** +// * Test if a Coupon can be non cumulative +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::isCumulative +// * +// */ +// public function testIsNotCumulative() +// { +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $actual = $coupon->isCumulative(); +// $this->assertFalse($actual); +// } +// +// +// /** +// * Test if a Coupon can remove postage +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::isRemovingPostage +// * +// */ +// public function testIsRemovingPostage() +// { +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, true, true); +// +// $actual = $coupon->isRemovingPostage(); +// $this->assertTrue($actual); +// } +// +// /** +// * Test if a Coupon won't remove postage if not set to +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::isRemovingPostage +// */ +// public function testIsNotRemovingPostage() +// { +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $actual = $coupon->isRemovingPostage(); +// $this->assertFalse($actual); +// } +// +// +// /** +// * Test if a Coupon has the effect expected (discount 10euros) +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// */ +// public function testGetEffect() +// { +// $adapter = new CouponBaseAdapter(); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $expected = 10; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon rule setter +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::setRules +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getRules +// */ +// public function testSetRulesValid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 20.00 +// ); +// $rule1 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 100.23 +// ); +// $rule2 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR, +// 421.23 +// ); +// +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0, $rule1, $rule2))); +// +// // Then +// $expected = 3; +// $this->assertCount($expected, $coupon->getRules()->getRules()); +// } +// +// /** +// * Test Coupon rule setter +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::setRules +// * @expectedException \Thelia\Exception\InvalidRuleException +// * +// */ +// public function testSetRulesInvalid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 20.00 +// ); +// $rule1 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 100.23 +// ); +// $rule2 = $this; +// +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0, $rule1, $rule2))); +// } +// +// /** +// * Test Coupon effect for rule Total Amount < 400 +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountInferiorTo400Valid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 400.00 +// ); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 10.00; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount <= 400 +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountInferiorOrEqualTo400Valid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR_OR_EQUAL, +// 400.00 +// ); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 10.00; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount == 400 +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountEqualTo400Valid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 400.00 +// ); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 10.00; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount >= 400 +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountSuperiorOrEqualTo400Valid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR_OR_EQUAL, +// 400.00 +// ); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 10.00; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount > 400 +// * +// * @covers Thelia\Coupon\type\RemoveXAmountManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountSuperiorTo400Valid() +// { +// // Given +// $adapter = new CouponBaseAdapter(); +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR, +// 400.00 +// ); +// $coupon = CouponManagerTest::generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 10.00; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } +// +// /** +// * Generate valid rule AvailableForTotalAmount +// * according to given operator and amount +// * +// * @param string $operator Operators::CONST +// * @param float $amount Amount with 2 decimals +// * +// * @return AvailableForTotalAmount +// */ +// protected function generateValidRuleAvailableForTotalAmountOperatorTo($operator, $amount) +// { +// $adapter = new CouponBaseAdapter(); +// $validators = array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// $operator, +// new PriceParam( +// $adapter, +// $amount, +// 'EUR' +// ) +// ) +// ); +// +// return new AvailableForTotalAmount($adapter, $validators); +// } + +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentForCategoryYTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentForCategoryYTest.php new file mode 100644 index 000000000..ac13d4ea0 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentForCategoryYTest.php @@ -0,0 +1,70 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RemoveXPercentForCategoryY Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentForCategoryYTest extends \PHPUnit_Framework_TestCase +{ + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } + +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// public function incompleteTest() +// { +// $this->markTestIncomplete( +// 'This test has not been implemented yet.' +// ); +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php new file mode 100644 index 000000000..7fc327df6 --- /dev/null +++ b/core/lib/Thelia/Tests/Coupon/Type/RemoveXPercentTest.php @@ -0,0 +1,458 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Coupon; + +use PHPUnit_Framework_TestCase; +use Thelia\Constraint\Rule\AvailableForTotalAmountManager; +use Thelia\Constraint\Rule\Operators; +use Thelia\Constraint\Validator\PriceParam; +use Thelia\Constraint\Validator\RuleValidator; +use Thelia\Coupon\Type\CouponInterface; +use Thelia\Coupon\Type\RemoveXPercentManager; + +//require_once '../CouponManagerTest.php'; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Unit Test RemoveXPercent Class + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class RemoveXPercentTest extends \PHPUnit_Framework_TestCase +{ + + public function testSomething() + { + // Stop here and mark this test as incomplete. + $this->markTestIncomplete( + 'This test has not been implemented yet.' + ); + } +// /** +// * Sets up the fixture, for example, opens a network connection. +// * This method is called before a test is executed. +// */ +// protected function setUp() +// { +// } +// +// /** +// * Test if a Coupon can be Cumulative +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::isCumulative +// * +// */ +// public function testIsCumulative() +// { +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, true, true); +// +// $actual = $coupon->isCumulative(); +// $this->assertTrue($actual); +// } +// +// /** +// * Test if a Coupon can be non cumulative +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::isCumulative +// * +// */ +// public function testIsNotCumulative() +// { +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $actual = $coupon->isCumulative(); +// $this->assertFalse($actual); +// } +// +// +// /** +// * Test if a Coupon can remove postage +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::isRemovingPostage +// * +// */ +// public function testIsRemovingPostage() +// { +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, true, true); +// +// $actual = $coupon->isRemovingPostage(); +// $this->assertTrue($actual); +// } +// +// /** +// * Test if a Coupon won't remove postage if not set to +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::isRemovingPostage +// */ +// public function testIsNotRemovingPostage() +// { +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $actual = $coupon->isRemovingPostage(); +// $this->assertFalse($actual); +// } +// +// +// /** +// * Test if a Coupon has the effect expected (discount 10euros) +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// */ +// public function testGetEffect() +// { +// $adapter = $this->generateFakeAdapter(245); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// $expected = 24.50; +// $actual = $coupon->getDiscount($adapter); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon rule setter +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::setRules +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getRules +// */ +// public function testSetRulesValid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 20.00 +// ); +// $rule1 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 100.23 +// ); +// $rule2 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR, +// 421.23 +// ); +// +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0, $rule1, $rule2))); +// +// // Then +// $expected = 3; +// $this->assertCount($expected, $coupon->getRules()->getRules()); +// } +// +// /** +// * Test Coupon rule setter +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::setRules +// * @expectedException \Thelia\Exception\InvalidRuleException +// * +// */ +// public function testSetRulesInvalid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 20.00 +// ); +// $rule1 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 100.23 +// ); +// $rule2 = $this; +// +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0, $rule1, $rule2))); +// } +// +// /** +// * Test Coupon effect for rule Total Amount < 400 +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountInferiorTo400Valid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR, +// 400.00 +// ); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 24.50; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount <= 400 +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountInferiorOrEqualTo400Valid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::INFERIOR_OR_EQUAL, +// 400.00 +// ); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 24.50; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount == 400 +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountEqualTo400Valid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::EQUAL, +// 400.00 +// ); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 24.50; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount >= 400 +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountSuperiorOrEqualTo400Valid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR_OR_EQUAL, +// 400.00 +// ); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 24.50; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Test Coupon effect for rule Total Amount > 400 +// * +// * @covers Thelia\Coupon\type\RemoveXPercentManager::getEffect +// * +// */ +// public function testGetEffectIfTotalAmountSuperiorTo400Valid() +// { +// // Given +// $rule0 = $this->generateValidRuleAvailableForTotalAmountOperatorTo( +// Operators::SUPERIOR, +// 400.00 +// ); +// $coupon = $this->generateValidCoupon(null, null, null, null, null, null, null, null, false, false); +// +// // When +// $coupon->setRules(new CouponRuleCollection(array($rule0))); +// +// // Then +// $expected = 24.50; +// $actual = $coupon->getDiscount(); +// $this->assertEquals($expected, $actual); +// } +// +// /** +// * Generate valid CouponInterface +// * +// * @param string $code Coupon Code +// * @param string $title Coupon Title +// * @param string $shortDescription Coupon short +// * description +// * @param string $description Coupon description +// * @param float $amount Coupon discount +// * @param bool $isEnabled Is Coupon enabled +// * @param \DateTime $expirationDate Coupon expiration date +// * @param CouponRuleCollection $rules Coupon rules +// * @param bool $isCumulative If is cumulative +// * @param bool $isRemovingPostage If is removing postage +// * @param bool $isAvailableOnSpecialOffers If is available on +// * special offers or not +// * @param int $maxUsage How many time a Coupon +// * can be used +// * +// * @return CouponInterface +// */ +// public function generateValidCoupon( +// $code = null, +// $title = null, +// $shortDescription = null, +// $description = null, +// $percent = null, +// $isEnabled = null, +// $expirationDate = null, +// $rules = null, +// $isCumulative = null, +// $isRemovingPostage = null, +// $isAvailableOnSpecialOffers = null, +// $maxUsage = null +// ) { +// $adapter = $this->generateFakeAdapter(245); +// +// if ($code === null) { +// $code = CouponManagerTest::VALID_CODE; +// } +// if ($title === null) { +// $title = CouponManagerTest::VALID_TITLE; +// } +// if ($shortDescription === null) { +// $shortDescription = CouponManagerTest::VALID_SHORT_DESCRIPTION; +// } +// if ($description === null) { +// $description = CouponManagerTest::VALID_DESCRIPTION; +// } +// if ($percent === null) { +// $percent = 10.00; +// } +// if ($isEnabled === null) { +// $isEnabled = true; +// } +// if ($isCumulative === null) { +// $isCumulative = true; +// } +// if ($isRemovingPostage === null) { +// $isRemovingPostage = false; +// } +// if ($isAvailableOnSpecialOffers === null) { +// $isAvailableOnSpecialOffers = true; +// } +// if ($maxUsage === null) { +// $maxUsage = 40; +// } +// +// if ($expirationDate === null) { +// $expirationDate = new \DateTime(); +// $expirationDate->setTimestamp(strtotime("today + 2 months")); +// } +// +// $coupon = new RemoveXPercent($adapter, $code, $title, $shortDescription, $description, $percent, $isCumulative, $isRemovingPostage, $isAvailableOnSpecialOffers, $isEnabled, $maxUsage, $expirationDate); +// +// if ($rules === null) { +// $rules = CouponManagerTest::generateValidRules(); +// } +// +// $coupon->setRules($rules); +// +// return $coupon; +// } +// +// +// /** +// * Generate valid rule AvailableForTotalAmount +// * according to given operator and amount +// * +// * @param string $operator Operators::CONST +// * @param float $amount Amount with 2 decimals +// * +// * @return AvailableForTotalAmount +// */ +// protected function generateValidRuleAvailableForTotalAmountOperatorTo($operator, $amount) +// { +// $adapter = new CouponBaseAdapter(); +// $validators = array( +// AvailableForTotalAmount::PARAM1_PRICE => new RuleValidator( +// $operator, +// new PriceParam( +// $adapter, +// $amount, +// 'EUR' +// ) +// ) +// ); +// +// return new AvailableForTotalAmount($adapter, $validators); +// } +// +// /** +// * Generate a fake Adapter +// * +// * @param float $cartTotalPrice Cart total price +// * +// * @return \PHPUnit_Framework_MockObject_MockObject +// */ +// public function generateFakeAdapter($cartTotalPrice) +// { +// $stubCouponBaseAdapter = $this->getMock( +// 'Thelia\Coupon\CouponBaseAdapter', +// array( +// 'getCartTotalPrice' +// ), +// array() +// ); +// +// $stubCouponBaseAdapter->expects($this->any()) +// ->method('getCartTotalPrice') +// ->will($this->returnValue(($cartTotalPrice))); +// +// return $stubCouponBaseAdapter; +// } +// +// /** +// * Tears down the fixture, for example, closes a network connection. +// * This method is called after a test is executed. +// */ +// protected function tearDown() +// { +// } + +} diff --git a/core/lib/Thelia/Tests/Rewriting/RewritingResolverTest.php b/core/lib/Thelia/Tests/Rewriting/RewritingResolverTest.php index a3ec561d2..6cd4bdf42 100755 --- a/core/lib/Thelia/Tests/Rewriting/RewritingResolverTest.php +++ b/core/lib/Thelia/Tests/Rewriting/RewritingResolverTest.php @@ -61,7 +61,7 @@ class RewritingResolverTest extends \PHPUnit_Framework_TestCase $resolver = new RewritingResolver(); $method = $this->getMethod('getOtherParameters'); - $actual = $method->invoke($resolver); + $method->invoke($resolver); } public function testGetOtherParameters() diff --git a/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php b/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php new file mode 100755 index 000000000..fac6ca643 --- /dev/null +++ b/core/lib/Thelia/Tests/TaxEngine/CalculatorTest.php @@ -0,0 +1,169 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\TaxEngine; + +use Propel\Runtime\Collection\ObjectCollection; +use Thelia\Model\Country; +use Thelia\Model\CountryQuery; +use Thelia\Model\Product; +use Thelia\Model\ProductQuery; +use Thelia\Model\Tax; +use Thelia\TaxEngine\Calculator; + +/** + * + * @author Etienne Roudeix + * + */ +class CalculatorTest extends \PHPUnit_Framework_TestCase +{ + protected function getMethod($name) + { + $class = new \ReflectionClass('\Thelia\TaxEngine\Calculator'); + $method = $class->getMethod($name); + $method->setAccessible(true); + + return $method; + } + + protected function getProperty($name) + { + $class = new \ReflectionClass('\Thelia\TaxEngine\Calculator'); + $property = $class->getProperty($name); + $property->setAccessible(true); + + return $property; + } + + /** + * @expectedException \Thelia\Exception\TaxEngineException + * @expectedExceptionCode 501 + */ + public function testLoadEmptyProductException() + { + $calculator = new Calculator(); + $calculator->load(new Product(), CountryQuery::create()->findOne()); + } + + /** + * @expectedException \Thelia\Exception\TaxEngineException + * @expectedExceptionCode 502 + */ + public function testLoadEmptyCountryException() + { + $calculator = new Calculator(); + $calculator->load(ProductQuery::create()->findOne(), new Country()); + } + + public function testLoad() + { + $productQuery = ProductQuery::create()->findOneById(1); + $countryQuery = CountryQuery::create()->findOneById(64); + + $calculator = new Calculator(); + + $taxRuleQuery = $this->getMock('\Thelia\Model\TaxRuleQuery', array('getTaxCalculatorGroupedCollection')); + $taxRuleQuery->expects($this->once()) + ->method('getTaxCalculatorGroupedCollection') + ->with($productQuery, $countryQuery) + ->will($this->returnValue('foo')); + + $rewritingUrlQuery = $this->getProperty('taxRuleQuery'); + $rewritingUrlQuery->setValue($calculator, $taxRuleQuery); + + $calculator->load($productQuery, $countryQuery); + + $this->assertEquals( + $productQuery, + $this->getProperty('product')->getValue($calculator) + ); + $this->assertEquals( + $countryQuery, + $this->getProperty('country')->getValue($calculator) + ); + $this->assertEquals( + 'foo', + $this->getProperty('taxRulesGroupedCollection')->getValue($calculator) + ); + } + + /** + * @expectedException \Thelia\Exception\TaxEngineException + * @expectedExceptionCode 503 + */ + public function testGetTaxAmountBadTaxRulesCollection() + { + $calculator = new Calculator(); + $calculator->getTaxAmount(500); + } + + /** + * @expectedException \Thelia\Exception\TaxEngineException + * @expectedExceptionCode 601 + */ + public function testGetTaxAmountBadAmount() + { + $taxRulesGroupedCollection = new ObjectCollection(); + + $calculator = new Calculator(); + + $rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); + $rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); + + $calculator->getTaxAmount('foo'); + } + + public function testGetTaxAmountAndGetTaxedPrice() + { + $taxRulesGroupedCollection = new ObjectCollection(); + $taxRulesGroupedCollection->setModel('\Thelia\Model\Tax'); + + $tax = new Tax(); + $tax->setVirtualColumn('taxRateSum', 10); + + $taxRulesGroupedCollection->append($tax); + + $tax = new Tax(); + $tax->setVirtualColumn('taxRateSum', 8); + + $taxRulesGroupedCollection->append($tax); + + $calculator = new Calculator(); + + $rewritingUrlQuery = $this->getProperty('taxRulesGroupedCollection'); + $rewritingUrlQuery->setValue($calculator, $taxRulesGroupedCollection); + + $taxAmount = $calculator->getTaxAmount(500); + $taxedPrice = $calculator->getTaxedPrice(500); + + /* + * expect : + * tax 1 = 500*0.10 = 50 // amout with tax 1 : 550 + * tax 2 = 550*0.08 = 44 // amout with tax 2 : 594 + * total tax amount = 94 + */ + $this->assertEquals(94, $taxAmount); + $this->assertEquals(594, $taxedPrice); + } +} diff --git a/core/lib/Thelia/Tools/I18n.php b/core/lib/Thelia/Tools/I18n.php new file mode 100644 index 000000000..4467bebcd --- /dev/null +++ b/core/lib/Thelia/Tools/I18n.php @@ -0,0 +1,57 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Tools; + +use Thelia\Model\Lang; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Helper for translations + * + * @package I18n + * @author Guillaume MOREL + * + */ +class I18n +{ + /** + * Create a \DateTime from a date picker form input + * The date format is the same as the one from the current User Session + * Ex : $lang = $session->getLang() + * + * @param Lang $lang Object containing date format + * @param string $date String to convert + * + * @return \DateTime + */ + public function getDateTimeFromForm(Lang $lang, $date) + { + $currentDateFormat = $lang->getDateFormat(); + + return \DateTime::createFromFormat($currentDateFormat, $date); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tools/PhpUnitUtils.php b/core/lib/Thelia/Tools/PhpUnitUtils.php new file mode 100644 index 000000000..89bd3b148 --- /dev/null +++ b/core/lib/Thelia/Tools/PhpUnitUtils.php @@ -0,0 +1,55 @@ +. */ +/* */ +/**********************************************************************************/ + +namespace Thelia\Tools; + +/** + * Created by JetBrains PhpStorm. + * Date: 8/19/13 + * Time: 3:24 PM + * + * Helper for Unit Testing + * + * @package Coupon + * @author Guillaume MOREL + * + */ +class PhpUnitUtils +{ + /** + * Allow to call a protected methods + * + * @param Object $obj Class name + namespace + * @param string $name Method name + * @param array $args Method arguments + * + * @return mixed protected method result + */ + public static function callMethod($obj, $name, array $args) + { + $class = new \ReflectionClass(get_class($obj)); + $method = $class->getMethod($name); + $method->setAccessible(true); + return $method->invokeArgs($obj, $args); + } +} \ No newline at end of file diff --git a/core/lib/Thelia/Tools/Rest/ResponseRest.php b/core/lib/Thelia/Tools/Rest/ResponseRest.php new file mode 100644 index 000000000..8618d460f --- /dev/null +++ b/core/lib/Thelia/Tools/Rest/ResponseRest.php @@ -0,0 +1,83 @@ +format = $format; + $serializer = $this->getSerializer(); + + if (isset($data)) { + $this->setContent($serializer->serialize($data, $this->format)); + } + + $this->headers->set('Content-Type', 'application/' . $this->format); + } + + /** + * Set Content to be serialized in the response, array or object + * + * @param array $data array or object to be serialized + * + * @return $this + */ + public function setRestContent($data) + { + $serializer = $this->getSerializer(); + + if (isset($data)) { + $this->setContent($serializer->serialize($data, $this->format)); + } + + return $this; + } + + /** + * Get Serializer + * + * @return Serializer + */ + protected function getSerializer() + { + $encoders = array(new XmlEncoder(), new JsonEncoder()); + $normalizers = array(new GetSetMethodNormalizer()); + + return new Serializer($normalizers, $encoders); + } + +} diff --git a/core/lib/Thelia/Tools/URL.php b/core/lib/Thelia/Tools/URL.php index 161175bbf..ffb81992d 100755 --- a/core/lib/Thelia/Tools/URL.php +++ b/core/lib/Thelia/Tools/URL.php @@ -121,6 +121,11 @@ class URL $base_url = $this->getBaseUrl(); + // TODO fix this ugly patch + if(strpos($path, "index_dev.php")) { + $path = str_replace('index_dev.php', '', $path); + } + // If only a path is requested, be sure to remove the script name (index.php or index_dev.php), if any. if ($path_only == self::PATH_TO_FILE) { // As the base_url always ends with '/', if we don't find / at the end, we have a script. @@ -189,6 +194,14 @@ class URL { if(ConfigQuery::isRewritingEnable()) { $this->retriever->loadViewUrl($view, $viewLocale, $viewId); + } else { + $allParametersWithoutView = array(); + $allParametersWithoutView['locale'] = $viewLocale; + if(null !== $viewId) { + $allParametersWithoutView[$view . '_id'] = $viewId; + } + $this->retriever->rewrittenUrl = null; + $this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView); } return $this->retriever; @@ -220,6 +233,14 @@ class URL } $this->retriever->loadSpecificUrl($view, $viewLocale, $viewId, $allOtherParameters); + } else { + $allParametersWithoutView = $viewOtherParameters; + $allParametersWithoutView['locale'] = $viewLocale; + if(null !== $viewId) { + $allParametersWithoutView[$view . '_id'] = $viewId; + } + $this->retriever->rewrittenUrl = null; + $this->retriever->url = URL::getInstance()->viewUrl($view, $allParametersWithoutView); } return $this->retriever; diff --git a/install/faker.php b/install/faker.php index f1e7691d7..5bb21d4fa 100755 --- a/install/faker.php +++ b/install/faker.php @@ -1,4 +1,11 @@ boot(); $faker = Faker\Factory::create(); -$con = \Propel\Runtime\Propel::getConnection(Thelia\Model\Map\ProductTableMap::DATABASE_NAME); +$con = \Propel\Runtime\Propel::getConnection( + Thelia\Model\Map\ProductTableMap::DATABASE_NAME +); $con->beginTransaction(); $currency = \Thelia\Model\CurrencyQuery::create()->filterByCode('EUR')->findOne(); @@ -358,6 +368,8 @@ try { } } + generateCouponFixtures($thelia); + $con->commit(); } catch (Exception $e) { echo "error : ".$e->getMessage()."\n"; @@ -371,6 +383,7 @@ function createProduct($faker, $category, $position, &$productIdList) $product->addCategory($category); $product->setVisible(rand(1, 10)>7 ? 0 : 1); $product->setPosition($position); + $product->setTaxRuleId(1); setI18n($faker, $product); $product->save(); @@ -398,7 +411,7 @@ function createCategory($faker, $parent, $position, &$categoryIdList, $contentId //add random associated content $alreadyPicked = array(); - for($i=1; $isetDescription($locale . ' : ' . $description); } } +/** + * Generate Coupon fixtures + */ +function generateCouponFixtures($thelia) +{ + $container = $thelia->getContainer(); + $adapter = $container->get('thelia.adapter'); + // Coupons + $coupon1 = new Thelia\Model\Coupon(); + $coupon1->setCode('XMAS'); + $coupon1->setType('thelia.coupon.type.remove_x_amount'); + $coupon1->setTitle('Christmas coupon'); + $coupon1->setShortDescription('Coupon for Christmas removing 10€ if your total checkout is more than 40€'); + $coupon1->setDescription('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras at luctus tellus. Integer turpis mauris, aliquet vitae risus tristique, pellentesque vestibulum urna. Vestibulum sodales laoreet lectus dictum suscipit. Praesent vulputate, sem id varius condimentum, quam magna tempor elit, quis venenatis ligula nulla eget libero. Cras egestas euismod tellus, id pharetra leo suscipit quis. Donec lacinia ac lacus et ultricies. Nunc in porttitor neque. Proin at quam congue, consectetur orci sed, congue nulla. Nulla eleifend nunc ligula, nec pharetra elit tempus quis. Vivamus vel mauris sed est dictum blandit. Maecenas blandit dapibus velit ut sollicitudin. In in euismod mauris, consequat viverra magna. Cras velit velit, sollicitudin commodo tortor gravida, tempus varius nulla. + +Donec rhoncus leo mauris, id porttitor ante luctus tempus. Curabitur quis augue feugiat, ullamcorper mauris ac, interdum mi. Quisque aliquam lorem vitae felis lobortis, id interdum turpis mattis. Vestibulum diam massa, ornare congue blandit quis, facilisis at nisl. In tortor metus, venenatis non arcu nec, sollicitudin ornare nisl. Nunc erat risus, varius nec urna at, iaculis lacinia elit. Aenean ut felis tempus, tincidunt odio non, sagittis nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec vitae hendrerit elit. Nunc sit amet gravida risus, euismod lobortis massa. Nam a erat mauris. Nam a malesuada lorem. Nulla id accumsan dolor, sed rhoncus tellus. Quisque dictum felis sed leo auctor, at volutpat lectus viverra. Morbi rutrum, est ac aliquam imperdiet, nibh sem sagittis justo, ac mattis magna lacus eu nulla. + +Duis interdum lectus nulla, nec pellentesque sapien condimentum at. Suspendisse potenti. Sed eu purus tellus. Nunc quis rhoncus metus. Fusce vitae tellus enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam tempor porttitor erat vitae iaculis. Sed est elit, consequat non ornare vitae, vehicula eget lectus. Etiam consequat sapien mauris, eget consectetur magna imperdiet eget. Nunc sollicitudin luctus velit, in commodo nulla adipiscing fermentum. Fusce nisi sapien, posuere vitae metus sit amet, facilisis sollicitudin dui. Fusce ultricies auctor enim sit amet iaculis. Morbi at vestibulum enim, eget adipiscing eros. + +Praesent ligula lorem, faucibus ut metus quis, fermentum iaculis erat. Pellentesque elit erat, lacinia sed semper ac, sagittis vel elit. Nam eu convallis est. Curabitur rhoncus odio vitae consectetur pellentesque. Nam vitae arcu nec ante scelerisque dignissim vel nec neque. Suspendisse augue nulla, mollis eget dui et, tempor facilisis erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ac diam ipsum. Donec convallis dui ultricies velit auctor, non lobortis nulla ultrices. Morbi vitae dignissim ante, sit amet lobortis tortor. Nunc dapibus condimentum augue, in molestie neque congue non. + +Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.'); + $coupon1->setAmount(10.00); + $coupon1->setIsUsed(1); + $coupon1->setIsEnabled(1); + $date = new \DateTime(); + $coupon1->setExpirationDate($date->setTimestamp(strtotime("today + 2 months"))); + + $rule1 = new AvailableForTotalAmountManager($adapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::SUPERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 40.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule1->setValidatorsFromForm($operators, $values); + + $rule2 = new AvailableForTotalAmountManager($adapter); + $operators = array( + AvailableForTotalAmountManager::INPUT1 => Operators::INFERIOR, + AvailableForTotalAmountManager::INPUT2 => Operators::EQUAL + ); + $values = array( + AvailableForTotalAmountManager::INPUT1 => 400.00, + AvailableForTotalAmountManager::INPUT2 => 'EUR' + ); + $rule2->setValidatorsFromForm($operators, $values); + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + $rules->add($rule2); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $container->get('thelia.constraint.factory'); + + $serializedRules = $constraintFactory->serializeCouponRuleCollection($rules); + $coupon1->setSerializedRules($serializedRules); + + $coupon1->setMaxUsage(40); + $coupon1->setIsCumulative(1); + $coupon1->setIsRemovingPostage(0); + $coupon1->save(); + + + + + + + + + // Coupons + $coupon2 = new Thelia\Model\Coupon(); + $coupon2->setCode('SPRINGBREAK'); + $coupon2->setType('thelia.coupon.type.remove_x_percent'); + $coupon2->setTitle('Springbreak coupon'); + $coupon2->setShortDescription('Coupon for Springbreak removing 10% if you have more than 4 articles in your cart'); + $coupon2->setDescription('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras at luctus tellus. Integer turpis mauris, aliquet vitae risus tristique, pellentesque vestibulum urna. Vestibulum sodales laoreet lectus dictum suscipit. Praesent vulputate, sem id varius condimentum, quam magna tempor elit, quis venenatis ligula nulla eget libero. Cras egestas euismod tellus, id pharetra leo suscipit quis. Donec lacinia ac lacus et ultricies. Nunc in porttitor neque. Proin at quam congue, consectetur orci sed, congue nulla. Nulla eleifend nunc ligula, nec pharetra elit tempus quis. Vivamus vel mauris sed est dictum blandit. Maecenas blandit dapibus velit ut sollicitudin. In in euismod mauris, consequat viverra magna. Cras velit velit, sollicitudin commodo tortor gravida, tempus varius nulla. + +Donec rhoncus leo mauris, id porttitor ante luctus tempus. Curabitur quis augue feugiat, ullamcorper mauris ac, interdum mi. Quisque aliquam lorem vitae felis lobortis, id interdum turpis mattis. Vestibulum diam massa, ornare congue blandit quis, facilisis at nisl. In tortor metus, venenatis non arcu nec, sollicitudin ornare nisl. Nunc erat risus, varius nec urna at, iaculis lacinia elit. Aenean ut felis tempus, tincidunt odio non, sagittis nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec vitae hendrerit elit. Nunc sit amet gravida risus, euismod lobortis massa. Nam a erat mauris. Nam a malesuada lorem. Nulla id accumsan dolor, sed rhoncus tellus. Quisque dictum felis sed leo auctor, at volutpat lectus viverra. Morbi rutrum, est ac aliquam imperdiet, nibh sem sagittis justo, ac mattis magna lacus eu nulla. + +Duis interdum lectus nulla, nec pellentesque sapien condimentum at. Suspendisse potenti. Sed eu purus tellus. Nunc quis rhoncus metus. Fusce vitae tellus enim. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam tempor porttitor erat vitae iaculis. Sed est elit, consequat non ornare vitae, vehicula eget lectus. Etiam consequat sapien mauris, eget consectetur magna imperdiet eget. Nunc sollicitudin luctus velit, in commodo nulla adipiscing fermentum. Fusce nisi sapien, posuere vitae metus sit amet, facilisis sollicitudin dui. Fusce ultricies auctor enim sit amet iaculis. Morbi at vestibulum enim, eget adipiscing eros. + +Praesent ligula lorem, faucibus ut metus quis, fermentum iaculis erat. Pellentesque elit erat, lacinia sed semper ac, sagittis vel elit. Nam eu convallis est. Curabitur rhoncus odio vitae consectetur pellentesque. Nam vitae arcu nec ante scelerisque dignissim vel nec neque. Suspendisse augue nulla, mollis eget dui et, tempor facilisis erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi ac diam ipsum. Donec convallis dui ultricies velit auctor, non lobortis nulla ultrices. Morbi vitae dignissim ante, sit amet lobortis tortor. Nunc dapibus condimentum augue, in molestie neque congue non. + +Sed facilisis pellentesque nisl, eu tincidunt erat scelerisque a. Nullam malesuada tortor vel erat volutpat tincidunt. In vehicula diam est, a convallis eros scelerisque ut. Donec aliquet venenatis iaculis. Ut a arcu gravida, placerat dui eu, iaculis nisl. Quisque adipiscing orci sit amet dui dignissim lacinia. Sed vulputate lorem non dolor adipiscing ornare. Morbi ornare id nisl id aliquam. Ut fringilla elit ante, nec lacinia enim fermentum sit amet. Aenean rutrum lorem eu convallis pharetra. Cras malesuada varius metus, vitae gravida velit. Nam a varius ipsum, ac commodo dolor. Phasellus nec elementum elit. Etiam vel adipiscing leo.'); + $coupon2->setAmount(10.00); + $coupon2->setIsUsed(1); + $coupon2->setIsEnabled(1); + $date = new \DateTime(); + $coupon2->setExpirationDate($date->setTimestamp(strtotime("today + 2 months"))); + + $rule1 = new AvailableForXArticlesManager($adapter); + $operators = array( + AvailableForXArticlesManager::INPUT1 => Operators::SUPERIOR, + ); + $values = array( + AvailableForXArticlesManager::INPUT1 => 4, + ); + $rule1->setValidatorsFromForm($operators, $values); + + $rules = new CouponRuleCollection(); + $rules->add($rule1); + + /** @var ConstraintFactory $constraintFactory */ + $constraintFactory = $container->get('thelia.constraint.factory'); + + $serializedRules = $constraintFactory->serializeCouponRuleCollection($rules); + $coupon2->setSerializedRules($serializedRules); + + $coupon1->setMaxUsage(-1); + $coupon2->setIsCumulative(0); + $coupon2->setIsRemovingPostage(1); + $coupon2->save(); +} diff --git a/install/insert.sql b/install/insert.sql index 774d22472..8b577fb8e 100755 --- a/install/insert.sql +++ b/install/insert.sql @@ -1109,3 +1109,25 @@ INSERT INTO `country_i18n` (`id`, `locale`, `title`, `description`, `chapo`, `po (268, 'en_US', 'USA - Alabama', '', '', ''), (268, 'es_ES', 'USA - Alabama', '', '', ''), (268, 'fr_FR', 'USA - Alabama', '', '', ''); + +INSERT INTO `tax` (`id`, `rate`, `created_at`, `updated_at`) + VALUES + (1, '19.6', NOW(), NOW()); + +INSERT INTO `tax_i18n` (`id`, `locale`, `title`) + VALUES + (1, 'fr_FR', 'TVA française à 19.6%'), + (1, 'en_UK', 'french 19.6% tax'); + +INSERT INTO `tax_rule` (`id`, `created_at`, `updated_at`) + VALUES + (1, NOW(), NOW()); + +INSERT INTO `tax_rule_i18n` (`id`, `locale`, `title`) + VALUES + (1, 'fr_FR', 'TVA française à 19.6%'), + (1, 'en_UK', 'french 19.6% tax'); + +INSERT INTO `tax_rule_country` (`tax_rule_id`, `country_id`, `tax_id`, `position`, `created_at`, `updated_at`) + VALUES + (1, 64, 1, 1, NOW(), NOW()); diff --git a/install/thelia.sql b/install/thelia.sql index 2fb3723ca..d38d45379 100755 --- a/install/thelia.sql +++ b/install/thelia.sql @@ -126,9 +126,6 @@ DROP TABLE IF EXISTS `tax_rule`; CREATE TABLE `tax_rule` ( `id` INTEGER NOT NULL AUTO_INCREMENT, - `code` VARCHAR(45), - `title` VARCHAR(255), - `description` TEXT, `created_at` DATETIME, `updated_at` DATETIME, PRIMARY KEY (`id`) @@ -142,14 +139,13 @@ DROP TABLE IF EXISTS `tax_rule_country`; CREATE TABLE `tax_rule_country` ( - `id` INTEGER NOT NULL, - `tax_rule_id` INTEGER, - `country_id` INTEGER, - `tax_id` INTEGER, - `none` TINYINT, + `tax_rule_id` INTEGER NOT NULL, + `country_id` INTEGER NOT NULL, + `tax_id` INTEGER NOT NULL, + `position` INTEGER NOT NULL, `created_at` DATETIME, `updated_at` DATETIME, - PRIMARY KEY (`id`), + PRIMARY KEY (`tax_rule_id`,`country_id`,`tax_id`), INDEX `idx_tax_rule_country_tax_id` (`tax_id`), INDEX `idx_tax_rule_country_tax_rule_id` (`tax_rule_id`), INDEX `idx_tax_rule_country_country_id` (`country_id`), @@ -157,7 +153,7 @@ CREATE TABLE `tax_rule_country` FOREIGN KEY (`tax_id`) REFERENCES `tax` (`id`) ON UPDATE RESTRICT - ON DELETE SET NULL, + ON DELETE CASCADE, CONSTRAINT `fk_tax_rule_country_tax_rule_id` FOREIGN KEY (`tax_rule_id`) REFERENCES `tax_rule` (`id`) @@ -1574,6 +1570,8 @@ CREATE TABLE `tax_rule_i18n` ( `id` INTEGER NOT NULL, `locale` VARCHAR(5) DEFAULT 'en_US' NOT NULL, + `title` VARCHAR(255), + `description` TEXT, PRIMARY KEY (`id`,`locale`), CONSTRAINT `tax_rule_i18n_FK_1` FOREIGN KEY (`id`) diff --git a/local/config/schema.xml b/local/config/schema.xml index e6e68c4b2..39f649650 100755 --- a/local/config/schema.xml +++ b/local/config/schema.xml @@ -1,4 +1,4 @@ - + @@ -96,19 +96,19 @@
- - + + +
- - - - - - + + + + + diff --git a/reset_install.sh b/reset_install.sh index 99a73573c..399156b67 100755 --- a/reset_install.sh +++ b/reset_install.sh @@ -1,34 +1,35 @@ #!/bin/bash # @author Guillaume MOREL -# v0.1 +# v0.2 echo -e "\033[47m\033[1;31m\n[WARN] This script will reset this Thelia2 install\n\033[0m" -if [ ! -f local/config/database.yml ]; then - echo "[FAILED] Please add your database informations in local/config/database.yml and start this script again." -else - echo -e "\n\e[01;34m[INFO] Downloading vendors\e[00m\n" - composer install --prefer-dist +echo -e "\n\e[01;34m[INFO] Clearing caches\e[00m\n" +php Thelia cache:clear - cd local/config/ +echo -e "\n\e[01;34m[INFO] Downloading vendors\e[00m\n" +composer install --prefer-dist - echo -e "\n\e[01;34m[INFO] Building Models file\e[00m\n" - ../../bin/propel build -v --output-dir=../../core/lib/ +cd local/config/ - echo -e "\n\e[01;34m[INFO] Building SQL CREATE file\e[00m\n" - ../../bin/propel sql:build -v --output-dir=../../install/ +echo -e "\n\e[01;34m[INFO] Building Models file\e[00m\n" +../../bin/propel build -v --output-dir=../../core/lib/ +echo -e "\n\e[01;34m[INFO] Building SQL CREATE file\e[00m\n" +../../bin/propel sql:build -v --output-dir=../../install/ - echo -e "\n\e[01;34m[INFO] Reloaded Thelia2 database\e[00m\n" - cd ../.. - rm install/sqldb.map - php Thelia thelia:dev:reloadDB +echo -e "\n\e[01;34m[INFO] Reloaded Thelia2 database\e[00m\n" +cd ../.. +rm install/sqldb.map +php Thelia thelia:dev:reloadDB - echo -e "\n\e[01;34m[INFO] Installing fixtures\e[00m\n" - php install/faker.php +echo -e "\n\e[01;34m[INFO] Installing fixtures\e[00m\n" +php install/faker.php - echo -e "\n\e[01;34m[INFO] Adding admin\e[00m\n" - php Thelia thelia:create-admin +echo -e "\n\e[01;34m[INFO] Adding admin\e[00m\n" +php Thelia thelia:create-admin --login_name thelia2 --password thelia2 --last_name thelia2 --first_name thelia2 - echo -e "\n\e[00;32m[SUCCESS] Reset done\e[00m\n" -fi \ No newline at end of file +echo -e "\n\e[01;34m[INFO] Clearing caches\e[00m\n" +php Thelia cache:clear + +echo -e "\n\e[00;32m[SUCCESS] Reset done\e[00m\n" \ No newline at end of file diff --git a/templates/admin/default/admin-layout.tpl b/templates/admin/default/admin-layout.tpl index 226355b7a..1a21b9165 100644 --- a/templates/admin/default/admin-layout.tpl +++ b/templates/admin/default/admin-layout.tpl @@ -227,15 +227,14 @@ {block name="after-javascript-include"}{/block} - {javascripts file='assets/js/bootstrap/bootstrap.js'} - - {/javascripts} - {block name="javascript-initialization"}{/block} + {debugbar_render} {* Modules scripts are included now *} {module_include location='footer_js'} - {debugbar_render} + {javascripts file='assets/js/bootstrap/bootstrap.js'} + + {/javascripts} \ No newline at end of file diff --git a/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js new file mode 100755 index 000000000..bf3a56df0 --- /dev/null +++ b/templates/admin/default/assets/bootstrap-datepicker/js/bootstrap-datepicker.js @@ -0,0 +1,474 @@ +/* ========================================================= + * bootstrap-datepicker.js + * http://www.eyecon.ro/bootstrap-datepicker + * ========================================================= + * Copyright 2012 Stefan Petre + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + +!function( $ ) { + + // Picker object + + var Datepicker = function(element, options){ + this.element = $(element); + this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy'); + this.picker = $(DPGlobal.template) + .appendTo('body') + .on({ + click: $.proxy(this.click, this)//, + //mousedown: $.proxy(this.mousedown, this) + }); + this.isInput = this.element.is('input'); + this.component = this.element.is('.date') ? this.element.find('.add-on') : false; + + if (this.isInput) { + this.element.on({ + focus: $.proxy(this.show, this), + //blur: $.proxy(this.hide, this), + keyup: $.proxy(this.update, this) + }); + } else { + if (this.component){ + this.component.on('click', $.proxy(this.show, this)); + } else { + this.element.on('click', $.proxy(this.show, this)); + } + } + + this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0; + if (typeof this.minViewMode === 'string') { + switch (this.minViewMode) { + case 'months': + this.minViewMode = 1; + break; + case 'years': + this.minViewMode = 2; + break; + default: + this.minViewMode = 0; + break; + } + } + this.viewMode = options.viewMode||this.element.data('date-viewmode')||0; + if (typeof this.viewMode === 'string') { + switch (this.viewMode) { + case 'months': + this.viewMode = 1; + break; + case 'years': + this.viewMode = 2; + break; + default: + this.viewMode = 0; + break; + } + } + this.startViewMode = this.viewMode; + this.weekStart = options.weekStart||this.element.data('date-weekstart')||0; + this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1; + this.onRender = options.onRender; + this.fillDow(); + this.fillMonths(); + this.update(); + this.showMode(); + }; + + Datepicker.prototype = { + constructor: Datepicker, + + show: function(e) { + this.picker.show(); + this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); + this.place(); + $(window).on('resize', $.proxy(this.place, this)); + if (e ) { + e.stopPropagation(); + e.preventDefault(); + } + if (!this.isInput) { + } + var that = this; + $(document).on('mousedown', function(ev){ + if ($(ev.target).closest('.datepicker').length == 0) { + that.hide(); + } + }); + this.element.trigger({ + type: 'show', + date: this.date + }); + }, + + hide: function(){ + this.picker.hide(); + $(window).off('resize', this.place); + this.viewMode = this.startViewMode; + this.showMode(); + if (!this.isInput) { + $(document).off('mousedown', this.hide); + } + //this.set(); + this.element.trigger({ + type: 'hide', + date: this.date + }); + }, + + set: function() { + var formated = DPGlobal.formatDate(this.date, this.format); + if (!this.isInput) { + if (this.component){ + this.element.find('input').prop('value', formated); + } + this.element.data('date', formated); + } else { + this.element.prop('value', formated); + } + }, + + setValue: function(newDate) { + if (typeof newDate === 'string') { + this.date = DPGlobal.parseDate(newDate, this.format); + } else { + this.date = new Date(newDate); + } + this.set(); + this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); + this.fill(); + }, + + place: function(){ + var offset = this.component ? this.component.offset() : this.element.offset(); + this.picker.css({ + top: offset.top + this.height, + left: offset.left + }); + }, + + update: function(newDate){ + this.date = DPGlobal.parseDate( + typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')), + this.format + ); + this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0); + this.fill(); + }, + + fillDow: function(){ + var dowCnt = this.weekStart; + var html = ''; + while (dowCnt < this.weekStart + 7) { + html += ''; + } + html += ''; + this.picker.find('.datepicker-days thead').append(html); + }, + + fillMonths: function(){ + var html = ''; + var i = 0 + while (i < 12) { + html += ''+DPGlobal.dates.monthsShort[i++]+''; + } + this.picker.find('.datepicker-months td').append(html); + }, + + fill: function() { + var d = new Date(this.viewDate), + year = d.getFullYear(), + month = d.getMonth(), + currentDate = this.date.valueOf(); + this.picker.find('.datepicker-days th:eq(1)') + .text(DPGlobal.dates.months[month]+' '+year); + var prevMonth = new Date(year, month-1, 28,0,0,0,0), + day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()); + prevMonth.setDate(day); + prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7); + var nextMonth = new Date(prevMonth); + nextMonth.setDate(nextMonth.getDate() + 42); + nextMonth = nextMonth.valueOf(); + var html = []; + var clsName, + prevY, + prevM; + while(prevMonth.valueOf() < nextMonth) { + if (prevMonth.getDay() === this.weekStart) { + html.push(''); + } + clsName = this.onRender(prevMonth); + prevY = prevMonth.getFullYear(); + prevM = prevMonth.getMonth(); + if ((prevM < month && prevY === year) || prevY < year) { + clsName += ' old'; + } else if ((prevM > month && prevY === year) || prevY > year) { + clsName += ' new'; + } + if (prevMonth.valueOf() === currentDate) { + clsName += ' active'; + } + html.push(''); + if (prevMonth.getDay() === this.weekEnd) { + html.push(''); + } + prevMonth.setDate(prevMonth.getDate()+1); + } + this.picker.find('.datepicker-days tbody').empty().append(html.join('')); + var currentYear = this.date.getFullYear(); + + var months = this.picker.find('.datepicker-months') + .find('th:eq(1)') + .text(year) + .end() + .find('span').removeClass('active'); + if (currentYear === year) { + months.eq(this.date.getMonth()).addClass('active'); + } + + html = ''; + year = parseInt(year/10, 10) * 10; + var yearCont = this.picker.find('.datepicker-years') + .find('th:eq(1)') + .text(year + '-' + (year + 9)) + .end() + .find('td'); + year -= 1; + for (var i = -1; i < 11; i++) { + html += ''+year+''; + year += 1; + } + yearCont.html(html); + }, + + click: function(e) { + e.stopPropagation(); + e.preventDefault(); + var target = $(e.target).closest('span, td, th'); + if (target.length === 1) { + switch(target[0].nodeName.toLowerCase()) { + case 'th': + switch(target[0].className) { + case 'switch': + this.showMode(1); + break; + case 'prev': + case 'next': + this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call( + this.viewDate, + this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) + + DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1) + ); + this.fill(); + this.set(); + break; + } + break; + case 'span': + if (target.is('.month')) { + var month = target.parent().find('span').index(target); + this.viewDate.setMonth(month); + } else { + var year = parseInt(target.text(), 10)||0; + this.viewDate.setFullYear(year); + } + if (this.viewMode !== 0) { + this.date = new Date(this.viewDate); + this.element.trigger({ + type: 'changeDate', + date: this.date, + viewMode: DPGlobal.modes[this.viewMode].clsName + }); + } + this.showMode(-1); + this.fill(); + this.set(); + break; + case 'td': + if (target.is('.day') && !target.is('.disabled')){ + var day = parseInt(target.text(), 10)||1; + var month = this.viewDate.getMonth(); + if (target.is('.old')) { + month -= 1; + } else if (target.is('.new')) { + month += 1; + } + var year = this.viewDate.getFullYear(); + this.date = new Date(year, month, day,0,0,0,0); + this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0); + this.fill(); + this.set(); + this.element.trigger({ + type: 'changeDate', + date: this.date, + viewMode: DPGlobal.modes[this.viewMode].clsName + }); + } + break; + } + } + }, + + mousedown: function(e){ + e.stopPropagation(); + e.preventDefault(); + }, + + showMode: function(dir) { + if (dir) { + this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir)); + } + this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); + } + }; + + $.fn.datepicker = function ( option, val ) { + return this.each(function () { + var $this = $(this), + data = $this.data('datepicker'), + options = typeof option === 'object' && option; + if (!data) { + $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options)))); + } + if (typeof option === 'string') data[option](val); + }); + }; + + $.fn.datepicker.defaults = { + onRender: function(date) { + return ''; + } + }; + $.fn.datepicker.Constructor = Datepicker; + + var DPGlobal = { + modes: [ + { + clsName: 'days', + navFnc: 'Month', + navStep: 1 + }, + { + clsName: 'months', + navFnc: 'FullYear', + navStep: 1 + }, + { + clsName: 'years', + navFnc: 'FullYear', + navStep: 10 + }], + dates:{ + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] + }, + isLeapYear: function (year) { + return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) + }, + getDaysInMonth: function (year, month) { + return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month] + }, + parseFormat: function(format){ + var separator = format.match(/[.\/\-\s].*?/), + parts = format.split(/\W+/); + if (!separator || !parts || parts.length === 0){ + throw new Error("Invalid date format."); + } + return {separator: separator, parts: parts}; + }, + parseDate: function(date, format) { + var parts = date.split(format.separator), + date = new Date(), + val; + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + if (parts.length === format.parts.length) { + var year = date.getFullYear(), day = date.getDate(), month = date.getMonth(); + for (var i=0, cnt = format.parts.length; i < cnt; i++) { + val = parseInt(parts[i], 10)||1; + switch(format.parts[i]) { + case 'dd': + case 'd': + day = val; + date.setDate(val); + break; + case 'mm': + case 'm': + month = val - 1; + date.setMonth(val - 1); + break; + case 'yy': + year = 2000 + val; + date.setFullYear(2000 + val); + break; + case 'yyyy': + year = val; + date.setFullYear(val); + break; + } + } + date = new Date(year, month, day, 0 ,0 ,0); + } + return date; + }, + formatDate: function(date, format){ + var val = { + d: date.getDate(), + m: date.getMonth() + 1, + yy: date.getFullYear().toString().substring(2), + yyyy: date.getFullYear() + }; + val.dd = (val.d < 10 ? '0' : '') + val.d; + val.mm = (val.m < 10 ? '0' : '') + val.m; + var date = []; + for (var i=0, cnt = format.parts.length; i < cnt; i++) { + date.push(val[format.parts[i]]); + } + return date.join(format.separator); + }, + headTemplate: ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '', + contTemplate: '' + }; + DPGlobal.template = '
'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'
'+prevMonth.getDate() + '
'+ + DPGlobal.headTemplate+ + ''+ + '
'+ + ''+ + '
'+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + '
'+ + '
'+ + '
'+ + ''+ + DPGlobal.headTemplate+ + DPGlobal.contTemplate+ + '
'+ + '
'+ + ''; + +}( window.jQuery ); \ No newline at end of file diff --git a/templates/admin/default/assets/img/ajax-loader.gif b/templates/admin/default/assets/img/ajax-loader.gif new file mode 100644 index 000000000..1321dd374 Binary files /dev/null and b/templates/admin/default/assets/img/ajax-loader.gif differ diff --git a/templates/admin/default/assets/js/json2.js b/templates/admin/default/assets/js/json2.js new file mode 100644 index 000000000..286c98ebe --- /dev/null +++ b/templates/admin/default/assets/js/json2.js @@ -0,0 +1,486 @@ +/* + json2.js + 2013-05-26 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = + /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. + */ + +/*jslint evil: true, regexp: true */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf + */ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (typeof JSON !== 'object') { + JSON = {}; +} + +(function () { + 'use strict'; + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function () { + + return isFinite(this.valueOf()) + ? this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' + : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function () { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' + ? c + : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 + ? '[]' + : gap + ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' + : '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + if (typeof rep[i] === 'string') { + k = rep[i]; + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 + ? '{}' + : gap + ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' + : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.prototype.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + text = String(text); + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/ + .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') + .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' + ? walk({'': j}, '') + : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); \ No newline at end of file diff --git a/templates/admin/default/assets/js/main.js b/templates/admin/default/assets/js/main.js new file mode 100644 index 000000000..c8fc1a7b7 --- /dev/null +++ b/templates/admin/default/assets/js/main.js @@ -0,0 +1,157 @@ +(function($, window, document){ + + $(function(){ + + // -- Init datepicker -- + if($('.date').length){ + //$('.date').datepicker(); + } + + // -- Init tablesorter -- + /*if($('.tablesorter').length){ + $('.tablesorter').tablesorter({ + widgets: ["filter", "stickyHeaders"], + widthFixed : false, + widgetOptions : { + filter_cssFilter : 'input-medium form-control', + filter_formatter : { + + 2 : function($cell, indx){ + return $.tablesorter.filterFormatter.uiDateCompare( $cell, indx, { + dateFormat: "dd/mm/yy", + changeMonth : true, + changeYear : true, + compare : '=' + }); + }, + + 3 : function($cell, indx){ + return $.tablesorter.filterFormatter.uiRange( $cell, indx, { + value: 1, + min: 1, + max: 50, + delayed: true, + valueToHeader: false, + exactMatch: false + }); + } + } + } + }); + }*/ + + // -- Effect description + if($('[name=effect]').length){ + var $effectSelect = $('[name=effect]'), + $helpBlock = $effectSelect.next('.help-block'); + + $effectSelect.change(function(){ + var description = $(this).find(":selected").data('description'); + $helpBlock.text(description); + }); + } + + // -- Max usage -- + if($('#is-unlimited').length){ + + if($('#is-unlimited').is(':checked')){ + $('#max-usage').hide().attr('value', '-1'); + } + + $('#is-unlimited').change(function(){ + if($('#is-unlimited').is(':checked')){ + $('#max-usage').hide().attr('value', '-1'); + } + else{ + $('#max-usage').show().val('').attr('value', ''); + } + }); + + } + + // -- Confirm Box -- + if($('[data-toggle="confirm"]').length){ + $('[data-toggle="confirm"]').click(function(e){ + + var $link = $(this); + var modal = $(this).data('target'); + + $(modal).modal('show'); + + $(modal).on('shown', function () { + $('[data-confirm]').attr('href', $link.attr('href')); + }); + + if($(modal).is(':hidden')){ + e.preventDefault(); + } + + }); + } + + // -- Mini browser -- + miniBrowser = function (root, url){ + + $.getJSON(url, { + root: root + }) + .done(function(data) { + var resultat = data; + + var breadcrumb = $('
'); + $(resultat.breadcrumb).each(function(k, v){ + breadcrumb.append( + $('').html(' > '), + $('').attr('href', '#').html(v.display).click(function(e){ + e.preventDefault(); + miniBrowser(v.url); + }) + ); + }); + + var categories = $('
'); + $(resultat.categories).each(function(k, v){ + categories.append( + $('

').append( + $('').attr('href', '#').html(v.titre).click(function(e){ + e.preventDefault(); + miniBrowser(v.id); + }) + ) + ); + }); + + var products = $('

'); + $(resultat.products).each(function(k, v){ + products.append( + $('

').append( + $('').attr('href', '#').html(v.titre).click(function(e){ + e.preventDefault(); + + $('#productToAdd_ref').val(v.ref); + $('#productToAdd_titre').val(v.titre); + $('#productToAdd_quantite').val(1); + + manageStock(v.variants, v.promo?v.prix2:v.prix); + + $('#productToAdd_tva').val(v.tva); + + $('.productToAddInformation').show(); + $('#btn_ajout_produit').show(); + }) + ) + ); + }); + + $('#minibrowser-breadcrumb').unbind().empty().append(breadcrumb); + $('#minibrowser-categories').unbind().empty().append(categories); + }) + .fail(function() { + console.log('An error occurred while reading from JSON file'); + }); + + } + + }); + +}(window.jQuery, window, document)); \ No newline at end of file diff --git a/templates/admin/default/assets/js/tablesorter/jquery.metadata.js b/templates/admin/default/assets/js/tablesorter/jquery.metadata.js new file mode 100644 index 000000000..07b10bae8 --- /dev/null +++ b/templates/admin/default/assets/js/tablesorter/jquery.metadata.js @@ -0,0 +1,116 @@ +/* + * Metadata - jQuery plugin for parsing metadata from elements + * + * Copyright (c) 2006 John Resig, Yehuda Katz, Jörn Zaefferer, Paul McLanahan + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Sets the type of metadata to use. Metadata is encoded in JSON, and each property + * in the JSON will become a property of the element itself. + * + * There are three supported types of metadata storage: + * + * attr: Inside an attribute. The name parameter indicates *which* attribute. + * + * class: Inside the class attribute, wrapped in curly braces: { } + * + * elem: Inside a child element (e.g. a script tag). The + * name parameter indicates *which* element. + * + * The metadata for an element is loaded the first time the element is accessed via jQuery. + * + * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements + * matched by expr, then redefine the metadata type and run another $(expr) for other elements. + * + * @name $.metadata.setType + * + * @example

This is a p

+ * @before $.metadata.setType("class") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from the class attribute + * + * @example

This is a p

+ * @before $.metadata.setType("attr", "data") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a "data" attribute + * + * @example

This is a p

+ * @before $.metadata.setType("elem", "script") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a nested script element + * + * @param String type The encoding type + * @param String name The name of the attribute to be used to get metadata (optional) + * @cat Plugins/Metadata + * @descr Sets the type of encoding to be used when loading metadata for the first time + * @type undefined + * @see metadata() + */ + +(function($) { + +$.extend({ + metadata : { + defaults : { + type: 'class', + name: 'metadata', + cre: /(\{.*\})/, + single: 'metadata' + }, + setType: function( type, name ){ + this.defaults.type = type; + this.defaults.name = name; + }, + get: function( elem, opts ){ + var data, m, e, attr, + settings = $.extend({},this.defaults,opts); + // check for empty string in single property + if ( !settings.single.length ) { settings.single = 'metadata'; } + + data = $.data(elem, settings.single); + // returned cached data if it already exists + if ( data ) { return data; } + + data = "{}"; + + if ( settings.type === "class" ) { + m = settings.cre.exec( elem.className ); + if ( m ) { data = m[1]; } + } else if ( settings.type === "elem" ) { + if( !elem.getElementsByTagName ) { return undefined; } + e = elem.getElementsByTagName(settings.name); + if ( e.length ) { data = $.trim(e[0].innerHTML); } + } else if ( elem.getAttribute !== undefined ) { + attr = elem.getAttribute( settings.name ); + if ( attr ) { data = attr; } + } + + if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; } + + data = eval("(" + data + ")"); + + $.data( elem, settings.single, data ); + return data; + } + } +}); + +/** + * Returns the metadata object for the first member of the jQuery object. + * + * @name metadata + * @descr Returns element's metadata object + * @param Object opts An object contianing settings to override the defaults + * @type jQuery + * @cat Plugins/Metadata + */ +$.fn.metadata = function( opts ){ + return $.metadata.get( this[0], opts ); +}; + +})(jQuery); \ No newline at end of file diff --git a/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.min.js b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.min.js new file mode 100644 index 000000000..a955fb2c7 --- /dev/null +++ b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.min.js @@ -0,0 +1,1477 @@ +/*! +* TableSorter 2.10.8 - Client-side table sorting with ease! +* @requires jQuery v1.2.6+ +* +* Copyright (c) 2007 Christian Bach +* Examples and docs at: http://tablesorter.com +* Dual licensed under the MIT and GPL licenses: +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl.html +* +* @type jQuery +* @name tablesorter +* @cat Plugins/Tablesorter +* @author Christian Bach/christian.bach@polyester.se +* @contributor Rob Garrison/https://github.com/Mottie/tablesorter +*/ +/*jshint browser:true, jquery:true, unused:false, expr: true */ +/*global console:false, alert:false */ +!(function($) { + "use strict"; + $.extend({ + /*jshint supernew:true */ + tablesorter: new function() { + + var ts = this; + + ts.version = "2.10.8"; + + ts.parsers = []; + ts.widgets = []; + ts.defaults = { + + // *** appearance + theme : 'default', // adds tablesorter-{theme} to the table for styling + widthFixed : false, // adds colgroup to fix widths of columns + showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered. + + headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = (class from cssIcon) + onRenderTemplate : null, // function(index, template){ return template; }, (template is a string) + onRenderHeader : null, // function(index){}, (nothing to return) + + // *** functionality + cancelSelection : true, // prevent text selection in the header + dateFormat : 'mmddyyyy', // other options: "ddmmyyy" or "yyyymmdd" + sortMultiSortKey : 'shiftKey', // key used to select additional columns + sortResetKey : 'ctrlKey', // key used to remove sorting on a column + usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89" + delayInit : false, // if false, the parsed table contents will not update until the first sort + serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used. + + // *** sort options + headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc. + ignoreCase : true, // ignore case while sorting + sortForce : null, // column(s) first sorted; always applied + sortList : [], // Initial sort order; applied initially; updated when manually sorted + sortAppend : null, // column(s) sorted last; always applied + + sortInitialOrder : 'asc', // sort direction on first click + sortLocaleCompare: false, // replace equivalent character (accented characters) + sortReset : false, // third click on the header will reset column to default - unsorted + sortRestart : false, // restart sort to "sortInitialOrder" when clicking on previously unsorted columns + + emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero + stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero + textExtraction : 'simple', // text extraction method/function - function(node, table, cellIndex){} + textSorter : null, // use custom text sorter - function(a,b){ return a.sort(b); } // basic sort + + // *** widget options + widgets: [], // method to add widgets, e.g. widgets: ['zebra'] + widgetOptions : { + zebra : [ 'even', 'odd' ] // zebra widget alternating row class names + }, + initWidgets : true, // apply widgets on tablesorter initialization + + // *** callbacks + initialized : null, // function(table){}, + + // *** css class names + tableClass : 'tablesorter', + cssAsc : 'tablesorter-headerAsc', + cssChildRow : 'tablesorter-childRow', // previously "expand-child" + cssDesc : 'tablesorter-headerDesc', + cssHeader : 'tablesorter-header', + cssHeaderRow : 'tablesorter-headerRow', + cssIcon : 'tablesorter-icon', // if this class exists, a will be added to the header automatically + cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name + cssProcessing : 'tablesorter-processing', // processing icon applied to header during sort/filter + + // *** selectors + selectorHeaders : '> thead th, > thead td', + selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort + selectorRemove : '.remove-me', + + // *** advanced + debug : false, + + // *** Internal variables + headerList: [], + empties: {}, + strings: {}, + parsers: [] + + // deprecated; but retained for backwards compatibility + // widgetZebra: { css: ["even", "odd"] } + + }; + + /* debuging utils */ + function log(s) { + if (typeof console !== "undefined" && typeof console.log !== "undefined") { + console.log(s); + } else { + alert(s); + } + } + + function benchmark(s, d) { + log(s + " (" + (new Date().getTime() - d.getTime()) + "ms)"); + } + + ts.log = log; + ts.benchmark = benchmark; + + function getElementText(table, node, cellIndex) { + if (!node) { return ""; } + var c = table.config, + t = c.textExtraction, text = ""; + if (t === "simple") { + if (c.supportsTextContent) { + text = node.textContent; // newer browsers support this + } else { + text = $(node).text(); + } + } else { + if (typeof t === "function") { + text = t(node, table, cellIndex); + } else if (typeof t === "object" && t.hasOwnProperty(cellIndex)) { + text = t[cellIndex](node, table, cellIndex); + } else { + text = c.supportsTextContent ? node.textContent : $(node).text(); + } + } + return $.trim(text); + } + + function detectParserForColumn(table, rows, rowIndex, cellIndex) { + var cur, + i = ts.parsers.length, + node = false, + nodeValue = '', + keepLooking = true; + while (nodeValue === '' && keepLooking) { + rowIndex++; + if (rows[rowIndex]) { + node = rows[rowIndex].cells[cellIndex]; + nodeValue = getElementText(table, node, cellIndex); + if (table.config.debug) { + log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"'); + } + } else { + keepLooking = false; + } + } + while (--i >= 0) { + cur = ts.parsers[i]; + // ignore the default text parser because it will always be true + if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node)) { + return cur; + } + } + // nothing found, return the generic parser (text) + return ts.getParserById('text'); + } + + function buildParserCache(table) { + var c = table.config, + // update table bodies in case we start with an empty table + tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'), + rows, list, l, i, h, ch, p, parsersDebug = ""; + if ( tb.length === 0) { + return c.debug ? log('*Empty table!* Not building a parser cache') : ''; + } + rows = tb[0].rows; + if (rows[0]) { + list = []; + l = rows[0].cells.length; + for (i = 0; i < l; i++) { + // tons of thanks to AnthonyM1229 for working out the following selector (issue #74) to make this work in IE8! + // More fixes to this selector to work properly in iOS and jQuery 1.8+ (issue #132 & #174) + h = c.$headers.filter(':not([colspan])'); + h = h.add( c.$headers.filter('[colspan="1"]') ) // ie8 fix + .filter('[data-column="' + i + '"]:last'); + ch = c.headers[i]; + // get column parser + p = ts.getParserById( ts.getData(h, ch, 'sorter') ); + // empty cells behaviour - keeping emptyToBottom for backwards compatibility + c.empties[i] = ts.getData(h, ch, 'empty') || c.emptyTo || (c.emptyToBottom ? 'bottom' : 'top' ); + // text strings behaviour in numerical sorts + c.strings[i] = ts.getData(h, ch, 'string') || c.stringTo || 'max'; + if (!p) { + p = detectParserForColumn(table, rows, -1, i); + } + if (c.debug) { + parsersDebug += "column:" + i + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n"; + } + list.push(p); + } + } + if (c.debug) { + log(parsersDebug); + } + c.parsers = list; + } + + /* utils */ + function buildCache(table) { + var b = table.tBodies, + tc = table.config, + totalRows, + totalCells, + parsers = tc.parsers, + t, v, i, j, k, c, cols, cacheTime, colMax = []; + tc.cache = {}; + // if no parsers found, return - it's an empty table. + if (!parsers) { + return tc.debug ? log('*Empty table!* Not building a cache') : ''; + } + if (tc.debug) { + cacheTime = new Date(); + } + // processing icon + if (tc.showProcessing) { + ts.isProcessing(table, true); + } + for (k = 0; k < b.length; k++) { + tc.cache[k] = { row: [], normalized: [] }; + // ignore tbodies with class name from css.cssInfoBlock + if (!$(b[k]).hasClass(tc.cssInfoBlock)) { + totalRows = (b[k] && b[k].rows.length) || 0; + totalCells = (b[k].rows[0] && b[k].rows[0].cells.length) || 0; + for (i = 0; i < totalRows; ++i) { + /** Add the table data to main data array */ + c = $(b[k].rows[i]); + cols = []; + // if this is a child row, add it to the last row's children and continue to the next row + if (c.hasClass(tc.cssChildRow)) { + tc.cache[k].row[tc.cache[k].row.length - 1] = tc.cache[k].row[tc.cache[k].row.length - 1].add(c); + // go to the next for loop + continue; + } + tc.cache[k].row.push(c); + for (j = 0; j < totalCells; ++j) { + t = getElementText(table, c[0].cells[j], j); + // allow parsing if the string is empty, previously parsing would change it to zero, + // in case the parser needs to extract data from the table cell attributes + v = parsers[j].format(t, table, c[0].cells[j], j); + cols.push(v); + if ((parsers[j].type || '').toLowerCase() === "numeric") { + colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0); // determine column max value (ignore sign) + } + } + cols.push(tc.cache[k].normalized.length); // add position for rowCache + tc.cache[k].normalized.push(cols); + } + tc.cache[k].colMax = colMax; + } + } + if (tc.showProcessing) { + ts.isProcessing(table); // remove processing icon + } + if (tc.debug) { + benchmark("Building cache for " + totalRows + " rows", cacheTime); + } + } + + // init flag (true) used by pager plugin to prevent widget application + function appendToTable(table, init) { + var c = table.config, + b = table.tBodies, + rows = [], + c2 = c.cache, + r, n, totalRows, checkCell, $bk, $tb, + i, j, k, l, pos, appendTime; + if (!c2[0]) { return; } // empty table - fixes #206 + if (c.debug) { + appendTime = new Date(); + } + for (k = 0; k < b.length; k++) { + $bk = $(b[k]); + if ($bk.length && !$bk.hasClass(c.cssInfoBlock)) { + // get tbody + $tb = ts.processTbody(table, $bk, true); + r = c2[k].row; + n = c2[k].normalized; + totalRows = n.length; + checkCell = totalRows ? (n[0].length - 1) : 0; + for (i = 0; i < totalRows; i++) { + pos = n[i][checkCell]; + rows.push(r[pos]); + // removeRows used by the pager plugin + if (!c.appender || !c.removeRows) { + l = r[pos].length; + for (j = 0; j < l; j++) { + $tb.append(r[pos][j]); + } + } + } + // restore tbody + ts.processTbody(table, $tb, false); + } + } + if (c.appender) { + c.appender(table, rows); + } + if (c.debug) { + benchmark("Rebuilt table", appendTime); + } + // apply table widgets + if (!init) { ts.applyWidget(table); } + // trigger sortend + $(table).trigger("sortEnd", table); + } + + // computeTableHeaderCellIndexes from: + // http://www.javascripttoolbox.com/lib/table/examples.php + // http://www.javascripttoolbox.com/temp/table_cellindex.html + function computeThIndexes(t) { + var matrix = [], + lookup = {}, + cols = 0, // determine the number of columns + trs = $(t).find('thead:eq(0), tfoot').children('tr'), // children tr in tfoot - see issue #196 + i, j, k, l, c, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow; + for (i = 0; i < trs.length; i++) { + cells = trs[i].cells; + for (j = 0; j < cells.length; j++) { + c = cells[j]; + rowIndex = c.parentNode.rowIndex; + cellId = rowIndex + "-" + c.cellIndex; + rowSpan = c.rowSpan || 1; + colSpan = c.colSpan || 1; + if (typeof(matrix[rowIndex]) === "undefined") { + matrix[rowIndex] = []; + } + // Find first available column in the first row + for (k = 0; k < matrix[rowIndex].length + 1; k++) { + if (typeof(matrix[rowIndex][k]) === "undefined") { + firstAvailCol = k; + break; + } + } + lookup[cellId] = firstAvailCol; + cols = Math.max(firstAvailCol, cols); + // add data-column + $(c).attr({ 'data-column' : firstAvailCol }); // 'data-row' : rowIndex + for (k = rowIndex; k < rowIndex + rowSpan; k++) { + if (typeof(matrix[k]) === "undefined") { + matrix[k] = []; + } + matrixrow = matrix[k]; + for (l = firstAvailCol; l < firstAvailCol + colSpan; l++) { + matrixrow[l] = "x"; + } + } + } + } + t.config.columns = cols; // may not be accurate if # header columns !== # tbody columns + return lookup; + } + + function formatSortingOrder(v) { + // look for "d" in "desc" order; return true + return (/^d/i.test(v) || v === 1); + } + + function buildHeaders(table) { + var header_index = computeThIndexes(table), ch, $t, + h, i, t, lock, time, c = table.config; + c.headerList = []; + c.headerContent = []; + if (c.debug) { + time = new Date(); + } + i = c.cssIcon ? '' : ''; // add icon if cssIcon option exists + c.$headers = $(table).find(c.selectorHeaders).each(function(index) { + $t = $(this); + ch = c.headers[index]; + c.headerContent[index] = this.innerHTML; // save original header content + // set up header template + t = c.headerTemplate.replace(/\{content\}/g, this.innerHTML).replace(/\{icon\}/g, i); + if (c.onRenderTemplate) { + h = c.onRenderTemplate.apply($t, [index, t]); + if (h && typeof h === 'string') { t = h; } // only change t if something is returned + } + this.innerHTML = '
' + t + '
'; // faster than wrapInner + + if (c.onRenderHeader) { c.onRenderHeader.apply($t, [index]); } + + this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; + this.order = formatSortingOrder( ts.getData($t, ch, 'sortInitialOrder') || c.sortInitialOrder ) ? [1,0,2] : [0,1,2]; + this.count = -1; // set to -1 because clicking on the header automatically adds one + this.lockedOrder = false; + lock = ts.getData($t, ch, 'lockedOrder') || false; + if (typeof lock !== 'undefined' && lock !== false) { + this.order = this.lockedOrder = formatSortingOrder(lock) ? [1,1,1] : [0,0,0]; + } + $t.addClass(c.cssHeader); + // add cell to headerList + c.headerList[index] = this; + // add to parent in case there are multiple rows + $t.parent().addClass(c.cssHeaderRow); + // allow keyboard cursor to focus on element + $t.attr("tabindex", 0); + }); + // enable/disable sorting + updateHeader(table); + if (c.debug) { + benchmark("Built headers:", time); + log(c.$headers); + } + } + + function commonUpdate(table, resort, callback) { + var c = table.config; + // remove rows/elements before update + c.$table.find(c.selectorRemove).remove(); + // rebuild parsers + buildParserCache(table); + // rebuild the cache map + buildCache(table); + checkResort(c.$table, resort, callback); + } + + function updateHeader(table) { + var s, c = table.config; + c.$headers.each(function(index, th){ + s = ts.getData( th, c.headers[index], 'sorter' ) === 'false'; + th.sortDisabled = s; + $(th)[ s ? 'addClass' : 'removeClass' ]('sorter-false'); + }); + } + + function setHeadersCss(table) { + var f, i, j, l, + c = table.config, + list = c.sortList, + css = [c.cssAsc, c.cssDesc], + // find the footer + $t = $(table).find('tfoot tr').children().removeClass(css.join(' ')); + // remove all header information + c.$headers.removeClass(css.join(' ')); + l = list.length; + for (i = 0; i < l; i++) { + // direction = 2 means reset! + if (list[i][1] !== 2) { + // multicolumn sorting updating - choose the :last in case there are nested columns + f = c.$headers.not('.sorter-false').filter('[data-column="' + list[i][0] + '"]' + (l === 1 ? ':last' : '') ); + if (f.length) { + for (j = 0; j < f.length; j++) { + if (!f[j].sortDisabled) { + f.eq(j).addClass(css[list[i][1]]); + // add sorted class to footer, if it exists + if ($t.length) { + $t.filter('[data-column="' + list[i][0] + '"]').eq(j).addClass(css[list[i][1]]); + } + } + } + } + } + } + } + + // automatically add col group, and column sizes if set + function fixColumnWidth(table) { + if (table.config.widthFixed && $(table).find('colgroup').length === 0) { + var colgroup = $(''), + overallWidth = $(table).width(); + $(table.tBodies[0]).find("tr:first").children("td").each(function() { + colgroup.append($('').css('width', parseInt(($(this).width()/overallWidth)*1000, 10)/10 + '%')); + }); + $(table).prepend(colgroup); + } + } + + function updateHeaderSortCount(table, list) { + var s, t, o, c = table.config, + sl = list || c.sortList; + c.sortList = []; + $.each(sl, function(i,v){ + // ensure all sortList values are numeric - fixes #127 + s = [ parseInt(v[0], 10), parseInt(v[1], 10) ]; + // make sure header exists + o = c.headerList[s[0]]; + if (o) { // prevents error if sorton array is wrong + c.sortList.push(s); + t = $.inArray(s[1], o.order); // fixes issue #167 + o.count = t >= 0 ? t : s[1] % (c.sortReset ? 3 : 2); + } + }); + } + + function getCachedSortType(parsers, i) { + return (parsers && parsers[i]) ? parsers[i].type || '' : ''; + } + + function initSort(table, cell, e){ + var a, i, j, o, s, + c = table.config, + k = !e[c.sortMultiSortKey], + $this = $(table); + // Only call sortStart if sorting is enabled + $this.trigger("sortStart", table); + // get current column sort order + cell.count = e[c.sortResetKey] ? 2 : (cell.count + 1) % (c.sortReset ? 3 : 2); + // reset all sorts on non-current column - issue #30 + if (c.sortRestart) { + i = cell; + c.$headers.each(function() { + // only reset counts on columns that weren't just clicked on and if not included in a multisort + if (this !== i && (k || !$(this).is('.' + c.cssDesc + ',.' + c.cssAsc))) { + this.count = -1; + } + }); + } + // get current column index + i = cell.column; + // user only wants to sort on one column + if (k) { + // flush the sort list + c.sortList = []; + if (c.sortForce !== null) { + a = c.sortForce; + for (j = 0; j < a.length; j++) { + if (a[j][0] !== i) { + c.sortList.push(a[j]); + } + } + } + // add column to sort list + o = cell.order[cell.count]; + if (o < 2) { + c.sortList.push([i, o]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (j = 1; j < cell.colSpan; j++) { + c.sortList.push([i + j, o]); + } + } + } + // multi column sorting + } else { + // get rid of the sortAppend before adding more - fixes issue #115 + if (c.sortAppend && c.sortList.length > 1) { + if (ts.isValueInArray(c.sortAppend[0][0], c.sortList)) { + c.sortList.pop(); + } + } + // the user has clicked on an already sorted column + if (ts.isValueInArray(i, c.sortList)) { + // reverse the sorting direction for all tables + for (j = 0; j < c.sortList.length; j++) { + s = c.sortList[j]; + o = c.headerList[s[0]]; + if (s[0] === i) { + s[1] = o.order[o.count]; + if (s[1] === 2) { + c.sortList.splice(j,1); + o.count = -1; + } + } + } + } else { + // add column to sort list array + o = cell.order[cell.count]; + if (o < 2) { + c.sortList.push([i, o]); + // add other columns if header spans across multiple + if (cell.colSpan > 1) { + for (j = 1; j < cell.colSpan; j++) { + c.sortList.push([i + j, o]); + } + } + } + } + } + if (c.sortAppend !== null) { + a = c.sortAppend; + for (j = 0; j < a.length; j++) { + if (a[j][0] !== i) { + c.sortList.push(a[j]); + } + } + } + // sortBegin event triggered immediately before the sort + $this.trigger("sortBegin", table); + // setTimeout needed so the processing icon shows up + setTimeout(function(){ + // set css for headers + setHeadersCss(table); + multisort(table); + appendToTable(table); + }, 1); + } + + // sort multiple columns + function multisort(table) { /*jshint loopfunc:true */ + var dir = 0, tc = table.config, + sortList = tc.sortList, l = sortList.length, bl = table.tBodies.length, + sortTime, i, k, c, colMax, cache, lc, s, order, orgOrderCol; + if (tc.serverSideSorting || !tc.cache[0]) { // empty table - fixes #206 + return; + } + if (tc.debug) { sortTime = new Date(); } + for (k = 0; k < bl; k++) { + colMax = tc.cache[k].colMax; + cache = tc.cache[k].normalized; + lc = cache.length; + orgOrderCol = (cache && cache[0]) ? cache[0].length - 1 : 0; + cache.sort(function(a, b) { + // cache is undefined here in IE, so don't use it! + for (i = 0; i < l; i++) { + c = sortList[i][0]; + order = sortList[i][1]; + // fallback to natural sort since it is more robust + s = /n/i.test(getCachedSortType(tc.parsers, c)) ? "Numeric" : "Text"; + s += order === 0 ? "" : "Desc"; + if (/Numeric/.test(s) && tc.strings[c]) { + // sort strings in numerical columns + if (typeof (tc.string[tc.strings[c]]) === 'boolean') { + dir = (order === 0 ? 1 : -1) * (tc.string[tc.strings[c]] ? -1 : 1); + } else { + dir = (tc.strings[c]) ? tc.string[tc.strings[c]] || 0 : 0; + } + } + var sort = $.tablesorter["sort" + s](table, a[c], b[c], c, colMax[c], dir); + if (sort) { return sort; } + } + return a[orgOrderCol] - b[orgOrderCol]; + }); + } + if (tc.debug) { benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time", sortTime); } + } + + function resortComplete($table, callback){ + $table.trigger('updateComplete'); + if (typeof callback === "function") { + callback($table[0]); + } + } + + function checkResort($table, flag, callback) { + // don't try to resort if the table is still processing + // this will catch spamming of the updateCell method + if (flag !== false && !$table[0].isProcessing) { + $table.trigger("sorton", [$table[0].config.sortList, function(){ + resortComplete($table, callback); + }]); + } else { + resortComplete($table, callback); + } + } + + function bindEvents(table){ + var c = table.config, + $this = c.$table, + j, downTime; + // apply event handling to headers + c.$headers + // http://stackoverflow.com/questions/5312849/jquery-find-self; + .find(c.selectorSort).add( c.$headers.filter(c.selectorSort) ) + .unbind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter') + .bind('mousedown.tablesorter mouseup.tablesorter sort.tablesorter keypress.tablesorter', function(e, external) { + // only recognize left clicks or enter + if ( ((e.which || e.button) !== 1 && !/sort|keypress/.test(e.type)) || (e.type === 'keypress' && e.which !== 13) ) { + return false; + } + // ignore long clicks (prevents resizable widget from initializing a sort) + if (e.type === 'mouseup' && external !== true && (new Date().getTime() - downTime > 250)) { return false; } + // set timer on mousedown + if (e.type === 'mousedown') { + downTime = new Date().getTime(); + return e.target.tagName === "INPUT" ? '' : !c.cancelSelection; + } + if (c.delayInit && !c.cache) { buildCache(table); } + // jQuery v1.2.6 doesn't have closest() + var $cell = /TH|TD/.test(this.tagName) ? $(this) : $(this).parents('th, td').filter(':first'), cell = $cell[0]; + if (!cell.sortDisabled) { + initSort(table, cell, e); + } + }); + if (c.cancelSelection) { + // cancel selection + c.$headers + .attr('unselectable', 'on') + .bind('selectstart', false) + .css({ + 'user-select': 'none', + 'MozUserSelect': 'none' // not needed for jQuery 1.8+ + }); + } + // apply easy methods that trigger bound events + $this + .unbind('sortReset update updateRows updateCell updateAll addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave '.split(' ').join('.tablesorter ')) + .bind("sortReset.tablesorter", function(e){ + e.stopPropagation(); + c.sortList = []; + setHeadersCss(table); + multisort(table); + appendToTable(table); + }) + .bind("updateAll.tablesorter", function(e, resort, callback){ + e.stopPropagation(); + ts.refreshWidgets(table, true, true); + ts.restoreHeaders(table); + buildHeaders(table); + bindEvents(table); + commonUpdate(table, resort, callback); + }) + .bind("update.tablesorter updateRows.tablesorter", function(e, resort, callback) { + e.stopPropagation(); + // update sorting (if enabled/disabled) + updateHeader(table); + commonUpdate(table, resort, callback); + }) + .bind("updateCell.tablesorter", function(e, cell, resort, callback) { + e.stopPropagation(); + $this.find(c.selectorRemove).remove(); + // get position from the dom + var l, row, icell, + $tb = $this.find('tbody'), + // update cache - format: function(s, table, cell, cellIndex) + // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr'); + tbdy = $tb.index( $(cell).parents('tbody').filter(':first') ), + $row = $(cell).parents('tr').filter(':first'); + cell = $(cell)[0]; // in case cell is a jQuery object + // tbody may not exist if update is initialized while tbody is removed for processing + if ($tb.length && tbdy >= 0) { + row = $tb.eq(tbdy).find('tr').index( $row ); + icell = cell.cellIndex; + l = c.cache[tbdy].normalized[row].length - 1; + c.cache[tbdy].row[table.config.cache[tbdy].normalized[row][l]] = $row; + c.cache[tbdy].normalized[row][icell] = c.parsers[icell].format( getElementText(table, cell, icell), table, cell, icell ); + checkResort($this, resort, callback); + } + }) + .bind("addRows.tablesorter", function(e, $row, resort, callback) { + e.stopPropagation(); + var i, rows = $row.filter('tr').length, + dat = [], l = $row[0].cells.length, + tbdy = $this.find('tbody').index( $row.parents('tbody').filter(':first') ); + // fixes adding rows to an empty table - see issue #179 + if (!c.parsers) { + buildParserCache(table); + } + // add each row + for (i = 0; i < rows; i++) { + // add each cell + for (j = 0; j < l; j++) { + dat[j] = c.parsers[j].format( getElementText(table, $row[i].cells[j], j), table, $row[i].cells[j], j ); + } + // add the row index to the end + dat.push(c.cache[tbdy].row.length); + // update cache + c.cache[tbdy].row.push([$row[i]]); + c.cache[tbdy].normalized.push(dat); + dat = []; + } + // resort using current settings + checkResort($this, resort, callback); + }) + .bind("sorton.tablesorter", function(e, list, callback, init) { + e.stopPropagation(); + $this.trigger("sortStart", this); + // update header count index + updateHeaderSortCount(table, list); + // set css for headers + setHeadersCss(table); + $this.trigger("sortBegin", this); + // sort the table and append it to the dom + multisort(table); + appendToTable(table, init); + if (typeof callback === "function") { + callback(table); + } + }) + .bind("appendCache.tablesorter", function(e, callback, init) { + e.stopPropagation(); + appendToTable(table, init); + if (typeof callback === "function") { + callback(table); + } + }) + .bind("applyWidgetId.tablesorter", function(e, id) { + e.stopPropagation(); + ts.getWidgetById(id).format(table, c, c.widgetOptions); + }) + .bind("applyWidgets.tablesorter", function(e, init) { + e.stopPropagation(); + // apply widgets + ts.applyWidget(table, init); + }) + .bind("refreshWidgets.tablesorter", function(e, all, dontapply){ + e.stopPropagation(); + ts.refreshWidgets(table, all, dontapply); + }) + .bind("destroy.tablesorter", function(e, c, cb){ + e.stopPropagation(); + ts.destroy(table, c, cb); + }); + } + + /* public methods */ + ts.construct = function(settings) { + return this.each(function() { + // if no thead or tbody, or tablesorter is already present, quit + if (!this.tHead || this.tBodies.length === 0 || this.hasInitialized === true) { + return (this.config && this.config.debug) ? log('stopping initialization! No thead, tbody or tablesorter has already been initialized') : ''; + } + // declare + var $this = $(this), table = this, + c, k = '', + m = $.metadata; + // initialization flag + table.hasInitialized = false; + // table is being processed flag + table.isProcessing = true; + // new blank config object + table.config = {}; + // merge and extend + c = $.extend(true, table.config, ts.defaults, settings); + // save the settings where they read + $.data(table, "tablesorter", c); + if (c.debug) { $.data( table, 'startoveralltimer', new Date()); } + // constants + c.supportsTextContent = $('x')[0].textContent === 'x'; + c.supportsDataObject = parseFloat($.fn.jquery) >= 1.4; + // digit sort text location; keeping max+/- for backwards compatibility + c.string = { 'max': 1, 'min': -1, 'max+': 1, 'max-': -1, 'zero': 0, 'none': 0, 'null': 0, 'top': true, 'bottom': false }; + // add table theme class only if there isn't already one there + if (!/tablesorter\-/.test($this.attr('class'))) { + k = (c.theme !== '' ? ' tablesorter-' + c.theme : ''); + } + c.$table = $this.addClass(c.tableClass + k); + c.$tbodies = $this.children('tbody:not(.' + c.cssInfoBlock + ')'); + // build headers + buildHeaders(table); + // fixate columns if the users supplies the fixedWidth option + // do this after theme has been applied + fixColumnWidth(table); + // try to auto detect column type, and store in tables config + buildParserCache(table); + // build the cache for the tbody cells + // delayInit will delay building the cache until the user starts a sort + if (!c.delayInit) { buildCache(table); } + // bind all header events and methods + bindEvents(table); + // get sort list from jQuery data or metadata + // in jQuery < 1.4, an error occurs when calling $this.data() + if (c.supportsDataObject && typeof $this.data().sortlist !== 'undefined') { + c.sortList = $this.data().sortlist; + } else if (m && ($this.metadata() && $this.metadata().sortlist)) { + c.sortList = $this.metadata().sortlist; + } + // apply widget init code + ts.applyWidget(table, true); + // if user has supplied a sort list to constructor + if (c.sortList.length > 0) { + $this.trigger("sorton", [c.sortList, {}, !c.initWidgets]); + } else if (c.initWidgets) { + // apply widget format + ts.applyWidget(table); + } + + // show processesing icon + if (c.showProcessing) { + $this + .unbind('sortBegin.tablesorter sortEnd.tablesorter') + .bind('sortBegin.tablesorter sortEnd.tablesorter', function(e) { + ts.isProcessing(table, e.type === 'sortBegin'); + }); + } + + // initialized + table.hasInitialized = true; + table.isProcessing = false; + if (c.debug) { + ts.benchmark("Overall initialization time", $.data( table, 'startoveralltimer')); + } + $this.trigger('tablesorter-initialized', table); + if (typeof c.initialized === 'function') { c.initialized(table); } + }); + }; + + // *** Process table *** + // add processing indicator + ts.isProcessing = function(table, toggle, $ths) { + table = $(table); + var c = table[0].config, + // default to all headers + $h = $ths || table.find('.' + c.cssHeader); + if (toggle) { + if (c.sortList.length > 0) { + // get headers from the sortList + $h = $h.filter(function(){ + // get data-column from attr to keep compatibility with jQuery 1.2.6 + return this.sortDisabled ? false : ts.isValueInArray( parseFloat($(this).attr('data-column')), c.sortList); + }); + } + $h.addClass(c.cssProcessing); + } else { + $h.removeClass(c.cssProcessing); + } + }; + + // detach tbody but save the position + // don't use tbody because there are portions that look for a tbody index (updateCell) + ts.processTbody = function(table, $tb, getIt){ + var holdr; + if (getIt) { + table.isProcessing = true; + $tb.before(''); + holdr = ($.fn.detach) ? $tb.detach() : $tb.remove(); + return holdr; + } + holdr = $(table).find('span.tablesorter-savemyplace'); + $tb.insertAfter( holdr ); + holdr.remove(); + table.isProcessing = false; + }; + + ts.clearTableBody = function(table) { + $(table)[0].config.$tbodies.empty(); + }; + + // restore headers + ts.restoreHeaders = function(table){ + var c = table.config; + // don't use c.$headers here in case header cells were swapped + c.$table.find(c.selectorHeaders).each(function(i){ + // only restore header cells if it is wrapped + // because this is also used by the updateAll method + if ($(this).find('.tablesorter-header-inner').length){ + $(this).html( c.headerContent[i] ); + } + }); + }; + + ts.destroy = function(table, removeClasses, callback){ + table = $(table)[0]; + if (!table.hasInitialized) { return; } + // remove all widgets + ts.refreshWidgets(table, true, true); + var $t = $(table), c = table.config, + $h = $t.find('thead:first'), + $r = $h.find('tr.' + c.cssHeaderRow).removeClass(c.cssHeaderRow), + $f = $t.find('tfoot:first > tr').children('th, td'); + // remove widget added rows, just in case + $h.find('tr').not($r).remove(); + // disable tablesorter + $t + .removeData('tablesorter') + .unbind('sortReset update updateAll updateRows updateCell addRows sorton appendCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd '.split(' ').join('.tablesorter ')); + c.$headers.add($f) + .removeClass(c.cssHeader + ' ' + c.cssAsc + ' ' + c.cssDesc) + .removeAttr('data-column'); + $r.find(c.selectorSort).unbind('mousedown.tablesorter mouseup.tablesorter keypress.tablesorter'); + ts.restoreHeaders(table); + if (removeClasses !== false) { + $t.removeClass(c.tableClass + ' tablesorter-' + c.theme); + } + // clear flag in case the plugin is initialized again + table.hasInitialized = false; + if (typeof callback === 'function') { + callback(table); + } + }; + + // *** sort functions *** + // regex used in natural sort + ts.regex = [ + /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters + /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, //date + /^0x[0-9a-f]+$/i // hex + ]; + + // Natural sort - https://github.com/overset/javascript-natural-sort + ts.sortText = function(table, a, b, col) { + if (a === b) { return 0; } + var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ], + r = ts.regex, xN, xD, yN, yD, xF, yF, i, mx; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (typeof c.textSorter === 'function') { return c.textSorter(a, b, table, col); } + // chunk/tokenize + xN = a.replace(r[0], '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); + yN = b.replace(r[0], '\\0$1\\0').replace(/\\0$/, '').replace(/^\\0/, '').split('\\0'); + // numeric, hex or date detection + xD = parseInt(a.match(r[2]),16) || (xN.length !== 1 && a.match(r[1]) && Date.parse(a)); + yD = parseInt(b.match(r[2]),16) || (xD && b.match(r[1]) && Date.parse(b)) || null; + // first try and sort Hex codes or Dates + if (yD) { + if ( xD < yD ) { return -1; } + if ( xD > yD ) { return 1; } + } + mx = Math.max(xN.length, yN.length); + // natural sorting through split numeric strings and default strings + for (i = 0; i < mx; i++) { + // find floats not starting with '0', string or 0 if not defined + xF = isNaN(xN[i]) ? xN[i] || 0 : parseFloat(xN[i]) || 0; + yF = isNaN(yN[i]) ? yN[i] || 0 : parseFloat(yN[i]) || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(xF) !== isNaN(yF)) { return (isNaN(xF)) ? 1 : -1; } + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + if (typeof xF !== typeof yF) { + xF += ''; + yF += ''; + } + if (xF < yF) { return -1; } + if (xF > yF) { return 1; } + } + return 0; + }; + + ts.sortTextDesc = function(table, a, b, col) { + if (a === b) { return 0; } + var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (typeof c.textSorter === 'function') { return c.textSorter(b, a, table, col); } + return ts.sortText(table, b, a); + }; + + // return text string value by adding up ascii value + // so the text is somewhat sorted when using a digital sort + // this is NOT an alphanumeric sort + ts.getTextValue = function(a, mx, d) { + if (mx) { + // make sure the text value is greater than the max numerical value (mx) + var i, l = a ? a.length : 0, n = mx + d; + for (i = 0; i < l; i++) { + n += a.charCodeAt(i); + } + return d * n; + } + return 0; + }; + + ts.sortNumeric = function(table, a, b, col, mx, d) { + if (a === b) { return 0; } + var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : -e || -1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : e || 1; } + if (isNaN(a)) { a = ts.getTextValue(a, mx, d); } + if (isNaN(b)) { b = ts.getTextValue(b, mx, d); } + return a - b; + }; + + ts.sortNumericDesc = function(table, a, b, col, mx, d) { + if (a === b) { return 0; } + var c = table.config, e = c.string[ (c.empties[col] || c.emptyTo ) ]; + if (a === '' && e !== 0) { return typeof e === 'boolean' ? (e ? -1 : 1) : e || 1; } + if (b === '' && e !== 0) { return typeof e === 'boolean' ? (e ? 1 : -1) : -e || -1; } + if (isNaN(a)) { a = ts.getTextValue(a, mx, d); } + if (isNaN(b)) { b = ts.getTextValue(b, mx, d); } + return b - a; + }; + + // used when replacing accented characters during sorting + ts.characterEquivalents = { + "a" : "\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5", // áàâãäąå + "A" : "\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5", // ÁÀÂÃÄĄÅ + "c" : "\u00e7\u0107\u010d", // çćč + "C" : "\u00c7\u0106\u010c", // ÇĆČ + "e" : "\u00e9\u00e8\u00ea\u00eb\u011b\u0119", // éèêëěę + "E" : "\u00c9\u00c8\u00ca\u00cb\u011a\u0118", // ÉÈÊËĚĘ + "i" : "\u00ed\u00ec\u0130\u00ee\u00ef\u0131", // íìİîïı + "I" : "\u00cd\u00cc\u0130\u00ce\u00cf", // ÍÌİÎÏ + "o" : "\u00f3\u00f2\u00f4\u00f5\u00f6", // óòôõö + "O" : "\u00d3\u00d2\u00d4\u00d5\u00d6", // ÓÒÔÕÖ + "ss": "\u00df", // ß (s sharp) + "SS": "\u1e9e", // ẞ (Capital sharp s) + "u" : "\u00fa\u00f9\u00fb\u00fc\u016f", // úùûüů + "U" : "\u00da\u00d9\u00db\u00dc\u016e" // ÚÙÛÜŮ + }; + ts.replaceAccents = function(s) { + var a, acc = '[', eq = ts.characterEquivalents; + if (!ts.characterRegex) { + ts.characterRegexArray = {}; + for (a in eq) { + if (typeof a === 'string') { + acc += eq[a]; + ts.characterRegexArray[a] = new RegExp('[' + eq[a] + ']', 'g'); + } + } + ts.characterRegex = new RegExp(acc + ']'); + } + if (ts.characterRegex.test(s)) { + for (a in eq) { + if (typeof a === 'string') { + s = s.replace( ts.characterRegexArray[a], a ); + } + } + } + return s; + }; + + // *** utilities *** + ts.isValueInArray = function(v, a) { + var i, l = a.length; + for (i = 0; i < l; i++) { + if (a[i][0] === v) { + return true; + } + } + return false; + }; + + ts.addParser = function(parser) { + var i, l = ts.parsers.length, a = true; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === parser.id.toLowerCase()) { + a = false; + } + } + if (a) { + ts.parsers.push(parser); + } + }; + + ts.getParserById = function(name) { + var i, l = ts.parsers.length; + for (i = 0; i < l; i++) { + if (ts.parsers[i].id.toLowerCase() === (name.toString()).toLowerCase()) { + return ts.parsers[i]; + } + } + return false; + }; + + ts.addWidget = function(widget) { + ts.widgets.push(widget); + }; + + ts.getWidgetById = function(name) { + var i, w, l = ts.widgets.length; + for (i = 0; i < l; i++) { + w = ts.widgets[i]; + if (w && w.hasOwnProperty('id') && w.id.toLowerCase() === name.toLowerCase()) { + return w; + } + } + }; + + ts.applyWidget = function(table, init) { + table = $(table)[0]; // in case this is called externally + var c = table.config, + wo = c.widgetOptions, + widgets = [], + time, i, w, wd; + if (c.debug) { time = new Date(); } + if (c.widgets.length) { + // ensure unique widget ids + c.widgets = $.grep(c.widgets, function(v, k){ + return $.inArray(v, c.widgets) === k; + }); + // build widget array & add priority as needed + $.each(c.widgets || [], function(i,n){ + wd = ts.getWidgetById(n); + if (wd && wd.id) { + // set priority to 10 if not defined + if (!wd.priority) { wd.priority = 10; } + widgets[i] = wd; + } + }); + // sort widgets by priority + widgets.sort(function(a, b){ + return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1; + }); + + // add/update selected widgets + $.each(widgets, function(i,w){ + if (w) { + if (init) { + if (w.hasOwnProperty('options')) { + wo = table.config.widgetOptions = $.extend( true, {}, w.options, wo ); + } + if (w.hasOwnProperty('init')) { + w.init(table, w, c, wo); + } + } else if (!init && w.hasOwnProperty('format')) { + w.format(table, c, wo, false); + } + } + }); + } + if (c.debug) { + w = c.widgets.length; + benchmark("Completed " + (init === true ? "initializing " : "applying ") + w + " widget" + (w !== 1 ? "s" : ""), time); + } + }; + + ts.refreshWidgets = function(table, doAll, dontapply) { + table = $(table)[0]; // see issue #243 + var i, c = table.config, + cw = c.widgets, + w = ts.widgets, l = w.length; + // remove previous widgets + for (i = 0; i < l; i++){ + if ( w[i] && w[i].id && (doAll || $.inArray( w[i].id, cw ) < 0) ) { + if (c.debug) { log( 'Refeshing widgets: Removing ' + w[i].id ); } + if (w[i].hasOwnProperty('remove')) { w[i].remove(table, c, c.widgetOptions); } + } + } + if (dontapply !== true) { + ts.applyWidget(table, doAll); + } + }; + + // get sorter, string, empty, etc options for each column from + // jQuery data, metadata, header option or header class name ("sorter-false") + // priority = jQuery data > meta > headers option > header class name + ts.getData = function(h, ch, key) { + var val = '', $h = $(h), m, cl; + if (!$h.length) { return ''; } + m = $.metadata ? $h.metadata() : false; + cl = ' ' + ($h.attr('class') || ''); + if (typeof $h.data(key) !== 'undefined' || typeof $h.data(key.toLowerCase()) !== 'undefined'){ + // "data-lockedOrder" is assigned to "lockedorder"; but "data-locked-order" is assigned to "lockedOrder" + // "data-sort-initial-order" is assigned to "sortInitialOrder" + val += $h.data(key) || $h.data(key.toLowerCase()); + } else if (m && typeof m[key] !== 'undefined') { + val += m[key]; + } else if (ch && typeof ch[key] !== 'undefined') { + val += ch[key]; + } else if (cl !== ' ' && cl.match(' ' + key + '-')) { + // include sorter class name "sorter-text", etc; now works with "sorter-my-custom-parser" + val = cl.match( new RegExp('\\s' + key + '-([\\w-]+)') )[1] || ''; + } + return $.trim(val); + }; + + ts.formatFloat = function(s, table) { + if (typeof s !== 'string' || s === '') { return s; } + // allow using formatFloat without a table; defaults to US number format + var i, + t = table && table.config ? table.config.usNumberFormat !== false : + typeof table !== "undefined" ? table : true; + if (t) { + // US Format - 1,234,567.89 -> 1234567.89 + s = s.replace(/,/g,''); + } else { + // German Format = 1.234.567,89 -> 1234567.89 + // French Format = 1 234 567,89 -> 1234567.89 + s = s.replace(/[\s|\.]/g,'').replace(/,/g,'.'); + } + if(/^\s*\([.\d]+\)/.test(s)) { + // make (#) into a negative number -> (10) = -10 + s = s.replace(/^\s*\(/,'-').replace(/\)/,''); + } + i = parseFloat(s); + // return the text instead of zero + return isNaN(i) ? $.trim(s) : i; + }; + + ts.isDigit = function(s) { + // replace all unwanted chars and match + return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : true; + }; + + }() + }); + + // make shortcut + var ts = $.tablesorter; + + // extend plugin scope + $.fn.extend({ + tablesorter: ts.construct + }); + + // add default parsers + ts.addParser({ + id: "text", + is: function() { + return true; + }, + format: function(s, table) { + var c = table.config; + if (s) { + s = $.trim( c.ignoreCase ? s.toLocaleLowerCase() : s ); + s = c.sortLocaleCompare ? ts.replaceAccents(s) : s; + } + return s; + }, + type: "text" + }); + + ts.addParser({ + id: "digit", + is: function(s) { + return ts.isDigit(s); + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "currency", + is: function(s) { + return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[,. ]/g,'')); // £$€¤¥¢ + }, + format: function(s, table) { + var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ""), table); + return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "ipAddress", + is: function(s) { + return (/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/).test(s); + }, + format: function(s, table) { + var i, a = s ? s.split(".") : '', + r = "", + l = a.length; + for (i = 0; i < l; i++) { + r += ("00" + a[i]).slice(-3); + } + return s ? ts.formatFloat(r, table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "url", + is: function(s) { + return (/^(https?|ftp|file):\/\//).test(s); + }, + format: function(s) { + return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s; + }, + type: "text" + }); + + ts.addParser({ + id: "isoDate", + is: function(s) { + return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s); + }, + format: function(s, table) { + return s ? ts.formatFloat((s !== "") ? (new Date(s.replace(/-/g, "/")).getTime() || "") : "", table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "percent", + is: function(s) { + return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15; + }, + format: function(s, table) { + return s ? ts.formatFloat(s.replace(/%/g, ""), table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "usLongDate", + is: function(s) { + // two digit years are not allowed cross-browser + // Jan 01, 2013 12:34:56 PM or 01 Jan 2013 + return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s); + }, + format: function(s, table) { + return s ? ts.formatFloat( (new Date(s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ''), table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "shortDate", // "mmddyyyy", "ddmmyyyy" or "yyyymmdd" + is: function(s) { + // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included + return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g," ").replace(/[\-.,]/g, "/")); + }, + format: function(s, table, cell, cellIndex) { + if (s) { + var c = table.config, ci = c.headerList[cellIndex], + format = ci.dateFormat || ts.getData( ci, c.headers[cellIndex], 'dateFormat') || c.dateFormat; + s = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/"); // escaped - because JSHint in Firefox was showing it as an error + if (format === "mmddyyyy") { + s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$1/$2"); + } else if (format === "ddmmyyyy") { + s = s.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, "$3/$2/$1"); + } else if (format === "yyyymmdd") { + s = s.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$1/$2/$3"); + } + } + return s ? ts.formatFloat( (new Date(s).getTime() || ''), table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "time", + is: function(s) { + return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s); + }, + format: function(s, table) { + return s ? ts.formatFloat( (new Date("2000/01/01 " + s.replace(/(\S)([AP]M)$/i, "$1 $2")).getTime() || ""), table) : s; + }, + type: "numeric" + }); + + ts.addParser({ + id: "metadata", + is: function() { + return false; + }, + format: function(s, table, cell) { + var c = table.config, + p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; + return $(cell).metadata()[p]; + }, + type: "numeric" + }); + + // add default widgets + ts.addWidget({ + id: "zebra", + priority: 90, + format: function(table, c, wo) { + var $tb, $tv, $tr, row, even, time, k, l, + child = new RegExp(c.cssChildRow, 'i'), + b = c.$tbodies; + if (c.debug) { + time = new Date(); + } + for (k = 0; k < b.length; k++ ) { + // loop through the visible rows + $tb = b.eq(k); + l = $tb.children('tr').length; + if (l > 1) { + row = 0; + $tv = $tb.children('tr:visible'); + // revered back to using jQuery each - strangely it's the fastest method + /*jshint loopfunc:true */ + $tv.each(function(){ + $tr = $(this); + // style children rows the same way the parent row was styled + if (!child.test(this.className)) { row++; } + even = (row % 2 === 0); + $tr.removeClass(wo.zebra[even ? 1 : 0]).addClass(wo.zebra[even ? 0 : 1]); + }); + } + } + if (c.debug) { + ts.benchmark("Applying Zebra widget", time); + } + }, + remove: function(table, c, wo){ + var k, $tb, + b = c.$tbodies, + rmv = (wo.zebra || [ "even", "odd" ]).join(' '); + for (k = 0; k < b.length; k++ ){ + $tb = $.tablesorter.processTbody(table, b.eq(k), true); // remove tbody + $tb.children().removeClass(rmv); + $.tablesorter.processTbody(table, $tb, false); // restore tbody + } + } + }); + +})(jQuery); diff --git a/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets-filter-formatter.js b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets-filter-formatter.js new file mode 100644 index 000000000..83bb8b793 --- /dev/null +++ b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets-filter-formatter.js @@ -0,0 +1,826 @@ +/*! Filter widget formatter functions - updated 6/4/2013 + * requires: tableSorter 2.7.7+ and jQuery 1.4.3+ + * + * uiSpinner (jQuery UI spinner) + * uiSlider (jQuery UI slider) + * uiRange (jQuery UI range slider) + * uiDateCompare (jQuery UI datepicker; 1 input) + * uiDatepicker (jQuery UI datepicker; 2 inputs, filter range) + * html5Number (spinner) + * html5Range (slider) + * html5Color (color) + */ +/*jshint browser:true, jquery:true, unused:false */ +/*global jQuery: false */ +;(function($){ +"use strict"; +$.tablesorter = $.tablesorter || {}; + +$.tablesorter.filterFormatter = { + + /**********************\ + jQuery UI Spinner + \**********************/ + uiSpinner: function($cell, indx, spinnerDef) { + var o = $.extend({ + min : 0, + max : 100, + step : 1, + value : 1, + delayed : true, + addToggle : true, + disabled : false, + exactMatch : true, + compare : '' + }, spinnerDef ), + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update (.tsfilter) namespace trigger by filter widget + .bind('change.tsfilter', function(){ + updateSpinner({ value: this.value, delayed: false }); + }), + $shcell = [], + c = $cell.closest('table')[0].config, + + // this function updates the hidden input and adds the current values to the header cell text + updateSpinner = function(ui) { + var chkd = true, state, + // ui is not undefined on create + v = ui && ui.value && $.tablesorter.formatFloat((ui.value + '').replace(/[><=]/g,'')) || $cell.find('.spinner').val() || o.value; + if (o.addToggle) { + chkd = $cell.find('.toggle').is(':checked'); + } + state = o.disabled || !chkd ? 'disable' : 'enable'; + $cell.find('.filter') + // add equal to the beginning, so we filter exact numbers + .val( chkd ? (o.compare ? o.compare : o.exactMatch ? '=' : '') + v : '' ) + .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end() + .find('.spinner').spinner(state).val(v); + // update sticky header cell + if ($shcell.length) { + $shcell.find('.spinner').spinner(state).val(v); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + } + }; + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldspin = o.spin; + o.create = function(event, ui) { + updateSpinner(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.spin = function(event, ui) { + updateSpinner(ui); + if (typeof o.oldspin === 'function') { o.oldspin(event, ui); } + }; + if (o.addToggle) { + $('
') + .appendTo($cell) + .find('.toggle') + .bind('change', function(){ + updateSpinner(); + }); + } + // make sure we use parsed data + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + // add a jQuery UI spinner! + $('') + .val(o.value) + .appendTo($cell) + .spinner(o) + .bind('change keyup', function(e){ + updateSpinner(); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + if (o.addToggle) { + $('
') + .appendTo($shcell) + .find('.toggle') + .bind('change', function(){ + $cell.find('.toggle')[0].checked = this.checked; + updateSpinner(); + }); + } + // add a jQuery UI spinner! + $('') + .val(o.value) + .appendTo($shcell) + .spinner(o) + .bind('change keyup', function(e){ + $cell.find('.spinner').val( this.value ); + updateSpinner(); + }); + }); + + // on reset + c.$table.bind('filterReset', function(){ + // turn off the toggle checkbox + if (o.addToggle) { + $cell.find('.toggle')[0].checked = false; + } + updateSpinner(); + }); + + updateSpinner(); + return $input; + }, + + /**********************\ + jQuery UI Slider + \**********************/ + uiSlider: function($cell, indx, sliderDef) { + var o = $.extend({ + value : 0, + min : 0, + max : 100, + step : 1, + range : "min", + delayed : true, + valueToHeader : false, + exactMatch : true, + compare : '', + allText : 'all' + }, sliderDef ), + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update (.tsfilter) namespace trigger by filter widget + .bind('change.tsfilter', function(){ + updateSlider({ value: this.value }); + }), + $shcell = [], + c = $cell.closest('table')[0].config, + + // this function updates the hidden input and adds the current values to the header cell text + updateSlider = function(ui) { + // ui is not undefined on create + var v = typeof ui !== "undefined" ? $.tablesorter.formatFloat((ui.value + '').replace(/[><=]/g,'')) || o.min : o.value, + val = o.compare ? v : v === o.min ? o.allText : v, + result = o.compare + val; + if (o.valueToHeader) { + // add range indication to the header cell above! + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')'); + } else { + // add values to the handle data-value attribute so the css tooltip will work properly + $cell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result); + } + // update the hidden input; + // ****** ADD AN EQUAL SIGN TO THE BEGINNING! <- this makes the slide exactly match the number ****** + // when the value is at the minimum, clear the hidden input so all rows will be seen + $cell.find('.filter') + .val( ( o.compare ? o.compare + v : v === o.min ? '' : (o.exactMatch ? '=' : '') + v ) ) + .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end() + .find('.slider').slider('value', v); + + // update sticky header cell + if ($shcell.length) { + $shcell.find('.slider').slider('value', v); + if (o.valueToHeader) { + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(' (' + result + ')'); + } else { + $shcell.find('.ui-slider-handle').addClass('value-popup').attr('data-value', result); + } + } + + }; + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + + // add span to header for value - only works if the line in the updateSlider() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldslide = o.slide; + o.create = function(event, ui) { + updateSlider(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.slide = function(event, ui) { + updateSlider(ui); + if (typeof o.oldslide === 'function') { o.oldslide(event, ui); } + }; + // add a jQuery UI slider! + $('
') + .appendTo($cell) + .slider(o); + + // on reset + c.$table.bind('filterReset', function(){ + $cell.find('.slider').slider('value', o.value); + updateSlider(); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + + // add a jQuery UI slider! + $('
') + .val(o.value) + .appendTo($shcell) + .slider(o) + .bind('change keyup', function(e){ + $cell.find('.slider').val( this.value ); + updateSlider(); + }); + + }); + + return $input; + }, + + /*************************\ + jQuery UI Range Slider (2 handles) + \*************************/ + uiRange: function($cell, indx, rangeDef) { + var o = $.extend({ + values : [0, 100], + min : 0, + max : 100, + range : true, + delayed : true, + valueToHeader : false + }, rangeDef ), + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update (.tsfilter) namespace trigger by filter widget + .bind('change.tsfilter', function(){ + var v = this.value.split(' - '); + if (this.value === '') { v = [ o.min, o.max ]; } + if (v && v[1]) { + updateUiRange({ values: v, delay: false }); + } + }), + $shcell = [], + c = $cell.closest('table')[0].config, + + // this function updates the hidden input and adds the current values to the header cell text + updateUiRange = function(ui) { + // ui.values are undefined for some reason on create + var val = ui && ui.values || o.values, + result = val[0] + ' - ' + val[1], + // make range an empty string if entire range is covered so the filter row will hide (if set) + range = val[0] === o.min && val[1] === o.max ? '' : result; + if (o.valueToHeader) { + // add range indication to the header cell above (if not using the css method)! + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')'); + } else { + // add values to the handle data-value attribute so the css tooltip will work properly + $cell.find('.ui-slider-handle') + .addClass('value-popup') + .eq(0).attr('data-value', val[0]).end() // adding value to data attribute + .eq(1).attr('data-value', val[1]); // value popup shown via css + } + // update the hidden input + $cell.find('.filter').val(range) + .trigger('search', ui && typeof ui.delayed === 'boolean' ? ui.delayed : o.delayed).end() + .find('.range').slider('values', val); + // update sticky header cell + if ($shcell.length) { + $shcell.find('.range').slider('values', val); + if (o.valueToHeader) { + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.currange').html(' (' + result + ')'); + } else { + $shcell.find('.ui-slider-handle') + .addClass('value-popup') + .eq(0).attr('data-value', val[0]).end() // adding value to data attribute + .eq(1).attr('data-value', val[1]); // value popup shown via css + } + } + + }; + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + + // add span to header for value - only works if the line in the updateUiRange() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + // add callbacks; preserve added callbacks + o.oldcreate = o.create; + o.oldslide = o.slide; + // add a jQuery UI range slider! + o.create = function(event, ui) { + updateUiRange(); // ui is an empty object on create + if (typeof o.oldcreate === 'function') { o.oldcreate(event, ui); } + }; + o.slide = function(event, ui) { + updateUiRange(ui); + if (typeof o.oldslide === 'function') { o.oldslide(event, ui); } + }; + $('
') + .appendTo($cell) + .slider(o); + + // on reset + c.$table.bind('filterReset', function(){ + $cell.find('.range').slider('values', o.values); + updateUiRange(); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + + // add a jQuery UI slider! + $('
') + .val(o.value) + .appendTo($shcell) + .slider(o) + .bind('change keyup', function(e){ + $cell.find('.range').val( this.value ); + updateUiRange(); + }); + + }); + + // return the hidden input so the filter widget has a reference to it + return $input; + }, + + /*************************\ + jQuery UI Datepicker compare (1 input) + \*************************/ + uiDateCompare: function($cell, indx, defDate) { + var o = $.extend({ + defaultDate : '', + cellText : '', + changeMonth : true, + changeYear : true, + numberOfMonths : 1, + compare : '' + }, defDate), + $hdr = $cell.closest('thead').find('th[data-column=' + indx + ']'), + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update (.tsfilter) namespace trigger by filter widget + .bind('change.tsfilter', function(){ + var v = this.value; + if (v) { + o.onClose(v); + } + }), + t, $shcell = [], + c = $cell.closest('table')[0].config; + + // make sure we're using parsed dates in the search + $hdr.addClass('filter-parsed'); + // Add date range picker + t = ''; + $(t).appendTo($cell); + + // add callbacks; preserve added callbacks + o.oldonClose = o.onClose; + + o.onClose = function( selectedDate, ui ) { + var date = new Date(selectedDate + ( o.compare.match('<') ? ' 23:59:59' : '' )).getTime() || ''; + $cell + // update hidden input + .find('.dateCompare').val( o.compare + date ) + .trigger('search').end() + .find('.date') + .datepicker('setDate', selectedDate); + + // update sticky header cell + if ($shcell.length) { + $shcell.find('.date').datepicker('setDate', selectedDate); + } + + if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); } + }; + $cell.find('.date').datepicker(o); + + if (o.filterDate) { + $cell.find('.date').datepicker('setDate', o.filterDate); + } + + // on reset + c.$table.bind('filterReset', function(){ + $cell.find('.date').val('').datepicker('option', 'currentText', '' ); + if ($shcell.length) { + $shcell.find('.date').val('').datepicker('option', 'currentText', '' ); + } + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + // add a jQuery datepicker! + $shcell + .append(t) + .find('.date') + .datepicker(o); + }); + + // return the hidden input so the filter widget has a reference to it + return $input.val( o.defaultDate ? o.defaultDate : '' ); + }, + + /*************************\ + jQuery UI Datepicker (2 inputs) + \*************************/ + uiDatepicker: function($cell, indx, defDate) { + var o = $.extend({ + from : '', + to : '', + textFrom : 'from', + textTo : 'to', + changeMonth : true, + changeYear : true, + numberOfMonths : 1 + }, defDate), + t, closeFrom, $shcell = [], + // Add a hidden input to hold the range values + $input = $('') + .appendTo($cell) + // hidden filter update (.tsfilter) namespace trigger by filter widget + .bind('change.tsfilter', function(){ + var v = this.value; + if (v.match(' - ')) { + v = v.split(' - '); + $cell.find('.dateTo').val(v[1]); + closeFrom(v[0]); + } else if (v.match('>=')) { + closeFrom( v.replace('>=', '') ); + } else if (v.match('<=')) { + o.onClose( v.replace('<=', '') ); + } + }), + c = $cell.closest('table')[0].config; + + // make sure we're using parsed dates in the search + $cell.closest('thead').find('th[data-column=' + indx + ']').addClass('filter-parsed'); + // Add date range picker + t = ''; + $(t).appendTo($cell); + + // add callbacks; preserve added callbacks + o.oldonClose = o.onClose; + + o.defaultDate = o.from || o.defaultDate; + + closeFrom = o.onClose = function( selectedDate, ui ) { + var from = ( (new Date(selectedDate)).getTime() || ''), + to = (new Date($cell.find('.dateTo').val() + ' 23:59:59').getTime() || ''), + range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : ''); + $cell + .find('.dateTo').datepicker('option', 'minDate', selectedDate ).end() + .find('.dateFrom').val(selectedDate).end() + // update hidden input + .find('.dateRange').val(range) + .trigger('search'); + // update sticky header cell + if ($shcell.length) { + $shcell + .find('.dateTo').datepicker('option', 'minDate', selectedDate ).end() + .find('.dateFrom').val(selectedDate); + } + if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); } + }; + + $cell.find('.dateFrom').datepicker(o); + o.defaultDate = o.to || '+7d'; // set to date +7 days from today (if not defined) + o.onClose = function( selectedDate, ui ) { + var from = new Date( $cell.find('.dateFrom').val() ).getTime() || '', + to = new Date( selectedDate + ' 23:59:59' ).getTime() || '', + range = from ? ( to ? from + ' - ' + to : '>=' + from ) : (to ? '<=' + to : ''); + $cell + .find('.dateFrom').datepicker('option', 'maxDate', selectedDate ).end() + .find('.dateTo').val(selectedDate).end() + .find('.dateRange').val(range) + .trigger('search'); + // update sticky header cell + if ($shcell.length) { + $shcell + .find('.dateFrom').datepicker('option', 'maxDate', selectedDate ).end() + .find('.dateTo').val(selectedDate); + } + if (typeof o.oldonClose === 'function') { o.oldonClose(selectedDate, ui); } + }; + $cell.find('.dateTo').datepicker(o); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + // add a jQuery datepicker! + $shcell.append(t).find('.dateTo').datepicker(o); + o.defaultDate = o.from || o.defaultDate || new Date(); + o.onClose = closeFrom; + $shcell.find('.dateFrom').datepicker(o); + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + $cell.find('.dateFrom, .dateTo').val(''); + if ($shcell.length) { + $shcell.find('.dateFrom, .dateTo').val(''); + } + }); + + // return the hidden input so the filter widget has a reference to it + t = o.from ? ( o.to ? o.from + ' - ' + o.to : '>=' + o.from ) : (o.to ? '<=' + o.to : ''); + return $input.val( t ); + }, + + /**********************\ + HTML5 Number (spinner) + \**********************/ + html5Number : function($cell, indx, def5Num) { + var t, o = $.extend({ + value : 0, + min : 0, + max : 100, + step : 1, + delayed : true, + disabled : false, + addToggle : true, + exactMatch : true, + compare : '', + skipTest: false + }, def5Num), + + // test browser for HTML5 range support + $number = $('').appendTo($cell), + // test if HTML5 number is supported - from Modernizr + numberSupported = o.skipTest || $number.attr('type') === 'number' && $number.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateNumber = function(v, delayed){ + var chkd = o.addToggle ? $cell.find('.toggle').is(':checked') : true; + $cell.find('input[type=hidden]') + // add equal to the beginning, so we filter exact numbers + .val( !o.addToggle || chkd ? (o.compare ? o.compare : o.exactMatch ? '=' : '') + v : '' ) + .trigger('search', delayed ? delayed : o.delayed).end() + .find('.number').val(v); + if ($cell.find('.number').length) { + $cell.find('.number')[0].disabled = (o.disabled || !chkd); + } + // update sticky header cell + if ($shcell.length) { + $shcell.find('.number').val(v)[0].disabled = (o.disabled || !chkd); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + } + }; + $number.remove(); + + if (numberSupported) { + t = o.addToggle ? '
' : ''; + t += ''; + // add HTML5 number (spinner) + $cell + .html(t + '') + .find('.toggle, .number').bind('change', function(){ + updateNumber( $cell.find('.number').val() ); + }) + .closest('thead').find('th[data-column=' + indx + ']') + .addClass('filter-parsed') // get exact numbers from column + // on reset + .closest('table').bind('filterReset', function(){ + // turn off the toggle checkbox + if (o.addToggle) { + $cell.find('.toggle')[0].checked = false; + if ($shcell.length) { + $shcell.find('.toggle')[0].checked = false; + } + } + updateNumber( $cell.find('.number').val() ); + }); + + // hidden filter update (.tsfilter) namespace trigger by filter widget + $cell.find('input[type=hidden]').bind('change.tsfilter', function(){ + updateNumber( this.value ); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + $shcell + .html(t) + .find('.toggle, .number').bind('change', function(){ + updateNumber( $shcell.find('.number').val() ); + }); + updateNumber( $cell.find('.number').val() ); + }); + + updateNumber( $cell.find('.number').val() ); + + } + + return numberSupported ? $cell.find('input[type="hidden"]') : $(''); + }, + + /**********************\ + HTML5 range slider + \**********************/ + html5Range : function($cell, indx, def5Range) { + var t, o = $.extend({ + value : 0, + min : 0, + max : 100, + step : 1, + delayed : true, + valueToHeader : true, + exactMatch : true, + compare : '', + allText : 'all', + skipTest : false + }, def5Range), + + // test browser for HTML5 range support + $range = $('').appendTo($cell), + // test if HTML5 range is supported - from Modernizr (but I left out the method to detect in Safari 2-4) + // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/inputtypes.js + rangeSupported = o.skipTest || $range.attr('type') === 'range' && $range.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateRange = function(v, delayed){ + /*jshint eqeqeq:false */ + v = (v + '').replace(/[<>=]/g,'') || o.min; // hidden input changes may include compare symbols + var t = ' (' + (o.compare ? o.compare + v : v == o.min ? o.allText : v) + ')'; + $cell.find('input[type=hidden]') + // add equal to the beginning, so we filter exact numbers + .val( ( o.compare ? o.compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ) ) + //( val == o.min ? '' : val + (o.exactMatch ? '=' : '')) + .trigger('search', delayed ? delayed : o.delayed).end() + .find('.range').val(v); + // or add current value to the header cell, if desired + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t); + // update sticky header cell + if ($shcell.length) { + $shcell.find('.range').val(v); + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curvalue').html(t); + } + }; + $range.remove(); + + if (rangeSupported) { + // add HTML5 range + $cell + .html('') + .closest('thead').find('th[data-column=' + indx + ']') + .addClass('filter-parsed') // get exact numbers from column + // add span to header for the current slider value + .find('.tablesorter-header-inner').append(''); + + $cell.find('.range').bind('change', function(){ + updateRange( this.value ); + }); + + // hidden filter update (.tsfilter) namespace trigger by filter widget + $cell.find('input[type=hidden]').bind('change.tsfilter', function(){ + /*jshint eqeqeq:false */ + var v = this.value; + if (v !== this.lastValue) { + this.lastValue = ( o.compare ? o.compare + v : ( v == o.min ? '' : ( o.exactMatch ? '=' : '' ) + v ) ); + this.value = this.lastValue; + updateRange( v ); + } + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx).empty(); + $shcell + .html('') + .find('.range').bind('change', function(){ + updateRange( $shcell.find('.range').val() ); + }); + updateRange( $cell.find('.range').val() ); + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + // just turn off the colorpicker + updateRange(o.value); + }); + + updateRange( $cell.find('.range').val() ); + + } + + return rangeSupported ? $cell.find('input[type="hidden"]') : $(''); + }, + + /**********************\ + HTML5 Color picker + \**********************/ + html5Color: function($cell, indx, defColor) { + var t, o = $.extend({ + value : '#000000', + disabled : false, + addToggle : true, + exactMatch : true, + valueToHeader : false, + skipTest : false + }, defColor), + // Add a hidden input to hold the range values + $color = $('').appendTo($cell), + // test if HTML5 color is supported - from Modernizr + colorSupported = o.skipTest || $color.attr('type') === 'color' && $color.val() !== 'test', + $shcell = [], + c = $cell.closest('table')[0].config, + + updateColor = function(v){ + v = v || o.value; + var chkd = true, + t = ' (' + v + ')'; + if (o.addToggle) { + chkd = $cell.find('.toggle').is(':checked'); + } + if ($cell.find('.colorpicker').length) { + $cell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd); + } + + $cell.find('input[type=hidden]') + .val( chkd ? v + (o.exactMatch ? '=' : '') : '' ) + .trigger('search'); + if (o.valueToHeader) { + // add current color to the header cell + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t); + } else { + // current color to span in cell + $cell.find('.currentColor').html(t); + } + + // update sticky header cell + if ($shcell.length) { + $shcell.find('.colorpicker').val(v)[0].disabled = (o.disabled || !chkd); + if (o.addToggle) { + $shcell.find('.toggle')[0].checked = chkd; + } + if (o.valueToHeader) { + // add current color to the header cell + $shcell.closest('thead').find('th[data-column=' + indx + ']').find('.curcolor').html(t); + } else { + // current color to span in cell + $shcell.find('.currentColor').html(t); + } + } + }; + $color.remove(); + + if (colorSupported) { + // add HTML5 color picker + t = '
'; + t += o.addToggle ? '
' : ''; + t += ''; + t += (o.valueToHeader ? '' : '(#000000)') + '
'; + $cell.html(t); + + // add span to header for the current color value - only works if the line in the updateColor() function is also un-commented out + if (o.valueToHeader) { + $cell.closest('thead').find('th[data-column=' + indx + ']').find('.tablesorter-header-inner').append(''); + } + + $cell.find('.toggle, .colorpicker').bind('change', function(){ + updateColor( $cell.find('.colorpicker').val() ); + }); + + // hidden filter update (.tsfilter) namespace trigger by filter widget + $cell.find('input[type=hidden]').bind('change.tsfilter', function(){ + updateColor( this.value ); + }); + + // on reset + $cell.closest('table').bind('filterReset', function(){ + // just turn off the colorpicker + $cell.find('.toggle')[0].checked = false; + updateColor( $cell.find('.colorpicker').val() ); + }); + + // has sticky headers? + c.$table.bind('stickyHeadersInit', function(){ + $shcell = c.widgetOptions.$sticky.find('.tablesorter-filter-row').children().eq(indx); + $shcell + .html(t) + .find('.toggle, .colorpicker').bind('change', function(){ + updateColor( $shcell.find('.colorpicker').val() ); + }); + updateColor( $shcell.find('.colorpicker').val() ); + }); + + updateColor( o.value ); + } + return colorSupported ? $cell.find('input[type="hidden"]') : $(''); + } + +}; + +})(jQuery); \ No newline at end of file diff --git a/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets.js b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets.js new file mode 100644 index 000000000..69c82b62f --- /dev/null +++ b/templates/admin/default/assets/js/tablesorter/jquery.tablesorter.widgets.js @@ -0,0 +1,1208 @@ +/*! tableSorter 2.8+ widgets - updated 6/4/2013 + * + * Column Styles + * Column Filters + * Column Resizing + * Sticky Header + * UI Theme (generalized) + * Save Sort + * [ "columns", "filter", "resizable", "stickyHeaders", "uitheme", "saveSort" ] + */ +/*jshint browser:true, jquery:true, unused:false, loopfunc:true */ +/*global jQuery: false, localStorage: false, navigator: false */ +;(function($){ +"use strict"; +var ts = $.tablesorter = $.tablesorter || {}; + +ts.themes = { + "bootstrap" : { + table : 'table table-bordered table-striped', + header : 'bootstrap-header', // give the header a gradient background + footerRow : '', + footerCells: '', + icons : '', // add "icon-white" to make them white; this icon class is added to the in the header + sortNone : 'bootstrap-icon-unsorted', + sortAsc : 'icon-chevron-up', + sortDesc : 'icon-chevron-down', + active : '', // applied when column is sorted + hover : '', // use custom css here - bootstrap class may not override it + filterRow : '', // filter row class + even : '', // even row zebra striping + odd : '' // odd row zebra striping + }, + "jui" : { + table : 'ui-widget ui-widget-content ui-corner-all', // table classes + header : 'ui-widget-header ui-corner-all ui-state-default', // header classes + footerRow : '', + footerCells: '', + icons : 'ui-icon', // icon class added to the in the header + sortNone : 'ui-icon-carat-2-n-s', + sortAsc : 'ui-icon-carat-1-n', + sortDesc : 'ui-icon-carat-1-s', + active : 'ui-state-active', // applied when column is sorted + hover : 'ui-state-hover', // hover class + filterRow : '', + even : 'ui-widget-content', // even row zebra striping + odd : 'ui-state-default' // odd row zebra striping + } +}; + +// *** Store data in local storage, with a cookie fallback *** +/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json) + if you need it, then include https://github.com/douglascrockford/JSON-js + + $.parseJSON is not available is jQuery versions older than 1.4.1, using older + versions will only allow storing information for one page at a time + + // *** Save data (JSON format only) *** + // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid + var val = { "mywidget" : "data1" }; // valid JSON uses double quotes + // $.tablesorter.storage(table, key, val); + $.tablesorter.storage(table, 'tablesorter-mywidget', val); + + // *** Get data: $.tablesorter.storage(table, key); *** + v = $.tablesorter.storage(table, 'tablesorter-mywidget'); + // val may be empty, so also check for your data + val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : ''; + alert(val); // "data1" if saved, or "" if not +*/ +ts.storage = function(table, key, val){ + var d, k, ls = false, v = {}, + id = table.id || $('.tablesorter').index( $(table) ), + url = window.location.pathname; + // https://gist.github.com/paulirish/5558557 + if ("localStorage" in window) { + try { + window.localStorage.setItem('_tmptest', 'temp'); + ls = true; + window.localStorage.removeItem('_tmptest'); + } catch(e) {} + } + // *** get val *** + if ($.parseJSON){ + if (ls){ + v = $.parseJSON(localStorage[key] || '{}'); + } else { + k = document.cookie.split(/[;\s|=]/); // cookie + d = $.inArray(key, k) + 1; // add one to get from the key to the value + v = (d !== 0) ? $.parseJSON(k[d] || '{}') : {}; + } + } + // allow val to be an empty string to + if ((val || val === '') && window.JSON && JSON.hasOwnProperty('stringify')){ + // add unique identifiers = url pathname > table ID/index on page > data + if (!v[url]) { + v[url] = {}; + } + v[url][id] = val; + // *** set val *** + if (ls){ + localStorage[key] = JSON.stringify(v); + } else { + d = new Date(); + d.setTime(d.getTime() + (31536e+6)); // 365 days + document.cookie = key + '=' + (JSON.stringify(v)).replace(/\"/g,'\"') + '; expires=' + d.toGMTString() + '; path=/'; + } + } else { + return v && v[url] ? v[url][id] : {}; + } +}; + +// Add a resize event to table headers +// ************************** +ts.addHeaderResizeEvent = function(table, disable, options){ + var defaults = { + timer : 250 + }, + o = $.extend({}, defaults, options), + c = table.config, + wo = c.widgetOptions, + headers, + checkSizes = function(){ + wo.resize_flag = true; + headers = []; + c.$headers.each(function(){ + var d = $.data(this, 'savedSizes'), + w = this.offsetWidth, + h = this.offsetHeight; + if (w !== d[0] || h !== d[1]) { + $.data(this, 'savedSizes', [ w, h ]); + headers.push(this); + } + }); + if (headers.length) { c.$table.trigger('resize', [ headers ]); } + wo.resize_flag = false; + }; + clearInterval(wo.resize_timer); + if (disable) { + wo.resize_flag = false; + return false; + } + c.$headers.each(function(){ + $.data(this, 'savedSizes', [ this.offsetWidth, this.offsetHeight ]); + }); + wo.resize_timer = setInterval(function(){ + if (wo.resize_flag) { return; } + checkSizes(); + }, o.timer); +}; + +// Widget: General UI theme +// "uitheme" option in "widgetOptions" +// ************************** +ts.addWidget({ + id: "uitheme", + priority: 10, + options: { + uitheme : 'jui' + }, + format: function(table, c, wo){ + var time, klass, $el, $tar, + t = ts.themes, + $t = c.$table, + theme = c.theme !== 'default' ? c.theme : wo.uitheme || 'jui', + o = t[ t[theme] ? theme : t[wo.uitheme] ? wo.uitheme : 'jui'], + $h = c.$headers, + sh = 'tr.' + (wo.stickyHeaders || 'tablesorter-stickyHeader'), + rmv = o.sortNone + ' ' + o.sortDesc + ' ' + o.sortAsc; + if (c.debug) { time = new Date(); } + if (!$t.hasClass('tablesorter-' + theme) || c.theme === theme || !table.hasInitialized){ + // update zebra stripes + if (o.even !== '') { wo.zebra[0] += ' ' + o.even; } + if (o.odd !== '') { wo.zebra[1] += ' ' + o.odd; } + // add table/footer class names + t = $t + // remove other selected themes; use widgetOptions.theme_remove + .removeClass( c.theme === '' ? '' : 'tablesorter-' + c.theme ) + .addClass('tablesorter-' + theme + ' ' + o.table) // add theme widget class name + .find('tfoot'); + if (t.length) { + t + .find('tr').addClass(o.footerRow) + .children('th, td').addClass(o.footerCells); + } + // update header classes + $h + .addClass(o.header) + .filter(':not(.sorter-false)') + .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(e){ + // toggleClass with switch added in jQuery 1.3 + $(this)[ e.type === 'mouseenter' ? 'addClass' : 'removeClass' ](o.hover); + }); + if (!$h.find('.tablesorter-wrapper').length) { + // Firefox needs this inner div to position the resizer correctly + $h.wrapInner('
'); + } + if (c.cssIcon){ + // if c.cssIcon is '', then no is added to the header + $h.find('.' + c.cssIcon).addClass(o.icons); + } + if ($t.hasClass('hasFilters')){ + $h.find('.tablesorter-filter-row').addClass(o.filterRow); + } + } + $.each($h, function(i){ + $el = $(this); + $tar = (c.cssIcon) ? $el.find('.' + c.cssIcon) : $el; + if (this.sortDisabled){ + // no sort arrows for disabled columns! + $el.removeClass(rmv); + $tar.removeClass(rmv + ' tablesorter-icon ' + o.icons); + } else { + t = ($t.hasClass('hasStickyHeaders')) ? $t.find(sh).find('th').eq(i).add($el) : $el; + klass = ($el.hasClass(c.cssAsc)) ? o.sortAsc : ($el.hasClass(c.cssDesc)) ? o.sortDesc : $el.hasClass(c.cssHeader) ? o.sortNone : ''; + $el[klass === o.sortNone ? 'removeClass' : 'addClass'](o.active); + $tar.removeClass(rmv).addClass(klass); + } + }); + if (c.debug){ + ts.benchmark("Applying " + theme + " theme", time); + } + }, + remove: function(table, c, wo){ + var $t = c.$table, + theme = typeof wo.uitheme === 'object' ? 'jui' : wo.uitheme || 'jui', + o = typeof wo.uitheme === 'object' ? wo.uitheme : ts.themes[ ts.themes.hasOwnProperty(theme) ? theme : 'jui'], + $h = $t.children('thead').children(), + rmv = o.sortNone + ' ' + o.sortDesc + ' ' + o.sortAsc; + $t + .removeClass('tablesorter-' + theme + ' ' + o.table) + .find(c.cssHeader).removeClass(o.header); + $h + .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover + .removeClass(o.hover + ' ' + rmv + ' ' + o.active) + .find('.tablesorter-filter-row').removeClass(o.filterRow); + $h.find('.tablesorter-icon').removeClass(o.icons); + } +}); + +// Widget: Column styles +// "columns", "columns_thead" (true) and +// "columns_tfoot" (true) options in "widgetOptions" +// ************************** +ts.addWidget({ + id: "columns", + priority: 30, + options : { + columns : [ "primary", "secondary", "tertiary" ] + }, + format: function(table, c, wo){ + var $tb, $tr, $td, $t, time, last, rmv, i, k, l, + $tbl = c.$table, + b = c.$tbodies, + list = c.sortList, + len = list.length, + // keep backwards compatibility, for now + css = (c.widgetColumns && c.widgetColumns.hasOwnProperty('css')) ? c.widgetColumns.css || css : + (wo && wo.hasOwnProperty('columns')) ? wo.columns || css : css; + last = css.length-1; + rmv = css.join(' '); + if (c.debug){ + time = new Date(); + } + // check if there is a sort (on initialization there may not be one) + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // detach tbody + $tr = $tb.children('tr'); + l = $tr.length; + // loop through the visible rows + $tr.each(function(){ + $t = $(this); + if (this.style.display !== 'none'){ + // remove all columns class names + $td = $t.children().removeClass(rmv); + // add appropriate column class names + if (list && list[0]){ + // primary sort column class + $td.eq(list[0][0]).addClass(css[0]); + if (len > 1){ + for (i = 1; i < len; i++){ + // secondary, tertiary, etc sort column classes + $td.eq(list[i][0]).addClass( css[i] || css[last] ); + } + } + } + } + }); + ts.processTbody(table, $tb, false); + } + // add classes to thead and tfoot + $tr = wo.columns_thead !== false ? 'thead tr' : ''; + if (wo.columns_tfoot !== false) { + $tr += ($tr === '' ? '' : ',') + 'tfoot tr'; + } + if ($tr.length) { + $t = $tbl.find($tr).children().removeClass(rmv); + if (list && list[0]){ + // primary sort column class + $t.filter('[data-column="' + list[0][0] + '"]').addClass(css[0]); + if (len > 1){ + for (i = 1; i < len; i++){ + // secondary, tertiary, etc sort column classes + $t.filter('[data-column="' + list[i][0] + '"]').addClass(css[i] || css[last]); + } + } + } + } + if (c.debug){ + ts.benchmark("Applying Columns widget", time); + } + }, + remove: function(table, c, wo){ + var k, $tb, + b = c.$tbodies, + rmv = (wo.columns || [ "primary", "secondary", "tertiary" ]).join(' '); + c.$headers.removeClass(rmv); + c.$table.children('tfoot').children('tr').children('th, td').removeClass(rmv); + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody + $tb.children('tr').each(function(){ + $(this).children().removeClass(rmv); + }); + ts.processTbody(table, $tb, false); // restore tbody + } + } +}); + +// Widget: filter +// ************************** +ts.addWidget({ + id: "filter", + priority: 50, + options : { + filter_childRows : false, // if true, filter includes child row content in the search + filter_columnFilters : true, // if true, a filter will be added to the top of each table column + filter_cssFilter : 'tablesorter-filter', // css class name added to the filter row & each input in the row + filter_filteredRow : 'filtered', // class added to filtered rows; needed by pager plugin + filter_formatter : null, // add custom filter elements to the filter row + filter_functions : null, // add custom filter functions using this option + filter_hideFilters : false, // collapse filter row when mouse leaves the area + filter_ignoreCase : true, // if true, make all searches case-insensitive + filter_liveSearch : true, // if true, search column content while the user types (with a delay) + filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available (visible) options within the drop down + filter_reset : null, // jQuery selector string of an element used to reset the filters + filter_searchDelay : 300, // typing delay in milliseconds before starting a search + filter_startsWith : false, // if true, filter start from the beginning of the cell contents + filter_useParsedData : false, // filter all data using parsed content + filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used. + filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value + + // regex used in filter "check" functions - not for general use and not documented + filter_regex : { + "regex" : /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/, // regex to test for regex + "child" : /tablesorter-childRow/, // child row class name; this gets updated in the script + "filtered" : /filtered/, // filtered (hidden) row class name; updated in the script + "type" : /undefined|number/, // check type + "exact" : /(^[\"|\'|=])|([\"|\'|=]$)/g, // exact match + "nondigit" : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser) + "operators" : /[<>=]/g // replace operators + } + }, + format: function(table, c, wo){ + if (c.parsers && !c.$table.hasClass('hasFilters')){ + var i, j, k, l, val, ff, x, xi, st, sel, str, + ft, ft2, $th, rg, s, t, dis, col, + fmt = ts.formatFloat, + last = '', // save last filter search + $ths = c.$headers, + css = wo.filter_cssFilter, + $t = c.$table.addClass('hasFilters'), + b = $t.find('tbody'), + cols = c.parsers.length, + parsed, time, timer, + + // dig fer gold + checkFilters = function(filter){ + var arry = $.isArray(filter), + v = (arry) ? filter : ts.getFilters(table), + cv = (v || []).join(''); // combined filter values + // add filter array back into inputs + if (arry) { + ts.setFilters( $t, v ); + } + if (wo.filter_hideFilters){ + // show/hide filter row as needed + $t.find('.tablesorter-filter-row').trigger( cv === '' ? 'mouseleave' : 'mouseenter' ); + } + // return if the last search is the same; but filter === false when updating the search + // see example-widget-filter.html filter toggle buttons + if (last === cv && filter !== false) { return; } + $t.trigger('filterStart', [v]); + if (c.showProcessing) { + // give it time for the processing icon to kick in + setTimeout(function(){ + findRows(filter, v, cv); + return false; + }, 30); + } else { + findRows(filter, v, cv); + return false; + } + }, + findRows = function(filter, v, cv){ + var $tb, $tr, $td, cr, r, l, ff, time, r1, r2, searchFiltered; + if (c.debug) { time = new Date(); } + for (k = 0; k < b.length; k++ ){ + if (b.eq(k).hasClass(c.cssInfoBlock)) { continue; } // ignore info blocks, issue #264 + $tb = ts.processTbody(table, b.eq(k), true); + $tr = $tb.children('tr:not(.' + c.cssChildRow + ')'); + l = $tr.length; + if (cv === '' || wo.filter_serversideFiltering){ + $tb.children().show().removeClass(wo.filter_filteredRow); + } else { + // optimize searching only through already filtered rows - see #313 + searchFiltered = true; + r = $t.data('lastSearch') || []; + $.each(v, function(i,val){ + // check for changes from beginning of filter; but ignore if there is a logical "or" in the string + searchFiltered = (val || '').indexOf(r[i] || '') === 0 && searchFiltered && !/(\s+or\s+|\|)/g.test(val || ''); + }); + // can't search when all rows are hidden - this happens when looking for exact matches + if (searchFiltered && $tr.filter(':visible').length === 0) { searchFiltered = false; } + // loop through the rows + for (j = 0; j < l; j++){ + r = $tr[j].className; + // skip child rows & already filtered rows + if ( wo.filter_regex.child.test(r) || (searchFiltered && wo.filter_regex.filtered.test(r)) ) { continue; } + r = true; + cr = $tr.eq(j).nextUntil('tr:not(.' + c.cssChildRow + ')'); + // so, if "table.config.widgetOptions.filter_childRows" is true and there is + // a match anywhere in the child row, then it will make the row visible + // checked here so the option can be changed dynamically + t = (cr.length && wo.filter_childRows) ? cr.text() : ''; + t = wo.filter_ignoreCase ? t.toLocaleLowerCase() : t; + $td = $tr.eq(j).children('td'); + for (i = 0; i < cols; i++){ + // ignore if filter is empty or disabled + if (v[i]){ + // check if column data should be from the cell or from parsed data + if (wo.filter_useParsedData || parsed[i]){ + x = c.cache[k].normalized[j][i]; + } else { + // using older or original tablesorter + x = $.trim($td.eq(i).text()); + } + xi = !wo.filter_regex.type.test(typeof x) && wo.filter_ignoreCase ? x.toLocaleLowerCase() : x; + ff = r; // if r is true, show that row + // val = case insensitive, v[i] = case sensitive + val = wo.filter_ignoreCase ? v[i].toLocaleLowerCase() : v[i]; + if (wo.filter_functions && wo.filter_functions[i]){ + if (wo.filter_functions[i] === true){ + // default selector; no "filter-select" class + ff = ($ths.filter('[data-column="' + i + '"]:last').hasClass('filter-match')) ? xi.search(val) >= 0 : v[i] === x; + } else if (typeof wo.filter_functions[i] === 'function'){ + // filter callback( exact cell content, parser normalized content, filter input value, column index ) + ff = wo.filter_functions[i](x, c.cache[k].normalized[j][i], v[i], i); + } else if (typeof wo.filter_functions[i][v[i]] === 'function'){ + // selector option function + ff = wo.filter_functions[i][v[i]](x, c.cache[k].normalized[j][i], v[i], i); + } + // Look for regex + } else if (wo.filter_regex.regex.test(val)){ + rg = wo.filter_regex.regex.exec(val); + try { + ff = new RegExp(rg[1], rg[2]).test(xi); + } catch (err){ + ff = false; + } + // Look for quotes or equals to get an exact match; ignore type since xi could be numeric + /*jshint eqeqeq:false */ + } else if (val.replace(wo.filter_regex.exact, '') == xi){ + ff = true; + // Look for a not match + } else if (/^\!/.test(val)){ + val = val.replace('!',''); + s = xi.search($.trim(val)); + ff = val === '' ? true : !(wo.filter_startsWith ? s === 0 : s >= 0); + // Look for operators >, >=, < or <= + } else if (/^[<>]=?/.test(val)){ + s = fmt(val.replace(wo.filter_regex.nondigit, '').replace(wo.filter_regex.operators,''), table); + // parse filter value in case we're comparing numbers (dates) + if (parsed[i] || c.parsers[i].type === 'numeric') { + rg = c.parsers[i].format('' + val.replace(wo.filter_regex.operators,''), table, $ths.eq(i), i); + s = (rg !== '' && !isNaN(rg)) ? rg : s; + } + // xi may be numeric - see issue #149; + // check if c.cache[k].normalized[j] is defined, because sometimes j goes out of range? (numeric columns) + rg = ( parsed[i] || c.parsers[i].type === 'numeric' ) && !isNaN(s) && c.cache[k].normalized[j] ? c.cache[k].normalized[j][i] : + isNaN(xi) ? fmt(xi.replace(wo.filter_regex.nondigit, ''), table) : fmt(xi, table); + if (/>/.test(val)) { ff = />=/.test(val) ? rg >= s : rg > s; } + if (/= 0; + r1 = s.length - 1; + while (ff && r1) { + ff = ff && xi.search($.trim(s[r1])) >= 0; + r1--; + } + // Look for a range (using " to " or " - ") - see issue #166; thanks matzhu! + } else if (/\s+(-|to)\s+/.test(val)){ + s = val.split(/(?: - | to )/); // make sure the dash is for a range and not indicating a negative number + r1 = fmt(s[0].replace(wo.filter_regex.nondigit, ''), table); + r2 = fmt(s[1].replace(wo.filter_regex.nondigit, ''), table); + // parse filter value in case we're comparing numbers (dates) + if (parsed[i] || c.parsers[i].type === 'numeric') { + rg = c.parsers[i].format('' + s[0], table, $ths.eq(i), i); + r1 = (rg !== '' && !isNaN(rg)) ? rg : r1; + rg = c.parsers[i].format('' + s[1], table, $ths.eq(i), i); + r2 = (rg !== '' && !isNaN(rg)) ? rg : r2; + } + rg = ( parsed[i] || c.parsers[i].type === 'numeric' ) && !isNaN(r1) && !isNaN(r2) ? c.cache[k].normalized[j][i] : + isNaN(xi) ? fmt(xi.replace(wo.filter_regex.nondigit, ''), table) : fmt(xi, table); + if (r1 > r2) { ff = r1; r1 = r2; r2 = ff; } // swap + ff = (rg >= r1 && rg <= r2) || (r1 === '' || r2 === '') ? true : false; + // Look for wild card: ? = single, * = multiple, or | = logical OR + } else if ( /[\?|\*]/.test(val) || /\s+OR\s+/.test(v[i]) ){ + s = val.replace(/\s+OR\s+/gi,"|"); + // look for an exact match with the "or" unless the "filter-match" class is found + if (!$ths.filter('[data-column="' + i + '"]:last').hasClass('filter-match') && /\|/.test(s)) { + s = '^(' + s + ')$'; + } + ff = new RegExp( s.replace(/\?/g, '\\S{1}').replace(/\*/g, '\\S*') ).test(xi); + // Look for match, and add child row data for matching + } else { + x = (xi + t).indexOf(val); + ff = ( (!wo.filter_startsWith && x >= 0) || (wo.filter_startsWith && x === 0) ); + } + r = (ff) ? (r ? true : false) : false; + } + } + $tr[j].style.display = (r ? '' : 'none'); + $tr.eq(j)[r ? 'removeClass' : 'addClass'](wo.filter_filteredRow); + if (cr.length) { cr[r ? 'show' : 'hide'](); } + } + } + ts.processTbody(table, $tb, false); + } + last = cv; // save last search + $t.data('lastSearch', v); + if (c.debug){ + ts.benchmark("Completed filter widget search", time); + } + $t.trigger('applyWidgets'); // make sure zebra widget is applied + $t.trigger('filterEnd'); + }, + buildSelect = function(i, updating, onlyavail){ + var o, t, arry = [], currentVal; + i = parseInt(i, 10); + t = $ths.filter('[data-column="' + i + '"]:last'); + // t.data('placeholder') won't work in jQuery older than 1.4.3 + o = ''; + for (k = 0; k < b.length; k++ ){ + l = c.cache[k].row.length; + // loop through the rows + for (j = 0; j < l; j++){ + // check if has class filtered + if (onlyavail && c.cache[k].row[j][0].className.match(wo.filter_filteredRow)) { continue; } + // get non-normalized cell content + if (wo.filter_useParsedData){ + arry.push( '' + c.cache[k].normalized[j][i] ); + } else { + t = c.cache[k].row[j][0].cells[i]; + if (t){ + arry.push( $.trim(c.supportsTextContent ? t.textContent : $(t).text()) ); + } + } + } + } + + // get unique elements and sort the list + // if $.tablesorter.sortText exists (not in the original tablesorter), + // then natural sort the list otherwise use a basic sort + arry = $.grep(arry, function(v, k){ + return $.inArray(v, arry) === k; + }); + arry = (ts.sortText) ? arry.sort(function(a, b){ return ts.sortText(table, a, b, i); }) : arry.sort(true); + + // Get curent filter value + currentVal = $t.find('thead').find('select.' + css + '[data-column="' + i + '"]').val(); + + // build option list + for (k = 0; k < arry.length; k++){ + t = arry[k].replace(/\"/g, """); + // replace quotes - fixes #242 & ignore empty strings - see http://stackoverflow.com/q/14990971/145346 + o += arry[k] !== '' ? '' : ''; + } + $t.find('thead').find('select.' + css + '[data-column="' + i + '"]')[ updating ? 'html' : 'append' ](o); + }, + buildDefault = function(updating){ + // build default select dropdown + for (i = 0; i < cols; i++){ + t = $ths.filter('[data-column="' + i + '"]:last'); + // look for the filter-select class; build/update it if found + if ((t.hasClass('filter-select') || wo.filter_functions && wo.filter_functions[i] === true) && !t.hasClass('filter-false')){ + if (!wo.filter_functions) { wo.filter_functions = {}; } + wo.filter_functions[i] = true; // make sure this select gets processed by filter_functions + buildSelect(i, updating, t.hasClass(wo.filter_onlyAvail)); + } + } + }, + searching = function(filter){ + if (typeof filter === 'undefined' || filter === true){ + // delay filtering + clearTimeout(timer); + timer = setTimeout(function(){ + checkFilters(filter); + }, wo.filter_liveSearch ? wo.filter_searchDelay : 10); + } else { + // skip delay + checkFilters(filter); + } + }; + if (c.debug){ + time = new Date(); + } + wo.filter_regex.child = new RegExp(c.cssChildRow); + wo.filter_regex.filtered = new RegExp(wo.filter_filteredRow); + // don't build filter row if columnFilters is false or all columns are set to "filter-false" - issue #156 + if (wo.filter_columnFilters !== false && $ths.filter('.filter-false').length !== $ths.length){ + // build filter row + t = ''; + for (i = 0; i < cols; i++){ + t += ''; + } + c.$filters = $(t += '').appendTo( $t.find('thead').eq(0) ).find('td'); + // build each filter input + for (i = 0; i < cols; i++){ + dis = false; + $th = $ths.filter('[data-column="' + i + '"]:last'); // assuming last cell of a column is the main column + sel = (wo.filter_functions && wo.filter_functions[i] && typeof wo.filter_functions[i] !== 'function') || $th.hasClass('filter-select'); + // use header option - headers: { 1: { filter: false } } OR add class="filter-false" + if (ts.getData){ + // get data from jQuery data, metadata, headers option or header class name + dis = ts.getData($th[0], c.headers[i], 'filter') === 'false'; + } else { + // only class names and header options - keep this for compatibility with tablesorter v2.0.5 + dis = (c.headers[i] && c.headers[i].hasOwnProperty('filter') && c.headers[i].filter === false) || $th.hasClass('filter-false'); + } + + if (sel){ + t = $('').appendTo( c.$filters.eq(i) ); + } + if (t) { + t.attr('placeholder', $th.data('placeholder') || $th.attr('data-placeholder') || ''); + } + } + if (t) { + t.addClass(css).attr('data-column', i); + if (dis) { + t.addClass('disabled')[0].disabled = true; // disabled! + } + } + } + } + $t + .bind('addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '.split(' ').join('.tsfilter '), function(e, filter){ + if (!/(search|filterReset|filterEnd)/.test(e.type)){ + e.stopPropagation(); + buildDefault(true); + } + if (e.type === 'filterReset') { + $t.find('.' + css).val(''); + } + if (e.type === 'filterEnd') { + buildDefault(true); + } else { + // send false argument to force a new search; otherwise if the filter hasn't changed, it will return + filter = e.type === 'search' ? filter : e.type === 'updateComplete' ? $t.data('lastSearch') : ''; + searching(filter); + } + return false; + }) + .find('input.' + css).bind('keyup search', function(e, filter){ + // emulate what webkit does.... escape clears the filter + if (e.which === 27) { + this.value = ''; + // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace + } else if ( (typeof wo.filter_liveSearch === 'number' && this.value.length < wo.filter_liveSearch && this.value !== '') || ( e.type === 'keyup' && + ( (e.which < 32 && e.which !== 8 && wo.filter_liveSearch === true && e.which !== 13) || (e.which >= 37 && e.which <=40) || (e.which !== 13 && wo.filter_liveSearch === false) ) ) ) { + return; + } + searching(filter); + }); + + // parse columns after formatter, in case the class is added at that point + parsed = $ths.map(function(i){ + return (ts.getData) ? ts.getData($ths.filter('[data-column="' + i + '"]:last'), c.headers[i], 'filter') === 'parsed' : $(this).hasClass('filter-parsed'); + }).get(); + + // reset button/link + if (wo.filter_reset && $(wo.filter_reset).length){ + $(wo.filter_reset).bind('click.tsfilter', function(){ + $t.trigger('filterReset'); + }); + } + if (wo.filter_functions){ + // i = column # (string) + for (col in wo.filter_functions){ + if (wo.filter_functions.hasOwnProperty(col) && typeof col === 'string'){ + t = $ths.filter('[data-column="' + col + '"]:last'); + ff = ''; + if (wo.filter_functions[col] === true && !t.hasClass('filter-false')){ + buildSelect(col); + } else if (typeof col === 'string' && !t.hasClass('filter-false')){ + // add custom drop down list + for (str in wo.filter_functions[col]){ + if (typeof str === 'string'){ + ff += ff === '' ? '' : ''; + ff += ''; + } + } + $t.find('thead').find('select.' + css + '[data-column="' + col + '"]').append(ff); + } + } + } + } + // not really updating, but if the column has both the "filter-select" class & filter_functions set to true, + // it would append the same options twice. + buildDefault(true); + + $t.find('select.' + css).bind('change search', function(e, filter){ + checkFilters(filter); + }); + + if (wo.filter_hideFilters){ + $t + .find('.tablesorter-filter-row') + .addClass('hideme') + .bind('mouseenter mouseleave', function(e){ + // save event object - http://bugs.jquery.com/ticket/12140 + var all, evt = e; + ft = $(this); + clearTimeout(st); + st = setTimeout(function(){ + if (/enter|over/.test(evt.type)){ + ft.removeClass('hideme'); + } else { + // don't hide if input has focus + // $(':focus') needs jQuery 1.6+ + if ($(document.activeElement).closest('tr')[0] !== ft[0]){ + // get all filter values + all = $t.find('.' + wo.filter_cssFilter).map(function(){ + return $(this).val() || ''; + }).get().join(''); + // don't hide row if any filter has a value + if (all === ''){ + ft.addClass('hideme'); + } + } + } + }, 200); + }) + .find('input, select').bind('focus blur', function(e){ + ft2 = $(this).closest('tr'); + clearTimeout(st); + st = setTimeout(function(){ + // don't hide row if any filter has a value + if ($t.find('.' + wo.filter_cssFilter).map(function(){ return $(this).val() || ''; }).get().join('') === ''){ + ft2[ e.type === 'focus' ? 'removeClass' : 'addClass']('hideme'); + } + }, 200); + }); + } + + // show processing icon + if (c.showProcessing) { + $t.bind('filterStart.tsfilter filterEnd.tsfilter', function(e, v) { + var fc = (v) ? $t.find('.' + c.cssHeader).filter('[data-column]').filter(function(){ + return v[$(this).data('column')] !== ''; + }) : ''; + ts.isProcessing($t[0], e.type === 'filterStart', v ? fc : ''); + }); + } + + if (c.debug){ + ts.benchmark("Applying Filter widget", time); + } + // add default values + $t.bind('tablesorter-initialized', function(){ + ff = ts.getFilters(table); + for (i = 0; i < ff.length; i++) { + ff[i] = $ths.filter('[data-column="' + i + '"]:last').attr(wo.filter_defaultAttrib) || ff[i]; + } + ts.setFilters(table, ff, true); + }); + // filter widget initialized + $t.trigger('filterInit'); + checkFilters(); + } + }, + remove: function(table, c, wo){ + var k, $tb, + $t = c.$table, + b = c.$tbodies; + $t + .removeClass('hasFilters') + // add .tsfilter namespace to all BUT search + .unbind('addRows updateCell update updateComplete appendCache search filterStart filterEnd '.split(' ').join('.tsfilter ')) + .find('.tablesorter-filter-row').remove(); + for (k = 0; k < b.length; k++ ){ + $tb = ts.processTbody(table, b.eq(k), true); // remove tbody + $tb.children().removeClass(wo.filter_filteredRow).show(); + ts.processTbody(table, $tb, false); // restore tbody + } + if (wo.filterreset) { $(wo.filter_reset).unbind('click.tsfilter'); } + } +}); +ts.getFilters = function(table) { + var c = table ? $(table)[0].config : {}; + if (c && c.widgetOptions && !c.widgetOptions.filter_columnFilters) { return $(table).data('lastSearch'); } + return c && c.$filters ? c.$filters.find('.' + c.widgetOptions.filter_cssFilter).map(function(i, el) { + return $(el).val(); + }).get() || [] : false; +}; +ts.setFilters = function(table, filter, apply) { + var $t = $(table), + c = $t.length ? $t[0].config : {}, + valid = c && c.$filters ? c.$filters.find('.' + c.widgetOptions.filter_cssFilter).each(function(i, el) { + $(el).val(filter[i] || ''); + }).trigger('change.tsfilter') || false : false; + if (apply) { $t.trigger('search', [filter, false]); } + return !!valid; +}; + +// Widget: Sticky headers +// based on this awesome article: +// http://css-tricks.com/13465-persistent-headers/ +// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech +// ************************** +ts.addWidget({ + id: "stickyHeaders", + priority: 60, + options: { + stickyHeaders : 'tablesorter-stickyHeader', + stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element + stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists + stickyHeaders_addResizeEvent : true, // trigger "resize" event on headers + stickyHeaders_includeCaption : true // if false and a caption exist, it won't be included in the sticky header + }, + format: function(table, c, wo){ + if (c.$table.hasClass('hasStickyHeaders')) { return; } + var $t = c.$table, + $win = $(window), + header = $t.children('thead:first'), + hdrCells = header.children('tr:not(.sticky-false)').children(), + innr = '.tablesorter-header-inner', + tfoot = $t.find('tfoot'), + filterInputs = '.' + (wo.filter_cssFilter || 'tablesorter-filter'), + $stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '', + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0, + $stickyTable = wo.$sticky = $t.clone() + .addClass('containsStickyHeaders') + .css({ + position : 'fixed', + margin : 0, + top : stickyOffset, + visibility : 'hidden', + zIndex : 2 + }), + stkyHdr = $stickyTable.children('thead:first').addClass(wo.stickyHeaders), + stkyCells, + laststate = '', + spacing = 0, + flag = false, + resizeHdr = function(){ + stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0; + var bwsr = navigator.userAgent; + spacing = 0; + // yes, I dislike browser sniffing, but it really is needed here :( + // webkit automatically compensates for border spacing + if ($t.css('border-collapse') !== 'collapse' && !/(webkit|msie)/i.test(bwsr)) { + // Firefox & Opera use the border-spacing + // update border-spacing here because of demos that switch themes + spacing = parseInt(hdrCells.eq(0).css('border-left-width'), 10) * 2; + } + $stickyTable.css({ + left : header.offset().left - $win.scrollLeft() - spacing, + width: $t.width() + }); + stkyCells.filter(':visible').each(function(i){ + var $h = hdrCells.filter(':visible').eq(i); + $(this) + .css({ + width: $h.width() - spacing, + height: $h.height() + }) + .find(innr).width( $h.find(innr).width() ); + }); + }; + // fix clone ID, if it exists - fixes #271 + if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; } + // clear out cloned table, except for sticky header + // include caption & filter row (fixes #126 & #249) + $stickyTable.find('thead:gt(0), tr.sticky-false, tbody, tfoot').remove(); + if (!wo.stickyHeaders_includeCaption) { + $stickyTable.find('caption').remove(); + } + // issue #172 - find td/th in sticky header + stkyCells = stkyHdr.children().children(); + $stickyTable.css({ height:0, width:0, padding:0, margin:0, border:0 }); + // remove resizable block + stkyCells.find('.tablesorter-resizer').remove(); + // update sticky header class names to match real header after sorting + $t + .addClass('hasStickyHeaders') + .bind('sortEnd.tsSticky', function(){ + hdrCells.filter(':visible').each(function(i){ + var t = stkyCells.filter(':visible').eq(i); + t + .attr('class', $(this).attr('class')) + // remove processing icon + .removeClass(c.cssProcessing); + if (c.cssIcon){ + t + .find('.' + c.cssIcon) + .attr('class', $(this).find('.' + c.cssIcon).attr('class')); + } + }); + }) + .bind('pagerComplete.tsSticky', function(){ + resizeHdr(); + }); + // http://stackoverflow.com/questions/5312849/jquery-find-self; + hdrCells.find(c.selectorSort).add( c.$headers.filter(c.selectorSort) ).each(function(i){ + var t = $(this), + // clicking on sticky will trigger sort + $cell = stkyHdr.children('tr.tablesorter-headerRow').children().eq(i).bind('mouseup', function(e){ + t.trigger(e, true); // external mouseup flag (click timer is ignored) + }); + // prevent sticky header text selection + if (c.cancelSelection) { + $cell + .attr('unselectable', 'on') + .bind('selectstart', false) + .css({ + 'user-select': 'none', + 'MozUserSelect': 'none' + }); + } + }); + // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned. + $t.after( $stickyTable ); + // make it sticky! + $win.bind('scroll.tsSticky resize.tsSticky', function(e){ + if (!$t.is(':visible')) { return; } // fixes #278 + var pre = 'tablesorter-sticky-', + offset = $t.offset(), + cap = -(wo.stickyHeaders_includeCaption ? 0 : $t.find('caption').height()), + sTop = $win.scrollTop() + stickyOffset, + tableHt = $t.height() - ($stickyTable.height() + (tfoot.height() || 0)), + vis = (sTop > offset.top - cap) && (sTop < offset.top - cap + tableHt) ? 'visible' : 'hidden'; + $stickyTable + .removeClass(pre + 'visible ' + pre + 'hidden') + .addClass(pre + vis) + .css({ + // adjust when scrolling horizontally - fixes issue #143 + left : header.offset().left - $win.scrollLeft() - spacing, + visibility : vis + }); + if (vis !== laststate || e.type === 'resize'){ + // make sure the column widths match + resizeHdr(); + laststate = vis; + } + }); + if (wo.stickyHeaders_addResizeEvent) { + ts.addHeaderResizeEvent(table); + } + + // look for filter widget + $t.bind('filterEnd', function(){ + if (flag) { return; } + stkyHdr.find('.tablesorter-filter-row').children().each(function(i){ + $(this).find(filterInputs).val( c.$filters.find(filterInputs).eq(i).val() ); + }); + }); + stkyCells.find(filterInputs).bind('keyup search change', function(e){ + // ignore arrow and meta keys; allow backspace + if ((e.which < 32 && e.which !== 8) || (e.which >= 37 && e.which <=40)) { return; } + flag = true; + var $f = $(this), col = $f.attr('data-column'); + c.$filters.find(filterInputs).eq(col) + .val( $f.val() ) + .trigger('search'); + setTimeout(function(){ + flag = false; + }, wo.filter_searchDelay); + }); + $t.trigger('stickyHeadersInit'); + + }, + remove: function(table, c, wo){ + c.$table + .removeClass('hasStickyHeaders') + .unbind('sortEnd.tsSticky pagerComplete.tsSticky') + .find('.' + wo.stickyHeaders).remove(); + if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table + // don't unbind if any table on the page still has stickyheaders applied + if (!$('.hasStickyHeaders').length) { + $(window).unbind('scroll.tsSticky resize.tsSticky'); + } + ts.addHeaderResizeEvent(table, false); + } +}); + +// Add Column resizing widget +// this widget saves the column widths if +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: "resizable", + priority: 40, + options: { + resizable : true, + resizable_addLastColumn : false + }, + format: function(table, c, wo){ + if (c.$table.hasClass('hasResizable')) { return; } + c.$table.addClass('hasResizable'); + var $t, t, i, j, s = {}, $c, $cols, w, tw, + $tbl = c.$table, + position = 0, + $target = null, + $next = null, + fullWidth = Math.abs($tbl.parent().width() - $tbl.width()) < 20, + stopResize = function(){ + if (ts.storage && $target){ + s[$target.index()] = $target.width(); + s[$next.index()] = $next.width(); + $target.width( s[$target.index()] ); + $next.width( s[$next.index()] ); + if (wo.resizable !== false){ + ts.storage(table, 'tablesorter-resizable', s); + } + } + position = 0; + $target = $next = null; + $(window).trigger('resize'); // will update stickyHeaders, just in case + }; + s = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {}; + // process only if table ID or url match + if (s){ + for (j in s){ + if (!isNaN(j) && j < c.$headers.length){ + c.$headers.eq(j).width(s[j]); // set saved resizable widths + } + } + } + $t = $tbl.children('thead:first').children('tr'); + // add resizable-false class name to headers (across rows as needed) + $t.children().each(function(){ + t = $(this); + i = t.attr('data-column'); + j = ts.getData( t, c.headers[i], 'resizable') === "false"; + $t.children().filter('[data-column="' + i + '"]').toggleClass('resizable-false', j); + }); + // add wrapper inside each cell to allow for positioning of the resizable target block + $t.each(function(){ + $c = $(this).children(':not(.resizable-false)'); + if (!$(this).find('.tablesorter-wrapper').length) { + // Firefox needs this inner div to position the resizer correctly + $c.wrapInner('
'); + } + // don't include the last column of the row + if (!wo.resizable_addLastColumn) { $c = $c.slice(0,-1); } + $cols = $cols ? $cols.add($c) : $c; + }); + $cols + .each(function(){ + $t = $(this); + j = parseInt($t.css('padding-right'), 10) + 10; // 8 is 1/2 of the 16px wide resizer grip + t = '
'; + $t + .find('.tablesorter-wrapper') + .append(t); + }) + .bind('mousemove.tsresize', function(e){ + // ignore mousemove if no mousedown + if (position === 0 || !$target) { return; } + // resize columns + w = e.pageX - position; + tw = $target.width(); + $target.width( tw + w ); + if ($target.width() !== tw && fullWidth){ + $next.width( $next.width() - w ); + } + position = e.pageX; + }) + .bind('mouseup.tsresize', function(){ + stopResize(); + }) + .find('.tablesorter-resizer,.tablesorter-resizer-grip') + .bind('mousedown', function(e){ + // save header cell and mouse position; closest() not supported by jQuery v1.2.6 + $target = $(e.target).closest('th'); + t = c.$headers.filter('[data-column="' + $target.attr('data-column') + '"]'); + if (t.length > 1) { $target = $target.add(t); } + // if table is not as wide as it's parent, then resize the table + $next = e.shiftKey ? $target.parent().find('th:not(.resizable-false)').filter(':last') : $target.nextAll(':not(.resizable-false)').eq(0); + position = e.pageX; + }); + $tbl.find('thead:first') + .bind('mouseup.tsresize mouseleave.tsresize', function(){ + stopResize(); + }) + // right click to reset columns to default widths + .bind('contextmenu.tsresize', function(){ + ts.resizableReset(table); + // $.isEmptyObject() needs jQuery 1.4+ + var rtn = $.isEmptyObject ? $.isEmptyObject(s) : s === {}; // allow right click if already reset + s = {}; + return rtn; + }); + }, + remove: function(table, c, wo){ + c.$table + .removeClass('hasResizable') + .find('thead') + .unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize') + .find('tr').children() + .unbind('mousemove.tsresize mouseup.tsresize') + // don't remove "tablesorter-wrapper" as uitheme uses it too + .find('.tablesorter-resizer,.tablesorter-resizer-grip').remove(); + ts.resizableReset(table); + } +}); +ts.resizableReset = function(table){ + table.config.$headers.filter(':not(.resizable-false)').css('width',''); + if (ts.storage) { ts.storage(table, 'tablesorter-resizable', {}); } +}; + +// Save table sort widget +// this widget saves the last sort only if the +// saveSort widget option is true AND the +// $.tablesorter.storage function is included +// ************************** +ts.addWidget({ + id: 'saveSort', + priority: 20, + options: { + saveSort : true + }, + init: function(table, thisWidget, c, wo){ + // run widget format before all other widgets are applied to the table + thisWidget.format(table, c, wo, true); + }, + format: function(table, c, wo, init){ + var sl, time, + $t = c.$table, + ss = wo.saveSort !== false, // make saveSort active/inactive; default to true + sortList = { "sortList" : c.sortList }; + if (c.debug){ + time = new Date(); + } + if ($t.hasClass('hasSaveSort')){ + if (ss && table.hasInitialized && ts.storage){ + ts.storage( table, 'tablesorter-savesort', sortList ); + if (c.debug){ + ts.benchmark('saveSort widget: Saving last sort: ' + c.sortList, time); + } + } + } else { + // set table sort on initial run of the widget + $t.addClass('hasSaveSort'); + sortList = ''; + // get data + if (ts.storage){ + sl = ts.storage( table, 'tablesorter-savesort' ); + sortList = (sl && sl.hasOwnProperty('sortList') && $.isArray(sl.sortList)) ? sl.sortList : ''; + if (c.debug){ + ts.benchmark('saveSort: Last sort loaded: "' + sortList + '"', time); + } + $t.bind('saveSortReset', function(e){ + e.stopPropagation(); + ts.storage( table, 'tablesorter-savesort', '' ); + }); + } + // init is true when widget init is run, this will run this widget before all other widgets have initialized + // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice. + if (init && sortList && sortList.length > 0){ + c.sortList = sortList; + } else if (table.hasInitialized && sortList && sortList.length > 0){ + // update sort change + $t.trigger('sorton', [sortList]); + } + } + }, + remove: function(table){ + // clear storage + if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); } + } +}); + +})(jQuery); diff --git a/templates/admin/default/assets/less/main.less b/templates/admin/default/assets/less/main.less index 7ad14e013..3498441a2 100644 --- a/templates/admin/default/assets/less/main.less +++ b/templates/admin/default/assets/less/main.less @@ -2,5 +2,4 @@ @import "bootstrap/bootstrap.less"; /* Thelia Admin */ -@import "thelia/thelia.less"; -// @import "thelia/responsive.less"; \ No newline at end of file +@import "thelia/thelia.less"; \ No newline at end of file diff --git a/templates/admin/default/assets/less/thelia/thelia.less b/templates/admin/default/assets/less/thelia/thelia.less index 3883c7067..8576272bf 100644 --- a/templates/admin/default/assets/less/thelia/thelia.less +++ b/templates/admin/default/assets/less/thelia/thelia.less @@ -247,4 +247,10 @@ .ui-slider{ margin-top: 23px; +} + +.loading{ + background: url("@{imgDir}/ajax-loader.gif") no-repeat; + height: 24px; + width: 24px; } \ No newline at end of file diff --git a/templates/admin/default/coupon-create.html b/templates/admin/default/coupon-create.html new file mode 100755 index 000000000..7cb31ee09 --- /dev/null +++ b/templates/admin/default/coupon-create.html @@ -0,0 +1,41 @@ +{extends file="admin-layout.tpl"} +{block name="check-permissions"}admin.coupon.create{/block} +{block name="page-title"}{intl l='Create coupon'}{/block} + +{block name="main-content"} +
+ + + + + + {form name="thelia.admin.coupon.creation"} + {include file='coupon/form.html' formAction={url path={$formAction}}} + {/form} + +
+ +{include file='includes/confirmation-modal.html'} +{/block} + +{block name="javascript-initialization"} + {javascripts file='assets/bootstrap-datepicker/js/bootstrap-datepicker.js'} + + {/javascripts} + + {javascripts file='assets/js/main.js'} + + {/javascripts} + + +{/block} diff --git a/templates/admin/default/coupon-list.html b/templates/admin/default/coupon-list.html new file mode 100755 index 000000000..331b97231 --- /dev/null +++ b/templates/admin/default/coupon-list.html @@ -0,0 +1,173 @@ +{extends file="admin-layout.tpl"} +{block name="check-permissions"}admin.coupon.view{/block} +{block name="page-title"}{intl l='Coupons'}{/block} + +{block name="main-content"} +
+ + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ List of enabled coupons +
CodeTitleExpiration dateUsage leftActions
XMAS13Coupon for XMAS -30 €18/10/201349 + Edit + Disable +
XMAS13Coupon for XMAS -30 €05/09/201320 + Edit + Disable +
XMAS13Coupon for XMAS -30 €03/12/20139 + Edit + Disable +
XMAS13Coupon for XMAS -30 €25/01/20134 + Edit + Disable +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ List of disabled coupons +
CodeTitleExpiration dateUsage leftActions
XMAS13Coupon for XMAS -30 €18/10/201349 + Edit + Enabled +
XMAS13Coupon for XMAS -20 €05/09/201349 + Edit + Enabled +
XMAS13Coupon for XMAS -50 €03/12/201349 + Edit + Enabled +
XMAS13Coupon for XMAS -5 €25/01/201349 + Edit + Enabled +
+
+
+ +
+ +{include file='includes/confirmation-modal.html' id="disable" message="{intl l='Do you really want to disable this element ?'}"} +{include file='includes/confirmation-modal.html' id="enable" message="{intl l='Do you really want to enable this element ?'}"} + +{/block} + + +{block name="javascript-initialization"} + + {javascripts file='assets/bootstrap-editable/js/bootstrap-editable.js'} + + {/javascripts} + + {javascripts file='assets/js/tablesorter/jquery.tablesorter.min.js'} + + {/javascripts} + + {javascripts file='assets/js/tablesorter/jquery.metadata.js'} + + {/javascripts} + + {javascripts file='assets/js/tablesorter/jquery.tablesorter.widgets.js'} + + {/javascripts} + + {javascripts file='assets/js/tablesorter/jquery.tablesorter.widgets-filter-formatter.js'} + + {/javascripts} + + {javascripts file='assets/js/main.js'} + + {/javascripts} +{/block} diff --git a/templates/admin/default/coupon-read.html b/templates/admin/default/coupon-read.html new file mode 100755 index 000000000..3c2d4bff1 --- /dev/null +++ b/templates/admin/default/coupon-read.html @@ -0,0 +1,124 @@ +{extends file="admin-layout.tpl"} +{block name="check-permissions"}admin.coupon.view{/block} +{block name="page-title"}{intl l='Coupon'}{/block} + +{block name="main-content"} +
+ + + + {loop type="coupon" name="read_coupon" id={$couponId} backend_context="true"} + + + +
+
+ +
+ + {if #IS_ENABLED}{else}{intl l='This coupon is disabled, you can enable to the bottom of this form.'}{/if} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{intl l='Title'}#TITLE
{intl l='Expiration date'}#EXPIRATION_DATE
{intl l='Usage left'} + {if #USAGE_LEFT} + + #USAGE_LEFT + + {else} + + 0 + + {/if} +
#SHORT_DESCRIPTION
#DESCRIPTION
+ {if #IS_CUMULATIVE} + + {intl l="May be cumulative"} + + {else} + + {intl l="Can't be cumulative"} + + {/if} +
+ {if #IS_REMOVING_POSTAGE} + + {intl l="Will remove postage"} + + {else} + + {intl l="Won't remove postage"} + + {/if} +
{intl l='Amount'}#AMOUNT
{intl l='Application field'} +
    + {foreach from=$APPLICATION_CONDITIONS item=rule name=rulesForeach} + {if !$smarty.foreach.rulesForeach.first} +
  • {intl l='And'}
  • + {/if} +
  • {$rule nofilter}
  • + {/foreach} +
+
{intl l='Actions'} + {intl l='Edit'} + {intl l='Enabled'} +
+ {/loop} +
+
+
+ +{include file='includes/confirmation-modal.html' id="enable" message="{intl l='Do you really want to enable this element ?'}"} + +{/block} + +{block name="javascript-initialization"} + {javascripts file='assets/js/main.js'} + + {/javascripts} + +{/block} diff --git a/templates/admin/default/coupon-update.html b/templates/admin/default/coupon-update.html new file mode 100755 index 000000000..9b6387cd7 --- /dev/null +++ b/templates/admin/default/coupon-update.html @@ -0,0 +1,161 @@ +{extends file="admin-layout.tpl"} +{block name="check-permissions"}admin.coupon.update{/block} +{block name="page-title"}{intl l='Update coupon'}{/block} + +{block name="main-content"} +
+ + + + + + {form name="thelia.admin.coupon.creation"} + {include file='coupon/form.html' formAction={url path={$formAction}} form=$form} + {/form} + +
+{/block} + +{include file='includes/confirmation-modal.html'} + +{block name="javascript-initialization"} + {javascripts file='assets/bootstrap-datepicker/js/bootstrap-datepicker.js'} + + {/javascripts} + + {javascripts file='assets/js/main.js'} + + {/javascripts} + + {javascripts file='assets/js/json2.js'} + + {/javascripts} + + +{/block} diff --git a/templates/admin/default/coupon/form.html b/templates/admin/default/coupon/form.html new file mode 100644 index 000000000..e22136d41 --- /dev/null +++ b/templates/admin/default/coupon/form.html @@ -0,0 +1,294 @@ +{$thelia_page_css_file = "assets/bootstrap-editable/css/bootstrap-editable.css"} +{include file='includes/notifications.html' message=$general_error} + +
+
+ + {form_hidden_fields form=$form} + + {form_field form=$form field='locale'} + + {/form_field} + + {form_field form=$form field='success_url'} + + {/form_field} + +
+
+
+
+ + {form_field form=$form field='code'} + + {if $error}{$message}{/if} + {/form_field} +
+ +
+ + {form_field form=$form field='title'} + + {if $error}{$message}{/if} + {/form_field} +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ {form_field form=$form field='expirationDate'} + + {if $error}{$message}{/if} + {/form_field} + +
+
+ +
+ + + {form_field form=$form field='maxUsage'} + + {if $error}{$message}{/if} + {/form_field} +
+
+ +
+
+
+
+ + {form_field form=$form field='effect'} + + {if $error}{$message}{/if} + {/form_field} + {$availableCoupons.0.toolTip} +
+
+ +
+
+ + {form_field form=$form field='amount'} + + {if $error}{$message}{/if} + {/form_field} +
+
+ + {*form_field form=$form field='category'*} + + {*if $error}{$message}{/if}*} + {*/form_field*} +
+
+
+ +
+ + {form_field form=$form field='shortDescription'} + + {if $error}{$message}{/if} + {/form_field} +
+
+ +
+
+ +
+ + {form_field form=$form field='description'} + + {if $error}{$message}{/if} + {/form_field} +
+ + +
+ +
+
+ +
+
+ + + + + + + + + + {include file='coupon/rules.html' rules=$rulesObject} + {*{foreach from=$rulesObject item=rule name=rulesForeach}*} + {**} + {**} + + {**} + {**} + {*{/foreach}*} + +
+ {intl l='Rules'} +
{intl l='Conditions'}{intl l='Actions'}
*} + {*{if !$smarty.foreach.rulesForeach.first}*} + {*{intl l='And'}*} + {*{/if}*} + {*{$rule.tooltip nofilter}*} + {**} + {* {intl l='Edit'}*} + {* {intl l='Delete'}*} + {*
+
+
+ +
+
+ + + + +
+ + + +
+ +
+ + +
+ +
+ {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {**} + {*
*} + {*
*} + {**} + + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {**} + {*
*} + {*
*} + + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {*
*} + {*
*} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {*
Categories list
*} + {*
*} + {*
*} +
+
+
+ + diff --git a/templates/admin/default/coupon/rule-input-ajax.html b/templates/admin/default/coupon/rule-input-ajax.html new file mode 100644 index 000000000..cf921932b --- /dev/null +++ b/templates/admin/default/coupon/rule-input-ajax.html @@ -0,0 +1,102 @@ +{*{$inputs.inputs|var_dump}*} +{foreach from=$inputs.inputs key=name item=input} + +
+
+ +
+
+ {if $input.type == 'select'} + + {else} + + {**} + {/if} +
+
+{/foreach} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {**} + {*
*} + {*
*} + {*
*} + {*
*} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {**} + {*
Categories list
*} + {*
*} + {*
*} + + \ No newline at end of file diff --git a/templates/admin/default/coupon/rules.html b/templates/admin/default/coupon/rules.html new file mode 100644 index 000000000..8dca66c49 --- /dev/null +++ b/templates/admin/default/coupon/rules.html @@ -0,0 +1,18 @@ +{foreach from=$rules item=rule name=rulesForeach} + + + {if !$smarty.foreach.rulesForeach.first} + {intl l='And'} + {/if} + {$rule nofilter} + + + + {intl l='Edit'} + + + {intl l='Delete'} + + + +{/foreach} diff --git a/templates/admin/default/customers.html b/templates/admin/default/customers.html new file mode 100644 index 000000000..ea498f72c --- /dev/null +++ b/templates/admin/default/customers.html @@ -0,0 +1,139 @@ + +{extends file="admin-layout.tpl"} + +{block name="page-title"}{intl l='Customer'}{/block} + +{block name="check-permissions"}admin.customer.view{/block} + +{block name="main-content"} + {assign var=customer_page value={$smarty.get.page|default:1}} + + +
+
+ + + {module_include location='customer_top'} + +
+
+
+ + + + {ifloop rel="customer_list"} + + + + + + + {module_include location='category_list_header'} + + + + + + + + + + + + + {loop name="customer_list" type="customer" current="false" visible="*" last_order="1" backend_context="1" page={$customer_page} limit={$display_customer}} + + + + + + + + {module_include location='customer_list_row'} + + + + + + + + {/loop} + + {/ifloop} +
+ {intl l="Customers list"} + + {module_include location='customer_list_caption'} + + {loop type="auth" name="can_create" roles="ADMIN" permissions="admin.customers.create"} + + + + {/loop} +
+ {intl l="customer ref"} + + {intl l="company"} + + {intl l="firstname & lastname"} + + {intl l="last order"} + {intl l='order amount'}{intl l='Actions'}
{#REF} + {#COMPANY} + + {#FIRSTNAME} {#LASTNAME} + + {format_date date=$LASTORDER_DATE} + + {format_number number=$LASTORDER_AMOUNT} + +
+ + {loop type="auth" name="can_change" roles="ADMIN" permissions="admin.customer.edit"} + + {/loop} + {loop type="auth" name="can_send_mail" roles="ADMIN" permissions="admin.customer.sendMail"} + + {/loop} + {loop type="auth" name="can_delete" roles="ADMIN" permissions="admin.customer.delete"} + + {/loop} +
+
+
+
+
+ + + {module_include location='customer_bottom'} +
+
+ +
    + {if #customer_page != 1} +
  • «
  • + {else} +
  • «
  • + {/if} + + {pageloop rel="customer_list"} + {if #PAGE != #CURRENT} +
  • #PAGE
  • + {else} +
  • #PAGE
  • + {/if} + + {if #PAGE == #LAST && #LAST != #CURRENT} +
  • »
  • + {else} +
  • »
  • + {/if} + {/pageloop} +
+
+
+ +
+
+ +{/block} \ No newline at end of file diff --git a/templates/admin/default/includes/confirmation-modal.html b/templates/admin/default/includes/confirmation-modal.html new file mode 100644 index 000000000..957960416 --- /dev/null +++ b/templates/admin/default/includes/confirmation-modal.html @@ -0,0 +1,36 @@ +{* + Params + - id : aside element id (default delete) + - title : modal title (default Confirmation) + - message : modal message (default Do you really want to delete this element ?) +*} +{block name="confirmation-modal"} + +{/block} \ No newline at end of file diff --git a/templates/admin/default/includes/coupon_breadcrumb.html b/templates/admin/default/includes/coupon_breadcrumb.html new file mode 100755 index 000000000..878d9605d --- /dev/null +++ b/templates/admin/default/includes/coupon_breadcrumb.html @@ -0,0 +1,5 @@ +{* Breadcrumb for coupon browsing and editing *} + +
  • Home
  • +
  • Coupon
  • +
  • Browse
  • \ No newline at end of file diff --git a/templates/admin/default/includes/notifications.html b/templates/admin/default/includes/notifications.html new file mode 100644 index 000000000..d559caa65 --- /dev/null +++ b/templates/admin/default/includes/notifications.html @@ -0,0 +1,11 @@ +{* + Params + - type : notification type (default alert) + - message : modal message +*} +{if $message} +
    + + {$message} +
    +{/if} \ No newline at end of file diff --git a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css new file mode 100755 index 000000000..a24a8e142 --- /dev/null +++ b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.css @@ -0,0 +1,19 @@ +.magnify { + position: relative; + cursor: none +} + +.magnify-large { + position: absolute; + display: none; + width: 175px; + height: 175px; + + -webkit-box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); + box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.85), 0 0 7px 7px rgba(0, 0, 0, 0.25), inset 0 0 40px 2px rgba(0, 0, 0, 0.25); + + -webkit-border-radius: 100%; + -moz-border-radius: 100%; + border-radius: 100% +} \ No newline at end of file diff --git a/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css new file mode 100755 index 000000000..15b9cc170 --- /dev/null +++ b/templates/default/assets/css/plugins/bootstrap-magnify/bootstrap-magnify.min.css @@ -0,0 +1 @@ +.magnify{position:relative;cursor:none}.magnify-large{position:absolute;display:none;width:175px;height:175px;-webkit-box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);-moz-box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);box-shadow:0 0 0 7px rgba(255,255,255,0.85),0 0 7px 7px rgba(0,0,0,0.25),inset 0 0 40px 2px rgba(0,0,0,0.25);-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%} \ No newline at end of file diff --git a/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.eot b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.eot new file mode 100755 index 000000000..87eaa4342 Binary files /dev/null and b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.eot differ diff --git a/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.svg b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.svg new file mode 100755 index 000000000..5fee06854 --- /dev/null +++ b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.ttf b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.ttf new file mode 100755 index 000000000..be784dc1d Binary files /dev/null and b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.ttf differ diff --git a/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.woff b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.woff new file mode 100755 index 000000000..2cc3e4852 Binary files /dev/null and b/templates/default/assets/font/bootstrap/glyphicons-halflings-regular.woff differ diff --git a/templates/default/assets/font/fontawesome/fontawesome-webfont.eot b/templates/default/assets/font/fontawesome/fontawesome-webfont.eot new file mode 100755 index 000000000..0662cb96b Binary files /dev/null and b/templates/default/assets/font/fontawesome/fontawesome-webfont.eot differ diff --git a/templates/default/assets/font/fontawesome/fontawesome-webfont.svg b/templates/default/assets/font/fontawesome/fontawesome-webfont.svg new file mode 100755 index 000000000..2edb4ec34 --- /dev/null +++ b/templates/default/assets/font/fontawesome/fontawesome-webfont.svg @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/default/assets/font/fontawesome/fontawesome-webfont.ttf b/templates/default/assets/font/fontawesome/fontawesome-webfont.ttf new file mode 100755 index 000000000..d36592469 Binary files /dev/null and b/templates/default/assets/font/fontawesome/fontawesome-webfont.ttf differ diff --git a/templates/default/assets/font/fontawesome/fontawesome-webfont.woff b/templates/default/assets/font/fontawesome/fontawesome-webfont.woff new file mode 100755 index 000000000..b9bd17e15 Binary files /dev/null and b/templates/default/assets/font/fontawesome/fontawesome-webfont.woff differ diff --git a/templates/default/assets/img/218x146.png b/templates/default/assets/img/218x146.png new file mode 100644 index 000000000..07f043b12 Binary files /dev/null and b/templates/default/assets/img/218x146.png differ diff --git a/templates/default/assets/img/280x196.png b/templates/default/assets/img/280x196.png new file mode 100644 index 000000000..0df3c9403 Binary files /dev/null and b/templates/default/assets/img/280x196.png differ diff --git a/templates/default/assets/img/700x320.png b/templates/default/assets/img/700x320.png new file mode 100644 index 000000000..32c9edcb1 Binary files /dev/null and b/templates/default/assets/img/700x320.png differ diff --git a/templates/default/assets/img/carousel/1200x390.png b/templates/default/assets/img/carousel/1200x390.png new file mode 100644 index 000000000..2de73de49 Binary files /dev/null and b/templates/default/assets/img/carousel/1200x390.png differ diff --git a/templates/default/assets/img/carousel/slider1.png b/templates/default/assets/img/carousel/slider1.png new file mode 100644 index 000000000..422b3ddc0 Binary files /dev/null and b/templates/default/assets/img/carousel/slider1.png differ diff --git a/templates/default/assets/img/carousel/slider2.png b/templates/default/assets/img/carousel/slider2.png new file mode 100644 index 000000000..8eb4049b7 Binary files /dev/null and b/templates/default/assets/img/carousel/slider2.png differ diff --git a/templates/default/assets/img/carousel/slider3.png b/templates/default/assets/img/carousel/slider3.png new file mode 100644 index 000000000..b3630ff60 Binary files /dev/null and b/templates/default/assets/img/carousel/slider3.png differ diff --git a/templates/default/assets/img/logo.gif b/templates/default/assets/img/logo.gif new file mode 100644 index 000000000..cfa396641 Binary files /dev/null and b/templates/default/assets/img/logo.gif differ diff --git a/templates/default/assets/img/payment/american-express.png b/templates/default/assets/img/payment/american-express.png new file mode 100644 index 000000000..853b43dae Binary files /dev/null and b/templates/default/assets/img/payment/american-express.png differ diff --git a/templates/default/assets/img/payment/cheque.png b/templates/default/assets/img/payment/cheque.png new file mode 100644 index 000000000..16d83ba11 Binary files /dev/null and b/templates/default/assets/img/payment/cheque.png differ diff --git a/templates/default/assets/img/payment/kwixo.png b/templates/default/assets/img/payment/kwixo.png new file mode 100644 index 000000000..2055f9c8a Binary files /dev/null and b/templates/default/assets/img/payment/kwixo.png differ diff --git a/templates/default/assets/img/payment/mastercard.png b/templates/default/assets/img/payment/mastercard.png new file mode 100644 index 000000000..28701c3dd Binary files /dev/null and b/templates/default/assets/img/payment/mastercard.png differ diff --git a/templates/default/assets/img/payment/visa.png b/templates/default/assets/img/payment/visa.png new file mode 100644 index 000000000..ef0447105 Binary files /dev/null and b/templates/default/assets/img/payment/visa.png differ diff --git a/templates/default/assets/img/product/1/118x85.png b/templates/default/assets/img/product/1/118x85.png new file mode 100644 index 000000000..cf9e98b4a Binary files /dev/null and b/templates/default/assets/img/product/1/118x85.png differ diff --git a/templates/default/assets/img/product/1/560x445.png b/templates/default/assets/img/product/1/560x445.png new file mode 100644 index 000000000..37fea1775 Binary files /dev/null and b/templates/default/assets/img/product/1/560x445.png differ diff --git a/templates/default/assets/js/bootstrap/affix.js b/templates/default/assets/js/bootstrap/affix.js new file mode 100755 index 000000000..c7be96e1d --- /dev/null +++ b/templates/default/assets/js/bootstrap/affix.js @@ -0,0 +1,126 @@ +/* ======================================================================== + * Bootstrap: affix.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#affix + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + this.$window = $(window) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = + this.unpin = null + + this.checkPosition() + } + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0 + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var scrollHeight = $(document).height() + var scrollTop = this.$window.scrollTop() + var position = this.$element.offset() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top() + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom() + + var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false : + offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' : + offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false + + if (this.affixed === affix) return + if (this.unpin) this.$element.css('top', '') + + this.affixed = affix + this.unpin = affix == 'bottom' ? position.top - scrollTop : null + + this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : '')) + + if (affix == 'bottom') { + this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + var old = $.fn.affix + + $.fn.affix = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom) data.offset.bottom = data.offsetBottom + if (data.offsetTop) data.offset.top = data.offsetTop + + $spy.affix(data) + }) + }) + +}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/alert.js b/templates/default/assets/js/bootstrap/alert.js new file mode 100755 index 000000000..663029ed8 --- /dev/null +++ b/templates/default/assets/js/bootstrap/alert.js @@ -0,0 +1,98 @@ +/* ======================================================================== + * Bootstrap: alert.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#alerts + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/button.js b/templates/default/assets/js/bootstrap/button.js new file mode 100755 index 000000000..fc73b555f --- /dev/null +++ b/templates/default/assets/js/bootstrap/button.js @@ -0,0 +1,109 @@ +/* ======================================================================== + * Bootstrap: button.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#buttons + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d); + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + .prop('checked', !this.$element.hasClass('active')) + .trigger('change') + if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active') + } + + this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/carousel.js b/templates/default/assets/js/bootstrap/carousel.js new file mode 100755 index 000000000..d8c4c243c --- /dev/null +++ b/templates/default/assets/js/bootstrap/carousel.js @@ -0,0 +1,217 @@ +/* ======================================================================== + * Bootstrap: carousel.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#carousel + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000 + , pause: 'hover' + , wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + this.sliding = true + + isCycling && this.pause() + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + .emulateTransitionEnd(600) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/collapse.js b/templates/default/assets/js/bootstrap/collapse.js new file mode 100755 index 000000000..92cc0bc76 --- /dev/null +++ b/templates/default/assets/js/bootstrap/collapse.js @@ -0,0 +1,179 @@ +/* ======================================================================== + * Bootstrap: collapse.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#collapse + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(window.jQuery); diff --git a/templates/default/assets/js/bootstrap/dropdown.js b/templates/default/assets/js/bootstrap/dropdown.js new file mode 100755 index 000000000..6093f11a8 --- /dev/null +++ b/templates/default/assets/js/bootstrap/dropdown.js @@ -0,0 +1,154 @@ +/* ======================================================================== + * Bootstrap: dropdown.js v3.0.0 + * http://twbs.github.com/bootstrap/javascript.html#dropdowns + * ======================================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== */ + + ++function ($) { "use strict"; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + var $el = $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we we use a backdrop because click events don't delegate + $('