Many to Many Resource Model Mapping

This is some boilerplate code to facilitate the use of many-to-many relationship tables in Magento. I found myself rewriting this code often, so this saves some time. This example links a sizeguide entity to attribute sets. Obviously you'll need to make the entity table and the relationship table first, and you'll need to change the code to match your column names, but this gets you most of the way:

Resource Model - Loading and Saving

/**
 * Load the attribute set relations onto an object
 *
 * This is public as we need to walk over objects loaded from a collection
 *
 * @param Varien_Object $object The object to add sets to
 *
 * @return void
 */
public function loadAttributeSets(Varien_Object $object)
{
    $select = $this->_getReadAdapter()
        ->select()
        ->from($this->getTable('sizeguide/attribute_set'), 'attribute_set_id')
        ->where('sizeguide_id = ?', $object->getId());
    $attributeIds = $this->_getReadAdapter()->fetchCol($select);
    $attributeIds = array_map('intval', $attributeIds);
    $object->setAttributeSets($attributeIds);
}

/**
 * Save the attribute set relations to a separate flat table
 *
 * @param Varien_Object $object The object to save sets for
 *
 * @return void
 */
protected function saveAttributeSets(Varien_Object $object)
{
    if ($object->dataHasChangedFor('attribute_sets')) {
        $writeAdaptor = $this->_getWriteAdapter();
        $attributeSetTable = $this->getTable('sizeguide/attribute_set');
        // delete existing relations
        $writeAdaptor->delete(
            $attributeSetTable,
            $writeAdaptor->quoteInto('sizeguide_id = ?', $object->getId())
        );
        // insert new relations
        $setIds = array_unique($object->getAttributeSets());
        if (is_array($setIds)) {
            $insert = array();
            foreach ($setIds as $setId) {
                $insert[] = array(
                    'sizeguide_id'     => $object->getId(),
                    'attribute_set_id' => $setId,
                );
            }
            if (count($insert)) {
                $writeAdaptor->insertMultiple(
                    $attributeSetTable,
                    $insert
                );
            }
        }
    }
}

/**
 * After load entity process
 *
 * @param Varien_Object $object
 *
 * @return Mage_Eav_Model_Entity_Abstract
 */
protected function _afterLoad(Varien_Object $object)
{
    $this->loadAttributeSets($object);

    return parent::_afterLoad($object);
}

/**
 * After save entity process
 *
 * @param Varien_Object $object
 *
 * @return Mage_Eav_Model_Entity_Abstract
 */
protected function _afterSave(Varien_Object $object)
{
    $this->saveAttributeSets($object);

    return parent::_afterSave($object);
}

Resource Collection Model - Loading Collection By Link

I was doing this on an EAV table, so I joined on e.entity_id, if you use flat you'll need to join on main_table.entity_id. Also, you'll want to change the method name based on what you're joining on. Note there is no magic here (as opposed to the resource model), you simply have to call the method.

Oh sorry - there is one peice of magic, which is to walk over all the items, calling loadAttributeSets() for each, otherwise they won't have that data loaded (because the collection doesn't do so).

/**
 * Load all guides with a relationship to the provided attribute set id
 *
 * @param int $id attribute set it
 *
 * @return Mage_Eav_Model_Entity_Collection_Abstract 
 */
public function addAttributeSetIdToFilter($id)
{
    $this->getSelect()
        ->join(
            array('as' => $this->getTable('sizeguide/attribute_set')),
            'e.entity_id = as.sizeguide_id',
            array()
        )
        ->where('as.attribute_set_id = ?', $id);

    return $this;
}

/**
 * After load entity process
 *
 * @param Varien_Object $object
 *
 * @return Mage_Eav_Model_Entity_Abstract
 */
protected function _afterLoad(Varien_Object $object)
{
    $this->loadAttributeSets($object);

    return parent::_afterLoad($object);
}
Mike Whitby Almost 10 years ago