Objects in the model layer: Part 2 | Rob Allen's DevNotes

:

I previously talked about the terms I use for objects in the model layer and now it's time to put some code on those bones. Note that,as always, all code here is example code and not production-ready.

An entity

My entities are plain old PHP objects:

There's nothing particularly complicated here. We have an object with a number of properties and some methods. This object represents a book, so we have properties of author, title and isbn. We need to be able to set and retrieve the properties so there is a get and set method for each one (only getId() and setId() are in the code snippet above to save space!)

Generally, I populate an entity from a mapper and use a pair of methods to do this: populate() and getArrayCopy(). These methods transfer the data in the properties to and from an array.

There are also entity-specific methods within the entity. For this object, I have a method called isValidIsbn(); for a user object, I may have a method called getFullName() which concatenates the user's first name and surname.

A mapper

The mapper knows how to load and save entities. This is a hand-rolled one:

In the mapper, I have methods that load with multiple entities and also ones that work on a single one. I like to use the method prefix "find" for methods that will return an array of entities and "load" for methods that return a single entity. This is just a stylistic thing, but I find it makes reading code easier. We then have save and delete methods that allow us to save and remove an entity from the data store.

This is just a skeleton of a specifically written mapper that users PDO. In a ZF2 application I use ZfcBaseMapperAbstractDbMapper and in other applications I tend to abstract the common code into a base class and extend.

Service objects

Lastly, service objects provide the API to the rest of the application:

A simple service object essentially proxies through to the mapper. I generally have more specific methods, such as fetchAllByTitle(), but that's a personal preference. In this example, I have an ZF2 event manager in play and the service object triggers events as required.

The service object is also useful when there are multiple related objects. For instance, if books had tags that were loaded separately, then I would have a method such as loadTagsIntoBook($book) on this service object. Of course, others prefer to use an ORM, such as Doctrine for these things.

Summary

This overview shows the type of methods that I have in each type of core object in my model layer. My controllers and view helpers only ever deal with service objects and entities, so I can change my mapper at any time.

You also need to think carefully where the business logic lives. I'm a fan of putting the logic in the entities as well as in service objects. Others tend to like their entities to be quite "dumb", though.