I have a product attribute with type "select", for example "manufacturer". No source model is defined, so Magento uses the default source model, defined in Mage_Eav_Model_Entity
:
const DEFAULT_SOURCE_MODEL = 'eav/entity_attribute_source_config';
But with this code:
$manufacturerAttribute = Mage::getModel('catalog/entity_attribute')
->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'manufacturer');
$values = $manufacturerAttribute->getSource()->getAllOptions();
I get this exception:
Source model "" not found for attribute "manufacturer"
Tracing down the error, I found that the default source model is actually fetched in Mage_Eav_Model_Entity_Attribute_Abstract
with:
protected function _getDefaultSourceModel()
{
return $this->getEntity()->getDefaultAttributeSourceModel();
}
and:
/**
* Retrieve entity instance
*
* @return Mage_Eav_Model_Entity_Abstract
*/
public function getEntity()
{
if (!$this->_entity) {
$this->_entity = $this->getEntityType();
}
return $this->_entity;
}
This looks all fine in the IDE but when I debug, I notice that getEntity
actually returns an object of Mage_Eav_Model_Entity_Type
which does not have a getDefaultAttributeSourceModel()
method, unlike Mage_Eav_Model_Entity_Abstract
. Looks like a bug in Magento to me…
What makes it even more confusing, is that _getDefaultSourceModel()
is overridden in Mage_Catalog_Model_Resource_Eav_Attribute
:
/**
* Get default attribute source model
*
* @return string
*/
public function _getDefaultSourceModel()
{
return 'eav/entity_attribute_source_table';
}
But since $attribute->getResource()
always gives me an instance of Mage_Eav_Model_Entity_Attribute
, I don't know how to make use of this.
I know that I could define the source model explicitly in an update script and that's how I usually handle it, but there has to be a proper way to make use of the default source model, I just can't figure it out.
Best Answer
Not exactly an answer, but a little long winded to be a comment...
I'd have to agree, that this is indeed a bug, or perhaps it should be framed as an 'unfinished feature'. As such I don't personally believe there is a 'proper way'. Since saving a new attribute model will set the source_model field (in
Mage_Eav_Model_Resource_Entity_Attribute::_beforeSave
) it should be impossible to create a new attribute without a source_model. Therefore it's arguably a bug inMage_Eav_Model_Entity_Setup::_insertAttribute
, which creates rows in the database directly, allowing for empty values in that column.Another interesting observation is that
getDefaultAttributeSourceModel
returnseav/entity_attribute_source_config
, whereas the value injected by_beforeSave
iseav/entity_attribute_source_table
(which falls inline with the default you saw in the catalog attribute). Comparing the two models, the former is actually pretty useless in itself. The docblock for the class points out that it should really be abstract, which seems to be the case. Unless 2 protected members (_options
and_configNodePath
) have a value, the class will always throw an exceptionFailed to load node %s from config
. The latter however will look in the table eav_attribute_option_value, which sounds much more useful.The closest I can get to an answer aside from 'fixing' the database, is to manually do what the
_beforeSave
would have done:Apologies if there's any false syllogisms here, it's getting late.