Design Patterns, MVC
How does the PHP MVC works?
The MVC pattern is a software architecture that separates an application into three main logical
components: the model, the view, and the controller. Each of these components are built to handle
specific development aspects of an application.
MVC is one of the most frequently used industry-standard web development framework to create scalable
and extensible projects.
MVC pattern isolates the application logic from the user interface layer and supports separation of
concerns.
Here are the components of MVC pattern:
-
Model:
The Model is responsible for managing the data of the application. It receives user input from the controller.
-
View:
The View is responsible for displaying all or a portion of the data to the user. It receives data from the controller.
- Controller:
The Controller is responsible for responding to user requests. It receives input from the user and instructs the model and view to perform actions based on that input.
Why do we need to implement a PHP MVC?
Implementing MVC in PHP offers several advantages for web development:
-
Separation of Concerns:
MVC enforces a clear separation between the data management (Model), presentation (View), and application logic (Controller). This separation makes code more modular and easier to maintain.
-
Code Reusability:
Because MVC promotes modular code, you can reuse models, views, and controllers across different parts of your application. This reduces redundancy and leads to more efficient development.
- Scalability:
By structuring your application with MVC, you can easily scale and extend it. Whether you need to add new features, change the user interface, or optimize database queries, MVC allows you to do so without affecting other parts of the application.
- Collaborative Development:
When working with a team of developers, MVC simplifies collaboration. Team members can focus on specific components (Model, View, or Controller) without interfering with each other's work.
Creating the Directory Structure
The first step in creating an MVC application is to create the directory structure. The directory structure is the same for all MVC applications. The directory structure is shown in the following image.
The Public folder
The public folder contains the static file that can be seen by the user. The public folder contains the following files and directories.
PHP
#
Options -MultiViews
RewriteEngine On
RewriteBase /HERAFY/public
# Accept loading of actual -f files and -d directories
# It means that if the user type a valid file name or a valid directory name ==> just open it
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
# If the user type a non-valid file name or a non-valid directory name
# Send everything else to the index page
# and save the rest in url
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
# Except for these
# RewriteCond $1 !^(config|core|css|js|robots\.txt)
?>
Result
Htaccess is short for Hypertext Access. It is a configuration file used by Apache-based web
servers.
Configuration files configure the initial settings of a program or, in this case, the
server. This means that the .htaccess file can be used to make the server behave in a
certain way. Each function is just a line of text, or code, which tells the server what to
do. You can add or change functionality by adding or changing the code in the .htaccess
file.
You can find more information on how to use an .htaccess file here.
PHP
require_once("../app/core/init.php");
$app = new \app\core\App;
?>
Result
The index.php file is the entry point of the application. It loads the init.php file and
creates an instance of the App class.
PHP
User-agent : *
Disallow: /admin/
Disallow: /ajax/
?>
Result
The robot.txt file is used to tell the search engines which pages to index and which pages
not to index.
User-agent does not allow the search engines to index the pages in the admin and ajax
directories.
You can find more information on how to use a robot.txt file
here.
The assets folder contains the CSS, JavaScript, and image files.
The CSS folder contains the CSS files.
The JavaScript folder contains the JavaScript files.
The images folder contains the image files.
The App folder
The app folder contains the application code. The app folder contains the following files and directories.
Creating the PHP Router
The next step in creating an MVC application is to create the PHP router. The PHP router is used to
route the requests to the appropriate controller.
The PHP router is created in the index.php file or as a separate class then called from index.php.
PHP
class App
{
//Default class, method and parameters
protected $controller = 'Home';
protected $method = 'index';
protected $params = [];
// A function that loads the controller when an App is instanciated in index.php ---> $app = new App;
public function __construct()
{
$url = $this->parseUrl();
if (isset($url[0])) {
//concatenation to get the full path and check if the controller exists
// which is in $url[0]
if (file_exists('../app/controllers/' . ucfirst($url[0]) . '.php')) {
//Replace with a new instance of this->controller
$this->controller = ucfirst($url[0]);
// remove it from the array
unset($url[0]);
} else {
//if there is no page then route to 404 error
//require ('../app/controllers/_404.php');
$this->controller = "_404";
}
}
require_once('../app/controllers/' . $this->controller . '.php');
$this->controller = new $this->controller;
//check if the method exists
if (isset($url[1])) {
if (method_exists($this->controller, $url[1])) {
$this->method = $url[1];
unset($url[1]);
}
}
//check if the array exists else return empty array
$this->params = $url ? array_values($url) : [];
// The next line will call a function specified by $this->method
// which is in the class $this->controller
// and give it a set of parameters specified by$this->params
call_user_func_array([$this->controller, $this->method], $this->params);
}
public function parseUrl()
{
//It will split the url using explode with / as parameter
if (isset($_GET['url'])) {
return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
}
}
}
?>
Result
The App class is used to route the requests to the appropriate controller. For example, if the
user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The App class will route the request to the Home controller, the index method, and the 1
parameter.
The App class has the following properties.
controller: The controller name. For example, Home or About.
method: The method name. For example, index or show.
params: The parameters. For example, 1 or 2.
The App class has the following methods.
parseUrl: The parseUrl method is used to parse the URL. For example, if the
user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The parseUrl method will return the following array.
Array ( [0] => home [1] => index [2] => 1 )
rtrim: The rtrim method is used to remove the trailing slash from the URL.
For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1/
The rtrim method will return the following URL.
http://localhost/HERAFY/public/home/index/1
filter_var: The filter_var method is used to filter the URL. The
FILTER_SANITIZE_URL
filter removes all illegal URL characters from a string.
explode: The explode method is used to split the URL into an array. For
example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The explode method will return the following array.
Array ( [0] => home [1] => index [2] => 1 )
isset: The isset method is used to check if the URL is set. For example, if
the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The isset method will return true.
__construct: The constructor method.
ucfirst: The ucfirst method is used to convert the first character of the
string to uppercase. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The ucfirst method will return the following string.
Home
file_exists: The file_exists method is used to check if the controller
exists. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The file_exists method will check if the Home controller exists.
unset: The unset method is used to remove the controller from the array.
For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The unset method will remove the Home controller from the array.
require_once: The require_once method is used to load the controller. For
example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The require_once method will load the Home controller.
method_exists: The method_exists method is used to check if the method
exists. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/show/1
The method_exists method will check if the show method exists in the Home controller.
array_values: The array_values method is used to return all the values of
an array. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/show/1
The array_values method will return the following array.
Array ( [0] => 1 )
call_user_func_array: The call_user_func_array method is used to call the
method of the controller. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The call_user_func_array method will call the index method of the Home controller.
Creating the PHP Controller
The next step in creating an MVC application is to create the PHP controller. The PHP controller is
used to handle the requests and load the views.
The PHP controller is created in the app/controllers folder.
The PHP controller has the following methods.
view: The view method is used to load the view.
model: The model method is used to load the model.
PHP
require_once('config.php');
class Controller
{
public function view($view, $My_Data = [])
{
if (!empty($My_Data)) {
extract($My_Data);
}
$FilePath = '../app/views/' . $view . '.view.php';
require_once($FilePath);
}
public function model($model)
{
$FilePath = './models/' . $model . '.php';
if (file_exists($FilePath)) {
require_once('./models/' . $model . '.php');
return new $model();
} else {
//if there is no page then route to 404 error
require('../app/views/404.view.php');
}
}
}
?>
Result
The Controller class is used to handle the requests and load the views.
The Controller class has the following methods.
view: The view method is used to create the path to the view. It takes two
parameters. The first parameter is the view name. The second parameter is the data that will be
passed to the view. For example, if the user types the following URL in the browser.
http://localhost/HERAFY/public/home/index/1
The view method will load the Home view.
model: The model method is used to create the path to the model. It takes
one parameter. The parameter is the model name. For example, if the user types the following
URL in the browser.
http://localhost/HERAFY/public/home/index/1
The model method will load the Home model.
The Controller class is extended by all the controllers.
These controllers are in the app/controllers folder.
For example, the Home controller is in the app/controllers/Home.php file.
The Home controller extends the Controller class.
PHP
// This is a controller
class Contact_Us extends app\core\Controller
{
public function index()
{
$this->view('Contact_Us');
}
}
?>
Result
The Contact_Us controller is used to handle the requests and load the views.
The Contact_Us controller extends the Controller class.
The Contact_Us controller has the following methods.
index: The index method is used to load the Contact_Us view.
PHP
// This is a controller
class _404 extends \app\core\Controller
{
public function index()
{
$this->view('404');
}
}
?>
Result
_404.php starts with an underscore because class names cannot start with a number.
The _404 controller is used to handle the requests and load the views.
The _404 controller extends the Controller class.
The _404 controller has the following methods.
index: The index method is used to load the 404 view.
Creating the Views
The app/views folder contains the view files. The view files are used to display the data.
For example, the Home view is in the app/views/Home.view.php file.
These are what the user sees when they visit the website.
They are requasted by the controller and then displayed to the user.
To summerize, the user type the URL in the browser, the URL is routed to the appropriate
controller, the controller loads the view, and the view is displayed to the user.
PHP
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Error 404</title>
</head>
<body>
<h1>Error 400004</h1>
</body>
</html>
?>
Result
The 404 view is used to display the 404 error.
The 404 view is in the app/views/404.view.php file.
Creating the Models
The Model.php file is used to connect to the database.
The Model.php file is in the app/core/Model.php file.
The Model.php file has the following methods.
Execute_Querry: The Execute_Querry method is used to execute the querry.
Connect_To_DataBase: The Connect_To_DataBase method is used to connect to the
database.
Disconnect_From_DataBase: The Disconnect_From_DataBase method is used to
disconnect from the database.
PHP
trait Model
{
use DataBase_Connection;
// Tnside the trait Model we have to define the CRUD methods
// CRUD = Create, Read, Update, Delete
// This way we can use these methods just by providing the table name and data
// $My_Table = table name
public $My_Table;
public $My_Errors = [];
public function Single_Result($My_Data)
{
$keys = array_keys($My_Data);
$My_Querry = "select * from $this->My_Table where ";
foreach ($keys as $key) {
$My_Querry .= $key . " = :" . $key . " && ";
}
$My_Querry = trim($My_Querry, " && ");
print_r($My_Querry);
$My_Results = $this->Execute_Querry($My_Querry, $My_Data);
if ($My_Results) {
return $My_Results[0];
} else {
return false;
}
}
public function Search_For($My_Data)
{
$keys = array_keys($My_Data);
$My_Querry = "select * from $this->My_Table where ";
foreach ($keys as $key) {
$My_Querry .= $key . " = :" . $key . " && ";
}
$My_Querry = trim($My_Querry, " && ");
return $this->Execute_Querry($My_Querry, $My_Data);
}
public function Insert($My_Data)
{
$keys = array_keys($My_Data);
$My_Querry = "insert into $this->My_Table (" . implode(",", $keys) . ") values (:" .
implode(",:", $keys) . ")";
print_r($My_Querry);
$this->Execute_Querry($My_Querry, $My_Data);
return false;
}
public function Update($id, $My_Data)
{
$keys = array_keys($My_Data);
$My_Querry = "select * from $this->My_Table where ";
foreach ($keys as $key) {
$My_Querry .= $key . " = :" . $key . " && ";
}
$My_Querry = trim($My_Querry, " && ");
$this->Execute_Querry($My_Querry, $My_Data);
return false;
}
public function Delete($My_Data)
{
$keys = array_keys($My_Data);
$My_Querry = "delete from $this->My_Table where ";
$this->Execute_Querry($My_Querry, $My_Data);
}
}
?>
Result
The app/models folder contains the model files. The model files are used to get the data from the
database.
For example, the Home model is in the app/models/Home.php file.
PHP
class Account_User
{
use Model;
public function Verify_My_Data($My_Data)
{
$this->My_Errors = [];
if (empty($My_Data['ism'])) {
$this->My_Errors['ism'] = "الرجاء ادخال الاسم";
}
if (empty($My_Data['laqab'])) {
$this->My_Errors['laqab'] = "الرجاء ادخال اللقب";
}
if (empty($My_Data['mostakhdim'])) {
$this->My_Errors['mostakhdim'] = "الرجاء ادخال اسم المستخدم";
} elseif (!filter_var($My_Data['mostakhdim'], FILTER_VALIDATE_EMAIL)) {
$this->My_Errors['mostakhdim'] = "الرجاء التأكد من اسم المستخدم";
}
if (empty($My_Data['kalimat_sir'])) {
$this->My_Errors['kalimat_sir'] = "الرجاء ادخال كلمة المرور";
}
if (empty($My_Data['Re_kalimat_sir'])) {
$this->My_Errors['Re_kalimat_sir'] = " الرجاء ادخال كلمة المرور مره اخرى";
}
/*
if($My_Data['Re_kalimat_sir'] != $My_Data['kalimat_sir'])
{
$this->My_Errors['Re_kalimat_sir'] = "كلمة المرور غير متطابقة";
}
*/
if (empty($this->My_Errors)) {
return true;
}
return false;
}
}
?>