How to use Magento models

Last time I wrote an article about using Magento helpers. Some of you liked it so I thought it would make sense to write another one, this time about models. The aim is to put some general overview of Magento models and a few thoughts on how to use them.

MVC

As we all know, Magento uses MVC architectural pattern that consists of model, view and controller layers. The model layer in general is considered a part of the application that should contain business logic.

Different frameworks approach models differently. As we can see over the years, php frameworks have evolved and service oriented architecture has become popular in PHP community. Modern frameworks use models only for maintaining state. In that case services are being used for altering model states which provides even higher level of decoupling.

Magento

Magento has more traditional approach.The model layer in is separated into 3 parts.

  • Entity models

  • Resource models with collections

  • Zend_Db

Entity models

Entity models (as I like to call them) usually inherit from Mage_Core_Model_Abstract which gives them some basic functionality. An instance of class that inherits from Mage_Core_Model_Abstract represents one unit of some entity that can be loaded, changed and saved. These models can be easily instantiated everywhere by their unique id which corresponds to their unique identifier in database:

Mage::getModel('catalog/product')->load(1);

Or with

Mage::getSingleton('catalog/product')->load(1);

Which stores instance in registry so the exact same object would be used throughout the application.

Resource models

Resource models are classes that are used for data management. When methods like load or save are called on entity models, resource models are called as they contain the logic which is used to actually read to and write data from database. In module configurations these classes usually have a table where they keep data:

<dusan_example>
    <class>Dusan_Example_Model</class>
    <resourceModel>dusan_example_resource</resourceModel>
</dusan_example>
<dusan_example_resource>
    <class>Dusan_Example_Model_Resource</class>
    <entities>
        <example>
            <table>dusan_example</table>
        </example>
    </entities>
</dusan_example_resource>

Core Magento gives us Flat and EAV resource models that have different data organization principles. Flat resource models keep data in a traditional way, where EAV models use EAV principle for managing data.

Collections are also part of resource models as they provide means to work with multiple objects. Collection is an object with multiple instances of entity model classes in it.

Zend_Db

In Magento case we can say that Zend_Db module is used as a helper class which provides query building functionality. It provides a consistent way of creating SQL queries for data retrieval and persistence. No parts of Zend_Db that implement Table Data Gateway pattern functionality (like Zend_Db_Table) are used.

Approach

What’s useful is that with this approach (in theory) one would need to change only resource classes (and install scripts) in order to adapt Magento to some other database.

There are some negative aspects. The fact that Magento models can be easily instantiated anywhere creates hidden dependencies inside models. Consider this code:

class Mage_Catalog_Model_Product extends Mage_Catalog_Model_Abstract
{
    public function getCategory()
    {
        $category = $this->getData(‘category’);
        if (is_null($category) && $this->getCategoryId()) {
            $category = Mage::getModel(‘catalog/category’)->load($this->getCategoryId());
            $this->setCategory($category);
        }
        return $category;
    }
}

It is not transparent that Mage_Catalog_Model_Product depends on Mage_Catalog_Model_Category, therefore somebody would have to analyze the entire module to find out class dependencies. I think this harms Magento modularity and makes it less decoupled.

Class dependencies should be transparent and easy to recognize so principles like loose coupling could be applied. Another great thing this approach provides is easiness to test class methods in unit tests by replacing real objects with mock objects in order to provide isolation.

Hopefully Magento2 will fix this by introducing dependency injection.

No queries in entity models

If you are building a database query or even worse using raw sql in your entity model you are doing something wrong. In Magento, entity model classes (classes that inherit from Mage_Core_Model_Abstract) should not contain anything database related because they are on higher level of abstraction.

One way to look at it is to ask yourself if the functionality would work after replacing your model’s resource model with a different one which uses a different database for example.

Not every model should extend Mage_Core_Model_Abstract

If a model is not meant to represent an entity that can be loaded, made changes on and saved, there is no need for it to extend Mage_Core_Model_Abstract. Good examples of this situation are Observer and Cron classes which do not extend anything in Magento Core.

You don’t have to follow the default model structure strictly, you should adjust it your needs.

Don’t do too much in one class

One misconception is that all of your logic should be in one model class. The M in MVC is more of a layer than some exact class. The rule that each class should have only one problem domain applies here as well.

If you notice that your model is doing a lot, try to separate the functionality into more than one class. I like to quote a simple rule mentioned by Ruby on Rails creator David Heinemeier Hansson in his talk where he says: if your class has more than 13 methods or if a folder contains more than 13 files, you should consider refactoring. I think it helps keeping stuff organized so the same rule can be applied here.

Performance

Always have performance in mind. Model is a part of the application that can dramatically impact performance. Making as few queries as possible and not loading models in a loop are things to keep an eye on.

Don’t use models in templates

You should never use models in your templates because this creates unmaintainable code and violates the whole idea of separating concerns. Whenever you have a need to use model in your template put that method call in a Block and then place the Block method in template.

 
 
 
 

Saying everything about models usage would require more than one article. These are only some basic recommendations.

Think I missed something? Post it as a comment please.

Would you like to recommend this article to your friends or colleagues?
Feel free to share.

facebooktwittergoogle_plusredditlinkedin
This article was posted in category Magento.

Leave a Reply

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

*

*

*