Save Attribute Value Per Store in Custom EAV Based Model – Magento Guide

attributeseavmodel

Let's say I have custom EAV entity type with it's tables that have store field (just like catalog/product tables have). Can default EAV resource model save data per store? From what I have seen, in Mage_Eav_Model_Entity_Abstract there is _saveAttribute method (which is used for inserting and updating) which does not create store_id key:

protected function _saveAttribute($object, $attribute, $value)
{
    $table = $attribute->getBackend()->getTable();
    if (!isset($this->_attributeValuesToSave[$table])) {
        $this->_attributeValuesToSave[$table] = array();
    }

    $entityIdField = $attribute->getBackend()->getEntityIdField();

    $data   = array(
        'entity_type_id'    => $object->getEntityTypeId(),
        $entityIdField      => $object->getId(),
        'attribute_id'      => $attribute->getId(),
        'store_id'          => $object->getStoreId(),
        'value'             => $this->_prepareValueForSave($value, $attribute)
    );

    $this->_attributeValuesToSave[$table][] = $data;

    return $this;
}

I have also seen that products use different mechanism for this (in Mage_Catalog_Model_Resource_Abstract):

    protected function _saveAttributeValue($object, $attribute, $value)
{
    $write   = $this->_getWriteAdapter();
    $storeId = (int)Mage::app()->getStore($object->getStoreId())->getId();
    $table   = $attribute->getBackend()->getTable();

    /**
     * If we work in single store mode all values should be saved just
     * for default store id
     * In this case we clear all not default values
     */
    if (Mage::app()->isSingleStoreMode()) {
        $storeId = $this->getDefaultStoreId();
        $write->delete($table, array(
            'attribute_id = ?' => $attribute->getAttributeId(),
            'entity_id = ?'    => $object->getEntityId(),
            'store_id <> ?'    => $storeId
        ));
    }

    $data = new Varien_Object(array(
        'entity_type_id'    => $attribute->getEntityTypeId(),
        'attribute_id'      => $attribute->getAttributeId(),
        'store_id'          => $storeId,
        'entity_id'         => $object->getEntityId(),
        'value'             => $this->_prepareValueForSave($value, $attribute)
    ));
    $bind = $this->_prepareDataForTable($data, $table);

    if ($attribute->isScopeStore()) {
        /**
         * Update attribute value for store
         */
        $this->_attributeValuesToSave[$table][] = $bind;
    } else if ($attribute->isScopeWebsite() && $storeId != $this->getDefaultStoreId()) {
        /**
         * Update attribute value for website
         */
        $storeIds = Mage::app()->getStore($storeId)->getWebsite()->getStoreIds(true);
        foreach ($storeIds as $storeId) {
            $bind['store_id'] = (int)$storeId;
            $this->_attributeValuesToSave[$table][] = $bind;
        }
    } else {
        /**
         * Update global attribute value
         */
        $bind['store_id'] = $this->getDefaultStoreId();
        $this->_attributeValuesToSave[$table][] = $bind;
    }

    return $this;
}

This leads me to believe that it is impossible to make EAV based models with values per store without some overwriting. Since I have seen that people mention that it is possible to do it, I would like someone to clarify this for me.

Best Answer

It's possible.
When I create an EAV entity I make the entity model extend Mage_Catalog_Model_Abstract, the resource model extends Mage_Catalog_Model_Resource_Abstract, and the resource collection model extends Mage_Catalog_Model_Resource_Collection_Abstract.
This way the entity behaves in a similar was to the product or category entity.

You can give this module creator a try. It's not yet in a final stage but it should work for simple modules. It has support for creating EAV entities.