
As you may have guessed from the title of the article, today we will discuss the most popular
MVC design
pattern , after
Singleton , although such a comparison is not entirely appropriate. Understanding the concept of MVC can help you in refactoring and resolving unpleasant situations in which your project may have fallen. In order to fill the gap, we implement the MVC pattern on the example of a simple business card site.
Table of contents
Introduction1.
Theory1.1.
Front Controller and Page Controller1.2.
URL Routing2.
Practice2.1.
Implementing a URL Router2.2.
Back to the MVC implementation2.3.
Implementing the Model and Controller descendant classes, creating View's2.3.1.
Create a homepage2.3.2.
Create a page "Portfolio"2.3.3.
Create the rest of the page3.
Result4.
Conclusion5.
Selection of useful links on a subjectIntroduction
Many are starting to write a project to work with a single task, without implying that it can grow into a multi-user control system, well, let's say, content or God forbid, production. And everything seems to be cool and cool, everything works until you begin to understand that the code that is written consists entirely of crutches and hardcodes. The code is intermingled with the layout, requests and crutches, sometimes not even readable. An urgent problem arises: when adding new features, you have to mess around with this code for a very long time, remembering “what was written there?” And curse yourself in the past.
')
You might even have heard about design patterns and even flipped through these beautiful books:
- E. Gamma, R. Helm, R. Johnson, J. Vlissidesses “Object-Oriented Design Techniques. Design patterns ";
- M. Fowler "Architecture of corporate software applications."
And many, not afraid of the huge manuals and documentation, tried to study any of the modern frameworks and faced with the complexity of understanding (due to the presence of many architectural concepts cleverly linked to each other) put the study and application of modern instrumentation into the "long box".
This article will be useful primarily for beginners. In any case, I hope that in a couple of hours you will be able to get an idea of the implementation of the MVC pattern, which underlies all modern web frameworks, as well as get “food” for further reflection on how to do it. At the end of the article is a selection of useful links that will also help you figure out what web frameworks consist of (besides MVC) and how they work.
Flared PHP programmers are unlikely to find in this article something new for themselves, but their comments and comments on the main text would be very useful! Because without theory, practice is impossible, and without practice, theory is useless, then first there will be a bit of theory, and then we move on to practice. If you are already familiar with the concept of MVC, you can skip the theory section and go straight to the practice.
1. Theory
The MVC pattern describes a simple way to build an application structure, the purpose of which is to separate business logic from the user interface. As a result, the application is easier scaled, tested, maintained and, of course, implemented.
Consider the conceptual diagram of the template MVC (in my opinion - this is the most successful scheme of those that I have seen):

