mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
[API][Admin] Validate product variants on product images
This commit is contained in:
parent
078ea0436c
commit
2bb655e2ee
12 changed files with 261 additions and 2 deletions
|
|
@ -97,5 +97,9 @@
|
|||
<argument type="service" id="sylius.repository.product" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_product_code_exists" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.validator.sylius_product_image_variants_belong_to_owner" class="Sylius\Bundle\CoreBundle\Validator\Constraints\ProductImageVariantsBelongToOwnerValidator">
|
||||
<tag name="validator.constraint_validator" alias="sylius_product_image_variants_belong_to_owner" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
|
||||
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/services/constraint-mapping-1.0.xsd">
|
||||
<class name="Sylius\Component\Core\Model\ProductImage">
|
||||
<constraint name="Sylius\Bundle\CoreBundle\Validator\Constraints\ProductImageVariantsBelongToOwner">
|
||||
<option name="groups">sylius</option>
|
||||
</constraint>
|
||||
|
||||
<property name="file">
|
||||
<constraint name="Image">
|
||||
<option name="maxSize">10M</option>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ sylius:
|
|||
file:
|
||||
max_size: The image is too big - {{ size }}{{ suffix }}. Maximum allowed size is {{ limit }}{{ suffix }}.
|
||||
upload_ini_size: The image is too big. Maximum allowed size is {{ limit }}{{ suffix }}.
|
||||
product_variant:
|
||||
not_belong_to_owner: 'The product variant with code "%productVariantCode%" does not belong to the product with "%ownerCode%", which is the owner of the image.'
|
||||
product_taxon:
|
||||
unique: Product taxons cannot be duplicated.
|
||||
product:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?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;
|
||||
|
||||
final class ProductImageVariantsBelongToOwner extends Constraint
|
||||
{
|
||||
public string $message = 'sylius.product_image.product_variant.not_belong_to_owner';
|
||||
|
||||
public function getTargets(): string
|
||||
{
|
||||
return self::CLASS_CONSTRAINT;
|
||||
}
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
return 'sylius_product_image_variants_belong_to_owner';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?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 Sylius\Component\Core\Model\ProductImageInterface;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class ProductImageVariantsBelongToOwnerValidator extends ConstraintValidator
|
||||
{
|
||||
public function validate(mixed $value, Constraint $constraint): void
|
||||
{
|
||||
/** @var ProductImageInterface $value */
|
||||
Assert::isInstanceOf($value, ProductImageInterface::class);
|
||||
|
||||
/** @var ProductImageVariantsBelongToOwner $constraint */
|
||||
Assert::isInstanceOf($constraint, ProductImageVariantsBelongToOwner::class);
|
||||
|
||||
/** @var ProductInterface $product */
|
||||
$owner = $value->getOwner();
|
||||
|
||||
foreach ($value->getProductVariants() as $productVariant) {
|
||||
if (!$owner->hasVariant($productVariant)) {
|
||||
$this->context->addViolation($constraint->message, [
|
||||
'%productVariantCode%' => $productVariant->getCode(),
|
||||
'%ownerCode%' => $owner->getCode(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<?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 Doctrine\Common\Collections\ArrayCollection;
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\CoreBundle\Validator\Constraints\ProductImageVariantsBelongToOwner;
|
||||
use Sylius\Component\Core\Model\ProductImageInterface;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Sylius\Component\Core\Model\ProductVariantInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
final class ProductImageVariantsBelongToOwnerValidatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(ExecutionContextInterface $executionContext): void
|
||||
{
|
||||
$this->initialize($executionContext);
|
||||
}
|
||||
|
||||
function it_is_a_constraint_validator(): void
|
||||
{
|
||||
$this->shouldImplement(ConstraintValidatorInterface::class);
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_value_is_not_product_image(): void
|
||||
{
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', [new \stdClass(), new ProductImageVariantsBelongToOwner()])
|
||||
;
|
||||
}
|
||||
|
||||
function it_throws_an_exception_if_constraint_is_not_product_image_variants_belong_to_owner(
|
||||
Constraint $constraint,
|
||||
ProductImageInterface $image,
|
||||
): void {
|
||||
$this
|
||||
->shouldThrow(\InvalidArgumentException::class)
|
||||
->during('validate', [$image, $constraint])
|
||||
;
|
||||
}
|
||||
|
||||
function it_adds_a_violation_if_any_variant_does_not_belong_to_a_product_which_is_an_owner(
|
||||
ExecutionContextInterface $executionContext,
|
||||
ProductImageInterface $image,
|
||||
ProductInterface $product,
|
||||
ProductVariantInterface $variant,
|
||||
): void {
|
||||
$image->getOwner()->willReturn($product);
|
||||
$image->getProductVariants()->willReturn(new ArrayCollection([$variant->getWrappedObject()]));
|
||||
|
||||
$product->getCode()->willReturn('MUG');
|
||||
$product->hasVariant($variant)->willReturn(false);
|
||||
|
||||
$variant->getCode()->willReturn('GREEN_MUG');
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'sylius.product_image.product_variant.not_belong_to_owner',
|
||||
['%productVariantCode%' => 'GREEN_MUG', '%ownerCode%' => 'MUG'],
|
||||
)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$this->validate($image, new ProductImageVariantsBelongToOwner());
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ class ProductImage extends Image implements ProductImageInterface
|
|||
|
||||
public function __construct()
|
||||
{
|
||||
/** @var ArrayCollection<array-key, ProductVariantInterface> $this->productVaraints */
|
||||
/** @var ArrayCollection<array-key, ProductVariantInterface> $this->productVariants */
|
||||
$this->productVariants = new ArrayCollection();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,11 +146,44 @@ final class ProductImagesTest extends JsonApiTestCase
|
|||
$response = $this->client->getResponse();
|
||||
$this->assertResponse(
|
||||
$response,
|
||||
'admin/product_image/post_product_image_with_type_response',
|
||||
'admin/product_image/post_product_image_with_type_and_variant_response',
|
||||
Response::HTTP_CREATED,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_creates_a_product_image_with_invalid_variant(): void
|
||||
{
|
||||
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'product/product_image.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
/** @var ProductInterface $product */
|
||||
$product = $fixtures['product_mug'];
|
||||
|
||||
/** @var ProductVariantInterface $productVariant */
|
||||
$productVariant = $fixtures['product_variant_cap_yellow'];
|
||||
|
||||
$this->client->request(
|
||||
method: 'POST',
|
||||
uri: sprintf('/api/v2/admin/products/%s/images', $product->getCode()),
|
||||
parameters: [
|
||||
'type' => 'banner',
|
||||
'productVariants' => [
|
||||
sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
||||
],
|
||||
],
|
||||
files: ['file' => $this->getUploadedFile('fixtures/mugs.jpg', 'mugs.jpg')],
|
||||
server: $header,
|
||||
);
|
||||
|
||||
$response = $this->client->getResponse();
|
||||
$this->assertResponse(
|
||||
$response,
|
||||
'admin/product_image/post_product_image_with_invalid_variant_response',
|
||||
Response::HTTP_UNPROCESSABLE_ENTITY,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_updates_only_the_type_and_variants_of_the_existing_product_image(): void
|
||||
{
|
||||
|
|
@ -191,6 +224,36 @@ final class ProductImagesTest extends JsonApiTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_updates_the_existing_product_image_with_invalid_variant(): void
|
||||
{
|
||||
$fixtures = $this->loadFixturesFromFiles(['authentication/api_administrator.yaml', 'product/product_image.yaml']);
|
||||
$header = array_merge($this->logInAdminUser('api@example.com'), self::CONTENT_TYPE_HEADER);
|
||||
|
||||
/** @var ProductImageInterface $productImage */
|
||||
$productImage = $fixtures['product_mug_thumbnail'];
|
||||
|
||||
/** @var ProductVariantInterface $productVariant */
|
||||
$productVariant = $fixtures['product_variant_cap_yellow'];
|
||||
|
||||
$this->client->request(
|
||||
method: 'PUT',
|
||||
uri: sprintf('/api/v2/admin/product-images/%s', $productImage->getId()),
|
||||
server: $header,
|
||||
content: json_encode([
|
||||
'productVariants' => [
|
||||
sprintf('/api/v2/admin/product-variants/%s', $productVariant->getCode()),
|
||||
],
|
||||
], JSON_THROW_ON_ERROR),
|
||||
);
|
||||
|
||||
$this->assertResponse(
|
||||
$this->client->getResponse(),
|
||||
'admin/product_image/put_product_image_with_invalid_variant_response',
|
||||
Response::HTTP_UNPROCESSABLE_ENTITY,
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_deletes_a_product_image(): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ Sylius\Component\Core\Model\ProductVariant:
|
|||
product: '@product_mug'
|
||||
fallbackLocale: 'en_US'
|
||||
currentLocale: 'en'
|
||||
product_variant_cap_yellow:
|
||||
code: 'CAP_YELLOW'
|
||||
product: '@product_cap'
|
||||
fallbackLocale: 'en_US'
|
||||
currentLocale: 'en'
|
||||
|
||||
Sylius\Component\Core\Model\ProductImage:
|
||||
product_mug_thumbnail:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/ConstraintViolationList",
|
||||
"@type": "ConstraintViolationList",
|
||||
"hydra:title": "An error occurred",
|
||||
"hydra:description": "The product variant with code \"CAP_YELLOW\" does not belong to the product with \"MUG\", which is the owner of the image.",
|
||||
"violations": [
|
||||
{
|
||||
"propertyPath": "",
|
||||
"message": "The product variant with code \"CAP_YELLOW\" does not belong to the product with \"MUG\", which is the owner of the image.",
|
||||
"code": null
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@context": "\/api\/v2\/contexts\/ConstraintViolationList",
|
||||
"@type": "ConstraintViolationList",
|
||||
"hydra:title": "An error occurred",
|
||||
"hydra:description": "The product variant with code \"CAP_YELLOW\" does not belong to the product with \"MUG\", which is the owner of the image.",
|
||||
"violations": [
|
||||
{
|
||||
"propertyPath": "",
|
||||
"message": "The product variant with code \"CAP_YELLOW\" does not belong to the product with \"MUG\", which is the owner of the image.",
|
||||
"code": null
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue