I am running a loop through a product collection like the following
$productCollection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('small_image')
->addAttributeToSelect('thumbnail')
->addAttributeToSelect('image')
->addAttributeToSelect('sku');
foreach($productCollection as $product){
$product->setSmallImage($product->getImage());
$product->setThumbnail($product->getImage());
$product->save();
}
I am setting the other image types to the same as the base image because the client forgot to set those in the import sheet. For some reason when doing this it is setting the visibility of all products to Catalog, Search. A lot of my products are suppose to be "Not Visible Individually", so of course this messes stuff up.
Any Idea why this value would change, and are there other values that might change based on how I looped through the product collection?
I think it is because i removed the addAttributeToSelect(*) and did it specific to the two attributes but when trying to do the product collection over 18k products it was crapping out
Ok so this is what I found. When saving an object in Magento, it will call the normal Model abstract save method, this then calls $this->_getResource()->save($this);
which will call the entity abstract save method, which eventually gets to /app/code/core/Mage/Eav/Model/Entity/Abstract.php and its _beforeSave()
method which calls the walkAttributes($partMethod, array $args=array())
method.
A long the way all the attributes are loaded the the Resource object of the entity. The walkAttributes method will go through all attributes associated to the entity and calls this method call_user_func_array(array($instance, $method), $args); and in my case it is calling the beforeSave method for an attribute, as you can see here
/app/code/core/Mage/Eav/Model/Entity/Attribute/Backend/Abstract.php
public function beforeSave($object)
{
$attrCode = $this->getAttribute()->getAttributeCode();
if (!$object->hasData($attrCode) && $this->getDefaultValue()) {
$object->setData($attrCode, $this->getDefaultValue());
}
}
So any attribute that does not have any data and has a default value, that default value is applied to the object, in sense overwriting my data that is really set just not loaded to my object. I am guessing the best way to loop over thousands of products is to set the pageSize to a number that your server can handle loading and then you can set addAttributeToSelect('*'). However I am not aware of the best way to loop over this correctly, so for me I might just load the product in the for loop and not set the attribute to select all.
Here is my attempt at looping over the whole collection, please post any improvements
$productCollection = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('*')->setPageSize(200);
for ($i = 1; $i <= $productCollection->getLastPageNumber(); $i++) {
if ($productCollection->isLoaded()) {
$productCollection->clear();
$productCollection->setPage($i);
$productCollection->setPageSize(200);
}
foreach ($productCollection as $product) {
echo $product->getId() . "
";
}
echo $i . "
";
}
I would like to still hear any other input on this as to whether this is the right thinking or explanation of the problem.
I actually found a better way to loop over a large collection, which is to use the resource iterator model and here is a tutorial on how to do so from the Fontis guys
http://www.fontis.com.au/blog/magento/loading-large-collections