In the MVC architecture, the model provides data and business logic rules, the view is responsible for the user interface, and the controller provides the interaction between the model and the view.
A typical workflow of an MVC application can be described as follows:
- When a user visits a web resource, the initialization script creates an instance of the application and launches it for execution.
This displays the view, say the main page of the site.
- The application receives a request from the user and determines the requested controller and action. In the case of the main page, the default action ( index ) is performed.
- An application instantiates a controller and runs an action method
in which, for example, contain model calls that read information from a database.
- After that, the action forms a view with the data obtained from the model and displays the result to the user.
Model - contains the business logic of the application and includes methods of sampling (it can be ORM methods), processing (for example, validation rules) and providing specific data, which often makes it very thick, which is quite normal.
The model should not interact directly with the user. All variables related to the user request must be processed in the controller.
The model should not generate HTML or other display code, which may vary depending on the user's needs. Such code should be processed in views.
The same model, for example: the user authentication model can be used both in the user and in the administrative part of the application. In this case, you can put the common code into a separate class and inherit from it, determining in successors specific methods for sub-applications.
View - used to set the external display of data obtained from the controller and model.
Types contain HTML markup and small PHP code inserts for crawling, formatting and displaying data.
Must not directly access the database. This should deal with the model.
Should not work with data obtained from a user request. This task should be performed by the controller.
Can directly access the properties and methods of the controller or models to get ready for output data.
Views are usually divided into a common template containing markup common to all pages (for example, a header and a footer) and parts of the template that are used to display data output from a model or display data entry forms.
The controller is the link that connects models, views, and other components to a production application. The controller is responsible for handling user requests. The controller should not contain SQL queries. They are best kept in models. The controller should not contain HTML and other markup. It is necessary to make the views.
In a well-designed MVC application, controllers are usually very thin and contain only a few dozen lines of code. What can not be said about Stupid Fat Controllers (SFC) in CMS Joomla. The logic of the controller is quite typical and most of it is made into base classes.
Models, on the contrary, are very thick and contain most of the code associated with data processing, since the data structure and business logic contained in them is usually quite specific for a particular application.
1.1. Front Controller and Page Controller
In most cases, the user interacts with the web application by clicking on the links. Look now at the address bar of the browser - this link you received this text. Other links, such as those on the right of this page, will give you other content. Thus, the link represents a specific command to the web application.
I hope you have already noticed that different sites may have perfect different formats for building the address bar. Each format can display the architecture of a web application. Although this is not always the case, in most cases it is a clear fact.
Consider two options for the address bar, which shows some text and user profile.
First option:
- www.example.com/article.php?id=3
- www.example.com/user.php?id=4
Here, each script is responsible for the execution of a particular command.
The second option:
- www.example.com/index.php?article=3
- www.example.com/index.php?user=4
And here all appeals take place in the same
index.php script.
You can see the approach with a lot of interaction points on the forums with the phpBB engine. Viewing the forum occurs through the
viewforum.php script, viewing the topic through
viewtopic.php , etc. The second approach, with access through a single physical script file, can be observed in my favorite CMS MODX, where all calls go through
index.php .
These two approaches are completely different. The first one is typical for the Page Controller pattern, and the second approach is implemented by the Request Controller pattern. The page controller is good to use for sites with fairly simple logic. In turn, the request controller combines all actions for processing requests in one place, which gives it additional capabilities, thanks to which you can accomplish more difficult tasks than are usually solved by the page controller. I will not go into the details of the implementation of the page controller, but I will only say that in the practical part it will be the query controller that is developed (some similarity).
1.2. URL Routing
URL routing allows you to configure the application to receive requests from URLs that do not match the actual application files, and also use
CNC , which is semantically meaningful to users and preferred for search engine optimization.
For example, for a normal page that displays a feedback form, the URL could look like this:
http://www.example.com/contacts.php?action=feedbackApproximate processing code in this case:
switch($_GET['action'])
{
case "about" :
require_once("about.php"); // " "
break;
case "contacts" :
require_once("contacts.php"); // ""
break;
case "feedback" :
require_once("feedback.php"); // " "
break;
default :
require_once("page404.php"); // "404"
break;
}
, .
URL :
http://www.example.com/contacts/feedbackcontacts , feedback — contacts, .. .
, - URL (, URL) .
, .
2.
:

