Magento Themes and Magento Extensions

Creating EAV based model(s) in Magento

Share

Magento EAV (Entity Attribute Value) data model is used to get flexibility for your data, but it brings more complexity than relation table model. If you need data model that will have flexible attributes which can be dynamically added, for example from Magento admin panel, then EAV is the best solution for you. If using EAV, you don’t need to change table structure for every new attribute like you do on flat tables (creating new colums).

Bad things which EAV flexibility brings are slower Queries and more complex table structures. Let’s talk more about performance, EAV system is slower than using flat table for resource model, because it uses a lot of mysql joins (depend on attributes number) and, as we know, Query with join data from other tables is always slower than select Query from one table. This problem can be solved with two solutions. For Enterprise Magento enable full page cache and page will be cached, so with or without EAV there won’t be any difference, only first load(slower for EAV) and after that all is cached. Second solution is to make flat table and indexer for creating table from EAV entity attributes.

After short brief about good and bad things with EAV let’s see how to create custom EAV model in example. For demonstration purposes let’s create Blog module with EAV resource model for posts, and focus will be on creating model, resource model and collection for post with installation. Admin part for adding new posts and custom attributes won’t be part of this article because they’re not required for our EAV model to work. I will demonstrate how to use EAV resurce model and Collection to get post(s) on frontend.

First we need to create our Blog module by adding module declaration in config, for this we’ll create Inchoo_Blog.xml in app\etc\modules\:
app\etc\modules\Inchoo_Blog.xml:


true
local

After registering our module, next step is to create folder structure for Module (Block, Helper, controllers, etc, Model and sql folders in module root folder – app\code\local\Inchoo\Blog\), and inside etc folder config.xml for module configuration:


1.0.0.0

Inchoo_Blog_Model

Inchoo_Blog_Helper

Inchoo_Blog_Block

xxx
In config file we add common options by declaring module version, models, helpers, blocks. After adding them, we add other config options needed for our module to work with entity tables. In config file we have declared model class so Magento can know what model to use with Mage::getModel.

For Blog posts we need to create post model, post resource model and post collection. First we’ll create post model in app/code/local/Inchoo/Blog/Model/ with file name Post.php:

class Inchoo_Blog_Model_Post extends Mage_Core_Model_Abstract
{

}
Note that Inchoo_Blog_Model_Post class extends Mage_Core_Model_Abstract, same as every other Model, but EAV magic starts in resource model. In post model class we need to define our resource model in _construct():

protected function _construct()
{
$this->_init(‘inchoo_blog/post’);
}
inchoo_blog/post is resource model that need to be declared in our config.xml and we’ll add it now in models node:

Inchoo_Blog_Model
inchoo_blog_resource

Inchoo_Blog_Model_Resource

inchoo_blog is model node name and post is file name for resource model. Magento creates path to resource model joining inchoo_blog resource class (Inchoo_Blog_Model_Resource) with resource model name (Post). After Magento join this from configuration we’ll get post resource class name (and path): Inchoo_Blog_Model_Resource_Post.

Now it’s time to create our resource model, so let’s create Post.php file in app/code/local/Inchoo/Blog/Model/Resource/ folder:

class Inchoo_Blog_Model_Resource_Post extends Mage_Eav_Model_Entity_Abstract
{

}
As you can see, our resurce model Inchoo_Blog_Model_Resource_Post extends Mage_Eav_Model_Entity_Abstract and this is how Magento handle EAV in resource model. To make this work with Entity tables we need to set options and default attributes, so to set options we’ll add this code:

public function __construct()
{
$resource = Mage::getSingleton(‘core/resource’);
$this->setType(‘inchoo_blog_post’);
$this->setConnection(
$resource->getConnection(‘blog_read’),
$resource->getConnection(‘blog_write’)
);
}
As you can see, we need to set resource and connection. For connection read and write we need to add in our module config file nodes where we define read and write connections:

core_write

core_read

$this->setType (‘inchoo_blog_post’) in our Post resource model init defines what entity type resource should be used. We’ll define this later in our module install script. Also in resource model we need to specify default attributes in _getDefaultAttributes() method:

protected function _getDefaultAttributes()
{
return array(
‘entity_type_id’,
‘attribute_set_id’,
‘created_at’,
‘updated_at’,
‘increment_id’,
‘store_id’,
‘website_id’
);
}
These are default attributes that will be loaded, but we’ll get back on them later. They’re not required to set because Mage_Eav_Model_Entity_Abstract already set them. You can do it only if you want to change default attributes.

After creating our resource model we need to create collection class, and we need to create it in app/code/local/Inchoo/Blog/Model/Resource/Post folder with file called Collection.php and that class has to extend EAV collection class abstract:

class Inchoo_Blog_Model_Resource_Post_Collection extends Mage_Eav_Model_Entity_Collection_Abstract
{

protected function _construct()
{
$this->_init(‘inchoo_blog/post’);
}

}
We have extended our collection class Inchoo_Blog_Model_Resource_Post_Collection with Mage_Eav_Model_Entity_Collection_Abstract and this gives us options for our resource model to work with EAV tables. As you can see, you need to set resource model like on any other collection ($this->_init(‘inchoo_blog/post’)).

After setting our model, resource model and collection we have created all functionalities that make this work with EAV. But, one more important step is required to make this actually work – create entity tables and add entity type. We’ll do this with our install script, first we need to set this in our config file:

Inchoo_Blog
Inchoo_Blog_Model_Resource_Setup

core_setup

Now we need to create two things, as you can see in configuration, we need Inchoo_Blog_Model_Resource_Setup class for our setup and setup file for version 1.0.0.0 like our version of module is. Setup class is needed for specifying what attributes model can save in entity tables, and we’ll use this class in our setup script. Let’s create our setup class in app/code/local/Inchoo/Blog/Model/Resource/:

array(
‘entity_model’ => ‘inchoo_blog/post’,
‘attribute_model’ => ”,
‘table’ => ‘inchoo_blog/post_entity’,
‘attributes’ => array(
‘title’ => array(
‘type’ => ‘varchar’,
‘backend’ => ”,
‘frontend’ => ”,
‘label’ => ‘Title’,
‘input’ => ‘text’,
‘class’ => ”,
‘source’ => ”,
‘global’ => 0,
‘visible’ => true,
‘required’ => true,
‘user_defined’ => true,
‘default’ => ”,
‘searchable’ => false,
‘filterable’ => false,
‘comparable’ => false,
‘visible_on_front’ => true,
‘unique’ => false,
),
‘author’ => array(
‘type’ => ‘varchar’,
‘backend’ => ”,
‘frontend’ => ”,
‘label’ => ‘Author’,
‘input’ => ‘text’,
‘class’ => ”,
‘source’ => ”,
‘global’ => 0,
‘visible’ => true,
‘required’ => true,
‘user_defined’ => true,
‘default’ => ”,
‘searchable’ => false,
‘filterable’ => false,
‘comparable’ => false,
‘visible_on_front’ => false,
‘unique’ => false,
),
),
)
);
return $entities;
}
}
You can see that our setup class extends Mage_Eav_Model_Entity_Setup and we’ve defined our entities and attributes. For entity is used inchoo_blog_post and that’s our entity type. This needs to be declared in our setup script and we’ve set it also in our post resource model. This is important step because we must set our attributes for entity model so our resource model can save them in entity tables.

For example, if our blog should have an author, we need to specify author attribute in getDefaultEntities method under our inchoo_blog_post entity attributes. If you don’t set attribute and use save on post model, Magento won’t know where to save data and your attribute won’t be saved. Good thing with attributes is that they’re only saved in tables, if you set them, but if you don’t set (for example author) on post and save, it will not save this attribute. This approach saves db space in comparison with flat table, as we know, flat table will have all attributes as columns and that columns have NULL value. And that is the biggest advantage of using EAV, especially if you have a lot attributes which are in most cases set for some blog posts.

One more important advantage in using EAV is to have attributes that will work for different languages(stores), you can see example of this in category/product EAV. When comparing flat table vs EAV, EAV advantages are that flat for some attributes can have mostly NULL values, and if you use EAV all attributes that have not been set won’t be saved anywhere – they will be saved only if you set them.

Lastly, for our post model to work, we need to make setup script for creating tables and to add entity type with attributes. If you check setup for catalog/product or customer, you can see that every table for EAV is created separately by installer. This approach is good if you want some additional columns in main entity table, if you don’t need that than create EntityTables, this method is best to use because it will automatically create all EAV tables (note that in 1.6 and 1.7 users reported bugs with this functionality). For our EAV to work we need main entity table (_entity at end of table name) and 6 additional tables for every data type to be saved. For example, every time you create a new blog post a new entity will be added to main entity table, and attributes to entity specific type tables (for example varchar type attribute to table that ends with _entity_varchar) if you’ve set attribute. Every attribute is new entry in specific attribute type table, so if you have set 5 attributes there will be 5 entries times stores(if you have 3 stores, it will be 15 entries – 5 attributes x 3 stores) in entity tables.

Comments are closed.