Home » Magento tutorial for developer » Magento tutorial for developer – Part 7 – Advanced ORM – Entity Attribute Value

Magento tutorial for developer – Part 7 – Advanced ORM – Entity Attribute Value

In the first ORM article we told you there were two kinds of Models in Magento. Regular, or “simple” Models, and Entity Attribute Value (or EAV) Models. We also told you this was a bit of a fib. Here’s where we come clean with Magento tutorial for developer – Part 7 – Advanced ORM – Entity Attribute Value

ALL Magento Models interacting with the database inherit from theMage_Core_Model_Abstract / Varien_Object chain. What makes something either a simple Model or an EAV Model is its Model Resource. While all resources extend the base Mage_Core_Model_Resource_Abstract class, simple Models have a resource that inherits from Mage_Core_Model_Resource_Db_Abstract, and EAV Models have a resource that inherits from Mage_Eav_Model_Entity_Abstract

If you think about it, this makes sense. As the end-programmer-user of the system you want a set of methods you can use to talk to and manipulate your Models. You don’t care what the back-end storage looks like, you just want to get properties and invoke methods that trigger business rules.

What is EAV

Wikipedia defines EAV as

Entity-Attribute-Value model (EAV), also known as object-attribute-value model and open schema is a data model that is used in circumstances where the number of attributes (properties, parameters) that can be used to describe a thing (an “entity” or “object”) is potentially very vast, but the number that will actually apply to a given entity is relatively modest. In mathematics, this model is known as a sparse matrix.

Another metaphor that helps me wrap my head around it is “EAV brings some aspects of normalization to the database table schema“. In a traditional database, tables have a fixed number of columns

Every product has a name, every product has a price, etc.

In an EAV Model, each “entity” (product) being modeled has a different set of attributes. EAV makes a lot of sense for a generic eCommerce solution. A store that sells laptops (which have a CPU speed, color, ram amount, etc) is going to have a different set of needs than a store that sells yarn (yarn has a color, but no CPU speed, etc.). Even within our hypothetical yarn store, some products will have length (balls of yarn), and others will have diameter (knitting needles).

There aren’t many open source or commercial databases that use EAV by default. There are none that are available on a wide variety of web hosting platforms. Because of that, the Magento engineers have built an EAV system out of PHP objects that use MySQL as a data-store. In other words, they’ve built an EAV database system on top of a traditional relational database.

In practice this means any Model that uses an EAV resource has its attributes spread out over a number of MySQL tables.

The above diagram is a rough layout of the database tables Magento consults when it looks up an EAV record for the catalog_product entity. Each individual product has a row in catalog_product_entity. All the available attributes in the entire system (not just for products) are stored in eav_attribute, and the actual attribute values are stored in tables with names like catalog_product_entity_varchar,catalog_product_entity_decimalcatalog_product_entity_etc..

Beyond the mental flexibility an EAV system gives you, there’s also the practical benefit of avoiding ALTER TABLE statements. When you add a new attribute for your products, a new row is inserted into eav_attribute. In a traditional relational database/single-table system, you’d need to ALTER the actual database structure, which can be a time consuming/risky proposition for tables with large data-sets.

The downside is there’s no one single simple SQL query you can use to get at all your product data. Several single SQL queries or one large join need to be made.

Implementing EAV

That’s EAV in a nutshell. The rest of this articles is a run-through of what’s needed to create a new EAV Model in Magento. It’s the hairiest thing you’ll read about Magento and it’s something that 95% of people working with the system will never need to do. However, understanding what it takes to build an EAV Model Resource will help you understand what’s going on with the EAV Resources that Magento uses.

Because the EAV information is so dense, we’re going to assume you’ve studied up and are already very familiar with Magento’s MVC and grouped class name features. We’ll help you along the way, but training wheels are off.

Weblog, EAV Style

We’re going to create another Model for a weblog post, but this time using an EAV Resource. To start with, setup and create a new module which responds at the the following URL

If you’re unsure how to do this, be sure you’ve mastered the concepts in the previous tutorials.

