Understanding MVC Views in PHP

Understanding MVC Views in PHP

Note: the MVC and MVC-inspired patterns are advanced constructs. They are meant to be used in codebases where ordinary object-oriented (that follows SOLID and other guidelines) code starts to become unmanageable. By introducing this pattern you would impose additional constraints, which then lets you to contain very complex applications. MVC is not meant for "hello world" apps.


Let's start from the beginning ...

The core idea behind MVC and MVC-inspired design patterns is Separation of Concerns. Said separation is two-fold:

  • model layer is separate from UI layer:
  • views are separated from controllers

Sample Image

Model layer (not "class" or "object") would contain several groups of structures, each dealing with as different aspect of business logic. The major parts would be:

  • domain objects: validation, business rules
  • storage abstraction: persistence and caching of data from domain objects
  • services: application logic

Also there might be mixed in repositories, units of work and others.

UI layer mostly consists of views and controllers. But they both utilize services to interact with the model layer. Services provide the way for controllers to change the state of model layer and for the views to gather information based on that new state.

In context of web the views and controllers form a loose pair, because of the request-response nature that web applications exhibit.

It should be noted that although controllers can alter the state of the current view directly, it's more common that these changes are effected through the model. One reason to alter the view directly is, for example, when instead of XML you need to respond with JSON.

Though it also could be argued that one could simple instantiate a different view for each output format and take advantage of polymorphism.


What is not view?

There is a widespread misconception that views are simply glorified template file. This mistake became extremely popular after release of RubyOnRails prototyping framework.

Views are not templates. If you use them as such, you break the core principle behind MVC and MVC-inspired patterns.

If you pretend that templates are views, it has an enormous impact on your architecture. There is no place for presentation logic in the view, therefore you push the presentation logic either in controller or model layer. The usual choice is "controller", because most of people understand that presentation logic has no place in model layer.

Essentially, this causes a merger of views and controllers.


What is view doing?

The responsibility of the view is to deal with presentation logic. In context of web the goal for view is to produce a response to the user (which, btw, is the browser not the human).

Technically it would be possible to create client side views, that user web sockets to observe model layer, but in practice it's virtually impossible to implement. Especially not in PHP environment.

To create this response view acquires information from model layer and, based on gathered data, either assembles response by distributing data to templates and rendering or sometimes simple sending a HTTP location header.

When using Post/Redirect/Get, the redirect part is performed by the view, not the controller as often people tend to do.


Highly subjective bit:

Lately I have preferred to interact with MVC using following approach:

  // the factory for services was injected in constructors
$controller->{ $method.$command }($request);
$response = $view->{ $command }();
$response->send();

The $method is the current REQUEST_METHOD, that has been adjusted fake a REST-like API, and the $command is what people usually call "action". The controller has separate routines for GET and POST (an other) requests. This helps to avoid having same if in every "action".

And on the view I call similarly named method, that prepares a response that is sent to the client.

Warning:I suspect that this setup contains an SRP violation. Adopting it as your own might be a bad idea.


What about DRY?

As you might have noticed already, there is a slight problem with having views as instances. You would end up with repeating pieces of code. For example: menu or pagination.

Lets look at pagination .. The pagination contains logic, but this logic is not related to the model layer. The model has no concept of "page". Instead this bit of logic would reside in the UI layer. But if each of your views contains or inherits pagination, then it would be a clear violation of SRP (and actually several other principles too).

To avoid this issue you can (and should, IMHO) introduce presentation objects in your views.

Note: while Fowler calls them "presentation models", I think that name just adds to the whole 'what is model' confusion. Therefore I would recommend to call them "presentation objects" instead.

The presentation objects deal with repeated pieces of logic. This makes the views much "lighter", and in some aspects starts to mirror the structure of services from the model layer.

The interaction between presentation objects and templates becomes similar to the interaction between domain objects and data mappers.


Do I always need all of this?

No. This specific approach is heavily geared towards code, where the UI layer has a lot of complexity and you need to separate the handling of input from presentation just to sane sane.

If your application has very simple UI, like .. emm .. you are making REST API for a larger integrated project. In such the pragmatic option can be to just merge every controller-view pair into single class.

