How to Resize Specific Product Image using Command Line in Magento 2
Steps to Resize Specific Product Image using Command Line in Magento 2:
Step 1: Create a di.xml file at the given path
app/code/Vendor/Extension/etc/di.xml
Now add the code as follows
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\Console\CommandListInterface">
<arguments>
<argument name="commands" xsi:type="array">
<item name="imagesResizeCommand" xsi:type="object">
Vendor\Extension\Console\Command\ImagesResizeCommand
</item>
</argument>
</arguments>
</type>
<type name="Vendor\Extension\Console\Command\ImagesResizeCommand">
<arguments>
<argument name="imageResizeScheduler" xsi:type="object">
Magento\MediaStorage\Service\ImageResizeScheduler\Proxy
</argument>
</arguments>
</type>
</config>
----------------------------------------------------------------------------------------------
Step 2: Now, you need to create the ImagesResizeCommand.php file at the below path
app/code/Vendor/Extension/Console/Command/ImagesResizeCommand.php
Then add the following code
<?php
declare(strict_types=1);
namespace Vendor\Extension\Console\Command;
use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\Console\Cli;
use Magento\MediaStorage\Service\ImageResize;
use Magento\MediaStorage\Service\ImageResizeScheduler;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\ProgressBarFactory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Magento\Framework\DB\Query\Generator;
use Magento\Framework\DB\Select;
use Magento\Framework\App\ResourceConnection;
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
use Magento\Catalog\Model\ResourceModel\Product\Image as Produc-tImage;
/**
* Resizes product images according to theme view definitions.
*/
class ImagesResizeCommand extends Command
{
/**
* Asynchronous image resize mode
*/
const ASYNC_RESIZE = 'async';
/**
* @var ImageResizeScheduler
*/
private $imageResizeScheduler;
/**
* @var ImageResize
*/
private $imageResize;
/**
* @var State
*/
private $appState;
/**
* @var ProgressBarFactory
*/
private $progressBarFactory;
/**
* @var ProductImage
*/
private $productImage;
/**
* @var ResourceConnection
*/
private $resourceConnection;
public function __construct(
State $appState,
ImageResize $imageResize,
ImageResizeScheduler $imageResizeScheduler,
ProgressBarFactory $progressBarFactory,
ProductImage $productImage,
Generator $generator,
ResourceConnection $resourceConnection
)
{
parent::__construct();
$this->appState = $appState;
$this->imageResize = $imageResize;
$this->imageResizeScheduler = $imageResizeScheduler;
$this->progressBarFactory = $progressBarFactory;
$this->productImage = $productImage;
$this->batchQueryGenerator = $generator;
$this->resourceConnection = $resourceConnection;
}
/**
* @inheritdoc
*/
protected function configure()
{
$this->setName('test:product:resize')
->setDefinition($this->getOptionsList());
$this->addOption(
'product_id',
null,
InputOption::VALUE_REQUIRED,
'Add Product ID'
);
}
/**
* Image resize command options list
*
* @return array
*/
private function getOptionsList() : array
{
return [
new InputOption(
self::ASYNC_RESIZE,
'a',
InputOption::VALUE_NONE,
'Resize image in asynchronous mode'
),
];
}
/**
* @inheritdoc
* @param InputInterface $input
* @param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInter-face $output)
{
$product_id = $input->getOption('product_id');
$result = $this->executeAsync($output, $product_id);
return $result;
}
/**
* Schedule asynchronous image resizing
*
* @param OutputInterface $output
* @param int $product_id
* @return int
*/
private function executeAsync(OutputInterface $output, $product_id): int
{
try
{
$errors = [];
$this->appState->setAreaCode(Area::AREA_GLOBAL);
/** @var ProgressBar $progress */
$progress = $this->progressBarFactory->create(
[
'output' => $output,
'max' => $this->getCountUsedProductImages($product_id)
]
);
$progress->setFormat(
"%current%/%max% [%bar%] %percent:3s%% %elapsed% %memory:6s% \t| <info>%message%</info>"
);
if ($output->getVerbosity() !== OutputInter-face::VERBOSITY_NORMAL)
{
$progress->setOverwrite(false);
}
$productImages = $this->getUsedProductImages($product_id);
foreach ($productImages as $image)
{
$result = $this->imageResizeScheduler->schedule($image['filepath']);
if (!$result)
{
$errors[$image['filepath']] = 'Error image scheduling: ' . $image['filepath'];
}
$progress->setMessage($image['filepath']);
$progress->advance();
}
}
catch (\Exception $e)
{
$output->writeln("<error>{$e->getMessage()}</error>");
return Cli::RETURN_FAILURE;
}
$output->write(PHP_EOL);
if (count($errors))
{
$output->writeln("<info>Product images resized with er-rors:</info>");
foreach ($errors as $error)
{
$output->writeln("<error>{$error}</error>");
}
}
else
{
$output->writeln("<info>Product images scheduled successful-ly</info>");
}
return Cli::RETURN_SUCCESS;
}
/**
* Get used product images.
*
* @param int $product_id
* @return \Generator
*/
private function getUsedProductImages($product_id): \Generator
{
$batchSelectIterator = $this->batchQueryGenerator->generate(
'value_id',
$this->getUsedImagesSelect($product_id),
100,
\Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
);
foreach ($batchSelectIterator as $select)
{
foreach ($this->resourceConnection->getConnection()->fetchAll($select) as $key => $value)
{
yield $key => $value;
}
}
}
/**
* Return select to fetch all used product images.
*
* @param int $product_id
* @return Select
*/
private function getUsedImagesSelect($product_id): Select
{
$query = 'images.disabled = 0 AND image_value.disabled = 0 AND image_value.entity_id = '.$product_id;
return $this->resourceConnection->getConnection()->select()->distinct()
->from(
['images' => $this->resourceConnection->getTableName(Gallery::GALLERY_TABLE)],
'value as filepath'
)->joinInner(
['image_value' => $this->resourceConnection->getTableName(Gallery::GALLERY_VALUE_TABLE)],
'images.value_id = image_value.value_id',
[]
)->where($query);
}
/**
* Get the number of unique and used images of products.
*
* @param int $product_id
* @return int
*/
private function getCountUsedProductImages($product_id): int
{
$select = $this->getUsedImagesSelect($product_id)
->reset('columns')
->reset('distinct')
->columns(
new \Zend_Db_Expr('count(distinct value)')
);
return (int) $this->resourceConnection->getConnection()->fetchOne($select);
}
}
----------------------------------------------------------------------------------------------
Step 3: After deploying this module, you need to execute this below command to resize a specific product image.
php bin/magento test:product:resize --product_id=1
Here, test:product:resize is custom command and product_id is an argument where you need to pass your product id.
Comments
Post a Comment