📜 ⬆️ ⬇️

MVC for the web: nowhere easier

In this article, we will look at the architectural pattern MVC (Model, View, Controller) as applied to web development, “in its pure form,” without involving any additional non-MVC structures and patterns. We will move from simple to complex, so for now we will not consider, for example, the further development of MVC - the HMVC (Hierarchical MVC) pattern. Although HMVC is undoubtedly much more interesting for developing web applications, its use does not eliminate the need to understand “ordinary” MVC.

An article in Wikipedia (namely, apparently, those who are just beginning to study MVC, most often fall into it), are replete with inaccuracies and vague wording, the definition itself, in fact, is incorrect, and the given scheme simply does not correspond to the one used in the web in general and when developing for PHP - in particular.

I found the most correct definition of the MVC pattern here :
')
The MVC design pattern involves the separation of application data, user interface, and control logic into three separate components: Model, View, and Controller — so that each component can be modified independently.

Let's clarify that the term “component” in this case has no connection with the components of some popular CMS or frameworks, and the components of Bitrix, for example, are generally constructed from all three components of MVC.
In the above definition, a component should be understood as some separate part of the code, each of which plays one of the Controller, Model, or View roles, where the Model is used to extract and manipulate application data. The View is responsible for displaying this data to the user (that is, applied to the web forms HTML / CSS sent by the server to the user's browser), and the Controller controls the entire orchestra.

Let's look at the classic scheme of a web application:

Picture 1



In this and the following figures, control lines (such as the ID of the requested blog entry or product in the store) are shown as dashed lines, and the actual application data (which can be stored in the database, or in the form of files on disk, or even , in memory - this question lies outside the MVC pattern). As applied to the web, the request and response go over HTTP, so we can conditionally assume that in this figure the headers of the HTTP request and response are indicated by a dotted line, and their solid bodies are shown by solid lines.

Having received Request 1, the Controller analyzes it, and depending on the processing results it may produce the following answer options (why the answer is number 4, it will become clear from the following figures):

1. Immediately give an error response (for example, when requesting a non-existent page, give only the HTTP header “404 Not found”)

2. If incoming Request 1 is recognized as correct, then, depending on whether it is a request to view or modify data, the Controller calls the appropriate Model method, such as Save or Load (Request 2 in Fig. 2).

Figure 2



Important note: the concept of MVC is not only not tied to any particular programming language, it is also not tied to the programming paradigm used. That is, you can easily design your application for MVC, while not using OOP, and design the Product Model for an online store in this way:

<? mixed Product_Load (int $id) { ... } //         FALSE   bool Product_Save (array $data) { ... } //  TRUE     $data,  FALSE   ?> 


So, depending on the Response 2 received from the Model, the Controller decides which of the Views to call to form the final response to the initial Request 1:

3.1. In case of failure - Submission for error message
3.2. In case of success - the View to display the requested data or a message on their successful preservation (if Request 1 was for data modification).

Figure 3



The question of who should check the validity and access rights of the input data (Controller or Model) is a subject of rather numerous disputes, since the MVC pattern does not describe such details. This means that in this matter the choice is yours (or the authors of your favorite framework or CMS made it for you).
In our practice, we follow this approach:
The controller checks the input data for “general” (that is, independent of the specific request) correctness, the compliance with the requirements of the Model for the validity of the stored data is checked by the corresponding Model method, and the access rights are checked by the Access method of a separate User class.

To call Views in PHP, a special class (or even several classes) is sometimes designed, for example, View (this is often found in MVC descriptions in the implementation of a framework), but this is not a requirement of MVC.
Also, View files are often called templates, and when using so-called template engines, the role of Views is played by the template itself, and templates (that is, files containing directly HTML markup) are called layouts in some frameworks.

Not quite clear the previous paragraph? Score, because we have each View is just a separate PHP file, and PHP itself is designed so that if we use the include statement in the execution of Request 3, Answer 3 and Answer 4 (remember, what is the answer to Request 1? ) are given to the browser automatically by the means of PHP itself.

Let's take an example.

We have two variants of Representations (templates) in which

<! - HTML.header -> will mean the HTML code that prefigures the main content in the web document being created (i.e., contains the doctype tag, the head container, the page heading code, etc.), and <! - HTML.footer -> - approximately the same, only for the page footer.

Listing 1. The product.tpl.php template displays data about the Product (which at the time of its call already contains the $ product object):



 <!-- HTML.header --> <h1><?=$product->Title;?></h1> <p>:<b class="price"><?=$product->Price;?></b></p> <p class="description"><?=$product->Description;?></p> <!-- HTML.footer --> 


Listing 2. The error.tpl.php template displays an error message (which is contained in the $ error variable):



 <!-- HTML.header --> <h1 class="error">: <?=$error;?></h1> <!-- HTML.footer --> 


Listing 3. The product.php controller that serves as a withdrawal of the Product will look something like this:



 <? include 'product.class.php'; //        //     , ,  //         function Error ($error) { //        ,  : header('  , , 400  404'); $error = '   , ,   '; include 'error.tpl.php'; //     exit; } if (!$id = ...) //  ""   1 error(...); //    if (!$user->Access(...)) error(403); if (!$product = Product::Load($id)) //  2    2 error('     '); include 'product.tpl.php'; //  3   3  4 ?> 


Those who love beautiful and optimized code may notice that the HTML.header and HTML.footer blocks are duplicated in both templates (also known as Views) error.tpl.php and product.tpl.php , and will probably want to bring them to the product controller . save.php :

 <!-- HTML.header --> <? //      3 ?> <!-- HTML.footer --> 


... and thus break the basic rule of MVC - separate the Controller, Model and View.

However, duplicate code is unequivocal Evil. What to do?
We have to go from MVC to HMVC!
But this is a topic for a separate article.

Source: https://habr.com/ru/post/181772/


All Articles