Next, we’ll create a new Model named Weblogeav. Remember, it’s the Resource that’s considered EAV. We design and configure our Model the exact same way, so let’s configure a Model similar to one we created in the first ORM article.

Again, so far this is setup similar to our regular Model Resource. We provide a <class/> that configures a PHP class, as well as an <entities/> section that will let Magento know the base table for an individual Model we want to create. The <eavblogpost/> tag is the name of the specific Model we want to create, and its inner<table/> tag specifies the base table this Model will use (more on this later).

Again, so far this is setup similar to our regular Model Resource. We provide a <class/> that configures a PHP class, as well as an <entities/> section that will let Magento know the base table for an individual Model we want to create. The <eavblogpost/> tag is the name of the specific Model we want to create, and its inner<table/> tag specifies the base table this Model will use (more on this later).

Where Does That File Go?

Until wide adoption of PHP 5.3 and namespaces, one of the trickier (and tedious) parts of Magento will remain remembering how <classname/>s relate to file paths, and then ensuring you create the correctly named directory structure and class files. After configuring any <classname/>s or URIs, you may find it useful to attempt to instantiate an instance of the class in a controller without first creating the class files. This way PHP will throw an exception telling me it can’t find a file, along with the file location. Give the following a try in your Index Controller.

As predicted, a warning should be thrown

In addition to telling us the path where we’ll need to define the new resource class this also serves as a configuration check. If we’d been warned with the following

we’d know our Model was misconfigured, as Magento was looking for the Model in code/core/Mage instead ofcode/local/Magentotutorial.

So, lets create our Model class

File: app/code/local/Magentotutorial/Complexworld/Model/Eavblogpost.php:

Remember, the Model itself is resource independent. A regular Model and an EAV Model both extend from the same class. It’s the resource that makes them different.

Clear your Magento cache, reload your page, and you should see a new warning.

As expected, we need to create a class for our Model’s resource. Let’s do it!

File: app/code/local/Magentotutorial/Complexworld/Model/Resource/Eavblogpost.php:

So, already we’re seeing a few differences between a simple Model Resource and an EAV Model Resource. First off, we’re extending the Mage_Eav_Model_Entity_Abstract class. WhileMage_Eav_Model_Entity_Abstract uses the same _construct concept as a regular Model Resource, there’s no _init method. Instead, we need to handle the init ourselves. This means telling the resource what connection-resources it should use, and passing a unique identifier into the setType method of our object.

Another difference in Mage_Eav_Model_Entity_Abstract is _construct is not an abstract method, primarily for reasons of backwards compatibility with older versions of the system.

So, with that, let’s clear the Magento cache and reload the page. You should see a new exception which reads

Magento is complaining that it can’t find a entity_type named complexworld_eavblogpost. This is the value you set above

Every entity has a type. Types will, among other things, let the EAV system know which attributes a Model uses, and allow the system to link to tables that store the values for attributes. We’ll need to let Magento know that we’re adding a new entity type. Take a look in the MySQL table named eav_entity_type.

This table contains a list of all the entity_types in the system. The unique identifiercomplexworld_eavblogpost corresponds to the entity_type_code column.

Systems and Applications

This illustrates the single most important Magento concept, one that many people struggle to learn.

Consider the computer in front of you. The OS (Mac OS X, Windows, Linux, etc.) is the software system. Your web browser (Firefox, Safari, IE, Opera) is the application. Magento is a system first, and an application second. You build eCommerce applications using the Magneto system. What gets confusing is, there’s a lot of places in Magento where the system code is exposed in a really raw form to the application code. The EAV system configuration living in the same database as your store’s data is an example of this.

If you’re going to get deep into Magento, you need to treat it like it’s an old Type 650 machine. That is to say, it’s the kind of thing you can’t effectively program applications in unless unless you have a deep understanding of the system itself.

Creating a Setup Resource

