The problems faced by a common model interface in frameworks

December 17, 2008 – 8:31 pm Tags:

You sometimes see people asking why the Zend Framework (or some others) don’t provide a library for the Model part in MVC.

While ZF provides data access classes in the form of Zend_Db and related components, it doesn’t provide any concrete examples of how you would implement a model class. This often confuses especially beginners.

Providing a common base model, or an interface for implementing models, does have certain benefits, but it also has some problems…

Definition

Let’s first define what I’m talking about. By “common model interface”, I’m refering to a predefined set of methods any model class needs to implement, or some defined behavior it needs to have. This could include things such as models must provide getFoo and setFoo methods for accessing their properties, they must provide findByFoo for finding instances etc. – or that it can implement the getters and setters using __set and __get magic methods.

Benefits of a common model interface

Framework components would benefit from this, as components such as the proposed Zend_Form_Model would be able to simply conform to the model interface, rather than having to require adapters that wrap the models into an interface the main class understands.

Another benefit would be to programmers using the framework, as there would be less complexity towards them in implementing models. They would have a defined best practice type of approach to work with, or they could use a bundled model library, or some library which supports the interface. When implementing models, they would have a defined behavior their models would need to conform to, which would make it a little less flexible, but it would benefit them by easily providing them with persistence or other features like the modelforms.

Basically, it would make a convention, similar to how controllers and actions are set up, that could streamline development if it was implemented well enough.

Problems of a model interface

The problems are mostly related to implementation. For one, it would make it essentially impossible to utilize any of the model-related functionality if your models don’t conform to the interface, which could be a problem for example when working with code written with another framework in mind.

At that point, you would either have to modify the interface of all the models, or create a wrapper object which can wrap any old-style model, and an adapter or other, that can take a model and wrap it with the wrapper model.

Another implementation issue would be how to make the interface flexible enough, yet easy to implement. For example, basic getters and setters would be relatively simple, but the models would need much more to be able to be used by a generic data persistence layer or other more complex component. If you take a look at the CU_Form_Model_Adapter_Interface, you can see there’s a lot of things the adapter needs to do, in order for the modelform to function.

Conclusion

I think we can safely say that this is a very problematic thing. While it may seem like a simple concept, in practice implementing it so, that it won’t restrict developers too much, or require them to write a lot of extra code, is very tricky.

I don’t think there is an easy way to solve this. An adapter based approach is probably quite sufficient – the adapter allows you to use any model types you like, as long as you write an adapter that can perform the required functionality – actually it doesn’t even have to be able to do everything, for example your adapter could lack the functionality for relations, and instead always return empty arrays for them.

More on models:
Using models as criteria objects for querying the database
Decoupling models from the database: Data Access Object pattern in PHP

Share this:

RSS feed Subscribe to my RSS feed

About the author

