Service Layer in PHP

I’ve been thinking about robust, extensible, and easy patterns or strategies for setting up an application. Starting from an MVC viewpoint, I feel there’s a need for an extra layer, a service layer.
The service layer can handle workflow that only represents business logic. This meas the Controllers and Models can focus on their own tasks, being handling request logic and persistence logic respectively.
Service layer is a broad concept, and there are many ideas and examples available, for different languages and frameworks. My goal is to try and sculpt it in such a way that it fits in with PHP and Zend Framework.

There are a couple of basic programming rules or guidelines you can to follow to make your system work, following them will make your system better in multiple disciplines:

  • easy to extend or add features
  • consistent¬†API, easy to understand for new developers
  • highly testable, and thus robust

The basic points on the agenda to accomplish such a system are:

  • keep logic separated, in this case: request, business and persistence logic
  • keep functional logic separated from object creation logic
  • work with interfaces where possible

This is intentionally all quite high level, just to give a quick overview. Next up is a more in depth look at how this will translate to the structure of the application.

To keep the logic separated

Specific logic will be assigned to an appropriate place where they can do there thing. Sounds easy enough.

The request logic will be handled by the Controllers:
Controllers take in request data and validate it, and determine whether to redirect or display output, and in the latter case, the format of the output. If a controller wants to perform any action related to business or persistence logic it consults the service layer.

The business logic
will be handled completely by the service layer:
Most MVC frameworks in the PHP landscape use fat models, who combine persistence logic with business logic. Although the persistence logic is delegated to a database abstraction layer beneath the models in most implementations, this approach still creates a high coupling between business and persistence logic. (P.S.: And if the model’s aren’t stuffed with both business and persistence logic, your controllers are probably bloated with request and business logic)
The business logic will be extracted into a service layer, which leaves the model with only getters and setters, and some persistence logic which it further delegates.

The persistence logic
will be delegated to a database abstraction layer, there are plenty around, the goal is to be able to use any with the service layer, but there will be a specific focus on Zend_Db_Table and Doctrine ORM.

Extract object creation logic

This is a widely practiced art, the factory method, abstract factory pattern and registry pattern are found all over Zend Framework. It makes for easy configuration and dependency injection. In creating factories and registries, the ZF naming will be used, e.g.: Service::factory() or $this->_serviceBroker.
This will benefit the code in both usability, consistency, and testability. It creates a consistent API for the developers, and makes dependency injection easy when writing unit tests. Working with interfaces and abstract classes will help a lot in this area.
Abstracted object creation also means high configurability, the factories creating the objects, can access the configuration and can perform actions on objects before they are released to be used. For instance if you ask a factory to create a UserService, you can configure the factory to subscribe a logger that reacts to certain events the UserService raises.

Side note

PHP 5.3 brings some nice new features to the party like late static binding which is really a godsend for creating abstract factories or implementing factory methods. If you’ve have it available, and are working with any factory patterns, be sure to check it out.