From eaa04bc9fcc959708fe679631bf5b433bda8d92d Mon Sep 17 00:00:00 2001 From: Serhii Zhuravel Date: Wed, 12 Feb 2020 16:06:46 +0200 Subject: [PATCH] GRKAS1/KSVA1: Fix duplicate images --- .../ProductImageDataConverter.php | 4 +- .../Processor/ProductImageImportProcessor.php | 104 +++++++++++++++--- ImportExport/Reader/ProductImageReader.php | 27 +++-- .../Strategy/ProductImageImportStrategy.php | 38 +------ ImportExport/Writer/ProductImageWriter.php | 54 --------- Resources/config/importexport.yml | 6 +- 6 files changed, 103 insertions(+), 130 deletions(-) delete mode 100644 ImportExport/Writer/ProductImageWriter.php diff --git a/ImportExport/DataConverter/ProductImageDataConverter.php b/ImportExport/DataConverter/ProductImageDataConverter.php index f10b5657..4021cd67 100644 --- a/ImportExport/DataConverter/ProductImageDataConverter.php +++ b/ImportExport/DataConverter/ProductImageDataConverter.php @@ -12,8 +12,8 @@ class ProductImageDataConverter extends BaseProductImageDataConverter */ public function convertToImportFormat(array $importedRecord, $skipNullValues = true) { - $importedRecord['types'][ProductImageType::TYPE_MAIN] = true; - $importedRecord['types'][ProductImageType::TYPE_LISTING] = true; + $importedRecord['types'][ProductImageType::TYPE_MAIN] = false; + $importedRecord['types'][ProductImageType::TYPE_LISTING] = false; $importedRecord['types'][ProductImageType::TYPE_ADDITIONAL] = true; return parent::convertToImportFormat($importedRecord, $skipNullValues); diff --git a/ImportExport/Processor/ProductImageImportProcessor.php b/ImportExport/Processor/ProductImageImportProcessor.php index 0016feaa..9e0bb9cd 100644 --- a/ImportExport/Processor/ProductImageImportProcessor.php +++ b/ImportExport/Processor/ProductImageImportProcessor.php @@ -3,34 +3,102 @@ namespace Oro\Bundle\AkeneoBundle\ImportExport\Processor; use Oro\Bundle\IntegrationBundle\ImportExport\Processor\StepExecutionAwareImportProcessor; +use Oro\Bundle\ProductBundle\Entity\Product; +use Oro\Bundle\ProductBundle\Entity\ProductImage; +use Oro\Bundle\ProductBundle\Entity\ProductImageType; class ProductImageImportProcessor extends StepExecutionAwareImportProcessor { /** * {@inheritdoc} */ - public function process($item) + public function process($items) { - if ($this->dataConverter) { - $item = $this->dataConverter->convertToImportFormat($item, false); + $images = []; + $product = null; + foreach ($items as $image) { + if ($this->dataConverter) { + $image = $this->dataConverter->convertToImportFormat($image, false); + } + + /** @var ProductImage $object */ + $object = $this->serializer->deserialize( + $image, + $this->getEntityName(), + null, + array_merge( + $this->context->getConfiguration(), + [ + 'entityName' => $this->getEntityName(), + ] + ) + ); + + if ($this->strategy) { + $object = $this->strategy->process($object); + if ($object) { + $product = $object->getProduct(); + $images[$object->getImage()->getOriginalFilename()] = $object; + } + } + } + + if (!$product) { + return null; + } + + return $this->mergeImages($product, $images); + } + + /** + * @param ProductImage[] $images + */ + private function mergeImages(Product $product, array $images): Product + { + $hasMain = false; + $hasListing = false; + $image = null; + + foreach ($product->getImages() as $image) { + if (!$image->getImage()) { + $product->removeImage($image); + + continue; + } + + $filename = $image->getImage()->getOriginalFilename(); + if (!in_array($filename, array_keys($images))) { + $product->removeImage($image); + + continue; + } + + $hasMain = $hasMain || $image->hasType(ProductImageType::TYPE_MAIN); + $hasListing = $hasListing || $image->hasType(ProductImageType::TYPE_LISTING); + + unset($images[$filename]); + } + + foreach ($images as $image) { + if (!$image->getImage()) { + continue; + } + + $product->addImage($image); + } + + if (!$hasMain) { + if ($product->getImages()->last()) { + $product->getImages()->last()->addType(ProductImageType::TYPE_MAIN); + } } - $object = $this->serializer->deserialize( - $item, - $this->getEntityName(), - null, - array_merge( - $this->context->getConfiguration(), - [ - 'entityName' => $this->getEntityName(), - ] - ) - ); - - if ($this->strategy) { - $object = $this->strategy->process($object); + if (!$hasListing) { + if ($product->getImages()->last()) { + $product->getImages()->last()->addType(ProductImageType::TYPE_LISTING); + } } - return $object ?: null; + return $product; } } diff --git a/ImportExport/Reader/ProductImageReader.php b/ImportExport/Reader/ProductImageReader.php index c6f2d94c..7b624585 100644 --- a/ImportExport/Reader/ProductImageReader.php +++ b/ImportExport/Reader/ProductImageReader.php @@ -53,16 +53,13 @@ protected function initializeFromContext(ContextInterface $context) continue; } - $images[] = [ - 'SKU' => $item['identifier'] ?? $item['code'], - 'Name' => basename($value['data']), - ]; + $identifier = $item['identifier'] ?? $item['code']; + $basename = basename($value['data']); + $images[$identifier][$basename] = ['SKU' => $identifier, 'Name' => $basename]; if ($this->getTransport()->isAkeneoMergeImageToParent() && !empty($item['parent'])) { - $images[] = [ - 'SKU' => $item['parent'], - 'Name' => basename($value['data']), - ]; + $identifier = $item['parent']; + $images[$identifier][$basename] = ['SKU' => $identifier, 'Name' => $basename]; } } } @@ -109,13 +106,15 @@ private function getTransport(): ?AkeneoSettings protected function processImagesDownload(array $items, ContextInterface $context) { foreach ($items as $item) { - foreach ($item['values'] as $values) { - foreach ($values as $value) { - if ('pim_catalog_image' !== $value['type'] || empty($value['data'])) { - continue; - } + foreach ($item['values'] as $code => $values) { + if (empty($this->attributesImageFilter) || in_array($code, $this->attributesImageFilter)) { + foreach ($values as $value) { + if ('pim_catalog_image' !== $value['type'] || empty($value['data'])) { + continue; + } - $this->getAkeneoTransport($context)->downloadAndSaveMediaFile('product_images', $value['data']); + $this->getAkeneoTransport($context)->downloadAndSaveMediaFile('product_images', $value['data']); + } } } } diff --git a/ImportExport/Strategy/ProductImageImportStrategy.php b/ImportExport/Strategy/ProductImageImportStrategy.php index 44bf1ee8..8705ab90 100644 --- a/ImportExport/Strategy/ProductImageImportStrategy.php +++ b/ImportExport/Strategy/ProductImageImportStrategy.php @@ -2,31 +2,16 @@ namespace Oro\Bundle\AkeneoBundle\ImportExport\Strategy; -use Oro\Bundle\BatchBundle\Item\Support\ClosableInterface; use Oro\Bundle\ImportExportBundle\Strategy\Import\ConfigurableAddOrReplaceStrategy; use Oro\Bundle\ProductBundle\Entity\ProductImage; -use Oro\Bundle\ProductBundle\Entity\ProductImageType; /** * Strategy to import product images. */ -class ProductImageImportStrategy extends ConfigurableAddOrReplaceStrategy implements ClosableInterface +class ProductImageImportStrategy extends ConfigurableAddOrReplaceStrategy { use ImportStrategyAwareHelperTrait; - /** - * @var array - */ - protected $processedSkus = []; - - /** - * {@inheritdoc} - */ - public function close() - { - $this->processedSkus = []; - } - /** * @param ProductImage $entity * @@ -34,31 +19,10 @@ public function close() */ protected function beforeProcessEntity($entity) { - $sku = $entity->getProduct()->getSku(); - if (!$entity->getImage()) { return null; } - $processedSkus = $this->processedSkus[$sku] ?? 0; - $processedSkus++; - if ($processedSkus > 1) { - $this->removeImageTypes($entity); - } - $this->processedSkus[$sku] = $processedSkus; - return parent::beforeProcessEntity($entity); } - - /** - * Denormalizer sets wrong keys so ProductImage::removeType doesn't work. - */ - private function removeImageTypes(ProductImage $entity) - { - foreach ($entity->getTypes() as $key => $type) { - if (in_array($type->getType(), [ProductImageType::TYPE_MAIN, ProductImageType::TYPE_LISTING])) { - unset($entity->getTypes()[$key]); - } - } - } } diff --git a/ImportExport/Writer/ProductImageWriter.php b/ImportExport/Writer/ProductImageWriter.php deleted file mode 100644 index cdfc8fa2..00000000 --- a/ImportExport/Writer/ProductImageWriter.php +++ /dev/null @@ -1,54 +0,0 @@ -products = []; - $this->images = []; - } - - public function flush() - { - if (!$this->products && !$this->images) { - return; - } - - $this->registry - ->getRepository(ProductImage::class) - ->createQueryBuilder('pi') - ->delete(ProductImage::class, 'pi') - ->andWhere('IDENTITY(pi.product) in (:ids)') - ->andWhere('IDENTITY(pi.image) not in (:images)') - ->setParameter('ids', $this->products) - ->setParameter('images', $this->images) - ->getQuery() - ->execute(); - - $this->products = null; - $this->images = null; - } - - protected function saveItems(array $items, EntityManager $em) - { - parent::saveItems($items, $em); - - /** @var ProductImage $item */ - foreach ($items as &$item) { - $this->products[$item->getProduct()->getId()] = $item->getProduct()->getId(); - $this->images[] = $item->getImage()->getId(); - } - } -} diff --git a/Resources/config/importexport.yml b/Resources/config/importexport.yml index 1d7ec0e6..d2588fc2 100644 --- a/Resources/config/importexport.yml +++ b/Resources/config/importexport.yml @@ -253,10 +253,6 @@ services: calls: - [setImportStrategyHelper, ['@oro_akeneo.strategy.import.helper']] - oro_akeneo.importexport.writer.product_image: - class: 'Oro\Bundle\AkeneoBundle\ImportExport\Writer\ProductImageWriter' - parent: oro_integration.writer.persistent_batch_writer - oro_akeneo.importexport.writer.attribute: class: '%oro_akeneo.importexport.writer.attribute.class%' parent: oro_entity_config.importexport.writer.attribute @@ -278,7 +274,7 @@ services: oro_akeneo.importexport.writer.cumulative.product_image: class: 'Oro\Bundle\AkeneoBundle\ImportExport\Writer\CumulativeWriter' arguments: - - '@oro_akeneo.importexport.writer.product_image' + - '@oro_integration.writer.persistent_batch_writer' - '@oro_platform.optional_listeners.manager' - '@doctrine' - '@oro_entity_config.config_manager'