Jani is a 15 year veteran of the software industry. He's currently available for consulting

  1. 14 Responses to “The problems faced by a common model interface in frameworks”

  2. It is possible to have a model implementation while retaining the flexibility of the current base classes.
    That way if you need basic CRUD functionality you extend ‘Zend_Db_Model?’ and if you need extensive functionality you extend Zend_Db.
    We currently do something along those lines.

    By Ekerete on Dec 18, 2008

  3. You would basically need to write your models twice if you were using something like that and say Doctrine_Record. First, Doctrine builds models, then you wrap Doctrine models into your interface.

    I suppose you could automate it with a build tool, but you could do the same with some pluggable adapter thing without a generator

    By Jani Hartikainen on Dec 18, 2008

  4. Hi

    Are you aware that model is NOT an orm?
    Model should be independent of any persistence layer, no matter is that database, webservice or Morse code :)
    So, why I see methods like getTable() or getRelationPkValue() in your sample implementation?

    Models have only behaviors that represent domain logic of your app. Nothing more, nothing less.
    Building application that way, makes future improvements (e.g. changing underlaying Propel to Doctrine) easier and faster than rewriting ORMish code inside controllers.

    In my opinion at the beginning model should be just plain PHP object with few framework tie-ins. Thats all :)

    Cheers, Alan

    By Alan on Dec 18, 2008

  5. That’s mostly a naming issue ;)

    Even if the model was outside a DB, it could have relations and the relations would quite likely need an ID (ie getRelationPkValue). Same goes for the table.. That could be the model’s name.

    If you look at the unit tests, I’m using plain PHP arrays with a mock adapter to represent data there. =)

    By Jani Hartikainen on Dec 18, 2008

  6. Well, not really :)

    If you really design your models as domain objects then you don’t need that. Everything magically appears as meaningful methods ie getCommentsRelatedToArticle($article) or deleteArticlesOfUser($user) on Blog model.

    Create methods when needed or when spec anticipates that.

    Cheers, Alan

    By Alan on Dec 18, 2008

  7. That’s one of the issues I’m refering to in the post. You can have methods like that, but how would you put them together in a sensible interface that could be adapted for usage in something like the modelform.

    The adapter attempts to tackle the problem, and I’d say it does a good job. You could insert logic into a custom adapter for determining the method name for your own naming system etc.

    By Jani Hartikainen on Dec 18, 2008

  8. Yeah, I understand that. The problem is that model doesn’t reveal its underlying structure like datatypes. It can’t :)

    This is charm of ORMs – form and validation generation is quick and simple. Sometimes it is matter of reasonable choice, to decide to throw away model and work directly on AR || ORM || TDG classes.

    Still, sticking to model has great benefits which will show up during maintaining or updating app.

    Cheers, Alan

    By Alan on Dec 18, 2008

  9. Yep, both approaches have their pros and cons.

    With non-orm style models, you could use reflection to determine field names based on setters and types on the setter parameters etc., and determine validation by attempting to set the data from the fields in the model and checking what errors you get and such, but it would be more tricky.

    By Jani Hartikainen on Dec 18, 2008

  10. Thanks for the post, interesting read. I’ve read a couple of articles now leaning towards the model being a purely business logic component and therefore not tied to the framework. My understanding is that in the Java world you have POJOs for the model objects and your DAOs use these POJOs (accepts them as parameters or returns them) and they use an ORM layer such as Hibernate to interact with the underlying data store.

    How would you implement the equivalent in the PHP world? Should we be coding POPOs (pure old PHP objects) as the model objects, ‘business logic’ objects (like managers) to implement business logic functionality and DAOs that use some sort of ORM layer (Propel, Doctrine, Zend_DB or whatever)? Then if you wanted to change your ORM you only need to change your DAOs? Or is this defeating the whole purpose of using PHP in the first place that you can get things done much faster and simpler?

    By Ziad on Dec 19, 2008

  11. Well, if your application requires such complex architechture, you can do it in a model -> dao -> doctrine/pdo/whatever -> db style. Of course, not all applications require a complex approach like that – you could just have the model itself act as the dao layer, as is the case if you use something like Doctrine models as your model.

    It all depends on your requirements.

    By Jani Hartikainen on Dec 19, 2008

  12. @Ziad: Jani is right – it depends.

    My experience tells me that the best approach is to use POPOs as containers encapsulating underlying persistence library (PDO, Doctrine, Zend_Service). Then you can “craft” your models as you see their responsibilities (logic).
    It’s heavily decoupled which is great in case of M in MVC :)

    Cheers

    By Alan on Dec 19, 2008

  13. The “problem” of a common model interface is something I solved over 10 years ago. I use the one-model-class-per-database-table approach where each concrete class inherits a huge amount of code from an abstract table class.

    Each Model class deals with the data validation, business rules and task-specific behaviour for each database table whereas all the SQL queries are constructed and executed in a separate Data Access Object (DAO).

    This is discussed in more detail in http://www.tonymarston.net/php-mysql/table-oriented-programming.html

    By Tony Marston on Sep 3, 2013

  1. 2 Trackback(s)

  2. Jan 22, 2009: Another idea for using models with forms | CodeUtopia
  3. Mar 15, 2009: Decoupling models from the database: Data Access Object pattern in PHP | CodeUtopia

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)