MVC: Model Layer

I think of the MVC model as an umbrella under which a whole other structure is required. It is the most critical layer of the MVC triad, and the layer that requires the most planning.

The Service Layer is the highest level layer of the model. It is the model’s interface to the outside word. Controllers call on it to complete complex tasks on behalf of users, and it coordinates the Domain objects and Data Mappers to carry out such tasks.

The Domain is a collection of classes that represent business objects. Class names are typically nouns such as 'user', 'customer' and 'product', and classes include both data and behaviour. Large and complex systems may benefit from a fully domain driven design approach, but smaller system may get by with just a few design rules.

Mapper classes translate between the object world and the RDBMS. There is often one Mapper class per Domain object, but this is certainly not always the case.


MVC: Presentation Layer

As mentioned, there is nothing particularly special about the Starter Application views and controllers beyond what is provided out of the ZF2 box. Controllers pass variables to views. View scripts render them.


It is worth noting that, with some extra coding in the Domain factories, view scripts can access an object’s properties, including multi-valued properties, without causing performance issues such as the N+1 selects problem. More on this later.

View Helpers

I use view helpers extensively to isolate complex logic and avoid duplication. They live in the Core\View\Helper namespace, with sub-namespaces for further organisation. They are registered in the module's configuration, usually as an invokable or a factory.


Zend\Form makes easy work of creating and rendering forms. In most cases however I revert to hand-crafted forms for complete control over the layout. The inlineScript view helper makes easy work of managing related javascript. 


The Starter Application's controllers extend from Zend's abstract controller and are therefore service-locator-aware. Controllers use the service locator to access other services including Service Layer services and Data Mappers. In addition, the Starter Application’s base controller inserts a helper trait.

All code examples in this discussion are based on the Foo-Bar application shown in the class diagram on the N+1 Selects Problem page. Here is an example of a Bar controller.

namespace Core\Controller;

class BarController extends AbstractController
    public function updateBazAction()

Helper Trait

The helper trait is inserted into most supertypes within the Starter Application, not just the abstract controller. It is a good place for any utilities that are used widely throughout an application. One such utility that the Starter Application uses extensively is getShortType, and this brings us to an important naming convention.

In the discussion on Domain objects you will see that there is often a 1-to-1 relationship between a Domain object and its associates. For example a Foo object may have an associated Foo proxy, Foo factory, and more. The getShortType function accepts an object or class name, and merely returns the unqualified name of the class. Client code may use this function to find out exactly which Domain object, proxy or factory it is working with.


PHP Starter Application

This is a starting point for applications with complex business logic. It is a PHP MVC skeleton with a Domain (Domain Model), Data Mapper and Service Layer. It uses Zend Framework 2 however may be ported to other frameworks quite easily. You are welcome to use it as the foundation for your next application.

The Starter Application includes:

  • A means of organising business logic (the Domain),
  • A flexible mechanism for database interaction (the Data Mapper),
  • A clean, clear API for client code (the Service Layer),
  • Factories for creating complex Domain objects,
  • An identity map to avoid duplicating Domain objects in memory,
  • Custom collections for Domain objects, and
  • Proxies for efficient loading of individual Domain objects and collections.

The Starter Application is aimed at intermediate-level developers who have ZF2 experience and are addressing problems which are too complex for transaction scripts or table modules. I am planning to maintain and improve both the code and this discussion, so please contribute any improvements by forking the code on github.


The Starter Application consists of two modules: Core and Mapper. All codes lives in Core, with the exception of the Data Mapper which is declared in Core and implemented in Mapper.

The presentation layer of the Starter Application (i.e. views and controllers), is straightforward. All the interesting work takes place in the model which includes the Domain, Data Mapper and Service Layer.

The MVC Model

Getting Started

To start building your own application you can:

  1. Install the Starter Application using the method described here
  2. Read each of the topics that follow, exploring the installed code as you go
  3. Follow the steps in Using the Starter Application