Understanding MVC
- Understanding MVC: The Basics
- Understanding MVC: Framework Conventions
- Understanding MVC: Coding
In the [intlink id=”453″ type=”post”]first part[/intlink] on this series about the MVC (Model-View-Controller) design pattern, I discuss the individual parts and what they represent. In the [intlink id=”505″ type=”post”]second part[/intlink], I layout some common conventions of MVC frameworks. Both of those posts lead up to this one, in which I want to talk about actual code. In my opinion, it’s not too hard to understand what MVC means, in theory, or to follow a framework’s naming rules, but then you start developing a project and can quickly become confused as to where you actually put your code.
The problem in properly executing the MVC architecture for many people is that it runs contrary to what they’ve done thus far. If you’re a PHP programmer creating a page that lists every department (in an employees-departments application), you’d likely have a PHP script that:
- Generates the initial HTML, including the HEAD and the start of the BODY
- Connects to the database
- Queries the database
- (Hopefully) confirms that there are query results
- Retrieves the query results in a loop
- Prints the query results within some HTML, perhaps a table or a list
- Frees the query results and closes the database connection (maybe, maybe not)
- Completes the HTML page.
And that’s what’s required in a rather basic page. Even if you use included files for the database connection and the HTML template, there’s still a lot going on. And if you link those department pages to another page that shows more information about the department, passing along the department ID in the URL, that other page will need to add some data validation steps. And if you have a page that both displays and handles a form, like for adding an employee, there’s way, way more code and logic to add. Not that there’s anything wrong with this, mind you—I still program this way as warranted—but it’s the antithesis of what MVC programming is about. You can think of MVC programming like a pyramid, with the Model at the bottom, the Controller in the middle, and the View at the top. The code should be distributed appropriately, with most of it in the Model, some in the Controller, and very little in the View.
From a programming standpoint, a View should do very little, mostly just echo out the values of variables. The most logic a View should have is using a conditional to confirm that a variable has a value before attempting to print it or creating a loop to print out all the values in an array. The View generates what the user sees, that’s it. The Controller has more logic and code to it, as it responds to user actions, and acts as an interface between Models and Views. But it’s a common mistake to put code in a Controller that should really go in a Model. A guiding principle of MVC design is “fat model, thin (or skinny) controller”. This means you should keep pushing your code down to the foundation of the application (aka, the pyramid’s base, the Model). In a post I saw about the MVC architecture, they describe the Model as “maintaining state” between HTTP requests. I think that’s a good way of describing it because it encompasses both stored data and processed data that doesn’t necessarily get stored. So a departments Model represents stored data that is added, updated, and retrieved in multiple requests, while a contact Model represents data entered by a user in a form, validated, and sent in an email.
(As a a complete aside, there are some very well done, very funny videos on MVC available at RailsEnvy.com. In particular, watch the ones called “Controller Obesity” and “Keeping Views Stupid”.)
So what does this mean in actual code? Well, to start, if your View contains more than echo/print, and the occasional control structure, you’re possibly doing something wrong. If you’re creating new variables in a View, you’re probably doing something wrong. In fact, so little PHP code goes into a View, that even printing out something in a loop is normally done like this, with the emphasis on the HTML:
<?php foreach($departments as $n=>$dept): ?> <li><?php echo $dept->something; ?></li> <?php endforeach; ?>
This is opposed to what one might do in a common PHP approach, with the emphasis on the PHP:
<?php foreach($departments as $n=>$dept) { echo '<li>' . $dept->something . '</li>'; } ?>
Now the code in the Controller is largely about…um…controlling the action, i.e., delegating responsibilities and reactions, responding to user input, etc. Controllers are classes, filled with methods that do the actual work. The work is largely retrieving specific Models (e.g., one record from a table or every record), calling upon a Model to be inserted, updated, or deleted, and calling upon a View to be rendered. The Model does everything else, like running the actual queries, validating the data, and so forth. However, in a framework, most of that code is built into the framework itself, so you can call a save or delete method on a Model, but the Model itself doesn’t have any such method defined (the Model inherits those methods from a framework class on which it’s derived).
Going back to an employees-departments example, say you want the page that lists the departments to also display each department head’s name. Presumably the employee ID of the person that is the department head would be stored in the department Model, like employee #14 is the head of Human Resources. To start, the Controller retrieves all the departments using that Model (this is Yii framework syntax):
$departments = Departments::model()->findAll();
The $departments variable gets passed along to the View so it can print them all out. This is basic MVC using Yii where, again, the departments Model doesn’t actually define a findAll() method, it just inherits one.
Now you also need to find the department head’s name for each department so that the View can display that. To find that person’s name, you’d need to fetch an employee Model whose employee ID matches the stored ID in the department Model. Using the Yii PHP framework, that code is
$emp = Employees::model()->findByPk($dept->departmentHeadId);
There you’re saying that you want to find the employee Model whose primary key value is the same as the departmentHeadId value in a given department Model.
What you absolutely don’t want to do is run that code or any similar query in the View. Very bad! Now, you might be inclined to put that code in the Controller, but in order to do that, you’d need to loop through each retrieved department, fetch the departmentHeadId, find the employee with that primary key value, and then associate the retrieved info with the department. Or you could retrieve all the employees and have the View find the corresponding employee record. In either case, it’s way too much code and logic to be outside of the Model.
To be clear, Yii, and other frameworks, support joins across Models, so in Yii, you’d do this (after identifying the relationship between the models):
$departments = Departments::model()->with('employees')->findAll();
But if that wasn’t an option in your framework, or if the two Models didn’t have a real, defined relationship, you could add this method to the department Model:
function getDepartmentHead() { $emp = Employees::model()->findByPk($this->departmentHeadId); if ($emp) { return "$emp->lastName, $emp->firstName"; } else { return 'unknown'; } }
Once this is defined, you still wouldn’t need to add any code to the Controller, you could just do this in the View, within the foreach loop:
echo $dept->getDepartmentHead;
As another example, say you want to display employees names in the format LastName, FirstName, or something more elaborate. If you write a method that does that, defined in the employees Model, you can call that method anywhere that uses an employees Model and that might require showing the person’s name. This would include the page that lists all employees, the page that shows the information for just one employee, and the page that shows the head of a department. For example, in the above getDepartmentHead() method, you could return $emp->getFormattedName().
Whew! So, per my usual habits, this post has become far longer than I expected. I hope that I achieved my goal of explaining MVC using real-world examples, in a way that illuminates and clarifies this approach. If I haven’t, let me know and I’ll expand upon this in a subsequent post. As a postscript, a few hours after originally posting this, I touched up the last few paragraphs, adding more code to better illustrate the point (perhaps).