Magento Asked by Niraj Patel on November 15, 2021
I have this code but Anybody tell me faster way to update products.
This below code takes much time. So any alternative solution for to save product in fast way and Can I also put sleep function at end of the for loop to less consume memory ?
Thank you
public function updateProducts(){
foreach($productIds as $productId){
$objectManager = MagentoFrameworkAppObjectManager::getInstance(); // instance of object manager
$product = $objectManager->create('MagentoCatalogModelProduct');
$product->load($productId);
$product->setSku('my-sku'); // Set your sku here
$product->setName('Sample Simple Product'); // Name of Product
$product->setStatus(1); // Status on product enabled/ disabled 1/0
$product->setWeight(10); // weight of product
$product->setVisibility(4);
$product->setPrice(100); // price of product
$product->setStockData(
array(
'use_config_manage_stock' => 0,
'manage_stock' => 1,
'is_in_stock' => 1,
'qty' => 14
)
);
$imageUrl = "https://example.com/img1.jpg";
$tmpDir = $this->getMediaDirTmpDir();
$newFileName = $tmpDir . baseName($imageUrl);
$result = $this->file->read($imageUrl, $newFileName);
if ($result) {
$_product->addImageToMediaGallery($newFileName,array('small','thumbnail','base'), $imageType, true, false);
}
$product->save();
unset($product);
}
}
protected function getMediaDirTmpDir(){
return $this->directoryList->getPath(DirectoryList::MEDIA) . DIRECTORY_SEPARATOR . 'tmp';
}
If you using console command for this propose that is very fast an useful things. For console command you need to do this below code. In between you have to put the product update csv in var/upload/ folder or you select other folder.
<?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="MagentoFrameworkConsoleCommandList">
<arguments>
<argument name="commands" xsi:type="array">
<item name="bulk_product_update" xsi:type="object">[Vendor][Namespace]ConsoleCommandUpdateProduct</item>
</argument>
</arguments>
</type>
</config>
<?php
namespace [Vendor][Namespace]ConsoleCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
class UpdateProduct extends Command
{
public function __construct(
MagentoStoreModelStoreManagerInterface $storeManager,
MagentoCatalogModelResourceModelProductAction $productAction,
MagentoCatalogModelProductFactory $productFactory,
MagentoCatalogInventoryApiStockRegistryInterface $stockRegistry,
MagentoFrameworkFileCsv $csv,
MagentoFrameworkFilesystemDriverFile $fileDriver,
MagentoFrameworkFilesystemDirectoryList $dir,
MagentoFrameworkFilesystemIoFile $file
)
{
$this->storeManager = $storeManager;
$this->productAction = $productAction;
$this->productFactory = $productFactory;
$this->stockRegistry = $stockRegistry;
$this->csv = $csv;
$this->fileDriver = $fileDriver;
$this->dir = $dir;
$this->file = $file;
parent::__construct();
}
protected function configure()
{
$this->setName('bulk:productupdate')
->setDescription('Bulk product update with stock & Images');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$csvFilePath = $this->dir->getPath('var').'/upload/product_data.csv';
if (!$this->fileDriver->isExists($csvFilePath)) {
throw new MagentoFrameworkExceptionLocalizedException(__('Invalid file upload attempt.'));
}
$storeIds = array_keys($this->storeManager->getStores());
$csvData = $this->csv->getData($csvFilePath);
$attributeArray = array();
foreach ($csvData as $row => $data) {
if ($row > 0){
$product = $this->productFactory->create()->load($data[$attributeArray['id']]);
if(isset($data[$attributeArray['qty']])) {
$stockData = array(
'use_config_manage_stock' => $data[$attributeArray['use_config_manage_stock']],
'manage_stock' => $data[$attributeArray['manage_stock']],
'is_in_stock' => $data[$attributeArray['is_in_stock']],
'qty' => $data[$attributeArray['qty']]
);
$stockItem = $this->stockRegistry->getStockItem($data[$attributeArray['id']]);
$stockItem->setData($stockData);
$stockItem->save();
}
$updateAttributes['sku'] = $data[$attributeArray['sku']];
$updateAttributes['name'] = $data[$attributeArray['name']];
$updateAttributes['status'] = $data[$attributeArray['status']];
$updateAttributes['weight'] = $data[$attributeArray['weight']];
$updateAttributes['visibility'] = $data[$attributeArray['visibility']];
$updateAttributes['price'] = $data[$attributeArray['price']];
foreach ($storeIds as $storeId) {
$this->productAction->updateAttributes([$data[$attributeArray['id']]], $updateAttributes, $storeId);
}
if (isset($data[$attributeArray['image']])) {
$imageUrl = $data[$attributeArray['image']];
$newFileName = $this->dir->getPath('media'). '/tmp/' . baseName($imageUrl);
$result = $this->file->read($imageUrl, $newFileName);
if ($result) {
$_product->addImageToMediaGallery($newFileName, array('small','thumbnail','base'), true, false);
}
}
$product->save();
$output->writeln('Update Complete Product: '.$data[$attributeArray['sku']]);
}
} else {
foreach($data as $key => $dataValue) {
$attributeArray[$dataValue] = $key;
}
}
}
$output->writeln('All product Update complete');
}
}
At last you need to run in terminal below command:
bin/magento bulk:productupdate
Answered by Ritesh Santra on November 15, 2021
In order to update product attribute programmatically I use below way which is much faster then to save whole object
public function __construct(
.....
MagentoCatalogModelResourceModelProductAction $productAction,
......
) {
$this->productAction = $productAction;
}
public function saveProductAttribute()
{
$cnt = 0;
try{
$product = $this->productRepository->get($sku,false, null,true);
if ($product->getSku()) {
$updateAttributes['attribute_code1'] = $value1;
$updateAttributes['attribute_code2'] = $value2;
$updateAttributes['attribute_code3'] = $value3;
$updateAttributes['attribute_code4'] = $value4;
$updateAttributes['attribute_code5'] = $value5;
$updateAttributes['attribute_code6'] = $value6;
$updateAttributes['attribute_code7'] = $value7;
$updateAttributes['attribute_code8'] = $value8;
// in below code 0 is store Id
$this->productAction->updateAttributes([$product->getId()], $updateAttributes, 0);
$cnt++;
}
} catch (Exception $e){
}
return $this;
}
Answered by Murtuza Zabuawala on November 15, 2021
I have a solution working on my local environment. Before posting the full solution, I'd like to verify your requirements:
My import has pros and cons: I do not claim it competes with Magento and it is not ready for production as it is but it is not far off if you accept that some validations may go amiss..
for instance: I do not verify whether the sku in the import is unique
I assume it is fine to imagine the images may all be in pub/media/tmp/
folder
my import assigns random data only to the attributes that appear in your question (see below how these random data are generated) and therefore you understand in the real world you will have some csv parsing to do? Also, the data outside the scope of your data is not updated, or even set to a null value for instance.. (that means special_price might need work to do..)
public function getStockData()
{
return [
'use_config_manage_stock' => 0,
'manage_stock' => rand(0,1),
'is_in_stock' => rand(0,1),
'qty' => rand(1, 456)
];
}
private function getProductRandomData(int $productId)
{
return [
'sku' => sprintf('SKUBAT%s', $productId),
'name' => sprintf('Name for product %s', $productId),
'status' => rand(0,1),
'weight' => rand(1, 456),
'visibility' => rand(0, 4),
'price' => rand(3, 67)
];
}
I do not validate the image extension but I create the image folders like Magento does.
finally, I do not use the product save function and that is why I am faster. Yet, I do run the indexes once the collection of products has been updated. That is why over 1 or 100 product, I may not be faster as the indexes will take a while to run. But over 10000, I will likely beat your script by couple of hours
In short, my solution is only as good as the time we have in a weekend and I hope you appreciate I have not come up with a genius script that outperforms years of work from Magento team.
If you could acknowledge the above is something that you have considered, I will post the solution.
https://bitbucket.org/magstaging/importbatchproduct/src
the above module has a command to run the product import.
php bin/magento mbs:import:product '1,2,3,4,5,6'
will import your data and images very fast, I'd say in 15 minutes for 10k but of course it depends on your server. But it will be definitely faster than your script as no product load is performed and no product save either.
It means unfortunately, the script may bypass plugin you may have on product save function for instance. But I can't read your system and I hope it will make your import happy..
Answered by Herve Tribouilloy on November 15, 2021
I answered a similar question on this ticket, you can create a command import by using the default Magento import model.
That means you can use Magento import template CSV file like UI at System -> Data Transfer -> Import / Export
Ref: https://magento.stackexchange.com/a/318174/85035
Let me know if you need a more detailed script.
Thanks
Answered by vinhphon on November 15, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP