Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento Collection Filtering functions

Tags:

php

mysql

magento

What is the difference between addAttributeToFilter() and addFieldToFilter() when dealing with Magento collections? Does it have anything to do with whether or not the value is an eav_attribute?

EDIT: According to http://www.magentocommerce.com/wiki/5_-_modules_and_development/catalog/using_collections_in_magento:

addFieldToFilter($attribute, $condition=null) -- alias for addAttributeToFilter()

Can anybody confirm this?

like image 348
nachito Avatar asked Sep 23 '11 20:09

nachito


1 Answers

Apologies, there's no short answer that doesn't mislead or confuse things here.

Important Point #1: The Magento core team is loath to remove or rename methods from the source tree. Startup culture meant they eschewed tests plus being a public project it meant they couldn't control what people did with their product. Rather than remove methods and risk breaking things, they'll leave methods in place that call the new method. This way, even if there's old code out there that calls the method, they're covered.

Important Point #2: The collection inheritance chain is screwy, and has been inconsistently applied in certain parts of the codebase. This is being cleaned up, but it can still easily throw you for a loop.

Important Point #3: I'm speculating on how a lot of this is meant to be used and happened. I am not the final authority here, I'm just someone trying to make sense of it. The specifics below refer to 1.6, but the concepts apply to all versions

All collections inherit from the class Varien_Data_Collection_Db. This is the class that models the basic concept of "collecting a series of objects loaded from the database". This class has a single method addFieldToFilter.

public function addFieldToFilter($field, $condition=null)
{
    $field = $this->_getMappedField($field);
    $this->_select->where($this->_getConditionSql($field, $condition), null, Varien_Db_Select::TYPE_CONDITION);
    return $this;
}

which is a simple implementation that adds a where clause to the theoretical query.

Next up, there are two abstract classes that have Varien_Data_Collection_Db as an ancestor. Mage_Core_Model_Resource_Db_Collection_Abstract and Mage_Eav_Model_Entity_Collection_Abstract.

Mage_Core_Model_Resource_Db_Collection_Abstract is the collection class for "regular, non EAV models". It has neither a addFieldToFilter method or an addAttributeToFilter method. It relies on the implementation in on the base Varien_Data_Collection_Db class.

Mage_Eav_Model_Entity_Collection_Abstract is the collection class for EAV models. It has an addAttributeToFilter method, which is more complex.

public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')
{
    if ($attribute === null) {
        $this->getSelect();
        return $this;
    }

    if (is_numeric($attribute)) {
        $attribute = $this->getEntity()->getAttribute($attribute)->getAttributeCode();
    } else if ($attribute instanceof Mage_Eav_Model_Entity_Attribute_Interface) {
        $attribute = $attribute->getAttributeCode();
    }

    if (is_array($attribute)) {
        $sqlArr = array();
        foreach ($attribute as $condition) {
            $sqlArr[] = $this->_getAttributeConditionSql($condition['attribute'], $condition, $joinType);
        }
        $conditionSql = '('.implode(') OR (', $sqlArr).')';
    } else if (is_string($attribute)) {
        if ($condition === null) {
            $condition = '';
        }
        $conditionSql = $this->_getAttributeConditionSql($attribute, $condition, $joinType);
    }

    if (!empty($conditionSql)) {
        $this->getSelect()->where($conditionSql, null, Varien_Db_Select::TYPE_CONDITION);
    } else {
        Mage::throwException('Invalid attribute identifier for filter ('.get_class($attribute).')');
    }

    return $this;
}

That's because an attribute query is not a straight "where" query. Also, this method was designed to take either an attribute name, or an attribute database ID, or an instantiated attribute object. You are not adding a field to the filter, you're adding an attribute to the filter. So, depending on the implementation of EAV and which table the attribute is stored in, you need to add a different bit of SQL code (a straight where query on the main table, a where added with one of the join tables, etc.)

This creates a problem. Because this EAV collection object inherits from the base collection object, the addFieldToFilter still exists, and would still add a basic where condition to the EAV query, which might confuse an end user by not doing what they thought. Therefore, the EAV collection class also has this

public function addFieldToFilter($attribute, $condition = null)
{
    return $this->addAttributeToFilter($attribute, $condition);
}

which wraps any call to addFieldToFilter to addAttributeToFilter (again, on an EAV model). So, if you have an EAV model, you can use addFieldToFilter or addAttributeToFilter. If you're working with a regular model, you may only call addFieldToFilter, addAttributeToFilter doesn't exist.

Ideally, the method names would have been unified from the start, but once the split happened, the Magento team chose to continue supporting the split in favor of backwards compatibility.

Wait, There's More

There's two collections left in the codebase that inherit directly from Varien_Data_Collection_Db. These are Mage_Sales_Model_Resource_Sale_Collection and Mage_Review_Model_Resource_Review_Summary_Collection. This number is higher in versions of Magento CE prior to 1.6. While this doesn't impact the question of filtering, it does confuse the inheritance chain, so you should watch out for it.

Many non-EAV collections will implement their own addFieldToFilter to do sanity checks on variables, or jigger the query paramaters a little if they're doing something a little non standard.

The EAV collections get in on this act as well by redefining addAttributeToFilter. Again, this is done to add custom logic that doesn't fit in with the basic Magento collection loading.

like image 163
Alan Storm Avatar answered Oct 04 '22 21:10

Alan Storm