diff --git a/src/Attribute/ImageAttributeProcessor.php b/src/Attribute/ImageAttributeProcessor.php new file mode 100644 index 0000000..1527b55 --- /dev/null +++ b/src/Attribute/ImageAttributeProcessor.php @@ -0,0 +1,70 @@ +productImageFactory = $productImageFactory; + $this->productImageRepository = $productImageRepository; + $this->imageAttribute = $imageAttribute; + } + + /** {@inheritdoc} */ + public function process(ProductInterface $product, Attribute $attribute): void + { + if (!$this->supports($attribute)) { + return; + } + + foreach ($product->getImagesByType('akeneo') as $productImage) { + $product->removeImage($productImage); + } + + if (null === $attribute->data()) { + return; + } + + /** @var ProductImageInterface|null $image */ + $productImage = $this->productImageRepository->findOneBy([ + 'owner' => $product, + 'type' => 'akeneo', + 'path' => $attribute->data(), + ]); + + if (null === $productImage) { + /** @var ProductImageInterface $productImage */ + $productImage = $this->productImageFactory->createNew(); + $productImage->setType('akeneo'); + $productImage->setPath($attribute->data()); + } + + $product->addImage($productImage); + } + + private function supports(Attribute $attribute): bool + { + return $this->imageAttribute === $attribute->attribute() && (null === $attribute->data() || is_string($attribute->data())); + } +} diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index bd201bd..44dfbe9 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -27,6 +27,7 @@ public function getConfigTreeBuilder() ->scalarNode('name_attribute')->defaultValue('name')->end() ->scalarNode('description_attribute')->defaultValue('description')->end() ->scalarNode('price_attribute')->defaultValue('price')->end() + ->scalarNode('image_attribute')->defaultValue('images')->end() ->end() ->end() ->end() diff --git a/src/DependencyInjection/SylakeSyliusConsumerExtension.php b/src/DependencyInjection/SylakeSyliusConsumerExtension.php index 511dadf..0164c1e 100644 --- a/src/DependencyInjection/SylakeSyliusConsumerExtension.php +++ b/src/DependencyInjection/SylakeSyliusConsumerExtension.php @@ -32,6 +32,10 @@ public function load(array $config, ContainerBuilder $container) 'sylake_sylius_consumer.denormalizer.product.price_attribute', $config['denormalizer']['product']['price_attribute'] ); + $container->setParameter( + 'sylake_sylius_consumer.denormalizer.product.image_attribute', + $config['denormalizer']['product']['image_attribute'] + ); } /** diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index 187ef03..3e71fcf 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -49,6 +49,13 @@ %sylake_sylius_consumer.denormalizer.product.price_attribute% + + + + + %sylake_sylius_consumer.denormalizer.product.image_attribute% + + diff --git a/tests/DependencyInjection/ExtensionTest.php b/tests/DependencyInjection/ExtensionTest.php index 53b7773..dd0c32a 100644 --- a/tests/DependencyInjection/ExtensionTest.php +++ b/tests/DependencyInjection/ExtensionTest.php @@ -20,6 +20,7 @@ public function it_adds_product_denormalization_parameters_by_default() $this->assertContainerBuilderHasParameter('sylake_sylius_consumer.denormalizer.product.name_attribute', 'name'); $this->assertContainerBuilderHasParameter('sylake_sylius_consumer.denormalizer.product.description_attribute', 'description'); $this->assertContainerBuilderHasParameter('sylake_sylius_consumer.denormalizer.product.price_attribute', 'price'); + $this->assertContainerBuilderHasParameter('sylake_sylius_consumer.denormalizer.product.image_attribute', 'images'); } /** diff --git a/tests/Functional/ProductSynchronizationTest.php b/tests/Functional/ProductSynchronizationTest.php index cb9cfbf..4955efe 100644 --- a/tests/Functional/ProductSynchronizationTest.php +++ b/tests/Functional/ProductSynchronizationTest.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\Assert; use Sylius\Bundle\FixturesBundle\Fixture\FixtureInterface; use Sylius\Component\Core\Model\ChannelInterface; +use Sylius\Component\Core\Model\ProductImageInterface; use Sylius\Component\Core\Model\ProductInterface; use Sylius\Component\Core\Model\ProductVariantInterface; use Sylius\Component\Core\Model\TaxonInterface; @@ -185,6 +186,123 @@ public function it_updates_an_existing_product_with_basic_product_information() Assert::assertFalse($product->isEnabled()); } + /** + * @test + */ + public function it_adds_a_new_product_with_images() + { + $this->consumer->execute(new AMQPMessage('{ + "type": "akeneo_product_updated", + "payload": { + "identifier": "AKNTS_BPXS", + "family": "tshirts", + "groups": [], + "variant_group": "akeneo_tshirt", + "categories": ["goodies", "tshirts"], + "enabled": true, + "values": { + "sku": [{"locale": null, "scope": null, "data": "AKNTS_BPXS"}], + "clothing_size": [{"locale": null, "scope": null, "data": "xs"}], + "main_color": [{"locale": null, "scope": null, "data": "black"}], + "name": [{"locale": null, "scope": null, "data": "Akeneo T-Shirt black and purple with short sleeve"}], + "secondary_color": [{"locale": null, "scope": null, "data": "purple"}], + "tshirt_materials": [{"locale": null, "scope": null, "data": "cotton"}], + "tshirt_style": [{"locale": null, "scope": null, "data": ["crewneck", "short_sleeve"]}], + "price": [{"locale": null, "scope": null, "data": [{"amount": 10, "currency": "EUR"}, {"amount": 14, "currency": "USD"}]}], + "description": [{"locale": "en_US", "scope": "mobile", "data": "T-Shirt description"}], + "picture": [{"locale": null, "scope": null, "data": null}], + "images": [{"locale": null, "scope": null, "data": "8\/7\/5\/3\/8753d08e04e7ecdda77ef77573cd42bbfb029dcb_image.jpg"}] + }, + "created": "2017-04-18T16:12:55+02:00", + "updated": "2017-04-18T16:12:55+02:00", + "associations": {"SUBSTITUTION": {"groups": [], "products": ["AKNTS_WPXS", "AKNTS_PBXS", "AKNTS_PWXS"]}} + }, + "recordedOn": "2017-05-22 10:13:34" + }')); + + /** @var ProductInterface|null $product */ + $product = $this->productRepository->findOneBy(['code' => 'AKNTS_BPXS']); + + Assert::assertNotNull($product); + + $akeneoProductImages = $product->getImagesByType('akeneo')->toArray(); + $akeneoProductImage = current($akeneoProductImages); + + Assert::assertNotFalse($akeneoProductImage); + Assert::assertSame('8/7/5/3/8753d08e04e7ecdda77ef77573cd42bbfb029dcb_image.jpg', $akeneoProductImage->getPath()); + Assert::assertSame('akeneo', $akeneoProductImage->getType()); + } + + /** + * @test + */ + public function it_updates_an_existing_product_with_images() + { + $this->consumer->execute(new AMQPMessage('{ + "type": "akeneo_product_updated", + "payload": { + "identifier": "AKNTS_BPXS", + "family": "tshirts", + "groups": [], + "variant_group": "akeneo_tshirt", + "categories": ["goodies", "tshirts"], + "enabled": true, + "values": { + "sku": [{"locale": null, "scope": null, "data": "AKNTS_BPXS"}], + "clothing_size": [{"locale": null, "scope": null, "data": "xs"}], + "main_color": [{"locale": null, "scope": null, "data": "black"}], + "name": [{"locale": null, "scope": null, "data": "Akeneo T-Shirt black and purple with short sleeve"}], + "secondary_color": [{"locale": null, "scope": null, "data": "purple"}], + "tshirt_materials": [{"locale": null, "scope": null, "data": "cotton"}], + "tshirt_style": [{"locale": null, "scope": null, "data": ["crewneck", "short_sleeve"]}], + "price": [{"locale": null, "scope": null, "data": [{"amount": 10, "currency": "EUR"}, {"amount": 14, "currency": "USD"}]}], + "description": [{"locale": "en_US", "scope": "mobile", "data": "T-Shirt description"}], + "picture": [{"locale": null, "scope": null, "data": null}], + "images": [{"locale": null, "scope": null, "data": "8\/7\/5\/3\/8753d08e04e7ecdda77ef77573cd42bbfb029dcb_image.jpg"}] + }, + "created": "2017-04-18T16:12:55+02:00", + "updated": "2017-04-18T16:12:55+02:00", + "associations": {"SUBSTITUTION": {"groups": [], "products": ["AKNTS_WPXS", "AKNTS_PBXS", "AKNTS_PWXS"]}} + }, + "recordedOn": "2017-05-22 10:13:34" + }')); + + $this->consumer->execute(new AMQPMessage('{ + "type": "akeneo_product_updated", + "payload": { + "identifier": "AKNTS_BPXS", + "family": "tshirts", + "groups": [], + "variant_group": "akeneo_tshirt", + "categories": ["goodies", "tshirts"], + "enabled": false, + "values": { + "sku": [{"locale": null, "scope": null, "data": "AKNTS_BPXS"}], + "clothing_size": [{"locale": null, "scope": null, "data": "xs"}], + "main_color": [{"locale": null, "scope": null, "data": "black"}], + "name": [{"locale": null, "scope": null, "data": "Akeneo T-Shirt black and purple with short sleeve (updated)"}], + "secondary_color": [{"locale": null, "scope": null, "data": "purple"}], + "tshirt_materials": [{"locale": null, "scope": null, "data": "cotton"}], + "tshirt_style": [{"locale": null, "scope": null, "data": ["crewneck", "short_sleeve"]}], + "price": [{"locale": null, "scope": null, "data": [{"amount": 10, "currency": "EUR"}, {"amount": 14, "currency": "USD"}]}], + "description": [{"locale": "en_US", "scope": "mobile", "data": "T-Shirt description (updated)"}], + "picture": [{"locale": null, "scope": null, "data": null}], + "images": [{"locale": null, "scope": null, "data": null}] + }, + "created": "2017-04-18T16:12:58+02:00", + "updated": "2017-04-18T16:12:55+02:00", + "associations": {"SUBSTITUTION": {"groups": [], "products": ["AKNTS_WPXS", "AKNTS_PBXS", "AKNTS_PWXS"]}} + }, + "recordedOn": "2017-05-22 10:13:34" + }')); + + /** @var ProductInterface|null $product */ + $product = $this->productRepository->findOneBy(['code' => 'AKNTS_BPXS']); + + Assert::assertNotNull($product); + Assert::assertSame([], $product->getImagesByType('akeneo')->toArray()); + } + /** * @test */