Your IP : 127.0.0.1


Current Path : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Import/Product/
Upload File :
Current File : /home/dev2.destoffenstraat.com/app/Firebear/ImportExport/Model/Import/Product/ImageProcessor.php

<?php

namespace Firebear\ImportExport\Model\Import\Product;

use Firebear\ImportExport\Model\Export\RowCustomizer\ProductVideo;
use Firebear\ImportExport\Model\Import\UploaderFactory;
use Firebear\ImportExport\Model\QueueMessage\ImagePublisher;
use Firebear\ImportExport\Traits\General;
use Firebear\ImportExport\Api\Data\SeparatorFormatterInterface;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product\Attribute\Backend\Sku;
use Magento\Catalog\Model\Product\Media\ConfigInterface as MediaConfig;
use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory;
use Magento\CatalogImportExport\Model\Import\Product;
use Magento\CatalogImportExport\Model\Import\Product\ImageTypeProcessor;
use Magento\CatalogImportExport\Model\Import\Product\MediaGalleryProcessor;
use Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory;
use Magento\MediaStorage\Service\ImageResize;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\ImportExport\Model\Import;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingError;
use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
use Magento\Store\Model\StoreManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Magento\Store\Model\Store;

/**
 * Class ImageProcessor
 * @package Firebear\ImportExport\Model\Import\Product
 */
class ImageProcessor
{
    use General;

    protected $mediaGalleryProcessor;

    protected $mediaGalleryAttributeId;

    protected $resourceModelFactory;

    /**
     * @var StoreManagerInterface
     */
    protected $storeManager;

    /**
     * @var ProductMetadataInterface
     */
    protected $productMetadata;

    /**
     * @var ImagePublisher
     */
    protected $imagePublisher;

    /**
     * @var array
     */
    protected $rows = [];

    /**
     * @var array
     */
    protected $config = [];

    /**
     * @var SerializerInterface
     */
    protected $serializer;

    protected $mediaGalleryTableName;

    protected $resource;

    protected $imagesArrayKeys = ['image', 'small_image', 'thumbnail', 'swatch_image', '_media_image', 'video_url'];

    protected $mediaImagesAttributes = [];

    protected $fileUploader;

    protected $uploaderFactory;

    /**
     * @var MediaConfig
     */
    protected $mediaConfig;

    protected $imageConfigField = ['image', 'small_image', 'thumbnail'];

    /**
     * @var LoggerInterface
     */
    protected $_logger;

    /**
     * @var array
     */
    protected $attrIds = [];

    protected $attrTypeId;

    /**
     * @var ProcessingErrorAggregatorInterface
     */
    protected $errorAggregator;

    /**
     * @var \Magento\Framework\Filesystem\Directory\WriteInterface
     */
    protected $mediaDirectory;

    /**
     * @var ImageTypeProcessor
     */
    protected $imageTypeProcessor;

    protected $productEntityTableName;

    protected $mediaGalleryValueTableName;

    protected $mediaGalleryEntityToValueTableName;

    protected $productEntityLinkField;

    /**
     * @var MetadataPool
     */
    protected $metadataPool;

    /**
     * @var SeparatorFormatterInterface
     */
    private $separatorFormatter;
    /**
     * @var AttributeCollectionFactory
     */
    protected $attributeCollectionFactory;

    /**
     * @var mixed
     */
    protected $imageResizeProcessor;

    /**
     * @var array
     */
    protected $imageResizeIgnoreList = [];

    /**
     * @var array
     */
    protected $bunchUploadedImages = [];

