Custom Product Attributes, Source Models and Flat Tables

How to add an attribute to product_flat_table

Either one of the following attribute settings is true:

  • backend_typ = 'static'
  • is_filterable > 0
  • used_in_product_listing = 1
  • is_used_for_promo_rules= 1
  • used_for_sort_by = 1

Or you add it manually by observing this event:
catalog_product_flat_prepare_columns

Attribute is not added - source models

If you attribute is still not added it might be, because \Mage_Eav_Model_Entity_Attribute_Abstract::getFlatColumns is called on the attribute, which checks wether a source model exists.

public function getFlatColumns()
{
    // If source model exists - get definition from it
    if ($this->usesSource() && $this->getBackendType() != self::TYPE_STATIC) {
        return $this->getSource()->getFlatColums();
    }
    // ...
}

As you can see, getFlatColums is called on your source model, which default implementation is:

// \Mage_Eav_Model_Entity_Attribute_Source_Abstract::getFlatColums
public function getFlatColums()
{
    return array();
}

Therefore your attribute is not added.

And implementation like this might help:

public function getFlatColums()
{
    $attributeCode = $this->getAttribute()->getAttributeCode();
    $column        = [
        'unsigned' => false,
        'default'  => null,
        'extra'    => null,
    ];

    if (Mage::helper('core')->useDbCompatibleMode()) {
        $column['type']    = 'varchar';
        $column['is_null'] = true;
    } else {
        $column['type']     = Varien_Db_Ddl_Table::TYPE_VARCHAR;
        $column['nullable'] = true;
        $column['comment']  = 'Seals column';
    }

    return [$attributeCode => $column];
}

*Update*

How to fill the field

After the final win that the column is created on the flat tables, it was NULL after reindexing. Something is missing and this is:

\Mage_Eav_Model_Entity_Attribute_Source_Abstract::getFlatUpdateSelect

This method has to return a Zend_Db_Select due to this:

\Mage_Catalog_Model_Resource_Product_Flat_Indexer::updateAttribute
// ...
$select = $attribute->getFlatUpdateSelect($storeId);
if ($select instanceof Varien_Db_Select) {
    if ($productIds !== null) {
        $select->where('e.entity_id IN(?)', $productIds);
    }
}
// ...

An example implementation which works for me:

public function getFlatUpdateSelect($store)
{
    return Mage::getResourceSingleton('eav/entity_attribute')
        ->getFlatUpdateSelect($this->getAttribute(), $store);
}

EAV attributes, default values and source models

EAV Attribute

I tried to add an EAV attribut, set a default value and that without using a source model, set this options:

$this->addAttribute('customer', 'customer_type', array(
    'type' => 'int'     
    'option' => array('values' => array('Customer', 'Artist'))
    'default' => 'Customer',
    [...]
);

Default value

Magento adds the values into the eav_attribute_option_value table and shows them in the backend. The problem is, if we save them as int, we can't set 'Customer' as default. And we can't set the eav_attribute_option_value.value_id, because we don't know it.

Solution

I removed the options from the attribute and added a soure model.

$this->addAttribute('customer', 'customer_type', array(
    'type' => 'int'     
    'source' => 'company_extension/entity_attribute_source_modelName',
    'default' => 1,
       [...]
);

A source model needs to implement the Mage_Eav_Model_Entity_Attribute_Source_Interface. To make life easier there is an abstract class Mage_Eav_Model_Entity_Attribute_Source_Abstract we can extend.

So just implement the source model, then you know the int value of your options and you can set it.