If you have to do a mass update of one (or more attributes) to the same value, you can use:
$this->_objectManager->get('Magento\Catalog\Model\Product\Action')
->updateAttributes($productIds, ['status' => $status], $storeId);
In this example, we're updating all products matched by id ($productIds is array of product IDs), by setting their status attribute to the $status value, for store $storeId.
If you want just to update single attribute in the collection of products, you can use (in your case):
...
foreach($productCollection as $product{
$product->addAttributeUpdate($attributeCode, $value, $store);
}
...
$attributeCode represents attribute name which has to be saved
$value represents the value which you want to set on the entity
$store represents store id, it can be $product->getStoreId()
Problem with addAttributeUpdate() is that updates attribute, but it doesn't update currently loaded product model. Take a look at the implementation in Magento\Catalog\Model\Product
:
/**
* Save current attribute with code $code and assign a new value
*
* @param string $code Attribute code
* @param mixed $value New attribute value
* @param int $store Store ID
* @return void
*/
public function addAttributeUpdate($code, $value, $store)
{
$oldValue = $this->getData($code);
$oldStore = $this->getStoreId();
$this->setData($code, $value);
$this->setStoreId($store);
$this->getResource()->saveAttribute($this, $code);
$this->setData($code, $oldValue);
$this->setStoreId($oldStore);
}
In that case it's better to use something like, productResource
is Magento\Catalog\Model\ResourceModel\Product
:
...
foreach($productCollection as $product{
// its sugessted to inject resource as dependency than using deprecated getResource() method.
// check reference for more information.
// $product->getResource()->saveAttribute($product, $attributeCode);
$this->productResource->saveAttribute($product, $attributeCode);
}
...
Lack of this solution becomes visible when you're working on large collections. That's why we have iterators which grabs data from database, one by one, and on that way, it prevents memory exhaustion.
...
$this->_dataObject = $this->_objectManager->get('Magento\Catalog\Model\Product');
$iterator = $this->_objectManager->get('Magento\Framework\Model\ResourceModel\Iterator')
$iterator->walk($productCollection->getSelect(), [[$this, 'walkCallback']]);
...
public function walkCallback($data)
{
$this->_dataObject->reset(); // clean up shared object
$this->_dataObject->setData($data['row']); // map data to product model
$this->_dataObject->setDescription('test');
$this->_dataObject->getResource()->saveAttribute($this->_dataObject, 'description'); // save only changed attribute instead of whole object
}
Those are ideas which you can use for manipulating collections.
Reference: https://github.com/magento/magento-coding-standard/pull/189