, , core Model, View Controller.
controllers, models views.
index.php .
bootstrap.php , .
; index.php :
ini_set('display_errors', 1);
require_once 'application/bootstrap.php';
.
,
bootstrap.php:
require_once 'core/model.php';
require_once 'core/view.php';
require_once 'core/controller.php';
require_once 'core/route.php';
Route::start(); //
. start.
2.1. URL
MVC . , ,
.htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
index.php, . Front Controller?!
route.php core. Route, , .
route.phpclass Route
{
static function start()
{
//
$controller_name = 'Main';
$action_name = 'index';
$routes = explode('/', $_SERVER['REQUEST_URI']);
//
if ( !empty($routes[1]) )
{
$controller_name = $routes[1];
}
//
if ( !empty($routes[2]) )
{
$action_name = $routes[2];
}
//
$model_name = 'Model_'.$controller_name;
$controller_name = 'Controller_'.$controller_name;
$action_name = 'action_'.$action_name;
// ( )
$model_file = strtolower($model_name).'.php';
$model_path = "application/models/".$model_file;
if(file_exists($model_path))
{
include "application/models/".$model_file;
}
//
$controller_file = strtolower($controller_name).'.php';
$controller_path = "application/controllers/".$controller_file;
if(file_exists($controller_path))
{
include "application/controllers/".$controller_file;
}
else
{
/*
,
404
*/
Route::ErrorPage404();
}
//
$controller = new $controller_name;
$action = $action_name;
if(method_exists($controller, $action))
{
//
$controller->$action();
}
else
{
//
Route::ErrorPage404();
}
}
function ErrorPage404()
{
$host = 'http://'.$_SERVER['HTTP_HOST'].'/';
header('HTTP/1.1 404 Not Found');
header("Status: 404 Not Found");
header('Location:'.$host.'404');
}
}
, ( ) . , .. . …
$_SERVER['REQUEST_URI'] .
:
example.ru/contacts/feedbackexplode . , ,
contacts , —
feedback.
( ) , , , , .
, , , :
example.com/portfolioexample.com/portfolio/index:
- model_portfolio.php models, Model_Portfolio;
- controller_portfolio.php controllers, Controller_Portfolio;
- Controller_Portfolio — action_index, .
, :
example.com/ufo«404»:
example.com/404, .
2.2. MVC
core route.php :
model.php, view.php controller.php
, , .
model.phpclass Model
{
public function get_data()
{
}
}
, . .
view.phpclass View
{
//public $template_view; // .
function generate($content_view, $template_view, $data = null)
{
/*
if(is_array($data)) {
//
extract($data);
}
*/
include 'application/views/'.$template_view;
}
}
,
generate . :
- $content_file — ;
- $template_file — ;
- $data — , . .
include (),
.
header, menu, sidebar footer, . .
controller.phpclass Controller {
public $model;
public $view;
function __construct()
{
$this->view = new View();
}
function action_index()
{
}
}
action_index — , , .
2.3. Model Controller, View's
! - :
- — «404»
controllers views. models.
template_view.php — , . :
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<?php include 'application/views/'.$content_view; ?>
</body>
</html>
CSS HTML- CSS JavaScript :
<link rel="stylesheet" type="text/css" href="/css/style.css" />
<script src="/js/jquery-1.6.2.js" type="text/javascript"></script>
, «», GitHub- , .
2.3.1.
controller_main.php, :
class Controller_Main extends Controller
{
function action_index()
{
$this->view->generate('main_view.php', 'template_view.php');
}
}
generate View c .
.
.
main_view.php:
<h1> !</h1>
<p>
<img src="/images/office-small.jpg" align="left" >
<a href="/"> TEAM</a> - - , , , - ...
</p>
PHP-.
:
, .
2.3.2. «»
, «» — .
, :
- pgsql mysql;
- , . , PEAR MDB2;
- ORM;
- NoSQL;
- .
, SQL- ORM-. .
model_portfolio.php models. :
class Model_Portfolio extends Model
{
public function get_data()
{
return array(
array(
'Year' => '2012',
'Site' => 'http://DunkelBeer.ru',
'Description' => '- Dunkel Löwenbraü "C ".'
),
array(
'Year' => '2012',
'Site' => 'http://ZopoMobile.ru',
'Description' => ' Zopo Android OS .'
),
// todo
);
}
}
controller_portfolio.php, :
class Controller_Portfolio extends Controller
{
function __construct()
{
$this->model = new Model_Portfolio();
$this->view = new View();
}
function action_index()
{
$data = $this->model->get_data();
$this->view->generate('portfolio_view.php', 'template_view.php', $data);
}
}
data ,
get_data, .
generate, : , c .
portfolio_view.php.
<h1></h1>
<p>
<table>
, .
<tr><td></td><td></td><td></td></tr>
<?php
foreach($data as $row)
{
echo '<tr><td>'.$row['Year'].'</td><td>'.$row['Site'].'</td><td>'.$row['Description'].'</td></tr>';
}
?>
</table>
</p>
, .
2.3.3.
. GitHub, , «».
3.
:
GitHub:
https://github.com/vitalyswipe/tinymvc/zipball/v0.1( ):
- Controller_Login , .
- Contorller_Admin , ( , ) logout .
— , , , .
4.
MVC CMS, , . , , .
, -, Yii Kohana, , - (, -) . MVC , Php, Html, CSS JavaScript .
CMF, - , -. CMS, MVC. , « », , ?!
P.S.: , . . : , . , … , . !
5.
- — , , . , ( ), .
5.1. MVC
5.2.
PHP , …
5.3. URL
5.4.
5.5.