It also can be a good step, when refactoring a legacy codebase, because this less-constrained approach lets you move entire chunks of old code. When you have isolated such pieces of older code and checked, that everything still works (since legacy code never has any tests .. that's how it becomes "legacy"), you then can start splitting it up further, while focusing on separating business logic from UI.


P.S. I myself am still struggling with figuring out a way how best to deal with views. This post is less of an answer and more like a snapshot of my current understanding.

Understanding MVC on PHP with real application implementation

If you want to create your own framework or just want to develop app with following oops and MVC concepts then you have to read about the concept of MVC.
Please read

  1. http://phpro.org/tutorials/Model-View-Controller-MVC.html - You can also
    download source from http://phpro.org/downloads/mvc-0.0.4.tar.gz
  2. http://php-html.net/tutorials/model-view-controller-in-php read and get
    download link from that page.

Please let me know if this is helpful and enough to create our own small MVC Framework.

Thanks

PHP MVC - How exactly do I use views?

A template isn't a view, but a view could use a template. Templates are just re-usable architecture/design that a view can be based on. Views are typically a specific page or page type.

Views should also have little to no business logic in it, and should be focused on the layout and design, hence why there should be little or no requires.

If your view is using a template, then you likely don't need to include things like footers and headers, depending on the template system you are using. But if you are creating the view without a template, you will likely have to include those on the view yourself.

Focus on maintainability, scalability and a separation of design and logic, and make your code re-usable whenever possible.

MVC in PHP – General understanding and specific questions

Let me first answer your questions, then place my take on it.

  1. There's no right way of writing MVC. There are so many flavors and variations, and that get even multiplied when talking about web MVC.
  2. About Logging in and Logging out. I think the most robust system would be a Role Based Access Control combined with an Access Control List, see How can I implement an Access Control List in my Web MVC application?.
  3. There are generally two approaches, either you have a 1:1 ratio between Controllers and Views, and then after the Controller is done, your bootstrap script calls the View with the same name (LoginController, LoginView), or your Controller returns the View name along with action and parameters, to be called by the bootstrapper. The view then picks a template, and that template can include other sub-templates (like the user bar, or the footer).
  4. In that case, your view needs to have an ability to select a different template based on the Accept: HTTP header (and send something like Accept: application/json in your AJAX requests). Your view then returns a JSON template instead of an HTML template.

What is wrong with your sketch?

Your model isn't just the gateway to your database, it's where all the logic happens. All the computation. See this yet another excellent answer that explains How should a model be structured in MVC?.

The idea of MVC is to simply separate your application into three layers: Input (controller), Logic (model) and Output (view). This is to extend on the usual way PHP works (here's a request, give me a response, all in the same page).

For that reason, implementation details may vary, the concept is what matters. "Web MVC" is merely the result of good OOP practices and some naming convention someone made up a few decades ago.

how should the view display, on MVC in PHP

TL;DR yes, kinda.

This is what one would call "Model 2 MVC" or "Web MVC" as defined by Java community in early 2000s.

The main difference from "classical MVC" is in the way how view interacts with model, because in the classical approach the view would observe the model for changes in its state. The controller would alter the model's state and the view would receive signal, that the model' state changed. Which would prompt the view to request only the information, that was directly related to the change of state.

But the classical approach is not all that pragmatic for the web. Which is where Model2MVC comes in.

Due to web's request-response nature, you will end up with pairs of controllers and views. And each view will already know what its paired controller will alter in the model's state. And it doesn't need to observer anything, because it will need all the page data anyway.

I hope this helps.

P.S. The reasons why you see so many claiming to use 'MVC', which is completely different from this, is RubyOnRails - it used 'MVC' as marketing buzzword.

MVC in PHP - How does the controller know the view?

I think that the best way is to use some kind of routing system so you have a map somewhere with the possible url pattern / page to show combinations and after deciding which controller to call you can load the appropriate view in your controller.

What you presented here seems somewhat blurred to me. I think that you should check out implementations out there like Pure mvc or symfony so you can get a grip on the concept quickly. I believe that you (or anyone else for that matter) shouldn't reinvent the wheel but study, understand and improve what you can get.

If you are going to create your own MVC framework then you should check out the basic MVC concepts and plan your software before trying to write it.

PHP MVC - handling views

CodeIgniter is one of the frameworks that provides an HTML helper to allow you to generate HTML through PHP code (like the latter case in your question).

While this will be marginally slower, the advantage is it ensures valid HTML is output. Take this example:

<h2>This is a header without a closing tag

The above is a common mistake which will fail silently. However, you cannot make the same mistake if you use the HTML helper function

echo heading('This is a header',2);

As for readability, anyone familiar with PHP should be able to understand either code fragment with little to no difficulty.

Am I understanding MVC in web development correctly?

ASP .NET MVC developer here, but I'm not sure that it matters given the nature of the question.

I try to think of a view as everything I need to render a particular operation. This will include stuff that is tied to specific business concepts, but also, will cover things like pagination and other concepts that aren't domain-specific problems, but still require some representation on the page.

Now, in terms of code operations, in some senses there isn't a lot you can do. You may have a part of your page that is dependent on, say, a collection being populated and having things in it. I have no real problem sticking in simple conditional constructs to handle things like this. It is code, but you could argue that its not important code. We aren't performing work per se, merely suppressing the display of certain elements based on the internal state of the view.

I'd argue that would apply to a lot of simple conditional display logic.

However, if you find that you are performing stuff that is more complex than that, it's probably best to change the model to give the view less work to do. e.g. if you're performing some nasty chained ternary in view-side markup, you may wish to consider encapsulating that logic in the construction of the model, instead of leaving it for the view to sort out.

So in conclusion, while simple on/off presentational constructs are generally okay (if a little messy) in views, consider creating extra properties etc on your model if you find your view code becoming inordinately complex or unmaintainable.

Getting familiar with MVC - how do I work with session logic, additional classes and background logic

User, context of MVC, is a domain object. However the session is a form of storage medium (just like cache, db or file-system). When you need to store data from User instance there, you use some type of data mapper to do it.

$user = $this->domainObjectFactory->build('user');
$user->setName('Korben')
->setSurname('Dallas');

if ( some_condition )
{
$mapper = $this->dataMapperFactory->create('session');
$mapper->store($user);
}

This code should provide an extremely simplified example for interaction between session and user.

Where do I add the user class?

As a domain object, the User instances should be used inside services and initialized using factories. In context of MVC, the services are structures in model layer, which deal with application logic. They manipulate and facilitate the interaction of domain object and storage abstractions.

How do I add and include user class to my MVC?

All of your classes should be added using autoloader. You should read about use of spl_autoload_register(), preferably while using namespaces.

The initialization of instance itself should be done by a factory. That lets you decouple your code from the class name of said instance.

How do I carry user class around my application?

You don't.

PHP applications do not persists. You have an HTTP request, yo do all the things you need with it, the response is sent and application is destroyed. The instances of User class will all be short-lived.

To recover the current user between requests you store an identifier in session. Do not dump whole objects in session. Instead, after you fetch user's identifier from session, you can recover the rest of user account details from other forms of storage (if you even need it).

This whole process should be preformed and managed by some sort of "recognition service" or "authentication service" from your model layer.

How do I perform login / logout logic and perform required actions?

The login request is at first handled by controller:

public function postLogin( $request )
{
$service = $this->serviceFactory->create('recognition');
$service->authenticate( $request->getParameter('username'),
$request->getParameter('password') );
}

The service tries to verify the user's credentials, which alters the state of model layer. The view instance then looks up that state and either redirects you to the landing page as authenticated user, or redirects you back to login page with an error message.

The service themselves would be shared between model controller and view via the factory. Which means that they would initialize each service only once and then just reuse it. Something along the lines of:

class ServiceFactory
{
private $cache = array();

public function create( $name )
{
if ( array_key_exists($name, $this->cache) === false )
{
$this->cache[$name] = new $name;
}
return $this->cache[$name];
}
}

Just keep in mind that his is an extremely simplified example.

For further reading I would recommend you to go through this collection of links. Also, you might find these 3 posts somewhat useful: this, this and this.



Related Topics



Leave a reply



Submit