0

When you upload a product image from backend to Magento that has the name that we are uploading like slide1.jpg I need to rename uploaded file name to productsku_slide1.jpg and same for other images.

In frontend when we save image as in gallery through any browser it should get downloaded with name productsku_slide1.jpg. Can anyone please provide solution for this ?

1 Answer 1

0
  1. You need to add your logic to catalog_product_save_commit_after event

app/code/Acme/StackExchange/etc/events.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="catalog_product_save_commit_after">
        <observer name="acme_stackexchange_observer_product_save_commit_after_media"
                  instance="Acme\StackExchange\Observer\Catalog\NormalizeProductMedia"/>
    </event>
</config>
  1. Observer to update image names and labels

app/code/Acme/StackExchange/Observer/Catalog/NormalizeProductMedia.php

<?php
declare(strict_types=1);

namespace Acme\StackExchange\Observer\Catalog;

use Acme\StackExchange\Model\ResourceModel\Catalog\Product\Gallery as GalleryResource;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Media\Config as MediaConfig;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\EntityManager\EntityMetadata;
use Magento\Framework\EntityManager\EntityMetadataInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\MediaStorage\Helper\File\Storage\Database as DatabaseStorage;
use Magento\MediaStorage\Model\File\Uploader as FileUploader;

class NormalizeProductMedia implements ObserverInterface
{
    /**
     * @var EntityMetadata|EntityMetadataInterface
     */
    protected $metadata;

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

    /**
     * @var GalleryResource
     */
    protected $galleryResource;

    /**
     * @var ProductAttributeInterface
     */
    protected $attribute;

    /**
     * @var WriteInterface
     */
    protected $mediaDirectory;

    /**
     * @var WriteInterface
     */
    protected $pubDirectory;

    /**
     * @var DatabaseStorage
     */
    protected $fileStorageDb;

    /**
     * @param MetadataPool $metadataPool
     * @param MediaConfig $mediaConfig
     * @param GalleryResource $galleryResource
     * @param ProductAttributeRepositoryInterface $attributeRepository
     * @param Filesystem $filesystem
     * @param DatabaseStorage $fileStorageDb
     * @throws FileSystemException
     * @throws NoSuchEntityException
     */
    public function __construct(
        MetadataPool $metadataPool,
        MediaConfig $mediaConfig,
        GalleryResource $galleryResource,
        ProductAttributeRepositoryInterface $attributeRepository,
        Filesystem $filesystem,
        DatabaseStorage $fileStorageDb
    ) {
        $this->metadata        = $metadataPool
            ->getMetadata(ProductInterface::class);
        $this->mediaConfig     = $mediaConfig;
        $this->attribute       = $attributeRepository->get('media_gallery');
        $this->galleryResource = $galleryResource;
        $this->mediaDirectory  = $filesystem
            ->getDirectoryWrite(DirectoryList::MEDIA);
        $this->pubDirectory    = $filesystem
            ->getDirectoryWrite(DirectoryList::PUB);
        $this->fileStorageDb   = $fileStorageDb;
    }

    /**
     * @inheritDoc
     */
    public function execute(Observer $observer): void
    {
        /** @var Product $product */
        $product = $observer->getEvent()->getData('product');
        $images  = $this->galleryResource->loadProductGalleryByAttributeId(
            $product, $this->attribute->getAttributeId());

        if (!$images) {
            return;
        }
        foreach ($images as &$image) {
            if ($image['media_type'] !== 'image') {
                continue;
            }
            $this->updateImageLabel($product, $image);

            if (!$this->fileStorageDb->checkDbUsage()) {
                $this->updateImageFilename($product, $image);
            }
        }
        unset($image);
    }

    /**
     * @param Product $product
     * @param array $image
     */
    protected function updateImageLabel(Product $product, array &$image): void
    {
        $isNameChanged = $product->dataHasChangedFor('name');

        if ((string)$image['label'] !== '' && !$isNameChanged) {
            return;
        }
        if ($isNameChanged) {
            $oldName = $product->getOrigData('name');
            // keep custom label
            if (stripos((string)$image['label'], $oldName . ' - ') === false) {
                return;
            }
        }

        $image['label'] = sprintf('%s - %d',
            $product->getName(), $image['position'] + 1);

        $storeId   = (int)$product->getStoreId();
        $linkField = $this->metadata->getLinkField();
        $data      = [
            'value_id' => $image['value_id'],
            'label'    => $image['label'],
            'position' => isset($image['position']) ? (int)$image['position'] : 0,
            'disabled' => isset($image['disabled']) ? (int)$image['disabled'] : 0,
            'store_id' => $storeId,
            $linkField => (int)$product->getData($linkField),
        ];

        try {
            $this->galleryResource->updateGalleryValue($data);

            $hasLabel = ['image', 'small_image', 'thumbnail'];
            $affected = $this->getAffectedMediaAttributes($product, $image);
            foreach ($affected as $attrCode) {
                if (in_array($attrCode, $hasLabel, true)) {
                    $product->setData($attrCode . '_label', $image['label']);
                    $product->addAttributeUpdate(
                        $attrCode . '_label',
                        $image['label'],
                        $storeId
                    );
                }
            }
        } catch (\Exception $e) {
        }
    }

