#patterns
#mvc
#php
#master-in-software-engineering
Project using MVC Pattern without OOP. In this first approach, you will understand how the pattern works and implement it in a project created from scratch.
- Getting Started
- Dependencies
- Contents
- 1. Prepare the constants
- 2. Application entry point
- 3. Main Views
- 4. Controllers
- 5. Models
- 6. Views
- Resources
First of all, you will need to clone this repo:
$ git clone https://github.com/assembler-school/repository-name
When you're creating a MVC project from scratch it's very important to follow correctly the creation steps in order to understand the execution flow. That is why in this workshop we have detailed the steps to follow for a correct operation of the application:
In order to call dynamically all the CSS, JS and PHP files, we must configure our project constants that will be accessed during the execution of the application. These files will be located in
./config/
<?php
$documentRoot = getcwd();
//BASE PATH -> FOR REFERENCE FILES
define("BASE_PATH", $documentRoot);
//BASE URL -> FOR LINK CSS
$uri = $_SERVER['REQUEST_URI'];
if (isset($uri) && $uri !== null) {
$uri = substr($uri, 1);
$uri = explode('/', $uri);
$uri = "http://$_SERVER[HTTP_HOST]" . "/" . $uri[0];
} else {
$uri = null;
}
define("BASE_URL", $uri);
<?php
include_once "baseConstants.php";
//CONTROLLERS
define("CONTROLLERS", BASE_PATH . '/controllers/');
//VIEWS
define("VIEWS", BASE_PATH . '/views/');
//MODELS
define("MODELS", BASE_PATH . '/models/');
//RESOURCES
define("RESOURCES", BASE_PATH . '/resources/');
<?php
define('HOST', 'localhost');
define('DB', 'mvc_basics');
define('USER', 'root');
define('PASSWORD', '');
define('CHARSET', 'utf8mb4');
For this part, you will need to create your local database. In this project, we created a SQL file with all the basic operations. You just need to execute the db.sql file in your database manager.
All the user requests must be done in the entry point, we will use query params in order to indicate which controller and function must be executed.
First of all, we need to require once the previous created constants files.
<?php
include_once "config/constants.php";
include_once "config/db.php";
Then we create the logic to manage what controller and action is called in the query params.
if (isset($_GET['controller'])) {
$controller = CONTROLLERS . $_GET['controller'] . "Controller.php";
$fileExists = file_exists($controller);
if ($fileExists) {
require_once $controller;
} else {
$errorMsg = "The page you are trying to access does not exist.";
require_once VIEWS . "error/error.php";
}
} else {
require_once VIEWS . "main/main.php";
}
As you can see in the previous step, we had two default views, now we're gonna create them.
This is the main view that is loaded only if the user doesn't specify any controller or it doesn't exists.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
</head>
<body>
<h1>Welcome to MVC Pattern Basics!</h1>
<div class="list-group">
<a class="list-group-item list-group-item-action" href="?controller=employee&action=getAllEmployees">Employee Controller</a>
</body>
</html>
This view will be always loaded when the user specifies a bad parameter. As you can see, we print an error message that we will see in the last steps.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
echo "<h1>". $errorMsg ."</h1>";
?>
</body>
</html>
This are the PHP files that are called in the index.php file. Here we will implement the functionalities of each controller.
Before we start, we need to require the model, that will be responsible of calling the database queries to obtain or modify the information. We will create the model later.
<?php
require_once MODELS . "employeeModel.php";
Now, we know that this is the controller that the user wants to load, but we also need to know which function to execute.
$action = "";
if (isset($_REQUEST["action"])) {
$action = $_REQUEST["action"];
}
if (function_exists($action)) {
call_user_func($action, $_REQUEST);
} else {
error("Invalid user action");
}
We are going to create the getAllEmployees
function, as you can see, there is a get()
function that is not created yet, this is a function of the model that we will create in the following step.
/* ~~~ CONTROLLER FUNCTIONS ~~~ */
function getAllEmployees()
{
$employees = get();
if (isset($employees)) {
require_once VIEWS . "/employee/employeeDashboard.php";
} else {
error("There is a database error, try again.");
}
}
Also we create the error
function in order to load the error view when something goes wrong.
function error($errorMsg)
{
require_once VIEWS . "/error/error.php";
}
As we said before, the models are responsible of calling the database queries to obtain or modify the information.
In order to send queries to the database, we need to create the connection.
<?php
// Create connection
function conn()
{
try {
$connection = "mysql:host=" . HOST . ";"
. "dbname=" . DB . ";"
. "charset=" . CHARSET . ";";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => FALSE,
];
$pdo = new PDO($connection, USER, PASSWORD, $options);
return $pdo;
} catch (PDOException $e) {
require_once(VIEWS . "/error/error.php");
}
}
First, we must require the previous database connection file in order to execute the database queries.
require_once("helper/dbConnection.php");
In this model we will create the get
function that we are executing in the employeeController.php
.
function get()
{
$query = conn()->prepare("SELECT e.id, e.name, e.email, g.name as 'gender', e.city, e.age, e.phone_number
FROM employees e
INNER JOIN genders g ON e.gender_id = g.id
ORDER BY e.id ASC;");
try {
$query->execute();
$employees = $query->fetchAll();
return $employees;
} catch (PDOException $e) {
return [];
}
}
View are the frontend part of the MVC pattern. Inside them we should create all the necessary code to show the information to the user.
This will be the file that shows all the records of the database.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
</head>
<body>
<h1>Employee Dashboard page!</h1>
<style type="text/css">
</style>
<table class="table">
<thead>
<tr>
<th class="tg-0pky">ID</th>
<th class="tg-0pky">Name</th>
<th class="tg-0lax">Email</th>
<th class="tg-0lax">Gender</th>
<th class="tg-0lax">City</th>
<th class="tg-0lax">Age</th>
<th class="tg-0lax">Phone Number</th>
<th class="tg-0lax">Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach ($employees as $index => $employee) {
echo "<tr>";
echo "<td class='tg-0lax'>" . $employee["id"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["name"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["email"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["gender"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["city"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["age"] . "</td>";
echo "<td class='tg-0lax'>" . $employee["phone_number"] . "</td>";
echo "<td colspan='2' class='tg-0lax'>
<a class='btn btn-secondary' href='?controller=employee&action=getEmployee&id=" . $employee["id"] . "'>Edit</a>
<a class='btn btn-danger' href='?controller=employee&action=deleteEmployee&id=" . $employee["id"] . "'>Delete</a>
</td>";
echo "</tr>";
}
?>
</tbody>
</table>
<a id="home" class="btn btn-primary" href="?controller=employee&action=createEmployee">Create</a>
<a id="home" class="btn btn-secondary" href="./">Back</a>
</body>
</html>