So, it’s theoretically possible to manually insert the rows you’ll need into the Magento database to get your Model working, but it’s not recommended. Fortunately, Magento provides a specialized Setup Resource that provides a number of helper method that will automatically create the needed records to get the system up and running.

So, for starters, configure the Setup Resource like you would any other.

Next, create its class file.

File: app/code/local/Magentotutorial/Complexworld/Model/Resource/Setup.php:

Take note that we’re extending from Mage_Eav_Model_Entity_Setup rather thanMage_Core_Model_Resource_Setup.

Finally, we’ll set up our installer script. If you’re not familiar with the naming conventions here, you’ll want to review the setup resource tutorial on Setup Resources.

File: app/code/local/Magentotutorial/Complexworld/sql/complexworld_setup/install-0.1.0.php:

Clear your Magento Cache, reload you page, and the above exception should be thrown, meaning you’ve correctly configured your Setup Resource.

NOTE: We’ll be building up our install script piece by piece. If you’ve read the previous tutorial, you’ll know you need to remove the setup’s row from the core_resource table and clear your cache to make an installer script re-run. For the remainder of this tutorial, please remember that anytime we add or remove an item from our installer and re-run it, you’ll need to remove this row from the database and clear your Magento cache. Normally you would create this file and run it once, a tutorial is something of an edge case.

Adding the Entity Type

To begin, add the following to your Setup Resource installer script, and then run the script by loading any page (after removing the above exception)

We’re calling the addEntityType method on our installer object. This method allows us to pass in the entity type (complexworld_eavblogpost) along with a list of parameters to set its default values. If you’ve run this script, you’ll notice new rows in the eav_attribute_groupeav_attribute_set, and eav_entity_type tables.

So, with that in place, if we reload our complexworld page, we’ll get a new error.

Creating the Data Tables

So, we’ve told Magento about our new entity type. Next, we need to add the MySQL tables that will be used to store all the entity values, as well as configure the system so it knows about these tables.

Our EAV Setup Resource has a method named createEntityTables which will automatically setup the tables we need, as well as add some configuration rows to the system. Let’s add the following line to our setup resource.

The createEntityTables method accepts two parameters. The first is the base table name, the second is a list of options. We’re using the Setup Resource’s getTable method to pull the table name from our config. If you’ve been following along, you know this should resolve to the string eavblog_posts. We’ve omitted the second parameter which is an array of options you’ll only need to used it for advanced situations that are beyond the scope of this tutorial.

After running the above script, you should have the following new tables in your database

You’ll also have an additional row in the eav_attribute_set table

So, let’s go back to our page and reload.

Success! You should see no errors or warnings, and and a dumpedMagentotutorial_Complexworld_Model_Eavblogpost — with no data.

Adding Attributes

The last step we need to take in our Setup Resource is telling Magento what attributes we want our EAV Model to have. This would be equivalent to adding new columns in a single database table setup. Again, the Setup Resource will help us. The method we’re interested in is addAttribute.

The code from the previous section was simply telling Magento about a type of entity that we add to the system. These next bits of code are what will actually add possible attributes for our new type to the system.

We do that with the method addAttribute. When we call addAttribute, Magento will need to do several things to install your entities.

To start with, we’ll give our Eavblogpost a single attribute named title.

All right, that’s a small pile of code. Let’s break it apart.

The first argument to addAttribute is the entity type code. It has to match the code specified when calling addEntityType. It tells Magento which entity we are adding the attribute to, in our example it is ourcomplexworld_eavblogpost entity. To see other available entities that come shipped with Magento, remember you can look into the eav_entity_type table at the entity_type_code column.

The second argument to addAttribute is the attribute code. It has to be unique within the given entity.

The third argument is where it get real interesting. This is an array of key value pairs, describing the attribute properties. For the sake of simplicity we’ve chose to define a single attribute, but you could go on to define as many as you’d like, by adding additional addAttribute calls to the setup script.

Array of Key Value Pairs that Define the Attribute

Finally, we have a long list of attribute properties.

