For example, it’s very straightforward to have an index.php controller be a procedural script like so:
<?php //include classes and functions //get some data from the database //and/or process a form submission //render HTML using your template system ?>
Then I can just navigate to http://example.com/index.php and the above procedural script is essentially acting as a simple controller. Here the controller mechanism is a basic procedural script.
How then do you make controllers classes instead of procedural scripts? Must the controller class always be tied to the routing mechanism?
No, I don’t think an Object Oriented controller in such as scenario necessarily needs to be tied to the routing mechanism. You could use Facade or Command patterns to call a controller without it (the controller) ever knowing the details of that call (or, more precisely, without having the controller object know more than it needs to about the call).
IMHO the advantage of passing for procedural controllers to Object Oriented ones doesn’t necessarily lie just in how well it can be isolated from the rooting part, but more in how you can more easily reuse and organize those OO controllers as opposed to procedural ones. What’s the rough estimate of the percentage of similar behavior that all your procedural controllers have between them? You could put all that into one “base” OO controller, and then re-use it via inheritance or composition (preferably, the latter) to pass that common behavior to all your other controllers, without having to duplicate it each time in the code (or cross-importing the procedural scripts one in-to the other).
==== update
As per the comment below, here’s an example inspired from Spring Framework’s old (v2) MVC module:
- one or more router objects. The router object(s) are configured with URL patterns and the corresponding controller objects for each pattern. This way, when the router is hit by a request (which matches a certain URL pattern), it will create an object with that request’s parameters (here you can but as many or as few details on the actual request as you like) and call the corresponding controller object passing him the request object
This way you have your controller not only isolated from the low level details of the request, but from the rooter as well (they communicate via an intermediate requet object, neither cares how it was produced or consumed, respectively)
-
multiple controller objects which map to one or more URL patterns each. Usually you’ll create an interface for the controller and that’s the only thing the router will know about each controller. Then you implement that interface into actual controllers according to each business need. Here you’ll take the most advantage of OO, as you can encapsulate common behavior into an Abstract controller class which you can then extend for certain controllers, etc
-
finally you’ll have one or more view resolver objects. These will be used by the controllers to know what view to show once they do their processing and create a model object. The view resolvers simply associate either URL pattern(s) or controller(s) to views.
-
as said earlier the controller will produce a model object. This guy will contain all the necessary data so that the view can update itself for the given action/workflow
Final considerations
-
according to what definition of MVC you embrace, this may or may not be a kosher implementation of the paradigm. In some MVC definitions it is said that the view has some kind of hooks or callbacks in the model such that when the model changes the view updates itself automatically, in other words, all the controller has to do is change the model and not worry about the view. In other definitions the view needs to be notified by the controller that the model has changed in order to update itself. You can go either way, usually to implement the first version, you’ll need some JavaScript library to help you with that. If you wanna steer clear clear of JS you can just implement the second version, and just refresh the view (via controller) when the model changes.
-
make sure to keep your model, view and controller objects cleanly separated (as much as possible). The controller should only get the necessary request data, and construct the model accordingly. If going from request data to model is complicated, make separate service objects that deal with it and just have them return th model to the controller so that it can pass it to the view (and notify it if necessary). The controller only deals with getting input data and passing the model to the view. The model should be super dumb, no business logic or anything like that in it. It should just hold the data for the view. The view itself should only be concerned with presentation, i.e. with formatting the data for the user, not with business logic or other heavy treatment of the model data (the model should contain the final data to display).
4