MVC dilemma
This article was written by nemetral.
Voices matter! Please feel free to share your opinion, ask for more explanations or point out divergences using comments.
No time to read this now? Bookmark it and come back later..
The most interesting questions often arise after theory has been explained, when getting hands dirty trying to write some code, organize and design a software architecture or start compiling existing snippets into a comprehensive framework. Following my posts on MVC (see and digg the “A gentle introduction to MVC” series: Part 1, Part 2 and Part 3), a reader recently asked me a couple of questions related to common MVC implementation issues.
I had a couple of questions with respect to your articles on gentle introduction to MVC. I *really* want to understand MVC. I have little experience with web development, so the things that I develop look “okay” on the surface, but they are messy underneath. I read so much about MVC that confused the heck out of me but then I finally came across your simple intro, and I think it’s a really nice start for me. If you wrote a book about more on the concept, I’d be the first to buy it. I think that I understand the general idea, but I think I’m having a tricky time with implementation. I would *really* appreciate if you could answer a couple of questions..
1. Mapping between controllers and models:
As part of a lab booking system that I’m working on, one screen handles the showing of existing bookings, addition of new bookings, and deletion of bookings. I call it “SAD” (show, add, delete). I’m having trouble with the SAD controller and SAD model. In my test “router”, I call the SAD controller if I see (through POST) the need to show/add/delete bookings. The SAD controller instantiates the SAD model .. it’s not quite clear if there’s always a one-to-one mapping between a view, controller, and model or whether my concept of a SAD controller and SAD model right from the get-go isn’t correct?
MVC is to be understood as a general guidance regarding code decoupling and organization. As such, there is no strict MVC rule requiring to map certain controllers to certain models. MVC can be implemented in various ways: the diversity of existing frameworks is certainly the best evidence of it. Back to your question: your concept of one SAD controller and one SAD model is right. I wouldn’t call it “SAD” though but rather “Bookings”, because the “SAD” operations can be executed on many different types of data (blog posts, users, images etc.): I personally always call controllers and associated models by the type of data they represent (as many other CodeIgniter hackers do) knowing that similar operations will be executed on them all (what you call “SAD”, which is by the way usually dubbed as CRUD for Create, Read, Update and Delete). Concerning the router: I usually prefer to rely on GET variables rather than POST variables (see my post about REST), i.e. configure the router so that it loads the controller when specific URLs are called. Both my controller and model are objects: for my controller, the object’s name would here be Bookings and each action I can undertake would be a method in my object. Here is some sample code for the object’s structure:
<?php
class Bookings
{
public function add()
{
// code goes here
}
public function edit()
{
// code goes here
}
public function delete()
{
// code goes here
}
}
?>
Each one of these methods would be bound to a specific URL:
- the add method would be bound to http://example.com/bookings/add
- the edit method would be bound to http://example.com/bookings/edit
- the delete method would be bound to http://example.com/bookings/delete
The router’s job is to effectively bind the URLs to the correct controller and methods (see some code snippets in Part 3 of my MVC series of post). Some methods may require a model, some other may not: this is why it is a good practice to instantiate the model from the called method of the controller. Say the add method requires the Bookings model, then I would instantiate it inside the method. Concerning the view, there will certainly not be a one-to-one mapping between the Bookings controller and the Bookings view: I need a specific view with a HTML form to add bookings, another one with another form to edit existing bookings but I don’t need a view for bookings deletion. These views can be seen as “sub views” (only the HTML forms) which can in turn be embedded into a more general view called a layout. To summarize, I would have a Bookings controller instantiated by the router, a Bookings model instantiated within the controller’s methods (if needed), a Bookings HTML layout (containing the <head> and most of the <body> tags) and several sub views inserted inside the layout depending on the controller’s method called.
2. User authentication
Now, let’s say that I want to add a booking - that is, a user types a booking name onto the SAD (view) , and clicks the “NEW” button. Is it the SAD controllers job to determine whether the user has access to write the booking or not and then to pass the request on to the SAD model for the actual write? Right now, $_SESSION['access'] has that detail, and the controller checks it, but I don’t know if that’s right. When it comes to actually writing the booking — the SAD model just uses a PHP class called “booking” that abstracts the booking idea (XML files for bookings). However, do I need to have a stub function for the “write()” call from class Booking in the SAD model class so that the controller can call it without having any understanding about the details of how a booking is stored?
Checking whether a user is allowed to interact with data is indeed part of the controller’s job, so what you’re doing there is perfectly in line with MVC principles. First the router maps a URL to a controller and a specific method; then the called method will find who the user is, what he can or can’t do and will therefore allow him to perform a specific action or not. If the action requires interaction with data, then the controller will delegate the task to its model (which in turn will typically be an object with methods like add(), edit(), delete() etc.). Either the model’s methods directly call the database and perform the action, or you can insert another layer of abstraction and further delegate the job to a specific class so that you can easily switch storage support (database, XML files etc.) later on for example. So the answer is: it mainly depends on the complexity of your project. Either you know you’ll stick to XML files and you can directly write the code in the model’s methods, or you’re not sure about it and call a third-party library to handle it.
3. Designing methods in the controller’s object:
I then have another class called “BookingDatabase” which knows how to see a list of all bookings, check if one exists, etc. If I want to check if a booking exists in the SAD controller before I call the “add booking” function in the SAD model, do I need to have a stub for the “exists” function from the BookingDatabase class in the SAD model as well so that the controller can check if a booking exists before writing it?
Now, let’s say I have another screen — the “EDIT” screen. I would then have an EDIT model and an EDIT controller — but this would need to write bookings as well — would the “edit” model then need to have it’s own stub of the booking classes write function?
Assuming that it makes sense to have an add_booking function in the SAD model — does it make sense to have one in the controller as well? The one checks that the user has access to write the booking, that the booking doesn’t already exist, that the booking name is valid (using functions from the model) and then calls the add_booking function from the SAD model to write the booking?
According to the structure I previously suggested, the edit action should be handled by the Bookings controller together with the Bookings model. So the edit feature would be implemented as a method in the Bookings controller, bound to a specific method in the Bookings model in charge of effectively editing the selecting records (through a third-party library or not). This method would call the main layout of the application but would insert a specific view in it: the edit view containing the HTML form. The other point you raise here is correct: you can check if a booking already exists in the Bookings controller by calling a specific method in the Bookings model. And the whole process you describe concerning the add_booking function is perfectly in line with MVC principles too.
4. Enhancing the views
A couple of my views have a couple of small associated javascript functions. Where do they go? Do they remain in the view? I’ve stuck them in the “controllers” directory in a separate .js files, added them to the view files.
Views are basically HTML files, and as such they can be enhanced with CSS and JavaScript. So these external sheets should be located in the same directory than the views. That said, this kind of organization depends on the framework you’re working with: with CodeIgniter, views are located far away in the arborescence and it’s a pain to insert CSS and JavaScript sheets, so I usually relocate them just one folder away from the root. As they can be located anywhere, it’s better to choose a folder close to the root as it’s easier to call them from the HTML views.
Conclusion
Almost everything I know in computer science was learnt the hard way (trial-and-error) or by reading tutorials or forums where hackers kindly explained stuff down to implementation details. Now that I have some experience and background in the industry, I am particularly glad to share what I know with you all. Don’t hesitate to send me questions and I shall publish an answer that will surely be useful to everybody.


