📖 MVC (Model View Controller) Design Pattern
Web sites and apps can be designed using a variety of different approaches. Some web sites can be created using simple, static HTML/CSS code while others require a more dynamic presence attempting to provide a more enriched and personalized user experience. In order to accomplish this goal, the web app must have additional elements to provide the enhanced experience. Often these enhancements require the use of a database to provide a storage for the myriad content for the user.
These enhanced sites can quickly grow in size and complexity resulting in additional technical challenges with content management and site security. Maintenance and site updates can also become problematic. This is sometimes referred to as spaghetti code, where the code base becomes difficult to read and maintain. MVC is a design pattern that was developed to help improve site maintenance and security for these more complex data-driven sites.
The Pattern
MVC (Model View Controller) is a design pattern that attempts to separate the code base into functional elements. Web sites are basically a repository of files where a server receives an HTTP requests from visitors and then returns a response with the appropriate HTML page. When these pages are designed to be more personalized with content, the resulting HTML response is no longer static. It is dynamically produced on demand often with content acquired from a database storage. This means there are 3 essential duties of a dynamic web site.
Essential Duties
- Receive and process requests.
- Access database content as needed.
- Return the formatted HTTP response.
These duties constitute the 3 main responsibilities of the MVC pattern where the Controller is responsible for receiving and processing requests, the Model is responsible for accessing data from the database and returning the result set to the controller and the View is the formatted HTML page that is used to return the formatted response.
Typical Single File PHP Page
Let's return for a moment to a typical single file PHP page where all the elements necessary to receive the request, acquire the data from the database and assemble the HTML response. Here is the code for that.
Original index.php File
<?php
$dsn = "mysql:
host=localhost;
dbname=adv_php;
charset=utf8;
port=3306";
$pdo = new PDO($dsn, "adv_php_user", "secret", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$stmt = $pdo->query("SELECT * FROM `products`");
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Products</title>
</head>
<body>
<h1>Products</h1>
<?php foreach ($products as $product) : ?>
<h2><?= htmlspecialchars($product["name"]) ?></h2>
<p><?= htmlspecialchars($product["description"]) ?></p>
<?php endforeach; ?>
</body>
</html>
When using this code in connection with an appropriate database, the output can be assembled from one page of code. This is fine for a small site with few pages, but once the site grows in complexity requiring several pages and related db tables, it can become unwieldy to update and maintain. Let's see how we can break this into the MVC components.
The Model
First let's remove the code that deals with the database connection. This is normally done using OOP classes to create a class that handles the data request.
Create a file called model.php to hold the class. In the model.php file, create a class called Model.Inside the Model we need to create the public getData()
function (method) to manage the db connection and query the db.
Note that class names are in StudlyCaps
and the method names are camelCase.
Cut and paste the db connection from the original index.php file to the Model class.
New model.php File
<?php
class Model
{
public function getData(): array
{
$dsn = "mysql:
host=localhost;
dbname=adv_php;
charset=utf8;
port=3306";
$pdo = new PDO($dsn, "adv_php_user", "secret", [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
$stmt = $pdo->query("SELECT * FROM `products`");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
The View
The next thing we can do is to remove the view from the original index.php file and place it in its own view.php file. Create a view.php file then cut and paste the HTML portion of the original index.php file. We do not need to create a class for the view.
New view.php File
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Products</title>
</head>
<body>
<h1>Products</h1>
<?php foreach ($products as $product) : ?>
<h2><?= htmlspecialchars($product["name"]) ?></h2>
<p><?= htmlspecialchars($product["description"]) ?></p>
<?php endforeach; ?>
</body>
</html>
The Controller
Next, we will create the controller to process the request. It will need to create a new Model object from the Model class, run the getData()
method to retrieve the db result set, then include the HTML view from the view.html file.
New controller.php File
<?php
class Controller
{
public function index()
{
require "model.php";
$model = new Model;
$products = $model->getData();
require "view.php";
}
}
Notice that the controller first requires the model.php file so the Model class and related getData()
method can be called. A new Model object is created and assigned to the $model
variable. Then the getData()
method is called from the $model
object. This will return the result set from the database and store it in the $products
array variable.
The index.php File
The index.php file is not deleted from the process. It is still the file the server will look for as the default file for HTTP requests. We use this file to instantiate the Controller and call the index()
method.
<?php
require "controller.php";
$controller = new Controller;
$controller->index();
Now the server will receive the request, and open the index.php file. The index.php file will create (instantiate) a new Controller object from the Controller class and call the index()
method which then instantiates a new Model object from the Model class to call the getData()
method. The Controller then passes the data result set to the view.php file end returns the response to the client.
This is a lot of work for a small return, but it will be well worth the effort in a large site.