MVC : Is this the correct sequence to initialize &

2019-03-05 09:16发布

I am trying to learn php MVC based webpage development.At first i literally thougt that it's just decoupling the project into 3 classes Model, View, Controller.But with help SO previous post comments, i realized that these are Not class but instead they are layers

// don't be confused my class/OOP style, it is just for conceptual purpose
Model.php Layer related code   
View.php Layer  related code   
Controller.php Layer related code   

User: index.php
//initiating model layer related things
$m = new Model;
// initiating Controller layer related things
$v = new Controller($m);
// initiating view layer related things
$c = new View($m, $c);

However, there are many MVC example over internet which are confusing and conflicting sometime.For example some suggest: controller have the access of both model & view, where other suggest view have the access of both.So please anyone check my code sequence to ensure that it does follow the MVC pattern correctly.

2条回答
▲ chillily
2楼-- · 2019-03-05 09:46

I will try to write only about the MVC variant used in web applications which is based on the original MVC pattern for the desktop apps, presented by Trygve Reenskaug in 1979.

In the original MVC pattern, the controller updates the model, the model notifies the view about the changes, and then the view pulls its data from it. Also, the M, V & C components were thought as related to a single control in a window (a button, a textbox, a checkbox, etc). If you had 15 controls on screen, then each of them had an MVC "attached" to it.

In the web applications, the notification step (from model to view) is not present. But the rest of the relations between the M, V & C components is maintained. So, in a web MVC, the controller updates the model and the view pulls its data from it. Also, all three components are related to a web page, not to a single control on it.

Both, controller and view, should never use domain objects, e.g. entities (as part of the domain model) directly. They communicate (separately) with the domain model only through application services (also named use cases). These services may delegate (multiple) tasks to (multiple) domain services. Which, in turn make use of the domain objects (entities). If external components and/or services are needed (like the ones in the persistence layer, e.g. repositories, datamappers, for example), then the connection between the domain model and them is made through the use of corresponding interfaces. These also are part of the domain layer.

The view should never access the controller. Why should it, at all? The controller interprets the request sent by the user (through the HTTP protocol, in web apps) and defers all the domain related work to the service layer in the domain, passing it the request data. So the controller only effects changes in the domain layer. On the other side, the view requests data only from the domain layer. It does this through services as well. So the view reads from the domain. Therefore, in your code, the view should receive only the $m as argument.

There is an important aspect regarding the view pulling data directly from the domain layer: If the view would expect to simply, directly present the data received from the domain, then this would mean that the domain would be responsible with the preparation (e.g. formatting) of the data for the view. But that would imply, that the model should know, in which format is to be the data prepared. E.g. the domain model would have to have knowledge about components residing outside its boundaries. This would not be good. So the role of the view is to receive unprepared data, to format it for the web page, and to present it. In a word, the view executes the presentation logic.

In a link bellow is a great presentation by Robert C. Martin about how the concerns should be separated between the components involved in an application, resulting in a good application architecture. Making a parallel between the above ideas and the ones presented in the presentation, you will discover, that there are two differences between them.

The first one is, that, in the video, the presentation layer consists of a presenter, a view model and a view. Whereas in the web MVC described above, the whole presentation logic is performed only by the view - which is not so good.

The second one is, that, in the video, the data to be processed and displayed by the presentation layer is pushed from the controller through the domain layer to the presentation layer. Now try to imagine yourself, that that presenter depends on an interactor (which, actually is an application service, a use case). E.g. that the arrow pointing from the presenter to the domain layer describes a dependency relation, instead of an inheritance one. Then the role of the presenter will be to pull information out of the domain layer. The analogy with the web MVC presented above is then obvious.

Resources:

Keynote: Architecture the Lost Years - Presentation given by Robert Martin, licensed under a Creative Commons Attribution ShareAlike 3.0.


Example 1 (in index.php): Display data

The user introduces the URL http://localhost/questions/12345 in the address bar of the browser and expects a html page with a question and multiple comments for it. Therefore the HTTP method is "GET". So no controller is needed, but only a view (for reading and displaying data from the domain model).

<?php

namespace Test\MvcExample;

use Lib\Http\Message\Response;
use Lib\Router\RouteCollection;
use Lib\Http\Message\ServerRequest;
use Lib\Http\MessageEmitter\ResponseEmitter;

/*
 * -----------------------------------------
 * Before dispatching by a front-controller.
 * -----------------------------------------
 */
$routes = new RouteCollection();
$routes->add('GET', '/questions/{id:\d+}', [
    'view' => [QuestionsView::class, 'index'],
]);

$request = new ServerRequest('GET', '/questions/12345' /* , other args */);
$response = new Response(/* args */);

/*
 * ------------------------------------------------------------------
 * Dispatched by a front-controller.
 * Route params are saved into the attributes list of server request.
 * ------------------------------------------------------------------
 */
$view = new QuestionsView(new Template(), new QuestionsService(), new CommentsService());

$response = $view->index($response, $request->getAttribute('id'));

/*
 * ----------------------------------------
 * After dispatching by a front-controller.
 * ----------------------------------------
 */
$responseEmitter = new ResponseEmitter();
$responseEmitter->emitResponse($response);

Example 2 (in index.php): Update and display data

At URL http://localhost/questions/edit/12345 the user edits the question in a form with attribute action="/questions/update" and clicks the submit button "Update". Therefore the HTTP method is "POST". So both a controller (for updating the model layer) and a view (for reading and displaying data from the model layer) are needed.

Instead of only using a view, one can change to other requirements. For example, to use a presenter and a view, both sharing a view-model.

<?php

namespace Test\MvcExample;

use Lib\Http\Message\Response;
use Lib\Router\RouteCollection;
use Lib\Http\Message\ServerRequest;
use Lib\Http\MessageEmitter\ResponseEmitter;

/*
 * -----------------------------------------
 * Before dispatching by a front-controller.
 * -----------------------------------------
 */
$routes = new RouteCollection();
$routes->add('POST', '/questions/update', [
    'controller' => [QuestionsController::class, 'updateQuestion'],
    'view' => [QuestionsView::class, 'getQuestionUpdated'],
]);

$request = new ServerRequest('POST', '/questions/update' /* , other args */);
$response = new Response(/* args */);

/*
 * ----------------------------------
 * Dispatched by a front-controller.
 * ----------------------------------
 */
$questionsService = new QuestionsService();

$controller = new QuestionsController($questionsService);
$controller->updateQuestion($request);

$view = new QuestionsView(new Template(), $questionsService);

$response = $view->getQuestionUpdated($response, $request);

/*
 * ----------------------------------------
 * After dispatching by a front-controller.
 * ----------------------------------------
 */
$responseEmitter = new ResponseEmitter();
$responseEmitter->emitResponse($response);
查看更多
趁早两清
3楼-- · 2019-03-05 10:03

In my opinion coming from PHP and Javascript Model - Where you data lives, and is manipulated for extraction. Controller - Pulls in data from model(s) and anything else and is moulded into something for the user, could be a view or and endpoint. View - UI which gets data from Controller and all passes data to controllers i.e forms. View never interacts with Model. A concept i like is Top heavy Models, light Controllers. I personally don't think their is a hard rule, just guides

查看更多
登录 后发表回答