17
November 25th, 2008
1:57 am
I too had an issue about how much processing code to do in the Controller and now all is done via Models and Views just include variables with results.
Great posts!
November 25th, 2008
5:51 am
Could you suggest a solution to an MVC pattern?
I have a Router that loads an appropriate Controller and want to build a CMS (dynamically created views) on my framework. Do I create a new Model that will load an appropriate page as requested (which is what Router is doing)? Or create a new Router invoked on specific Controllers?
November 25th, 2008
9:27 pm
@Radek: I actually would suggest you to keep the Router at the very beginning and then load the appropriate method of the Controller. Say you want to edit the Posts page, then your initial Router would load the “Edit” method of Controller “Posts” which in turn would call the “Posts” Model’s method to retrieve information from database and then display it in the “Posts Edit” View.
November 26th, 2008
2:53 am
@nemetral: Thanks for the helpful comment, I do that for actions that I know will be included, but what about pages that I create dynamically and thus don’t know their name?
Right now it works this way:
2) Router launches blogController
1) blogController connects to articlesModel::getRequestedArticle()
2) articlesModel::getRequestedArticle() figures out the route requested ($_GET['route']) and returns $article back from the database (db::query())
3) blogController now decides whether to launch index() function or private article($article) function.
Is this ‘proper’?
November 27th, 2008
1:43 am
@Radek: you’ve correctly broken down the whole process. The only thing I would change would be to make blogController check the $_GET['route'] variable and include this variable as an argument to articlesModel::getRequestedArticle(). Once you get the data pulled out of the database through the Model and back to the Controller, you can decide which View to call.
November 28th, 2008
1:38 am
@nemetral: Perfect, thank you!
December 5th, 2008
12:47 am
Hi:
First of all, thanks for all the tutorials. This is by far the best tutorial I have read on MVC because you explain things by steps and explanation is detailed too. Thanks.
What I don’t understand is, say, in above example we needed to also display “last 5 visited pages” for the logged in user.
Lets say that user is in booking/view. Then how do I show that list of visited pages?
Should I leave it to View (Mine is View class which calls template) to decide? Or should I put that in controller?
Then further problem can be if, say, right side bar needs to have some data (user’s booking list) which is specific to that page (controller?) and then some data which is generic regardless of the page (list of 5 users).
As you can see, I have confused my self to a point where even I can’t understand me.
Please suggest.
December 5th, 2008
9:43 pm
@Jaswinder: pure MVC suggests you to make the Controller control everything. In your case, your Controller should identify the logged-in user and call a method in the Model to retrieve his last 5 visited pages. The Controller then collects the list and passes it along to the View which in turn displays it in the template along with the whole content of the page. Same for your second point: basic MVC suggests that your Controller should handle both page-specific and non page-specific data and pass it along to the View. Still, in order to make your architecture more flexible, you can create libraries and helpers focused on specified (repetitive) tasks, these libraries and helpers being called by Controllers, Models and Views. Also, have a look at partials and components as featured in Symfony framework: they allow you to isolate specific chunks of code from the whole MVC organization and avoid rewriting the same code again and again.
December 5th, 2008
10:46 pm
Thanks nemetral.
I read that. I like the idea of partials and components. However, wouldn’t it be a good idea to be able to reuse that code?
For Example, if I have news model, I can put that function there. I can then use that to display headlines in, say, news/view or on sidebar. I can maybe call it in a different controller, say, archive/2008. To display headlines on the sidebar in that page, I may call my model like
$newsModel = new Model_News_Wrapper();
$news = new Model_News($news->getHeadlines($limit));
$this->template->headlines = $news;
I am not contradicting you but I am just wondering if above design will and if it’ll be flexible in future situations.
Also, about wrapper and class, I am not sure if I am going the right way but I want to use model class to store the information retrieved from model wrapper.
Thanks again for your time.
December 6th, 2008
12:02 am
@Jaswinder: partials and components are precisely aimed at being reused (like plain inclusion in PHP); same for libraries and helpers. The difference is that libraries can help you lighten the code in Controllers whereas partials and components slightly move away from MVC (since you embed chunks of logic directly inside the templates). Regarding your question on wrappers, I actually use the class in itself as a wrapper for methods: each method from the Controller class calls one or several methods from the Model class which return results. I give further details on that point in A Gentle Introduction to MVC.
December 6th, 2008
3:58 am
@nemetral
I did read that and all other tutorials you wrote. Thanks for those BTW. They helped a lot as I was getting confused with all other tutorials.
I see your point. The reason I asked was, I saw somebody creating 2 classes (other than controllers). One to get results from class and other to use those results under the similar context (User::Firstname, User::Lastname; but information is retrieved via UserMapper and User class initialized). I was just wondering if that is just another designer specific approach or MVC related.
With my example in last post (headlines), I wanted to say that if I wrote that heading function in News Model, then I could use same function for components or to display headings for main news page. If I use it as component then wouldn’t I’d be duplicating the work? Unless you are are calling News Model from component function.
As you can see, I am confused a bit on this issue and tried to search it in many places. You are the first to answer me and give that link to Symfony.
I think I am treating this comment section as forum post, but I was hoping that if I get my answer here, it may help somebody else too.
Thanks again for your answers and tutorials.
December 6th, 2008
11:22 am
@Jaswinder: components are small spicy extras to the classic MVC architecture and of course they can load a specific method from an existing model. MVC wants you to separate logic from presentation, but does not prevent you from reusing a same model in different controllers or components. You can imagine a MVC architecture with as many controllers as “data types” need to be treated (posts, comments, users etc.) all linked to a unique model which would gather all the queries. Or, as I do, you can split the controllers by sections of the website and attach a model to each one of these controllers, the redundant code being placed in shared libraries (like models but shared among controllers). Each MVC framework has its own vision about how your webapp should be structured, and my vision is greatly influenced by CodeIgniter.
December 6th, 2008
6:35 pm
@nemetral
That clears it up. Thanks a lot for taking your time and clarify this.
I have started looking at CodeIgniter after your tutorials. It seems like a good one to me.
I was thinking to design one of my own, just to get some practice, but I think I am going towards same direction as CodeIgniter, so I’ll use it. No need to re-invent wheels.
Thanks again for clearing this and all the tutorials. It helped.
March 18th, 2009
10:33 pm
This is by far the best MVC introduction I have ever seen. I have looked around, bought a book on design patterns; but this beats all! I love the fact that you actually keep it simple - us newbies just want an easy to understand explanation and a basic working example that just shows the basic three parts of a MVC framework. It has really helped me out. Thanks a million!!!!
April 16th, 2009
11:40 pm
I really liked your introduction a lot. I have a question regarding controller bloat. How do you keep your controllers from getting loaded with many different functions that may not have anything to do with each other. It’s easy to see a one controller per model relationship when your doing simple CRUD operations. But when the domain gets more complicated, how do you make the decision to break up controllers beyond one per model. Also, from what I’ve gathered reading about MVC, it seems to suggest that a one controller per view method may be better if you want to keep things simple and fast. What do you think?
April 24th, 2009
11:53 pm
@Lee: in the MVC pattern, the Controller is here to organize everything i.e. process the request arguments, launch the Model, reorganize the data and call the View. Controller bloat is indeed quite common. I personally do not mind to bloat my Controllers as long as the code remains readable. But if you mind it, the solution would be to abstract common procedures or data treatment into Libraries (again, I’m thinking to CodeIgniter which allows you to do all that in a simple and efficient way). Libraries allow you to encapsulate some procedures which not purely data-related (these are Models) into separate objects and methods. Say your Controller needs to randomly match pairs of names extracted from your database (through the Model), you could spare a few lines of code from your Controller code by writing it into a Library and then simply call this Library from within your Controller.
June 1st, 2009
3:26 pm
Thanks for Sharing Your Knowledge. Its very helpful
Thanks
Perochak