Add validation for cart item quantity range

This commit is contained in:
Wojdylak 2024-09-27 16:11:06 +02:00
parent 06c6fe06f9
commit 0e2772054e
No known key found for this signature in database
GPG key ID: 7509E560A6821ABE
8 changed files with 171 additions and 5 deletions

View file

@ -16,7 +16,7 @@ Feature: Changing quantity of a product in cart
Then I should see "T-Shirt banana" with quantity 2 in my cart
And my cart items total should be "$25.08"
@todo-api @ui @javascript
@api @ui @javascript
Scenario: Increasing quantity of an item in cart beyond the threshold
Given I see the summary of my cart
When I change product "T-Shirt banana" quantity to 20000 in my cart

View file

@ -291,7 +291,7 @@ final class CartContext implements Context
*/
public function iShouldBeNotifiedThatTheQuantityOfThisProductMustBeBetween(ProductInterface $product): void
{
Assert::false($this->responseChecker->hasViolationWithMessage(
Assert::true($this->responseChecker->hasViolationWithMessage(
$this->shopClient->getLastResponse(),
'Quantity must be between 1 and 9999.',
));

View file

@ -19,10 +19,11 @@
</option>
</constraint>
<property name="quantity">
<constraint name="Range">
<constraint name="Sylius\Bundle\CoreBundle\Validator\Constraints\CartItemQuantityRange">
<option name="min">1</option>
<option name="minMessage">sylius.order_item.quantity.min</option>
<option name="groups">sylius</option>
<option name="groups">
<value>sylius</value>
</option>
</constraint>
<constraint name="NotBlank">
<option name="message">sylius.order_item.quantity.not_blank</option>

View file

@ -136,5 +136,11 @@
<argument type="service" id="sylius.repository.zone" />
<tag name="validator.constraint_validator" alias="sylius_zone_code_exists" />
</service>
<service id="sylius.validator.cart_item_quantity_range" class="Sylius\Bundle\CoreBundle\Validator\Constraints\CartItemQuantityRangeValidator">
<argument type="service" id="property_accessor" />
<argument>%sylius.order_item_quantity_modifier.limit%</argument>
<tag name="validator.constraint_validator" alias="sylius_cart_item_quantity_range" />
</service>
</services>
</container>

View file

@ -27,5 +27,13 @@
<value>sylius_checkout_complete</value>
</option>
</constraint>
<property name="quantity">
<constraint name="Sylius\Bundle\CoreBundle\Validator\Constraints\CartItemQuantityRange">
<option name="min">1</option>
<option name="groups">
<value>sylius</value>
</option>
</constraint>
</property>
</class>
</constraint-mapping>

View file

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Range;
final class CartItemQuantityRange extends Range
{
public string $notInRangeMessage = 'sylius.cart_item.quantity.not_in_range';
public function validatedBy(): string
{
return 'sylius_cart_item_quantity_range';
}
public function getTargets(): string
{
return Constraint::PROPERTY_CONSTRAINT;
}
}

View file

@ -0,0 +1,40 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Sylius\Bundle\CoreBundle\Validator\Constraints;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\RangeValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
final class CartItemQuantityRangeValidator extends RangeValidator
{
public function __construct(
PropertyAccessorInterface $propertyAccessor,
private readonly int $orderItemQuantityModifierLimit,
) {
parent::__construct($propertyAccessor);
}
public function validate(mixed $value, Constraint $constraint): void
{
if (!$constraint instanceof CartItemQuantityRange) {
throw new UnexpectedTypeException($constraint, CartItemQuantityRange::class);
}
$constraint->max = $this->orderItemQuantityModifierLimit;
parent::validate($value, $constraint);
}
}

View file

@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace spec\Sylius\Bundle\CoreBundle\Validator\Constraints;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\CoreBundle\Validator\Constraints\CartItemQuantityRange;
use Sylius\Bundle\CoreBundle\Validator\Constraints\CountryCodeExists;
use Sylius\Component\Addressing\Model\CountryInterface;
use Sylius\Resource\Doctrine\Persistence\RepositoryInterface;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface;
final class CartItemQuantityRangeValidatorSpec extends ObjectBehavior
{
const MESSAGE = 'sylius.cart_item.quantity.not_in_range';
function let(PropertyAccessorInterface $propertyAccessor, ExecutionContextInterface $context): void
{
$this->beConstructedWith($propertyAccessor, 17);
$this->initialize($context);
}
function it_throws_an_exception_if_constraint_is_not_an_instance_of_cart_item_quantity_range(
Constraint $constraint,
): void {
$this
->shouldThrow(UnexpectedTypeException::class)
->during('validate', [9, $constraint])
;
}
function it_does_nothing_if_value_is_empty(
ExecutionContextInterface $context,
): void {
$this->validate(null, new CartItemQuantityRange(min: 1));
$context->buildViolation(self::MESSAGE)->shouldNotHaveBeenCalled();
}
function it_does_nothing_if_value_is_in_range(
RepositoryInterface $countryRepository,
ExecutionContextInterface $context,
CountryInterface $country,
): void {
$this->validate(5, new CartItemQuantityRange(min: 1));
$context->buildViolation(self::MESSAGE)->shouldNotHaveBeenCalled();
}
function it_adds_a_violation_if_value_is_not_in_range(
ExecutionContextInterface $context,
ConstraintViolationBuilderInterface $constraintViolationBuilder,
): void {
$constraintViolationBuilder->addViolation()->shouldBeCalled();
$constraintViolationBuilder->setCode(CartItemQuantityRange::NOT_IN_RANGE_ERROR)->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->atPath(Argument::any())->willReturn($constraintViolationBuilder);
$constraintViolationBuilder->setParameter(Argument::cetera())->willReturn($constraintViolationBuilder);
$context->buildViolation(self::MESSAGE)->shouldBeCalled()->willReturn($constraintViolationBuilder);
$this->validate(18, new CartItemQuantityRange(min: 1));
}
}