PHP bespoke sites using the MVP pattern

I’m trying to get my head around the Model-View-Presenter pattern and how it can be used in PHP websites.

When Googling MVC it seems most tutorials and frameworks claim to use MVC but actually have implemented MVP. Either way, I’ve looked into it and MVP looks like what I am trying to achieve in my code for better separation of concerns. This is likely to be a lengthy discussion if anyone has the stamina to answer my questions so I’ll only ask a few questions at a time. :wink:

Firstly, I understand MVP, to work like this:

  1. Presenter take user input and decides what information is needed; Presenter requests that data from Model.
  2. Model represents data though is not simply a class per database table (or JSON file, XML file, etc); it could be several classes. Presenter requests and manipulates data through public functions that represent tasks that model would carry out. For example a User model might have the public function getNumBlogsPosted().
  3. Once the Presenter has decided what to do it passes the data to the View. The View then loads a template file which is basically HTML with simple PHP or a templating language. Since I’m using PHP the View (presumably) escapes all the data for output (htmlspecialchars and urlencode).

Is this overview correct? Assuming it is, I have a few general questions:

  1. Is it right for the View to do the escaping or should that be done in the template?
  2. Would the Presenter do the URL routing or is that typically done before the Presenter is initialised?
  3. Similarly, where would you put hard-coded config like database connection details?
  4. Does the Presenter have to be a class? Are they any advantages to it being one? (See last point for why I ask this)
  5. Is a rule-of-thumb that the View is merely HTML generation, the Presenter takes user input, deals with the model and then sends it to the View and everything else should be done in the model. For example, should sending an email from a contact forms be done in the Model?
  6. Finally, my current bespoke sites have a bootstrap that loads settings and initialises about 15 core objects (like database connection object, formatter object, password hasher, etc) that are used by the front and back end.
    Would I now need to inject all these as dependencies into the Presenter (seeing as I use Dependency Injection throughout)?

Thanks.

The confusion is because all those user interface patterns – MVC, MVP, and also PAC (another that gets mentioned around here a lot) – were defined for rich applications such as desktop software, and none of them can be sensibly applied word for word to server-side web applications.

Mostly yes, but to reinforce my last point, be aware of a few caveats. In the Wikipedia description, for example, it says that the view routes user commands to the presenter. The view even instantiates the presenter itself. In desktop software, that makes sense. In desktop software, the view has to come first, because the only way you can get any user input is to make a window that the user can interact with. But in server-side web applications, the user input is ready and waiting for us the moment the application starts, and making a view first would be redundant and silly. So as you read about these patterns, keep in mind that these are for desktop software, and they’ll never be perfectly applicable to the web.

In the templates. Because the escaping you do will be context-sensitive. Quick and dirty example:

<p><?= $hello ?> <script>document.write('<?= $world ?>');</script></p>

In one place, you need to escape HTML characters, and in the other you need to escape a mix of JavaScript and HTML characters. No doubt HTML escaping is what we need most of the time, but sometimes context matters.

Also, it isn’t set in stone that the view needs to be a class at all. You may find it has nothing to do except load a template.

So, obviously, in the world of desktop software that MVP was defined for, this kind of question doesn’t make any sense. The solution that virtually all web frameworks has settled on is to do the routing before any presenter/controller is initialized. In fact, the match we get from routing is how we decide which presenter/controller to use.

Web frameworks are a bit more diverse on this one. Some, mostly the older frameworks, would have you define constants in some config.php file. Modern frameworks tend to use either Yaml or XML, and the framework’s entry point / application class / kernel would load that config and use it to initalize a service container.

Not necessarily, no. For example, closure functions are starting to be a popular choice. But classes give you the option to keep multiple presenter/controller actions in the same class (typically CRUD actions are grouped together), which allows you to use private methods to consolidate similar code.

