MVC and the Repository Pattern: Roles of Controllers, Models, and Repositories? MVC and the Repository Pattern: Roles of Controllers, Models, and Repositories? php php

MVC and the Repository Pattern: Roles of Controllers, Models, and Repositories?


1. Is this a correct implementation of the repository pattern?

I'm not sure where you been doing that research, but you have got it wrong.

  • Repositories as for separating the domain objects from data mappers.

  • There no such thing as "models". Model in MVC design pattern is one of the to main layers: presentation layer and model layer.

  • And the repository pattern is incompatible with active record (anti)pattern, which combines domain and storage logic in single instance, thus causing a major SRP violation.

To use a real world example for, when and how to use a repository here is an example:

You are creating some document management tool, where said documents can come from several sources (for example: local SQL database, SOAP service and cache). In this situation you create a repository, which deals with the "routing" of storage. It is the part of application, that decides which data mapper to use for storing/retrieving each document.

The goal of repository is to separate the domain logic from the interaction with storage. For the system, that was described above, a repository would also let add new data sources, without need to rewrite large amounts of code (if any). You could just add another type of mapper for the document.

2. Should the controller create a User object and then pass that into the model?

To begin with, controller itself should not create anything. Instead your controller should use a factory for acquiring instance of the object that you need. This factory can be provided to the controller through constructor or some other method. This is called: Dependency Injection (to learn more about it, watch this lecture).

Also, as noted above, model is a layer, not any specific class or object. The responsibility of controller is to alter the state of model layer (by passing data to it). You could interact with domain objects and mappers (or repositories) directly in the controller, but it would mean leaking some of the business logic in the controller. It is recommended to instead use services, which then manipulates said domain objects and storage related structures.

As for the issue with 10+ parameter, that you would require for creation of new user account, let's assume you have action with following footprint:

public function postUser( Request $request ){    ....}

If the action gets called with specific Request instance, you have two options how to deal with large amount of parameters:

  1. Wrap the instance in a decorator, which would let you call a single method for forming the data from request in a specific array. Then you pass this array to the service(s).

  2. Form the array inside the controller's action and pass it, where th data is required.

The former solution is more suited for large scale applications, where such formation of data would be required repeatedly though-out the code. But in a small/medium projects the second option is the common-sense approach.

Thing is, the job of the controller is to take the user's input, and distribute it to the model layer and current view. And formation of such array fits right-in with this mandate.

3. (..) main object that is just a simple data structure with no behavior and then (..)

No. Domain object is not "simple data". It is where most of the domain business logic resides in the application.

And forget about magical ORMs. First step for implementing a repository is to separate the domain and storage logic. Domain object handles the validation and business rules, mapper deals with persistence and data integrity (small example here).

Another thing that you must realize is that repositories for web application do not really interact with in-memory persistence (apart from cache). Instead your repository would be juggling mappers for different data sources.


Should the controller create a User object and then pass that into the model?

I'm not sure what you mean by "pass that into the model" -- the User object is the model. "Controller" and "model" represent different layers in the design, they are not specific objects, and there shouldn't be a separate UserModel object as you mentioned.

The repository interface itself is generally considered part of the model, though the domain objects shouldn't be saving themselves -- this should be done in the controller.

Your controller's job would then be to interpret the request and create a User object, then use the repository to save the user:

$user = new User(...); // based on Request$repository->save($user);

it looks like to me I would need to have a domain object that is just a simple data structure with no behavior

This is not true, you can and should encapsulate behaviour in your domain objects. As for how persistence is actually implemented, a good ORM should take care of most of the details and you shouldn't have to create additional classes by hand.