My Zend Framework Model Layer: Part Service, Part ORM

January 20th, 2010 by rvdavid Leave a reply »

The Model Layer of the MVC triad: I’ve been thinking this over for the past few months since using the Doctrine ORM and I think I’ve finally made some progress to get this issue licked. In the past, I’ve agonised over this issue and blogged about my progress. Some weeks or days later I tried to probe the community on what they would do, Now I think I’d have an idea on what I would do.

After some more thought and lots of research on the subject, I’ve come to a solid point where I actually have something to try out which seems semantic aside from the naming of the class (Service Class) – but this is derived from what some people are talking about in ZF circles starting from Matthew Weier O’Phinney who was coining it as the “Gateway to the Domain” from early on, then later changing it to “Service Class”.

The Service Class

So this is what I chose to go with:  For each model class, I’ve got a Database Agnostic Service class - in fact, it uses the Entities Produced by Doctrine ORM to talk to the database, but isn’t entirely reliant upon Doctrine to Provide the Model Layer on it’s own. Using Doctrine as your Model Layer alone I suppose is better than extending Zend_Db which is highly discouraged by everyone, but you still have the database dependency.

I thought well, I’ve done a lot of feeling around the subject, maybe I’ll just ask around. So over to twitter I go. I sent Matthew Weier O’Phinney a tweet asking if it is right that Doctrine models are relatively empty whilst Model services are filled with business logic and he answered: “Absolutely. Plain old PHP is perfect for entities.” but I had no idea WTF that meant.

The Service Layer uses the Model which is the Entity. My further attempt to clarify the situation and continue discussion didn’t get a response – maybe because I had to condense words and use accronymns to fit the message in or he had just become too busy. So on my own I go again.

After mulling over it a few, I thought I’d just run with what I’ve got. It seems to be semantic, but it has a lot of responsibilities:

  • The Model Service Class is a Resource.
  • The Model Service uses the ACL layer to check if a Role Identified has the Privileges to make it’s request prior to usage.
  • The Model Service creates Entities by using its Model Factory/Finder methods such as FindById it then returns either an array or an Entity based on what Hydration mode was specified (default is array).
  • The Model Service creates Forms and uses it for Validation
  • The Model Service provides the CRUD methods so that the Controller does not have to worry about instantiating and configuring models to Create Update or Delete data.
  • The Model Service uses Zend_Cache and can use caching on non-changing data such as lookup lists status or types and large collections of data used in drop downs, lists or datagrids.
  • Although there is no factory for it, the Model Service can create and use other Model Service classes.
  • The Service Layer is not passed to the View either. The View is configured by the Controller and has data shoved into properties/member variables.
  • The Service Object can be passed to the View if required, so that the View can use the Sevice object to interrogate models on it’s own. We trust that those writing the View Markup will only be using the service object _strictly for reading only_.

I’ve been working with this setup for a few weeks now. This method is very testable and makes for an extremely thin Controller Layer.

What do you guys think?

Have we over engineered this thing? Should it be called the Service Layer as more and more people are coining it as? What suggestions can you make to make this better?

if you enjoyed this post, make sure you subscribe to my RSS feed!
You can also follow me on Twitter here.

Related posts:

  1. Zend Framework Model – Research into Possible Domain Model Solutions
  2. How would you handle this? – Service Layer slowly getting polluted (or so it seems)!
  3. Started Draft Post on Zend Framework, Doctrine & PHPUnit Setup
  4. Test Results on Memory Usage of Zend Framework and Doctrine with APC
  5. Our New PHP 5 Framework Cubix developed to 2.1
Advertisement

