diff --git a/UPGRADE-API-1.11.md b/UPGRADE-API-1.11.md index 39d115b5a16..7dff0b545fe 100644 --- a/UPGRADE-API-1.11.md +++ b/UPGRADE-API-1.11.md @@ -1,5 +1,27 @@ # UPGRADE FROM `v1.10.X` TO `v1.11.0` +1. The product images should have a proper prefix (`/media/image/`) added to the path, so the images could be resolved. + This is now done out of the box and response of `Product Image` resource is now: + + ```diff + { + "@context": "/api/v2/contexts/ProductImage", + "@id": "/api/v2/shop/product-images/123", + "@type": "ProductImage", + "id": "123", + "type": "thumbnail", + - "path": "uo/product.jpg", + + "path": "/media/image/uo/product.jpg" + } + ``` + + To change the prefix you need to set parameter in ``app/config/packages/_sylius.yaml``: + + ```yaml + sylius_api: + product_image_prefix: 'media/image' + ``` + 1. `Sylius\Bundle\ApiBundle\Doctrine\Filters\ExchangeRateFilter` and `Sylius\Bundle\ApiBundle\Doctrine\Filters\TranslationOrderNameAndLocaleFilter` has been moved to `Sylius\Bundle\ApiBundle\Doctrine\Filter\ExchangeRateFilter` and `Sylius\Bundle\ApiBundle\Doctrine\Filter\TranslationOrderNameAndLocaleFilter` respectively. 1. `Sylius\Bundle\ApiBundle\View\CartShippingMethodInterface` and `Sylius\Bundle\ApiBundle\View\CartShippingMethod` have been removed. diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingProductsContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingProductsContext.php index 4c9679b3c60..f944dbaa73f 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingProductsContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingProductsContext.php @@ -563,7 +563,7 @@ private function hasProductImage(Response $response, ProductInterface $product): return isset($productFromResponse['images'][0]) && - $productFromResponse['images'][0]['path'] === $product->getImages()->first()->getPath() + str_contains($productFromResponse['images'][0]['path'], $product->getImages()->first()->getPath()) ; } diff --git a/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php b/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php index a6a824c604b..9c4632f8759 100644 --- a/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php +++ b/src/Sylius/Bundle/ApiBundle/DependencyInjection/Configuration.php @@ -33,6 +33,11 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultFalse() ->end() ->end() + ->children() + ->variableNode('product_image_prefix') + ->defaultValue('media/image') + ->end() + ->end() ; return $treeBuilder; diff --git a/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php b/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php index 77c4c3f221d..2aebd76bbfc 100644 --- a/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php +++ b/src/Sylius/Bundle/ApiBundle/DependencyInjection/SyliusApiExtension.php @@ -27,6 +27,7 @@ public function load(array $configs, ContainerBuilder $container): void $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $container->setParameter('sylius_api.enabled', $config['enabled']); + $container->setParameter('sylius_api.product_image_prefix', $config['product_image_prefix']); $loader->load('services.xml'); } diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml index b09b0cb5223..d28b17cd716 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/serializers.xml @@ -36,6 +36,11 @@ + + %sylius_api.product_image_prefix% + + + diff --git a/src/Sylius/Bundle/ApiBundle/Serializer/ProductImageNormalizer.php b/src/Sylius/Bundle/ApiBundle/Serializer/ProductImageNormalizer.php new file mode 100644 index 00000000000..63d9e75e11c --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Serializer/ProductImageNormalizer.php @@ -0,0 +1,72 @@ +prefix = $this->validatePrefix($prefix); + } + + public function normalize($object, $format = null, array $context = []) + { + Assert::isInstanceOf($object, ProductImageInterface::class); + Assert::keyNotExists($context, self::ALREADY_CALLED); + + $context[self::ALREADY_CALLED] = true; + + $data = $this->normalizer->normalize($object, $format, $context); + + $data['path'] = $this->prefix . $data['path']; + + return $data; + } + + public function supportsNormalization($data, $format = null, $context = []): bool + { + if (isset($context[self::ALREADY_CALLED])) { + return false; + } + + return $data instanceof ProductImageInterface; + } + + private function validatePrefix(string $prefix): string + { + if (\DIRECTORY_SEPARATOR !== substr($prefix, 0, 1)) { + $prefix = \DIRECTORY_SEPARATOR . $prefix; + } + + if (\DIRECTORY_SEPARATOR === substr($prefix, -1)) { + return $prefix; + } + + return $prefix . \DIRECTORY_SEPARATOR; + } +} diff --git a/src/Sylius/Bundle/ApiBundle/spec/Serializer/ProductImageNormalizerSpec.php b/src/Sylius/Bundle/ApiBundle/spec/Serializer/ProductImageNormalizerSpec.php new file mode 100644 index 00000000000..718f5c23e65 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/Serializer/ProductImageNormalizerSpec.php @@ -0,0 +1,50 @@ +beConstructedWith('prefix', '/prefix', '/prefix/', 'prefix/'); + } + + function it_implements_context_aware_normalizer_interface(): void + { + $this->shouldImplement(ContextAwareNormalizerInterface::class); + } + + function it_supports_only_product_image_interface(ProductImageInterface $productImage, OrderInterface $order): void + { + $this->supportsNormalization($productImage)->shouldReturn(true); + $this->supportsNormalization($order)->shouldReturn(false); + } + + function it_serializes_product_image_with_proper_prefix( + NormalizerInterface $normalizer, + ProductImageInterface $productImage + ): void { + $this->setNormalizer($normalizer); + + $normalizer->normalize($productImage, null, ['product_image_normalizer_already_called' => true])->willReturn(['path' => 'some_path']); + + $this->normalize($productImage, null, [])->shouldReturn(['path' => '/prefix/some_path']); + } +} diff --git a/tests/Api/DataFixtures/ORM/product_image.yaml b/tests/Api/DataFixtures/ORM/product_image.yaml index 373553eb318..09d9523035c 100644 --- a/tests/Api/DataFixtures/ORM/product_image.yaml +++ b/tests/Api/DataFixtures/ORM/product_image.yaml @@ -8,4 +8,4 @@ Sylius\Component\Core\Model\Product: Sylius\Component\Core\Model\ProductImage: product_thumbnail: type: "thumbnail" - path: "/uo/product.jpg" + path: "uo/product.jpg" diff --git a/tests/Api/Responses/Expected/admin/get_product_image_response.json b/tests/Api/Responses/Expected/admin/get_product_image_response.json index b7b91d8cb29..426a45c6c94 100644 --- a/tests/Api/Responses/Expected/admin/get_product_image_response.json +++ b/tests/Api/Responses/Expected/admin/get_product_image_response.json @@ -4,5 +4,5 @@ "@type": "ProductImage", "id": "@integer@", "type": "thumbnail", - "path": "\/uo\/product.jpg" + "path": "\/media\/image\/uo\/product.jpg" } diff --git a/tests/Api/Responses/Expected/admin/get_product_images_response.json b/tests/Api/Responses/Expected/admin/get_product_images_response.json index 2a5a6081975..d81cf67f482 100644 --- a/tests/Api/Responses/Expected/admin/get_product_images_response.json +++ b/tests/Api/Responses/Expected/admin/get_product_images_response.json @@ -8,7 +8,7 @@ "@type": "ProductImage", "id": "@integer@", "type": "thumbnail", - "path": "\/uo\/product.jpg" + "path": "\/media\/image\/uo\/product.jpg" } ], "hydra:totalItems": 1 diff --git a/tests/Api/Responses/Expected/shop/get_product_image_response.json b/tests/Api/Responses/Expected/shop/get_product_image_response.json index 3156370acaa..7da3858e6c4 100644 --- a/tests/Api/Responses/Expected/shop/get_product_image_response.json +++ b/tests/Api/Responses/Expected/shop/get_product_image_response.json @@ -4,5 +4,5 @@ "@type": "ProductImage", "id": "@integer@", "type": "thumbnail", - "path": "\/uo\/product.jpg" + "path": "\/media\/image\/uo\/product.jpg" }