Paul Jones is wrong
CONTROLLERS NEVER TOUCH TEMPLATES
The controller does not sit between the models and views. This is a very, very common misconception about the MVC pattern, and all it does is create busy box double coding where values are first loaded into the controller, then placed into the view. It really needs to stop.
The view layer is not just templates, it’s the code that manages them as well. Further, it is quite ok for views to query the model layer for data requisite for their display. The controller’s job is to insure the correct view has been loaded for the user’s request, and that the user meets the criteria necessary to have access to that view.
What distinguishes the model layer is it only answers questions. It never asks anything of the other two layers. It provides data on demand to the other layers but it doesn’t initiate contact with them.
The controller layer starts up the model layer, often fetches its routing map from the model and based on that loads the views required for the response and then sends the response back once the view has composed them. But there’s significant division of these tasks between several classes. A Dependency Injector has the business of loading classes, Page Controllers interpret user requests, Routers determine page controllers. There is no master “controller” class.
Views (not templates, and certainly not controllers despite the misconception) load data from models required to display whatever it is they are displaying. It’s the view classes that manage the template bindings to the data. A view class is not the same thing as a template or template engine (if you’re stupid enough to use one of those in PHP - but that’s a whole other rant).
One area of constant tripping is the instantiation of objects. This job goes to a Dependency Injection Controller, which is perhaps a framework’s most fundamental piece. These controllers abstract out the process of providing objects with their dependencies. These days they hash this out using PHP’s Reflection API and type hinting which allows objects to call out their needs in their __construct method. The configuration of this controller will determine if any given class is a singleton or not - if it is then it will pass a reference to that existing object to the newly started object, and if it isn’t a singleton it will start a new copy of the dependency for the new object.
A controller’s job in this setup isn’t as Paul incorrectly states “assign values to view template” - its job is to assign the models themselves to it. Views do not need and therefore should not know how to start new classes. However, they do know what models they need and will state those needs in their constructor. The Page Controller class that starts the view doesn’t and shouldn’t know what models the view needs, this is double coding and a waste. Instead the Dependency injector is the part of the control layer that provides the model to the view, and it does this according to the view’s construct arguments. The page controller itself has no role to play in this. Once the view starts it can ask its model for data.
This goes down the chain. Say the model class is for a table in the database. It will need a copy of the connection object to the database. Again, neither it nor the page controller know how to get this object, that’s on the dependency injector, and the dependency injector only knows to do this because of the model’s construct statement. The page controller may need the model for its own purposes, particularly to post data into it, but it doesn’t always need to do this. That’s why, unlike the model and view classes, it has a reference to the dependency injector itself and can arbitrarily request classes from the injector - something only classes in the control layer should be allowed to do.
The dependency injector is the lynchpin. An excellent one was written by Tom Butler who used to be a particularly vocal member of this board, though I haven’t seen him around lately…
That page goes into even more details on how dependency injection works.
So with all the above in mind, let’s re-examine program flow under MVC - the right way.
- Boot code loads the configuration, readies the Dependency Injection controller, and uses it to load the Router/Dispatcher.
- The router determines specific Page Controller required, loads it, and passes control to it. This may or may not involve invoking a specific method on the Page Controller, depending on the framework’s design.
- The Page Controller performs the actions of the request, particularly if its a post, and handles authentication and the like. If an error occurs the page controller for handling errors is loaded, otherwise the Page Controller loads the appropriate View.
- The View has its relevant models as part of its construct statement, so these will be provided to it by the Dependency Injection controller as it is created.
- The View queries its Models for the specific data needed to fulfill the user request provided to the view by the controller. It puts that data into the template and evals the template (or has a template engine parse it)
- The output of this step passes back to the controller, which hands it off to a response object.
- The response object sends the http headers and echos the response. Some frameworks may then pass program flow back to the dispatcher to handle caching and shutdown tasks before script termination, or the script may enter a wait state for the next user request if its designed for persistent connections.
The goal of any design pattern is to restrict and regulate the scope of each block of code’s responsibility, and how much each can talk to the others. Each layer has specific and limited lines of communication to the others in order to maintain testable code. However confusing these lines, as so often happens with MVC, or proceeding with an incomplete understanding of their intent can lead to redundant busy-box code which has the opposite effect of making the code harder to debug and more brittle to change.
Also keep in mind that, from a certain point of view, the PHP code is entirely a controller. The true model is the database engine. The view is the browser. Strictly speaking, the output of the PHP these days is also only a model - HTML documents are a model, CSS comprises the view by controlling the actual appearance and format of the data, and JavaScript are controllers in their own right that happen to execute client side. The server PHP provides pointers to the correct CSS and JS in the response, but it rarely actually loads them since they are static files. In some setups the PHP doesn’t even send HTML anymore, but instead sends a JSON object to allow JavaScript to compose the DOM. So PHP is in this case transforming the model data from one format to another and controlling the access to it. Currently the HTML structure has some control of the appearance of the data, but as CSS continues to evolve the structure of the HTML is becoming increasingly less significant to layout, particularly in browsers that support flex layouts that can reorder content blocks.
That said the divisions between areas of concern in a large PHP program remain useful so long as they are correctly understood and implemented.