38 comments

  1. I quite agree with your service layer modelisation. To make this better I suggest to use an Inversion of Control container for Dependency Injection management. I recently developed tools to facilitate Dependency Injection for your services within Zend Framework applications with Symfony Dependency Injection container.

    I’m gonna blog about it soon but you can already check my work on my Bitbucket : http://bit.ly/4IeGIj.

    Do not hesitate to provide feedbacks :)

    • rvdavid says:

      I’ve not had to play with DI just yet, but have always been interested. Had a browse through your bitbucket – and will have a closer look later. I’ll keep an eye on your blog and provide feedback / ask questions when you blog about this subject.

      Cheers.

  2. Luke Barton says:

    Sounds sane. Would love to see some code though :)

  3. Peter Smit says:

    Is your code (or some example) available online? It would be easier in that way to evaluate and learn from it!

    • rvdavid says:

      Hi Luke and Peter,

      Unfortunately, the version that I have is very rudimentary at this point in time and will not serve as a good example and may end up confusing you – as I feel I am a little confused myself for instance, I’ve just added a Service Registry as part of the constructor and made a method called “getService()” which uses the Registry to create and return a Service.

      Once I perfect this and other little bits I’m not entirely happy with, I’ll be posting the code and make it available from either github or some other repository as part of my “Zend Framework, Doctrine and PHPUnit set up” post – so keep an eye out for it.

  4. Bill Karwin says:

    In DDD parlance, I thought the term Service Layer is used for the Controller. The Model is called the Application Layer.

    You kind of touch on this, but I think another prime responsibility of a Model is to abstract the physical design of the database. A logical entity often maps to multiple db tables. Don’t assume “complex” means “rare.” :-)

    Managing full CRUD lifecycle for complex objects is tricky, and the code to do that is better encapsulated in the Model. Whereas the Controller or View should be ignorant of the physical database design.

    If the Model provides an interface for the types of high-level operations one would need given the specific domain (as opposed to generic CRUD functions), then the Controller and View have an easier time using the Model without screwing anything up.

    This means the Model could be thought of as a Facade pattern, providing a simplified interface to a collection of other objects.

    PS: I worked on Zend_Db up to ZF 1.0. In the documentation, I deliberately did not mention the term “Model” once. Because a Table is not a Model.

    • rvdavid says:

      > In DDD parlance, I thought the term
      > Service Layer is used for the Controller.
      > The Model is called the Application Layer.

      What do you think about term “Model Service” layer? This at least implies that it’s part of the Model… Not sure really, which is why I asked the question.

      > You kind of touch on this, but I think
      > another prime responsibility of a Model is
      > to abstract the physical design of the
      > database. A logical entity often maps to
      > multiple db tables. Don’t assume “complex” means “rare.”

      > Managing full CRUD lifecycle for complex
      > objects is tricky, and the code to do that is > better encapsulated in the Model. Whereas
      > the Controller or View should be ignorant of
      > the physical database design.

      Absolutely. The Model Service Layer abstracts complex logic as well as data source and provides a simple interface to it’s users (Controllers, Other Model Service Classes, Views)…

      > If the Model provides an interface for the
      > types of high-level operations one would
      > need given the specific domain (as
      > opposed to generic CRUD functions), then
      > the Controller and View have an easier
      > time using the Model without screwing
      > anything up.

      >This means the Model could be thought of > as a Facade pattern, providing a simplified
      > interface to a collection of other objects.

      Again, I agree with this. Thank you for confirming it. With the exception of factory methods, I see The Model Service Layer methods map directly to business requirements.

      When I talk about “CRUD methods” in my post above, I should have been more specific. I’m not at all talking about generic crud methods, but methods which create, update or delete as they are required.

      For instance, I have a UserStatus Model Service that I use to fetch the records to be used as options in a filteringSelect.

      So I have one method named: “fetchAllStatusAsKeyValue()” in this service class.

      I name it in a way that it maps to directly business requirements and describes what it does. Rather than a generic listStatus() which we used to do.

      This Model Service class is used by the SystemUserModel Service class to populate the status_id filteringSelect within getUserForm().

      > PS: I worked on Zend_Db up to ZF 1.0. In
      > the documentation, I deliberately did not
      > mention the term “Model” once. Because a
      > Table is not a Model.

      This may have been the case and it may have been an obvious thing to you and others with a higher level of understanding of model layer architecture, but due to the absence of the Model Layer and any documentation on the matter at the time aside from something along the lines of “you devs need to take care of the model yourselves”, everyone was blindly walking around and misleading each other with “the model extends Zend_Db_Table_Abstract” – I was one of the lost sheep for a while. Even bought a book by Rob Allen that tells us to extend Zend_Db to build the model layer.

      So I thought this was the right way for a while. :) – but it most certainly isn’t.

  5. DarkSmith says:

    Hey ! Nice to see some article about this important subject :)
    We are doing exactly the same thing for our service layer and using it in production , it works really good !

    As Loic said, you can add a DI container to retrieve your services. On our side we are using a ServiceLocator like in Java or Flex.

    If you continue this series of article i’ll be happy to give you some advice !

    Bye

  6. David Penner says:

    @Luke: Definitely check out the link to Matthew’s article above (http://weierophinney.net/matthew/archives/202-Model-Infrastructure.html) as well as the others in that series if you want to look at some code that implements a good chunk of the ideas. I read that a year ago and it changed my whole outlook on the M in MVC.

    Great article! I think the bullet points in the article are great. The ACL integration is key especially to keep controllers nice and slim. Also think about how much harder it would be to implement, e.g., an API (via perhaps JSON-RPC) if all the ACL code is tucked away in a front controller plugin or (even worse) in your controller.

    The only issue I might take is with:

    “The Service Layer is not passed to the View either. The View is configured by the Controller and has data shoved into properties/member variables.”

    I realize this is somewhat controversial in the whole MVC idea: whether or not views should have access to the model (if I understand what you are saying correctly), but it seems to me to be a bit limiting if the view is not allowed direct access to the model.

    For example implementing all sorts of view helpers so that generating tables, lists, or any other sorts of common interface components that require input from the model becomes rather fragile if it requires a controller having set a view variable. To my thinking it’s just better to let the view get whatever it needs.

    Generally how I do this is to implement a view helper that takes a single string argument that is the name of a particular service layer object (the instance is cached so subsequent calls return the same instance to preserve state between views).

    Overall though I am in complete agreement. Thanks for the article.

  7. paul says:

    Personally I like to use a Repository class to encapsulate access to my data store. The repository is inside my model layer. The repository provides commands that other object can query against. The commands return either an instance or a collection of entities. Most of the time the command methods are just a facade for the queries that are made against a Zend Db Table class.

    The benefit of this is that the code that interacts has no idea that there is even a persistence layer.

    Currently I have my controller talking to the Repository, although I have recently changing things up by having the Service Layer talking directly to it, to keep my controller thin.

    Anyone else using a Repository in their PHP projects?

    • rvdavid says:

      I’ve heard of repository, but never really dug in too deep to use it.

      Your Repository seems similar to the Model Service concept described here.

      My Controller layer is pretty thin due to a well defined interface in the Model Service layer which maps to requirements.

      • Federico says:

        Hi David,

        The Repository is a type of Service, but has nothing to do with the Service Layer. Repositories are part of the Domain Layer. The Repository provides a higher level of data manipulation, acts as a link between the Domain and Persistence Layers (Entity DAO). The Repository pattern is a very common pattern, and most ORMs use it.

        Service classes are not part of the Domain or Persistence Layers and therefore do not provide methods to access data, such as dynamic finders. Dynamic finders are usually found in the Repository.

        Some people get confused when they use an ORM for the first time, because they think that ORM is a pattern, and it’s not. Mapping relationships is just a technique that uses different patterns to solve the problem of converting data between incompatible systems, e.g. DataMapper, DAO, Factory, Repository, Service Locator, etc.

    • Federico says:

      Hi Paul, I’m using the Repository pattern as well:

      app/controllers
      app/daos
      app/domain
      app/persistence
      app/repositories
      app/services
      app/views

      I really like GORM, and even though they got rid of the Repositories and DAOs, it allows you to build complex domains using a DDD approach.

      I haven’t got that far yet, I’m still using these two patterns:

      http://fedecarg.codepad.org/9iWX4l7e

  8. Excellent post quite informative post i have learn more than enough from this post thanks for sharing.

  9. rvdavid says:

    Great feedback guys. Look I just got back to work and will be respoding to your comments later in the day. :)

  10. Tomas says:

    Hi,

    another great post of yours! :)

    I agree with all the points, but this one:
    *) The Model Service creates Forms and uses it for Validation

    In my opinion the service does not have to know the form because the form can be application specific. It can be stored together in one module like we know it from ZF, but form should be instantiated by controller depending the action that is being called.

    The application can have several points of data inflow – form, csv, SOAP etc and its controllers duty to decide how to obtain and pass the data to model and then eventually store it through service.

    I agree on the validation in the service. Using visitor pattern the service can check the correct state of the model before calling repository.

    I am also trying to solve all these relationships and apply them to ZF, so hopefully you are gonna show us some code to make it all clear in real life :)

    My biggest problem is how to validate changing properties of model. Imagine following situation:
    *) controller finds the entity through UserService
    *) pass the data from form to user
    *) calls the UserService to store the model

    How do I check whether property of entity can or cannot be changed. Let’s say address can be changed any time. Unlike userName, it cannot be changed by user, but can be changed by admin. Where and how do I make this checking of changed value based on role of logged in user??

  11. hadrien says:

    I’ve been implementing such classes whithin a project based on cakephp… this design helped me to keep the code clean and to isolate the business logic into this service layer. Which is clearly an advantage when it comes to unit test the business rules…

    Then the model classes only implemented the data access and basic data validation rules, whereas the controllers methods are crystal clear and got the only responsibility to route the users actions and the service layer results.

    This design allowed me to decouple the data manipulated whithin the “user layer” (views & controller) from the structure of the data model.

    However, in my case, the layer services method where implemented static… which could be considered as an heresy, cause in some way, it breaks the ObjectOriented paradigm of the rest of the application (referred as the “anemic data model” anti-pattern by Martin Fowler).

    I’m still wondering what design can keep these advatages while being implemented the Oo way ?

    • rvdavid says:

      I don’t know if this will help you any, but it helped me put a lot of things into perspective:

      http://www.slideshare.net/weierophinney/zend-framework-workshop-dpc09

      The above is a link link Matthew’s slides from Zend Framework Workshop in April 2009. Would have been spectacular if I could have been there…

      There’s some info on the Service Layer from slide 64.

      Hope this helps.

    • Hello hadrien,
      I think you will definitely benefit from a Dependency Injection container. The Inversion of Control pattern implemented for Dependency Injection is an Object Oriented design that takes care of your services lifecycle.

      As a consequence you do not have to use static methods, singletons or factories for your services. They are all managed by the Dependency Injection container which is in charge of their instantiation, configuration and injection as shared instances.

      Check my previous comment for an integration of Symfony’s Dependency Injection container with a Zend Framework application. Do not hesitate also to go through the Symfony’s component documentation: http://components.symfony-project.org/dependency-injection/.

  12. Tom says:

    It’s real funny to read your toughts and the struggle you have getting it right, because im there too. Im completly lost in the world of OOP and the patterns.

    My mind is really exploding with al the information you find on the internet. Im really at a point I want to give it up on all. I’m loosing the fun in programming.

    I’m really used to procedural programming and not so on OOP.

    And somehow it all looks very wrong to me because for that milliseconds that it takes for the request coming in being handled and answered back by your program. With al those OOP concepts and patterns where are creating dozens of object instances load in dozens of files and for what ????

    Just to ask the server auth me and give me a list of for example users.

    And lets face it even for the most demanding applications on the web. We are really overcomplexing the problems.

    I mean using ZF and Doctrine together you create request that eat up lots of memory for a couple of milliseconds it will live ????

    Is this really justified for web developement ???
    When you develop for the desktop it’s a complete differrent story offcourse. There your program will stay longer active has more memory available etc.

    And does oop really speed up the process of development?

    Just some thoughts by someone who is getting lost in the world of web development./

    • rvdavid says:

      > My mind is really exploding with al the
      > information you find on the internet. Im really
      > at a point I want to give it up on all. I’m
      > loosing the fun in programming.

      Been there, done that – the fun will come back once you understand OOP – believe me, I was feeling exactly the same when I dove into the steep learning curve.

      The thing is, the learning curve will probably get deeper and deeper for you (it did for me) to the point where you think you’ll never master OOP.

      But you will reach a point where you understand OOP and can actually think along this paradigm.

      Don’t give up man, enlightenment is just around the corner.

      I’ll skip the other questions because they seem like rhetorical questions and my answers will just be a regurgitation of past discussions regarding procedural vs OOP paradigm.

      > And does oop really speed up the process
      > of development?

      I can answer this with a most definite “YES!” Not only that, but since you can write unit tests for your components, your code quality will also improve – and your confidence in your code will also increase as your code is backed up by tests.

      You seem like you’re very bewildered and somewhat discouraged at the moment. My advice for you is to try and build some apps using OOP so you don’t get caught up in analysis paralysis and have a working base you can use to test your ideas on.

      Other than that, I really don’t know what else to tell you aside from keep at it.

      Good luck buddy! :) Always happy to help a beginner.

  13. Ryan Horn says:

    I find this is where a lot of growing pains happen with OOP and MVC. The big idea is to reduce complexity and dependency, so when business logic balloons in an MVC based application, that simple “M” does not cut it anymore. But you need to understand what “M” represents. Yes, as far as the acronym goes, it’s a “Model”. But what it really represents is your business objects and logic, or your domain’s behavior and data. PoEAA calls this the “Domain Model”. In its simplest form this can be a set of models that interact with the database (in the case of the simplest MVC application). In more complex forms it could be a collection of different patterns including “Data Mapper”, “Service Layer”, “Repository”, etc. It all depends on the needs and complexity of your application. I see the “Domain Model” as more of a conceptual pattern rather than concrete as it can encapsulate many other patterns working in conjunction to complete your business layer.

    In terms of determining where certain logic should go or when to use a pattern, it really depends. The first thing I always ask myself is what generalized layer does the logic belong to (which is usually immediately apparent). Once that’s figured out, you need to take a look at the objects that compose that layer and determine where the best fit is. You can treat this as a process of elimination by asking yourself what the responsibility of each object is within the layer (what pattern does it follow) and whether adding the logic would disrupt the object’s integrity. Ex: If adding logic to a model added a dependency, I would find another place for it (as models should be fiercely independent). You also need to know the patterns being followed inside and out to make this decision.

    There’s times where there is no good answer. For example, when you need to add validation, but it has a very specific use case, do you place it in the model, adding complexity for one use case? Or do you put it in the application layer where that one use case can happen? This boils down to what makes the most sense in terms of testing/debugging/maintenance. Fowler suggests that you err on the side of consistency and logical grouping. Increasing the size of your model is probably better than spreading the responsibility of validation between layers (making it harder to find).

    Also remember that design patterns are not answers. They are at best recommendations and provide a common vocabulary for OOP designers. They do not solve your problem, but they have probably solved a similar one in the past.

    • rvdavid says:

      Your advice is precisely fitting in with my train of thought.

      I’ve experienced the example you gave when you were making a point about how there are no good answers and I did as Fowler suggested – err on the side of consistency.

      Thank you for contributing. Please keep in touch.

  14. I belie in the evolution: “Gateway to the Domain” => “Service Class” => “Mapper”

    Actually, I believe that is where we stand right now! Looking at developments in the zend framework and a ‘best practice example’ in the quick start tutorial download. http://framework.zend.com/demo/ZendFrameworkQuickstart.zip

    I Also believe that this reflects the ideas in the refered post about the Model Infrastructure by Matthew Weier O’Phinney (d.d. December-2008)
    http://weierophinney.net/matthew/archives/202-Model-Infrastructure.html

    I don’t know about adding the functionality for Acl, Forms, Cache etc to a Mapper/Service class. That particular code would get toooo Hot ;)

    • rvdavid says:

      Hi Leonard,

      Implementing forms and cache actually worked well for me. The reason that it’s not called a mapper, is that I don’t see Service as a mapper.

      A Data Mapper deals directly with Data and Domain objects/entities, whereas I see the Service Layer as dealing with functionality. Need a form? Let the service layer do it.

      Need to validate a form? let the service layer do it, in ZF’s case, this is done by providing a proxy method to the form’s isValid($data) method.

      Rather than placing the logic in the controller layer, all this is encapsulated into a nice utility Service class. We avoid making the Service class from being a god class by making it specific to a controller.

      I would say that the Service Layer could even use Data Mappers to fetch data for the controller. Anyone correct me if I’m wrong of course.

      One thing I did find difficult was implementing ACL into the Service Layer… Maybe I didn’t look into it as much as I should have… I’ve got a better head on me at this point in time so perhaps I’ll revisit the ACL functionality into the Service layer.

      But other than that, I can vouch that I am definitely enjoying what seems to be a very nice separation of concerns between the model and controller layers… So far anyway…

  15. Very interesting. I have many of the same architectural issues. I still struggle with them.

    One interesting implementation of a service layer is in the source code to Ben Scholzen’s blog:

    http://www.dasprids.de/

    It has services, which calls mappers to populate models. Services comes from a dependency injection system. It supports Acl on the services. It even has instructions for a Phing build/deployment.

    I have found it to be fascinating and very instructive.

    He has released the source code at:

    http://site.svn.dasprids.de/trunk

    Cheers!

    • rvdavid says:

      Hi David,

      Thanks for the heads up. I’ll definitely check it out for inspiration and if it’s complete enough, maybe I’ll even use it for my service layer.

      Thanks again!

  16. Yan Cou says:

    Hi There. I know it’s a long shot, after 2 years from the last comment here. But I’m in this exact position right now.

    I think I have some terminology issues, Could you please confirm the followings, that would be an awesome timesaver.

    About :
    the “Gateway to the Domain” from early on, then later changing it to “Service Class”.
    - Do you just acknowledged the right words was service class and it does the same thing as the gateway to the domain ?
    if not, what’s the difference ?
    (is it where some could use collections ?)

    - Regarding Value object (or domain model).

    Technically, do you have a model_user that has an entity attribute (doctrine`s entity) or is the model_user your doctrine entity ?

    Thanks for a great post and good feedback from the community. It feels good to see other people with the same challenges.

Leave a Reply

Notify me of followup comments via e-mail. You can also subscribe without commenting.