diff --git a/ImportExport/DataConverter/AttributeDataConverter.php b/ImportExport/DataConverter/AttributeDataConverter.php index de11504e..21f66e86 100644 --- a/ImportExport/DataConverter/AttributeDataConverter.php +++ b/ImportExport/DataConverter/AttributeDataConverter.php @@ -9,6 +9,7 @@ use Oro\Bundle\AkeneoBundle\Tools\Generator; use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; use Oro\Bundle\EntityConfigBundle\ImportExport\DataConverter\EntityFieldDataConverter; +use Symfony\Component\Translation\TranslatorInterface; /** * Converts data to import format. @@ -23,11 +24,19 @@ class AttributeDataConverter extends EntityFieldDataConverter /** @var DoctrineHelper */ protected $doctrineHelper; + /** @var TranslatorInterface */ + protected $translator; + public function setDoctrineHelper(DoctrineHelper $doctrineHelper) { $this->doctrineHelper = $doctrineHelper; } + public function setTranslator(TranslatorInterface $translator) + { + $this->translator = $translator; + } + /** * {@inheritdoc} */ @@ -35,7 +44,28 @@ public function convertToImportFormat(array $importedRecord, $skipNullValues = t { $type = AttributeTypeConverter::convert($importedRecord['type']); if (!$type) { - throw new InvalidItemException(sprintf('Type "%s" is not supported', $type), $importedRecord); + $message = sprintf( + 'Attribute "%s" type "%s" is not supported', + $importedRecord['code'], + $importedRecord['type'] + ); + + if ($this->translator instanceof TranslatorInterface) { + $this->context->addError( + $this->translator->trans( + 'oro.akeneo.error', + [ + '%error%' => $message, + '%item%' => json_encode( + $importedRecord, + \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE + ), + ] + ) + ); + } + + throw new InvalidItemException($message, $importedRecord); } $importedRecord['type'] = $type; diff --git a/ImportExport/Reader/ProductImageReader.php b/ImportExport/Reader/ProductImageReader.php index 5fbeb8a2..5435aa98 100644 --- a/ImportExport/Reader/ProductImageReader.php +++ b/ImportExport/Reader/ProductImageReader.php @@ -63,7 +63,12 @@ protected function initializeFromContext(ContextInterface $context) continue; } - if (!in_array($value['type'], ['pim_catalog_image', 'pim_assets_collection'])) { + $imageAttributes = [ + 'pim_catalog_image', + 'pim_assets_collection', + 'pim_catalog_asset_collection', + ]; + if (!in_array($value['type'], $imageAttributes)) { continue; } @@ -117,6 +122,12 @@ protected function processImagesDownload(array $items, ContextInterface $context $this->akeneoFileManager->registerMediaFile($value['data']); } + if (in_array($value['type'], ['pim_catalog_asset_collection'])) { + foreach ($value['data'] as $data) { + $this->akeneoFileManager->registerAssetMediaFile($data); + } + } + if (in_array($value['type'], ['pim_assets_collection'])) { if (!is_array($value['data'])) { continue; diff --git a/ImportExport/Reader/ProductReader.php b/ImportExport/Reader/ProductReader.php index 43bf05d7..4605d2a9 100644 --- a/ImportExport/Reader/ProductReader.php +++ b/ImportExport/Reader/ProductReader.php @@ -48,6 +48,12 @@ protected function processFileTypeDownload(array $items, ContextInterface $conte $this->akeneoFileManager->registerMediaFile($value['data']); } + if (in_array($value['type'], ['pim_catalog_asset_collection'])) { + foreach ($value['data'] as $data) { + $this->akeneoFileManager->registerAssetMediaFile($data); + } + } + if (in_array($value['type'], ['pim_assets_collection'])) { if (!is_array($value['data'])) { continue; diff --git a/Integration/AkeneoFileManager.php b/Integration/AkeneoFileManager.php index 563569fd..41d5c3a5 100644 --- a/Integration/AkeneoFileManager.php +++ b/Integration/AkeneoFileManager.php @@ -17,6 +17,9 @@ class AkeneoFileManager /** @var string[] */ private $referenceEntityMediaFile = []; + /** @var string[] */ + private $assetMediaFile = []; + /** @var AkeneoTransport */ private $akeneoTransport; @@ -46,7 +49,12 @@ public function registerAsset(string $code, string $uri): void public function registerReferenceEntityMediaFile(string $uri): void { - $this->assets[basename($uri)] = $uri; + $this->referenceEntityMediaFile[basename($uri)] = $uri; + } + + public function registerAssetMediaFile(string $uri): void + { + $this->assetMediaFile[basename($uri)] = $uri; } public function download(File $file, string $path): void @@ -70,10 +78,15 @@ public function download(File $file, string $path): void ); } + if (array_key_exists($basename, $this->assetMediaFile)) { + $this->akeneoTransport->downloadAndSaveAssetMediaFile($this->assetMediaFile[$basename]); + } + unset( $this->mediaFiles[$basename], $this->assets[$basename], - $this->referenceEntityMediaFile[$basename] + $this->referenceEntityMediaFile[$basename], + $this->assetMediaFile[$basename] ); } } diff --git a/Integration/AkeneoTransport.php b/Integration/AkeneoTransport.php index 1830ad12..14a9fb4d 100644 --- a/Integration/AkeneoTransport.php +++ b/Integration/AkeneoTransport.php @@ -426,6 +426,39 @@ public function downloadAndSaveReferenceEntityMediaFile(string $code): void } } + public function downloadAndSaveAssetMediaFile(string $code): void + { + if ($this->fileManager->hasFile($code)) { + return; + } + + try { + $content = $this->client + ->getAssetMediaFileApi() + ->download($code) + ->getBody() + ->getContents(); + } catch (\Throwable $e) { + $this->logger->critical( + 'Error on downloading asset.', + ['message' => $e->getMessage(), 'exception' => $e] + ); + + return; + } + + try { + $this->fileManager->writeToStorage($content, $code); + } catch (\Throwable $e) { + $this->logger->critical( + 'Error during saving asset.', + ['message' => $e->getMessage(), 'exception' => $e] + ); + + return; + } + } + protected function initAttributesList() { if (empty($this->attributes)) { diff --git a/Integration/AkeneoTransportInterface.php b/Integration/AkeneoTransportInterface.php index 37bfddb7..25ef9902 100644 --- a/Integration/AkeneoTransportInterface.php +++ b/Integration/AkeneoTransportInterface.php @@ -63,4 +63,6 @@ public function downloadAndSaveMediaFile(string $code): void; public function downloadAndSaveAsset(string $code, string $file): void; public function downloadAndSaveReferenceEntityMediaFile(string $code): void; + + public function downloadAndSaveAssetMediaFile(string $code): void; } diff --git a/Integration/Iterator/ProductIterator.php b/Integration/Iterator/ProductIterator.php index d625e0f0..349a45b7 100644 --- a/Integration/Iterator/ProductIterator.php +++ b/Integration/Iterator/ProductIterator.php @@ -18,6 +18,8 @@ class ProductIterator extends AbstractIterator private $assets = []; + private $assetsFamily = []; + public function __construct( ResourceCursorInterface $resourceCursor, AkeneoPimClientInterface $client, @@ -94,26 +96,72 @@ private function setAssetCode(array &$product): void { foreach ($product['values'] as $code => &$values) { foreach ($values as $key => &$value) { - if ($value['type'] !== 'pim_assets_collection') { - continue; + if ($value['type'] === 'pim_assets_collection') { + $data = []; + $source = (array)$value['data']; + $value['data'] = []; + foreach ($source as $assetCode) { + if (array_key_exists($assetCode, $this->assets)) { + $data = $this->assets[$assetCode]; + + continue; + } + + $assetData = $this->client->getAssetApi()->get($assetCode); + $assets = $assetData['reference_files'] ?? []; + foreach ($assets as $asset) { + if (empty($asset['code'])) { + continue; + } + + $this->assets[$assetCode][] = $asset['code']; + $data[$assetCode] = $this->assets[$assetCode]; + } + } + $value['data'] = $data; } - $codes = []; - foreach ((array)$value['data'] as &$code) { - if (array_key_exists($code, $this->assets)) { - $codes[$code] = $this->assets[$code]; + if ($value['type'] === 'pim_catalog_asset_collection') { + $data = []; + $source = (array)$value['data']; + $value['data'] = []; + $assetFamily = $this->attributes[$code]['reference_data_name'] ?? null; + if (!$assetFamily) { + continue; + } + $assetFamilyData = $this->getAssetsFamily($assetFamily); + $valueField = $assetFamilyData['attribute_as_main_media'] ?? null; + if (!$valueField) { continue; } - $asset = $this->client->getAssetApi()->get($code); - if (!empty($asset['reference_files'][0]['code'])) { - $this->assets[$code] = $asset['reference_files'][0]['code']; + foreach ($source as $assetCode) { + if (array_key_exists($assetFamily . $assetCode, $this->assets)) { + $data = array_merge($data, $this->assets[$assetFamily . $assetCode]); + + continue; + } + + $this->assets[$assetFamily . $assetCode] = []; + + $assetData = $this->client->getAssetManagerApi()->get($assetFamily, $assetCode); + $assets = $assetData['values'][$valueField] ?? []; + foreach ($assets as $asset) { + if (empty($asset['data'])) { + continue; + } - $codes[$code] = $this->assets[$code]; + if (!pathinfo($asset['data'], \PATHINFO_EXTENSION)) { + continue; + } + + $this->assets[$assetFamily . $assetCode][$assetCode] = $asset['data']; + $data[$assetCode] = $asset['data']; + } } + $value['data'] = $data; } - $value['data'] = $codes; } } } @@ -130,4 +178,15 @@ private function setSku(array &$product): void $product['sku'] = (string)$sku; } + + private function getAssetsFamily(string $assetFamily): array + { + if (array_key_exists($assetFamily, $this->assetsFamily)) { + return $this->assetsFamily[$assetFamily] ?? []; + } + + $this->assetsFamily[$assetFamily] = $this->client->getAssetFamilyApi()->get($assetFamily); + + return $this->assetsFamily[$assetFamily] ?? []; + } } diff --git a/Resources/config/importexport.yml b/Resources/config/importexport.yml index 6205bf14..83ae9f09 100644 --- a/Resources/config/importexport.yml +++ b/Resources/config/importexport.yml @@ -131,6 +131,7 @@ services: calls: - [ setDoctrineHelper, [ '@oro_entity.doctrine_helper' ] ] - [ setConfigManager, [ '@oro_config.manager' ] ] + - [ setTranslator, [ '@translator' ] ] oro_akeneo.importexport.strategy.attribute: class: 'Oro\Bundle\AkeneoBundle\ImportExport\Strategy\AttributeImportStrategy' diff --git a/Tools/AttributeTypeConverter.php b/Tools/AttributeTypeConverter.php index 905e5fb2..ffca8c05 100644 --- a/Tools/AttributeTypeConverter.php +++ b/Tools/AttributeTypeConverter.php @@ -21,6 +21,7 @@ class AttributeTypeConverter 'akeneo_reference_entity' => 'enum', 'pim_catalog_multiselect' => 'multiEnum', 'pim_assets_collection' => 'multiFile', + 'pim_catalog_asset_collection' => 'multiFile', 'akeneo_reference_entity_collection' => 'multiEnum', ];