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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With