    /**
     * ImageProcessor constructor.
     * @param Filesystem $filesystem
     * @param LoggerInterface $logger
     * @param StoreManagerInterface $storeManager
     * @param SerializerInterface $serializer
     * @param UploaderFactory $uploaderFactory
     * @param ResourceModelFactory $resourceModelFactory
     * @param ImagePublisher $imagePublisher
     * @param ProductMetadataInterface $productMetadata
     * @param ProcessingErrorAggregatorInterface $errorAggregator
     * @param MediaConfig $mediaConfig
     * @param MetadataPool $metadataPool
     * @param ConsoleOutput $output
     * @param SeparatorFormatterInterface $separatorFormatter
     * @param AttributeCollectionFactory $attributeCollectionFactory
     * @throws \Magento\Framework\Exception\FileSystemException
     */
    public function __construct(
        Filesystem $filesystem,
        LoggerInterface $logger,
        StoreManagerInterface $storeManager,
        SerializerInterface $serializer,
        UploaderFactory $uploaderFactory,
        ResourceModelFactory $resourceModelFactory,
        ImagePublisher $imagePublisher,
        ProductMetadataInterface $productMetadata,
        ProcessingErrorAggregatorInterface $errorAggregator,
        MediaConfig $mediaConfig,
        MetadataPool $metadataPool,
        ConsoleOutput $output,
        SeparatorFormatterInterface $separatorFormatter,
        AttributeCollectionFactory $attributeCollectionFactory
    ) {
        $this->storeManager = $storeManager;
        $this->serializer = $serializer;
        $this->productMetadata = $productMetadata;
        $this->imagePublisher = $imagePublisher;
        $this->resourceModelFactory = $resourceModelFactory;
        $this->uploaderFactory = $uploaderFactory;
        $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT);
        $this->output = $output;
        $this->_logger = $logger;
        $this->errorAggregator = $errorAggregator;
        $this->mediaConfig = $mediaConfig;
        $this->metadataPool = $metadataPool;
        $this->separatorFormatter = $separatorFormatter;
        if (class_exists(ImageTypeProcessor::class)) {
            $this->imageTypeProcessor = ObjectManager::getInstance()
                ->get(ImageTypeProcessor::class);
        }
        if (class_exists(MediaGalleryProcessor::class)) {
            $this->mediaGalleryProcessor = ObjectManager::getInstance()
                ->get(MediaVideoGallery::class);
        }
        if (class_exists(ImageResize::class)) {
            $this->imageResizeProcessor = ObjectManager::getInstance()
                ->get(ImageResize::class);
        }
        $this->attributeCollectionFactory = $attributeCollectionFactory;
    }

    /**
     * @param $rowData
     * @param $mediaGallery
     * @param $existingImages
     * @param $uploadedImages
     * @param $rowNum
     * @param $existingAttributeImages
     * @throws LocalizedException
     */
    public function processMediaGalleryRows(
        &$rowData,
        &$mediaGallery,
        &$existingImages,
        &$uploadedImages,
        $rowNum,
        $existingAttributeImages
    ) {
        $disabledImages = [];
        $rowSku = $this->getCorrectSkuAsPerLength($rowData);
        if (!empty($this->config['remove_images']) && array_key_exists($rowSku, $existingImages)
            && empty($rowData[Product::COL_STORE])) {
            $this->removeExistingImages($existingImages[$rowSku], $existingAttributeImages);
            $this->clearPartUploadedImages($uploadedImages, $existingImages[$rowSku]);
            unset($existingImages[$rowSku]);
        }
        if ($this->config['remove_images'] & !empty($rowData[Product::COL_STORE])
            && !empty($existingAttributeImages[$rowData[Product::COL_SKU]]) && !empty($existingImages[$rowSku])) {
            $removeImages = [];
            foreach ($existingImages[$rowSku] as $keyImage => $image) {
                if (empty($existingAttributeImages[$rowData[Product::COL_SKU]][$keyImage])) {
                    $removeImages[$keyImage] = $image;
                    continue;
                }
                $stores = array_flip(array_keys($existingAttributeImages[$rowData[Product::COL_SKU]][$keyImage]));
                unset($stores[$rowData[Product::COL_STORE]]);
                unset($stores['admin']);
                if (!$stores) {
                    $removeImages[$keyImage] = $image;
                }
            }
            if ($removeImages) {
                $this->removeExistingImages($removeImages, $existingAttributeImages);
                $this->clearPartUploadedImages($uploadedImages, $removeImages);
                foreach ($removeImages as $key => $removeImage) {
                    unset($existingImages[$rowSku][$key]);
                }
            }
        }
        $nonExistentImages = [];
        if (empty($this->config['remove_images'])) {
            if (array_key_exists($rowSku, $existingImages)) {
                foreach ($existingImages[$rowSku] as $keyImage => $image) {
                    if (is_array($image) && !empty($image['value'])) {
                        $mediaFile = $image['value'];
                    } else {
                        $mediaFile = $keyImage;
                    }
                    $filePath = $this->mediaDirectory->getAbsolutePath(
                        '/pub/' .
                        DirectoryList::MEDIA .
                        DIRECTORY_SEPARATOR .
                        $this->mediaConfig->getMediaPath($mediaFile)
                    );
                    if (!file_exists($filePath)) {
                        $nonExistentImages[$keyImage] = $image;
                        unset($existingImages[$rowSku][$keyImage]);
                    }
                }
            }
            if (!empty($nonExistentImages)) {
                $this->removeExistingImages($nonExistentImages, $existingAttributeImages);
                $this->clearPartUploadedImages($uploadedImages, $nonExistentImages);
            }
        }
        $rowData = $this->checkAdditionalImages($rowData);
        if (isset($this->config['source_type']) && $this->config['source_type'] === 'rest') {
            unset($rowData['additional_images']);
        }

        if (isset($rowData['image']) && !empty($this->config['copy_base_image'])) {
            if (!isset($rowData['thumbnail'])) {
                $rowData['thumbnail'] = $rowData['image'];
            }
            if (!isset($rowData['small_image'])) {
                $rowData['small_image'] = $rowData['image'];
            }
        }

        list($rowImages, $rowLabels) = $this->getImagesFromRow($rowData);

        if (isset($rowData['_media_is_disabled'])) {
            $disabledImages = array_flip(
                explode($this->getMultipleValueSeparator(), $rowData['_media_is_disabled'])
            );
        }

        $rowData[Product::COL_MEDIA_IMAGE] = [];
        $imagePosition = 0;
        if (isset($existingImages[$rowSku])) {
            $existingProductImages = $existingImages[$rowSku];
            $existingImagesPosition = array_map(
                function ($value) {
                    if (is_array($value)) {
                        return (int) $value['position'] ?? 0;
                    } else {
                        return 0;
                    }
                },
                $existingProductImages
            );
            if ($existingImagesPosition) {
                $imagePosition = max($existingImagesPosition);
            }
        }
        foreach ($rowImages as $column => $columnImages) {
            foreach ($columnImages as $position => $columnImage) {
                list($isAlreadyUploaded, $alreadyUploadedFile) = $this
                    ->checkAlreadyUploadedImages($existingImages, $columnImage, $rowSku);

                if (isset($uploadedImages[$columnImage])) {
                    $uploadedFile = $uploadedImages[$columnImage];
                } elseif ($isAlreadyUploaded) {
                    $uploadedFile = $alreadyUploadedFile;
                } else {
                    $uploadedFile = $this->uploadMediaFiles(trim($columnImage), true);

                    if ($uploadedFile) {
                        $uploadedImages[$columnImage] = $uploadedFile;
                    } else {
                        $this->addRowError(
                            sprintf(
                                __('Wrong URL/path used for attribute %s For SKU : "'.$rowData['sku'].'" in rows'),
                                $column
                            ),
                            $rowData['rowNum'] ?? $rowNum,
                            null,
                            null,
                            ProcessingError::ERROR_LEVEL_WARNING
                        );
                        $rowData[$column] = null;
                    }
                }

                if ($uploadedFile && $column !== Product::COL_MEDIA_IMAGE) {
                    $rowData[$column] = $uploadedFile;
                }

                $imageNotAssigned = !isset($existingImages[$rowSku][$uploadedFile]);
                $this->bunchUploadedImages[$columnImage] = $uploadedFile;

                if ($uploadedFile && $imageNotAssigned) {
                    if ($column == Product::COL_MEDIA_IMAGE) {
                        $rowData[$column][] = $uploadedFile;
                    }
                    $pos = ++$imagePosition;
                    $mediaData = [
                        'attribute_id' => $this->getMediaGalleryAttributeId(),
                        'label' => $rowLabels[$column][$position] ?? '',
                        'position' => $pos,
                        'disabled' => isset($disabledImages[$columnImage]) ? '1' : '0',
                        'value' => $uploadedFile,
                    ];

                    if ($this->getUploader()->checkValidUrl($columnImage)) {
                        $mediaData[ProductVideo::VIDEO_URL_COLUMN] = $columnImage;
                    }

                    $this->prepareMediaGallery($mediaData, $mediaGallery, $rowData);
                    $existingImages[$rowSku][$uploadedFile] = true;
                } elseif (!empty($existingImages[$rowSku][$uploadedFile]['value_id'])) {
                    $storeViewCode = $rowData[Product::COL_STORE_VIEW_CODE] ?? 'admin';
                    $storeId = $this->getStoreIdByCode($storeViewCode) ?? 0;
                    $uploadedFileData = $existingImages[$rowSku][$uploadedFile];
                    $newImageLabel = $rowLabels[$column][$position] ?? '';
                    $createNewLabel = empty($existingImages[$rowSku][$uploadedFile]['create_new_label']);

                    if ($newImageLabel) {
                        $mediaData = [
                            'label' => $newImageLabel,
                            'position' => $uploadedFileData['position'] ?? $imagePosition,
                            'disabled' => isset($disabledImages[$columnImage]) ? '1' : '0',
                            'value_id' => $uploadedFileData['value_id'],
                            'store_id' => $storeId,
                            'create_new_label' => $createNewLabel,
                            $this->getProductEntityLinkField() => $uploadedFileData[$this->getProductEntityLinkField()]
                        ];
                        $this->prepareMediaGallery($mediaData, $mediaGallery, $rowData);
                        $existingImages[$rowSku][$uploadedFile]['create_new_label'] = true;
                    }
                }
            }
        }
    }

    /**
     * Preparing media gallery data
     *
     * @param $mediaData
     * @param $mediaGallery
     * @param $rowData
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    private function prepareMediaGallery($mediaData, &$mediaGallery, $rowData)
    {
        $rowSku = $rowData['sku'];
        if (version_compare($this->productMetadata->getVersion(), '2.2.4', '>=')) {
            if (empty($rowData[Product::COL_STORE_VIEW_CODE])) {
                $mediaGallery[Store::DEFAULT_STORE_ID][$rowSku][] = $mediaData;
            } else {
                $storeId = $this->getStoreIdByCode($rowData[Product::COL_STORE_VIEW_CODE]);
                $mediaGallery[$storeId][$rowSku][] = $mediaData;
            }
        } else {
            $mediaGallery[$rowSku][] = $mediaData;
        }
    }

    /**
     * @param $uploadedImages
     * @param $images
     * @return $this
     */
    public function clearPartUploadedImages(&$uploadedImages, $images)
    {
        foreach (array_flip($uploadedImages) as $path => $image) {
            if (!empty($images[$path])) {
                unset($uploadedImages[$image]);
            }
        }
        return $this;
    }

    /**
     * @param $conf
     * @return $this
     */
    public function setConfig($conf)
    {
        $this->config = $conf;
        return $this;
    }

    /**
     * @return mixed|string
     */
    public function getMultipleValueSeparator()
    {
        $separator = Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR;
        if (!empty($this->config[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR])) {
            $separator = $this->config[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR];
        }
        return $this->separatorFormatter->format($separator);
    }

    /**
     * @param $message
     * @throws LocalizedException
     */
    public function processImportImages($message)
    {
        $message = $this->serializer->unserialize($message);
        $this->config = $message['config'];
        $rows = $message['data'];
        $mediaGallery = $uploadedImages = [];
        $existingImages = $this->mediaGalleryProcessor->getExistingImages($rows);
        $existingAttributeImages = $this->getExistingAttributeImages($rows);

        foreach ($rows as $rowNum => &$rowData) {
            $this->processMediaGalleryRows(
                $rowData,
                $mediaGallery,
                $existingImages,
                $uploadedImages,
                $rowNum,
                $existingAttributeImages
            );
        }

        $this->saveMediaGallery($mediaGallery);
        if (!empty($this->config['deferred_images'])) {
            $this->saveImageConfig($rows);
        }
        if (!empty($this->config['image_resize'])) {
            $this->addLogWriteln(__('Start resizing images for the bunch'), $this->getOutput(), 'info');
            $this->processImageResize();
            $this->addLogWriteln(__('Resizing images for the bunch is complete'), $this->getOutput(), 'info');
        }
        $this->mediaGalleryProcessor->resetIdBySku();
    }

    /**
     * @return void
     */
    public function processImageResize()
    {
        if (!$this->imageResizeProcessor) {
            return;
        }
        try {
            if (!empty($this->bunchUploadedImages)) {
                foreach ($this->bunchUploadedImages as $path) {
                    if ($path && !in_array($path, $this->imageResizeIgnoreList)) {
                        $this->imageResizeProcessor->resizeFromImageName($path);
                        $this->imageResizeIgnoreList[] = $path;
                    }
                }
            }
        } catch (\Exception $e) {
            $this->addLogWriteln($e->getMessage(), $this->getOutput(), 'error');
        }
    }

    /**
     * @param $rows
     * @throws \Exception
     */
    protected function saveImageConfig($rows)
    {
        $insertBunch = [];
        $this->mediaGalleryProcessor->initDataQueue($rows);
        foreach ($this->getStoreIds() as $storeId) {
            foreach ($rows as $row) {
                foreach ($this->imageConfigField as $field) {
                    if (isset($row[$field])) {
                        $insertBunch[] = [
                            'attribute_id' => $this->getAttributeIdByCode($field),
                            $this->getProductEntityLinkField() => $this->mediaGalleryProcessor->getIdBySku($row['sku']),
                            'value' => $row[$field],
                            'store_id' => $storeId
                        ];
                    }
                }
            }
        }

        if ($insertBunch) {
            $conn = $this->getResource()->getConnection();
            $conn->insertOnDuplicate(
                $this->getResource()->getTable('catalog_product_entity_varchar'),
                $insertBunch
            );
        }
    }

    /**
     * @param $code
     * @return mixed
     */
    protected function getAttributeIdByCode($code)
    {
        if (isset($this->attrIds[$code])) {
            return $this->attrIds[$code];
        }

        $connection = $this->getResource()->getConnection();
        $query = $connection->select()
            ->from($this->getResource()->getTable('eav_attribute'), 'attribute_id')
            ->where(
                "attribute_code = '{$code}' AND entity_type_id = ?",
                $this->getAttributeTypeCode()
            );

        $this->attrIds[$code] = $connection->fetchOne($query);
        return $this->attrIds[$code];
    }

    /**
     * @return string
     */
    protected function getAttributeTypeCode()
    {
        if ($this->attrTypeId) {
            return $this->attrTypeId;
        }

        $connection = $this->getResource()->getConnection();
        $query = $connection->select()
            ->from(['st' => $this->getResource()->getTable('eav_entity_type')])
            ->where('st.entity_type_code = ?', ProductAttributeInterface::ENTITY_TYPE_CODE);
        $this->attrTypeId = $connection->fetchOne($query);

        return $this->attrTypeId;
    }

    /**
     * @param array $mediaGalleryData
     * @return $this
     */
    protected function saveMediaGallery(array $mediaGalleryData)
    {
        if (empty($mediaGalleryData)) {
            return $this;
        }

        if (!empty($this->config['deferred_images'])) {
            $this->mediaGalleryProcessor->initDataQueue($mediaGalleryData);
        }

        $this->mediaGalleryProcessor->saveMediaGallery($mediaGalleryData);

        return $this;
    }

    /**
     * @return array
     */
    protected function getStoreIds()
    {
        $storeIds = array_merge(
            array_keys($this->storeManager->getStores()),
            [0]
        );
        return $storeIds;
    }

    /**
     * Get Store Id By Store Code
     *
     * @param $storeViewCode
     * @return int
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    protected function getStoreIdByCode($storeViewCode)
    {
        $storeByCode = $this->storeManager->getStore($storeViewCode);
        return $storeByCode->getId();
    }

    /**
     * @param array $newMediaValues
     * @param array $attributeImages
     * @return $this
     */
    public function removeExistingImages(array $newMediaValues, array $attributeImages = []): self
    {
        try {
            $this->initMediaGalleryResources();

            $connection = $this->getResource()->getConnection();
            $connection->delete(
                $this->mediaGalleryTableName,
                $connection->quoteInto('value_id IN (?)', array_column($newMediaValues, 'value_id'))
            );

            if ($attributeImages) {
                $valueIds = [];
                foreach ($newMediaValues as $newMediaValue) {
                    if (!empty($attributeImages[$newMediaValue['sku']][$newMediaValue['value']])) {
                        foreach ($attributeImages[$newMediaValue['sku']][$newMediaValue['value']] as $items) {
                            $valueIds = array_merge($valueIds, array_column($items, 'value_id'));
                        }
                    }
                }
                if ($valueIds) {
                    $connection->delete(
                        $connection->getTableName('catalog_product_entity_varchar'),
                        $connection->quoteInto('value_id IN (?)', $valueIds)
                    );
                }
            }

            if (!empty($this->config['remove_images_dir'])) {
                $table = $connection->getTableName('catalog_product_entity_varchar');
                $existValues = $connection->fetchCol(
                    $connection->select()->from($table, ['value'])
                        ->where('value IN (?)', array_column($newMediaValues, 'value'))
                );

                foreach ($newMediaValues as $newMediaValue) {
                    if (in_array($newMediaValue['value'], $existValues)) {
                        continue;
                    }
                    $mediaPath = DirectoryList::PUB . DIRECTORY_SEPARATOR . DirectoryList::MEDIA .
                        DIRECTORY_SEPARATOR . $this->mediaConfig->getMediaPath($newMediaValue['value']);
                    $productImage = $this->mediaDirectory
                        ->getAbsolutePath($mediaPath);
                    if ($this->mediaDirectory->isExist($productImage)) {
                        $this->addLogWriteln(
                            __('Remove Image for Product %1 from media directory', $newMediaValue[Product::COL_SKU]),
                            $this->getOutput(),
                            'info'
                        );
                        $this->mediaDirectory->delete($productImage);
                    }
                }
            }
        } catch (\Exception $e) {
            $this->_logger->critical($e->getMessage());
        }

        return $this;
    }

    /**
     * Init media gallery resources.
     *
     * @return void
     */
    public function initMediaGalleryResources()
    {
        if (null == $this->mediaGalleryTableName) {
            $this->productEntityTableName = $this->getResource()->getTable('catalog_product_entity');
            $this->mediaGalleryTableName = $this->getResource()->getTable('catalog_product_entity_media_gallery');
            $this->mediaGalleryValueTableName = $this->getResource()->getTable(
                'catalog_product_entity_media_gallery_value'
            );
            $this->mediaGalleryEntityToValueTableName = $this->getResource()->getTable(
                'catalog_product_entity_media_gallery_value_to_entity'
            );
        }
    }

    /**
     * @return \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel
     */
    protected function getResource()
    {
        if (!$this->resource) {
            $this->resource = $this->resourceModelFactory->create();
        }
        return $this->resource;
    }

    /**
     * Divide additionalImages for old Magento version
     * @param $rowData
     *
     * @return mixed
     */
    public function checkAdditionalImages($rowData)
    {
        if (version_compare($this->productMetadata->getVersion(), '2.1.11', '<')) {
            $newImage = [];
            if (isset($rowData['additional_images'])) {
                $importImages = explode($this->getMultipleValueSeparator(), $rowData['additional_images']);
                $newImage = $importImages;
            }
            if (!empty($newImage)) {
                $rowData['additional_images'] = implode(',', $newImage);
            }
        }
        return $rowData;
    }

    /**
     * @param array $rowData
     * @return array
     */
    public function getImagesFromRow(array $rowData)
    {
        $images = [];
        $labels = [];
        foreach ($this->getMediaImagesAttributes() as $column) {
            if (!empty($rowData[$column])) {
                $images[$column] = array_unique(
                    array_map(
                        'trim',
                        explode($this->getMultipleValueSeparator(), $rowData[$column])
                    )
                );

                if (!empty($rowData[$column . '_label'])) {
                    $labels[$column] = $this->parseMultipleValues($rowData[$column . '_label']);

                    if (count($labels[$column]) > count($images[$column])) {
                        $labels[$column] = array_slice($labels[$column], 0, count($images[$column]));
                    }
                }
            }
        }

        return [$images, $labels];
    }

    /**
     * @return array
     */
    public function getMediaImagesAttributes()
    {
        if (empty($this->mediaImagesAttributes)) {
            $attributeCollection = $this->attributeCollectionFactory->create();
            $attributeCollection->addFieldToSelect('attribute_code');
            $attributeCollection->addFieldToFilter('frontend_input', 'media_image');

            $attributesCode = $attributeCollection->getColumnValues('attribute_code');
            $this->mediaImagesAttributes = array_unique(array_merge($attributesCode, $this->imagesArrayKeys));
        }
        return $this->mediaImagesAttributes;
    }

    /**
     * Parse values from multiple attributes fields
     *
     * @param string $labelRow
     * @return array
     */
    private function parseMultipleValues($labelRow)
    {
        return $this->parseMultiselectValues(
            $labelRow,
            $this->getMultipleValueSeparator()
        );
    }

    /**
     * @param $values
     * @param string $delimiter
     * @return array
     */
    public function parseMultiselectValues($values, $delimiter = Product::PSEUDO_MULTI_LINE_SEPARATOR)
    {
        if (empty($this->config[Import::FIELDS_ENCLOSURE])) {
            return explode($delimiter, $values);
        }
        if (preg_match_all('~"((?:[^"]|"")*)"~', $values, $matches)) {
            return $values = array_map(
                function ($value) {
                    return str_replace('""', '"', $value);
                },
                $matches[1]
            );
        }
        return [$values];
    }

    /**
     * @param array $rowData
     *
     * @return mixed
     */
    public function getCorrectSkuAsPerLength(array $rowData)
    {
        return strlen($rowData[Product::COL_SKU]) > Sku::SKU_MAX_LENGTH ?
            substr($rowData[Product::COL_SKU], 0, Sku::SKU_MAX_LENGTH) : $rowData[Product::COL_SKU];
    }

    /**
     * @return mixed
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getMediaGalleryAttributeId()
    {
        if (!$this->mediaGalleryAttributeId) {
            /** @var $resource \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModel */
            $resource = $this->resourceModelFactory->create();
            $this->mediaGalleryAttributeId =
                $resource->getAttribute(Product::MEDIA_GALLERY_ATTRIBUTE_CODE)->getId();
        }
        return $this->mediaGalleryAttributeId;
    }

    /**
     * @param $existingImages
     * @param $columnImage
     * @param $rowSku
     * @return array
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function checkAlreadyUploadedImages(&$existingImages, $columnImage, $rowSku)
    {
        $alreadyUploadedFile = $existingImages[$rowSku][$columnImage]['value'] ?? '';
        $isUploaded = '';
        if (empty($alreadyUploadedFile)) {
            $uploadedFileName = hash('sha256', $columnImage);
            $isUploaded = $this->getUploader()::getDispersionPath($uploadedFileName)
                . DIRECTORY_SEPARATOR . $uploadedFileName;
        }
        $isAlreadyUploaded = false;
        foreach ($this->getUploader()->getAllowedFileExtension() as $fileExtension) {
            if (!empty($isUploaded)) {
                $alreadyUploadedFile = $isUploaded . '.' . $fileExtension;
            }
            if (array_key_exists($rowSku, $existingImages)
                && array_key_exists($alreadyUploadedFile, $existingImages[$rowSku])
            ) {
                $isAlreadyUploaded = true;
                break;
            }
        }
        return [$isAlreadyUploaded, $alreadyUploadedFile];
    }

    /**
     * @param string $fileName
     * @param bool $renameFileOff
     * @param array $existingUpload
     *
     * @return string
     */
    public function uploadMediaFiles($fileName, $renameFileOff = false, $existingUpload = [])
    {
        $uploadedFile = '';
        try {
            $result = $this->getUploader()->move($fileName, $renameFileOff, $existingUpload);
            if (!empty($result)) {
                $uploadedFile = $result['file'];
            }
        } catch (\Exception $e) {
            $this->_logger->critical($e->getMessage());
            $uploadedFile = null;
        }
        return $uploadedFile;
    }

    /**
     * @return \Magento\CatalogImportExport\Model\Import\Uploader
     * @throws LocalizedException
     * @throws \Magento\Framework\Exception\FileSystemException
     */
    protected function getUploader()
    {
        $DS = DIRECTORY_SEPARATOR;
        if ($this->fileUploader === null) {
            $this->fileUploader = $this->uploaderFactory->create();
            $this->fileUploader->init();
            $this->fileUploader->setEntity($this);
            $dirConfig = DirectoryList::getDefaultConfig();
            $dirAddon = $dirConfig[DirectoryList::MEDIA][DirectoryList::PATH];
            if (!empty($this->config[Import::FIELD_NAME_IMG_FILE_DIR])) {
                $tmpPath = $this->config[Import::FIELD_NAME_IMG_FILE_DIR];
            } else {
                $tmpPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath('import');
            }
            if (preg_match('/\bhttps?:\/\//i', $tmpPath, $matches)) {
                $tmpPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath('import');
            }
            if (!$this->fileUploader->setTmpDir($tmpPath)) {
                throw new LocalizedException(
                    __('File directory \'%1\' is not readable.', $tmpPath)
                );
            }
            $destinationDir = "catalog/product";
            $destinationPath = $dirAddon . $DS . $this->mediaDirectory->getRelativePath($destinationDir);

            $this->mediaDirectory->create($destinationPath);
            if (!$this->fileUploader->setDestDir($destinationPath)) {
                throw new LocalizedException(
                    __('File directory \'%1\' is not writable.', $destinationPath)
                );
            }
        }

        return $this->fileUploader;
    }

    /**
     * @return ProcessingErrorAggregatorInterface
     */
    public function getErrorAggregator()
    {
        return $this->errorAggregator;
    }

    /**
     * Add error with corresponding current data source row number.
     *
     * @param string $errorCode Error code or simply column name
     * @param int $errorRowNum Row number.
     * @param string $colName OPTIONAL Column name.
     * @param string $errorMessage OPTIONAL Column name.
     * @param string $errorLevel
     * @param string $errorDescription
     * @return $this
     */
    public function addRowError(
        $errorCode,
        $errorRowNum,
        $colName = null,
        $errorMessage = null,
        $errorLevel = ProcessingError::ERROR_LEVEL_CRITICAL,
        $errorDescription = null
    ) {
        $errorCode = (string)$errorCode;
        $this->getErrorAggregator()->addError(
            $errorCode,
            $errorLevel,
            $errorRowNum,
            $colName,
            $errorMessage,
            $errorDescription
        );

        return $this;
    }

    /**
     * @return string
     * @throws \Exception
     */
    private function getProductEntityLinkField()
    {
        if (!$this->productEntityLinkField) {
            $this->productEntityLinkField = $this->metadataPool
                ->getMetadata(ProductInterface::class)
                ->getLinkField();
        }
        return $this->productEntityLinkField;
    }

    /**
     * @return array
     */
    public function getBunchUploadedImages()
    {
        return $this->bunchUploadedImages;
    }

    /**
     * @param $bunch
     * @return array
     * @throws \Exception
     */
    public function getExistingAttributeImages($bunch): array
    {
        $mediaImagesAttributes = $this->getMediaImagesAttributes();
        $resource = $this->getResource();
        $conn = $this->getResource()->getConnection();
        $query = $conn->select()->from(
            ['cpe' => $resource->getTable('catalog_product_entity')],
            ['sku' => 'cpe.sku', 'store_code' => 'st.code', 'image' => 'cpev.value']
        )->join(
            ['cpev' => $resource->getTable('catalog_product_entity_varchar')],
            'cpe.' . $this->getProductEntityLinkField() . '=' . 'cpev.' . $this->getProductEntityLinkField()
        )->join(['ea' => $resource->getTable('eav_attribute')], 'cpev.attribute_id=ea.attribute_id')
            ->join(['st' => $resource->getTable('store')], 'cpev.store_id=st.store_id')
            ->where('ea.attribute_code IN(?)', $mediaImagesAttributes)
            ->where('cpe.sku IN(?)', array_column($bunch, Product::COL_SKU));
        $result = [];
        foreach ($conn->fetchAll($query) as $item) {
            $result[$item['sku']][$item['image']][$item['store_code']][] = [
                'value_id' => $item['value_id'],
                'store_id' => $item['store_id'],
                'attribute_id' => $item['attribute_id'],
            ];
        }
        return $result;
    }
}