A guiding principle I’ve used is to imagine that I’m also writing this code to run as a command line application. If some chuck of code is truly part of the business logic, then it would be needed in both the web app and the cli app, and it probably belongs in the model. But if some chunk of code is needed only for the web application (like a redirect, for example), then it isn’t business logic, and it probably belongs in the presenter/controller.

“Need” is perhaps too strong of a word. Injecting the presenter/controller is by no means a bad idea. Though this is one of the few places where modern frameworks tend to opt for a service locator style.

Hi Jeff,

Thanks for the detailed response. I read it and let it settle over the weekend.

I agree with you about MVC/MVP having to be changed for web applications. Also, I like your test to determine if something is part of the Model or not.

A few more questions:

  1. If I load settings from a XML file, would it be considered bad practice to define constants from here?
  2. Would redirects be the job of the View or the Presenter? I think it would be neater to do it in the Presenter but I did read the a View is technically a view from the browser’s perspective, not the user’s.
  3. Just to be clear: would the model send emails? (E.g. contact form)
  4. If your library already has a class that closely represents a model (e.g. User) would you just inherit from the library class?

Regarding dependency injection, I don’t want to use a service locater. I can’t help thinking it’s pointless going through the hassle of injecting all those objects into individual container classes. I’ve looked at a few libraries/frameworks and they (the Controller classes) seem to just call a single function.

Finally, when frameworks like Laravel register POSTs in the router (e.g. /user/register/), how do these work? It seems to be all routing should be done via GET.

Thanks.

They (probably all well written frameworks) use the header in the HTTP request to determine the type of request it is. Laravel’s docs are a bit weak on explaining this. It only explains how you can retrieve the method of the request. Symony’s docs are better at explaining what is happening internally and since Laravel uses Symfony’s HTTPFoundation component, it is also valid for Laravel.

Scott

Do you mean define('GLOBAL_CONSTANT', $valueFromXml);? If that’s what you mean, I wouldn’t do that. Avoid anything global like the plague. Prefer instead to pass required values as arguments.

There’s no official MVP answer for this, because redirects don’t exist in desktop software. But in current web frameworks, the most common choice by far is to do redirects in the presenter.

I’m going to say probably yes, but without knowing the purpose your email serves, I can’t say for sure. This is where thinking in terms of a CLI app can be useful. Would you still want this email sent even if someone was interacting with your program through a CLI?

I’m going to tentatively say yes, but it depends on the details.

I’m not sure what you mean here. Even if you used a service locator style in certain places, you’d still have just one container class.

In modern frameworks, those functions are usually a shortcut to the container, so those are all service locator without being obvious that they’re service locator.

They take into account the REQUEST_METHOD in addition to the URL. Both have to match for the route to match.

Thanks for the links.

In Laravel, for example,what would the difference be between:

Route::get('foo/bar', function()
{
    return 'Hello World';
});

And…

Route::post('foo/bar', function()
{
    return 'Hello World';
});

Am I right in saying in both cases foo/bar is the part of the URL after the domain but which one is called depends on the header? I can help thinking it’s better to just check the appropriate part of the URL and then perform an action depending on whether or not various POST vars are set.

Finally, in Laravel you can set routes as things like user/{id}. Do routing classes usually automatically set PHP vars ($id in this case) or should the Presenter do that?

  1. Yep, that’s what I mean. I pretty much agree with you but I personally feel constants can be good in that they can’t be changed. Do you not use them at all?

  2. I agree, makes sense.

  3. Agree.

  4. Agree, again.

  5. This is the bit I’m most torn on. What I mean is if I make the Presenter a class I then have to inject a ton of objects into it. Whereas, if I just include a PHP file I don’t. Do you think that making the Presenter a class is more trouble than it’s worth?