Most of these define how Magento would build a backend form element for this attribute, and probably you’ll won’t have to deal with the,. That said, the one important property you’ll want to make note of is

This defines the type of the value that the attribute will contain. You’ll recall that we added table for each attribute type

While these do not refer to the MySQL column types, (but instead the EAV attribute types), their names (varchar, datetime, etc.) are indicative of the values they’ll hold.

All of these attribute properties are optional, if we wouldn’t have specified them, Magento would have used a default value. These default values are defined in the _prepareValues method of theMage_Eav_Model_Entity_Setup class (inherited by our setup class).

The second argument to the method calls to _getValue is the array key from our addAttribute argument array, and the third is the default value. So by default Magento would assume you are adding a varchar attribute with a text input.

Adding the other attributes

Lets add attributes for the blog post content and the post date. This is what the complete install script looks like.

So, now that we have everything in place, lets refresh things one last time to run our installer script. After callingaddAttribute, we should have

  1. A new row in eav_entity_type for the complexworld_eavblogpost entity type
  2. A new row in eav_attribute for the title attribute
  3. A new row in eav_attribute for the content attribute
  4. A new row in eav_attribute for the date attribute
  5. A new row in eav_entity_attribute

Tying it all Together

This is clearly the lamest.blogmodel.ever, but lets try adding some rows and iterating through a collection and get the heck out of here before our heads explode. Add the following two actions to your Index Controller.

Let’s populate some entries! Load up the following URL

If you take a look at your database, you should see 10 new rows in the eavblog_posts table.

as well as 10 new rows in the eavblog_posts_varchar table.

Notice that eavblog_posts_varchar is linked to eavblog_posts by the entity_id column.

Finally, let’s pull our Models back out. Load the following URL in your browser

This should give us a

So Close! We didn’t make a class for our collection object! Fortunately, doing so is just as easy as with a regular Model Resource. Add the following file with the following contents

File: Magentotutorial/Complexworld/Model/Resource/Eavblogpost/Collection.php:

This is just a standard Magento _construct method to initialize the Model. With this in place, reload the page, and we’ll see all the titles and the content outputted. But notice, the date value is missing!

Which Attributes?

Those of you with sharp eyes may have noticed something slightly different about the collection loading.

Because querying for EAV data can be SQL intensive, you’ll need to specify which attributes it is you want your Models to fetch for you. This way the system can make only the queries it needs. If you’re willing to suffer the performance consequences, you can use a wild card to grab all the attributes

Jumping Off

So, that should give you enough information to be dangerous, or at least enough information so you’re not drowning the next time you’re trying to figure out why the yellow shirts aren’t showing up in your store. There’s still plenty to learn about EAV; here’s a few topics I would have liked to cover in greater detail, and may talk about in future articles

  1. EAV Attributes: Attributes aren’t limited to datetime, decimal, int, text and varchar. You can create your own class files to model different attributes. This is what the attribute_model entity property is for.
  2. Collection Filtering: Filtering on EAV collections can get tricky, especially when you’re dealing with the above mentioned non-simple attributes. You need to use the addAttributeToFilter method on your collection before loading.
  3. The Magento EAV Hierarchy: Magento has taken their basic EAV Model and built up a hierarchy that’s very tied to store functionality, as well as including strategies to reduce the number of queries an EAV Model generates (the concept of a flat Model, for example)

EAV Models are, without a doubt, the most complicated part of the Magento system that an ecommerce web developer will need to deal with. Remember to take deep breaths and that, at the end of the day, its just programming. Everything happens for a concrete reason, you just need to figure out why.

About Alan Storm

avatar
Alan Storm is a technology strategist, software developer and writer living and working in Portland, OR. He publishes articles on his website http://alanstorm.com and is the creator of the Magento development extension Commerce Bug.

One comment

  1. avatar

    Hi Alan,
    I have done everything you have described in this tutorial. When i run showcollection action it is showing
    “Attempt to add an invalid object” error. When i check in the table it has 10 content as it is in your tutorial. Need your suggestion and answer Alan.
    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Scroll To Top