Question

In my resource model I have defined a field as serializable (see property $_serializableFields in Mage_Core_Model_Resource_Db_Abstract): Magento handles automatically serialization/unserialization of the contents when loading data from the database and before saving the object.

This works perfectly, but when I iterate over a collection of those objects, the field contents are not unserialized automatically. I tried with $collection->walk('afterLoad') but soon realized that unserializeFields() is triggered in the resource model load(), and not in afterLoad() like I first thought. What is the best practice in this case? How do I get this field unserialized automatically? I can of course reload the object in my loop, doing something like $object = $object->load($object->getId()), but I was wondering if there is a smarter way to achieve this.

Was it helpful?

Solution

I can of course reload the object in my loop, doing something like $object = $object->load($object->getId())

This is not a reload - this is a load. Items (model instances) in collections are not loaded. They merely have had an associative array of result row data applied to them. It's an important and slightly confusing difference between these collection-owned model instances and those which are self-load data through their resource model.

In your collection's _afterLoad(), iterate over the _items and unserialize() the appropriate field:

protected function _afterLoad()
{
    parent::_afterLoad();
    foreach ($this->getItems() as $item) {
        $item->setData('field',unserialize($item->getData('field')));
        $item->setDataChanges(false);
        //The above sets items as not dirty.
        //Value will be serialized on save via resource model.
    }
    return $this;
}

OTHER TIPS

To do this for product collections I added an event listener to catalog_product_collection_load_after and to iterate over all products.

/**
 * Apply backend manipulations of attributes to collection items.
 * Listens to catalog_product_collection_load_after.
 *
 * @param Varien_Event_Observer $observer
 * @return Mage_Catalog_Model_Observer
 */
public function loadCollectionAttributes(Varien_Event_Observer $observer)
{
    $collection = $observer->getCollection();
    /* @var $collection Mage_Catalog_Model_Resource_Product_Collection */
    foreach ($collection as $product) {
        /* @var $product Limora_Catalog_Model_Product */
        foreach ($product->getAttributes() as $attribute) {
            /* @var $attribute Mage_Eav_Model_Attribute */
            $attribute->getBackend()->afterLoad($product);
        }
    }
}

Or more simply, in your resource model collection:-

class Collection 
extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
    protected function _afterLoad()
    {
        parent::_afterLoad();
        foreach ($this->getItems() as $item) {
            $this->getResource()->unserializeFields($item);
            $item->setDataChanges(false);
        }
        return $this;
   }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top