This is what routing is for in most frameworks. Depending on the URL, you route to a class, which has actions as methods. You can route both get and post URLs to the same class for instance and just handle the different requests through different actions. One could argue this breaks SRP. So you would probably rather want to have a controller class per request method. The thing that the frameworks mix up is where the view actually kicks in. For instance, why do GET requests even need to be “routed” to a “controller” class? Why can’t the view directly handle all GET requests? I’ve been told, this architecture is continued in most frameworks, because they try and represent the old and well known “page controller” pattern from yesteryear. For every “page” you have some controller. I guess that would be the right excuse too. @TomB has some interesting thoughts on this.

In Laravel (and Symfony), it is the routing component, which sets you up with PHP variables coming in from URL parameters.

Scott

Why do GET requests even need to be “routed” to a “controller” class? Why can’t the view directly handle all GET requests?

In MVP, isn’t this so that the View can be “dumb”? I.e. unaware of what is going on with regards to obtaining the data.

Depending on the URL, you route to a class, which has actions as methods

What do you think is the advantage of having a Controller or Presenter as a class? Typically, I see each Presenter only doing between one and a handful of tasks therefore I’m struggling to see the advantage of writing a class per Presenter against just including a PHP file.

In Laravel (and Symfony), it is the routing component, which sets you up with PHP variables coming in from URL parameters.

Just to be sure if I declared user/{id} as a route would $id automatically be set once I get to the Presenter?

From Wikipedia

A view requests information from the model that it uses to generate an output representation to the user.

In most frameworks, you are left to call the model yourself in a controller, to “pass on” to your view. I (also) think this step shouldn’t be necessary for GET requests. To me, if anything, controllers should be the “dumbest” parts of the system. Current frameworks suggest the same or similar through the best practice of “thin controllers/ fat models”, but the way they are architected to resemble the old page controller pattern means some devs get lulled into making fat controllers anyway.

What are the advantages of OOP? If you can make thin controllers, (which call on other classes for more general shared model logic across many views) you are doing the “thin controller/ fat model” right. Still, you need logic to take a request to a response and depending on the pages/ views you have, you need a number of controllers/ presenters to make it happen.

Yes.

Scott

You might want to read: http://symfony.com/doc/current/book/http_fundamentals.html

I think it’s important to understand the web Request/Response cycle.

You will often see routes like this:

GET /users (list of users)
GET /users/:id (specific user)
POST /users (create user)
PUT /users/:id (replace existing user with new user)
PATCH /users/:id (update existing user)

So the request method is important.

As far as the mailing issue, this is where event driven programming can come in. Let’s suppose you make a new user in your controller. You may or may not want to send some emails. Your controller can just:

$eventDispatcher->dispatch('NEW_USER',$user);

You can then have one or more listeners for the NEW_USER event. The listeners can decide if emails need to be sent. This helps to decouple your code. One popular event dispatcher is: http://symfony.com/doc/2.7/components/event_dispatcher/index.html

Thanks, Scott.

A view requests information from the model that it uses to generate an output representation to the user.

That’s MVC, not MVP though, surely. I am trying to implement the latter. In MVP the View does nothing apart from render the output. It seems while many web platforms claim to use the MVC pattern they are actually implementing MVP.

What are the advantages of OOP? If you can make thin controllers, (which call on other classes for more general shared model logic across many views) you are doing the “thin controller/ fat model” right. Still, you need logic to take a request to a response and depending on the pages/ views you have, you need a number of controllers/ presenters to make it happen.

Do you think injecting a load of objects into a Presenter class beats just including a PHP file? I’m not disagreeing with you; I’m genuinely ignorant as to why it’s a good idea.

That’s very useful, thanks.

When values are passed as arguments, I find I need constants a lot less. Any function or class can tinker with their local copy without affecting anyone else.

How will your included PHP file get access to the things it needs? Globals? That’s a bad sign.

I do agree though that a presenter class would probably need a lot of things injected, which is probably why most (I think perhaps all) of the modern frameworks use a service locator style here. That is, you would inject just one object – the container object. And from that, you can get() whatever service or value you need.