    /**
     * @param Product $product
     * @param array $image
     */
    protected function updateImageFilename(
        Product $product,
        array &$image
    ): void {
        $file    = $image['file'];
        if (empty($file)) {
            return;
        }

        if (strpos($file, $product->getSku() . '_') !== false) {
            return;
        }

        $newFile = false;
        $oldFile = $file;
        if (!$this->mediaDirectory->isExist($this->mediaConfig->getMediaPath($oldFile))) {
            return;
        }

        $affected = $this->getAffectedMediaAttributes($product, $image);
        $fileExt  = strtolower(pathinfo($oldFile, PATHINFO_EXTENSION));
        $fileExt  = strtr($fileExt, ['jpeg' => 'jpg']);

        try {
            for ($i = 1; $i < 500; $i++) {
                $tmpName = sprintf('%s_slide%d.%s',
                    $product->getSku(), $i, $fileExt);
                $tmpPath = FileUploader::getDispersionPath($tmpName);
                $tmpFile = $this->mediaConfig->getMediaPath($tmpPath . '/' . $tmpName);

                if (!$this->mediaDirectory->isExist($tmpFile)) {
                    $newFile = $tmpPath . '/' . $tmpName;
                    break;
                }
            }

            if (!$newFile) {
                return;
            }

            $this->mediaDirectory->renameFile(
                $this->mediaConfig->getMediaPath($oldFile),
                $this->mediaConfig->getMediaPath($newFile)
            );

            $this->clearProductCache($newFile);

            $image['file'] = $newFile;

            $this->saveGalleryEntity($image);
            $this->saveAffectedAttributes($product, $affected, $newFile);
        } catch (\Exception $e) {
        }
    }

    /**
     * @param Product $product
     * @param array $image
     * @return array
     */
    protected function getAffectedMediaAttributes(
        Product $product,
        array $image
    ): array {
        $file = $image['new_file'] ?? $image['file'];
        if (empty($file)) {
            return [];
        }

        $affected   = [];
        $attributes = $this->mediaConfig->getMediaAttributeCodes();
        foreach ($attributes as $attrCode) {
            if ($product->getData($attrCode) === $file) {
                $affected[] = $attrCode;
            }
        }

        return $affected;
    }

    /**
     * @param Product $product
     * @param array $affected
     * @param string $file
     */
    protected function saveAffectedAttributes(
        Product $product,
        array $affected,
        string $file
    ): void {
        foreach ($affected as $attrCode) {
            $product->setData($attrCode, $file);
            $product->addAttributeUpdate(
                $attrCode,
                $file,
                (int)$product->getStoreId()
            );
        }
    }

    /**
     * @param array $image
     */
    protected function saveGalleryEntity(array $image): void
    {
        $data = [
            'value_id'     => $image['value_id'],
            'attribute_id' => (int)$this->attribute->getAttributeId(),
            'value'        => $image['file'],
            'media_type'   => $image['media_type'],
            'disabled'     => $image['disabled'] ?? 0,
        ];

        $this->galleryResource->saveDataRow(
            $this->galleryResource::GALLERY_TABLE,
            $data,
            ['value']
        );
    }

    /**
     * @param string $file
     */
    protected function clearProductCache(string $file): void
    {
        try {
            $pattern = sprintf('cache/*/%s', ltrim($file, '/'));
            $path    = $this->mediaConfig->getBaseMediaPath();
            $result  = $this->mediaDirectory->search($pattern, $path);
            foreach ($result as $cacheFile) {
                $this->mediaDirectory->delete($cacheFile);
            }
        } catch (\Exception $e) {
        }
    }
}
  1. Some extend to Gallery Resource

app/code/Acme/StackExchange/Model/ResourceModel/Catalog/Product/Gallery.php

<?php
declare(strict_types=1);

namespace Acme\StackExchange\Model\ResourceModel\Catalog\Product;

use Magento\Framework\DataObject;
use Magento\Framework\Exception\LocalizedException;

class Gallery extends \Magento\Catalog\Model\ResourceModel\Product\Gallery
{
    public function updateGalleryValue(array $data)
    {
        $connection = $this->getConnection();
        $linkField  = $this->metadata->getLinkField();

        if (!isset($data['value_id'], $data[$linkField], $data['store_id'])) {
            throw new LocalizedException(__('Missed required fields for Media Gallery Value'));
        }
        unset($data['record_id']);

        $data = $this->_prepareDataForTable(
            new DataObject($data),
            $this->getTable(self::GALLERY_VALUE_TABLE)
        );

        $select = $connection->select()
            ->from($this->getTable(self::GALLERY_VALUE_TABLE), 'record_id')
            ->where('value_id = ?', (int)$data['value_id'])
            ->where($linkField . ' = ?', (int)$data[$linkField])
            ->where('store_id = ?', (int)$data['store_id']);
        $recordId = $connection->fetchOne($select);

        if ($recordId !== false) {
            $connection->update(
                $this->getTable(self::GALLERY_VALUE_TABLE),
                $data,
                $connection->quoteInto('record_id = ?', (int)$recordId)
            );
        } else {
            $connection->insert(
                $this->getTable(self::GALLERY_VALUE_TABLE),
                $data
            );
        }

        return $this;
    }
}

Feel free to update a logic inside according to you requirements

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.