We often need to do more than just display static content. First we probably need to query the database. Depending on the results of that query, we might decide to show a 404 page, or a “not authorized” page, or send a redirect, to name a few possibilities. If all goes well, then we forward the results of that query to a template for rendering, and the template doesn’t need to know or care what sort of query produced the results it’s rendering.

Agreed.

[The Symfony documentation][1] explains how you can reference objects (services) from within the service container pretty well and explains the advantages.

As you’ll see, the real power of the container is realized when you need to create a service that depends on one or more other services in the container.

…(What) if you decide later that (a) class needs a second or third constructor argument? What if you decide to refactor your code and rename the class? In both cases, you’d need to find every place where the (class) is instantiated and modify it. Of course, the service container gives you a much more appealing option.

Using references is a very powerful tool that allows you to create independent service classes with well-defined dependencies. … When you define this dependency in the service container, the container takes care of all the work of instantiating the classes.

Scott
[1]: http://symfony.com/doc/current/book/service_container.html#referencing-injecting-services

Yes, I understand that is how most frameworks work. I am just throwing in some ideas here and it is very theoretical on my part…currently. :blush:

Scott

Hi Jeff/Scott,

The bootstrap sets up all the core objects so when you include the Presenter they’re already available; there’s nothing to pass. Maybe I need to look at having a DI container, I don’t know.

Does a service locator affect unit testing?

Although this doesn’t answer your question directly, you might want to read this thread.

Scott

There are literally tens thousands of discussions on MV* patterns. I doubt if anyone is every going to come up with the ideal one. I think you need to deal with the requirements of each route individually.

Start with the basics of separating code and presentation:

$router->map(['GET'],'/',function($request,$response)
{
  $title = 'Index Page';
  ob_start();
  require 'views/index.html.php';
  return $response->getBody()->write(ob_get_clean());
});

This is working code which happens to be based on the Slim 3 framework but could be used in pretty much any framework. It’s very easy and is actually all that is needed for many pages. Is it MVC? MVP? MVWTF? Don’t know and don’t really care.

Suppose you want to use a more friendly template system such as twig:

$router->map(['GET'],'/users',function($request,$response) use ($dependencyInjectionContainer)
{
  $twig = $dependencyInjectionContainer->get('twig');
  $params = ['title' => 'Users Page'];
  $html = $twig->render('users'html'twig',$params);
  return $response->getBody()->write($html);
});

Again, working code and now you can do all your common header/footer/layout stuff.

Suppose the users page needs to make a REST call to get a list of users:

$router->map(['GET'],'/api/users',function($request,$response) use ($dic)
{
  $userRepository = $dic->get('user_repository');
  $users = $userRepository->findAll():
  $usersJson = json_encode($users);
  $response->getBody()->write($usersJson);
  return $response->withHeader('Content-Type','application/json; charset=utf-8');
});

Even though these closures are pretty simple, at some point we might want to start grouping some common functionality into something like a Symfony controller.

$router->map(['GET'],'/user/{id}/show',function($request,$response,$attrs) use ($dic)
{
  $userId = $attrs['id']; // Pulled from {id} in the request
  $controller = $dic['user_controller'];
  return $controller->showAction($request,$response,$userId);
});

And finally, when the request needs it, we can go crazy:

$router->map(['GET'],'/user/{id}/edit',function($request,$response,$attrs) use ($dic)
{
  $model = $dic['user_model_factory']->create($attrs);
  $form= $dic['user_form_factory']->create($attrs);
  $controller = $dic['user_controller'];
  $controller->editAction($model,$form);
  $view = $dic['user_view_factory']->create($attrs);
  $html = $view->render($model,$form);
  return $response->getBody()->write($html);
});

Side note: I have always been a bit amused that there is no F in most MV* patterns. Yet form processing is often the most complex part of dealing with a request.

In any event, you can make as many objects as you feel are needed and wire them up without much difficulty. I hope I have also shown one approach to using a dependency injection container.

1 Like