Я работаю над личным проектом HMVC:
static
или global
), нет синглтонов. Все необходимые зависимости вводятся в конструктор абстрактного контроллера. Если я хочу переопределить этот конструктор, тогда я должен передать все эти зависимости в конструкторе дочернего контроллера.
class UsersController extends AbstractController { private $authentication; public function __construct( Config $config , Request $request , Session $session , View $view , Response $response , Logger $logger , Authentication $authentication // Domain model service ) { parent::__construct(/* All dependencies except authentication service */); $this->authentication = $authentication; } // Id passed by routing. public function authenticateUser($id) { // Use the authentication service... } }
Список зависимостей будет расти далее. Это необходимо изменить. Поэтому я думал о:
Response
будет зависеть от представлений. Request
, Session
, Logger
и т. Д .; Request
, Session
, Logger
и т. Д .; AbstractController
. Я пытаюсь найти элегантный способ справиться с этой задачей, и я буду благодарен за любые предложения. Спасибо.
Я отвечу на свой вопрос. Когда я это написал, у меня уже был хороший обзор того, что многие опытные разработчики рекомендуют относительно внедрения зависимостей в MVC и MVC.
Таким образом, ни одно из этих решений, похоже, полностью не вписывалось в структуру моего проекта HMVC, что бы я ни делал. Итак, я вырыл дальше, пока не понял, что такое недостающее звено. Для этого я полностью признателен Тому Батлеру , создателю следующих великих статей:
Его работы основаны на глубоком, хорошо аргументированном анализе концепций MVC. Они не только очень легко следовать, но и поддерживаются объяснительными примерами. Одним словом: замечательный вклад в сообщество MVC и разработчиков.
То, что я напишу дальше, предназначено только для того, чтобы просто представить свои принципы своими собственными словами, имея в виду как-то их завершить, предоставить им комплиментарную перспективу и показать шаги, которые следуют за мной, когда я реализовал их в своем проект. Все отзывы по теме, идеям и принципам и рабочим процессам, изображенные здесь, принадлежат Тому Батлеру .
Итак, какова недостающая ссылка в моем проекте HMVC? Это называется ОТДЕЛЕНИЕ КОНЦЕРН .
Для простоты я попытаюсь объяснить это, обратившись только к одному контроллеру, одному действию контроллера, одному представлению, одной модели (объекту домена) и одному шаблону (файлу), представляя их в контексте User
.
Концепция MVC, наиболее известная на веб-сайте, а также реализованная некоторыми популярными структурами, которые я изучал, сосредоточена на принципе предоставления контроллеру контроля над представлением и моделью. Чтобы отобразить что-то на экране, вам нужно будет сообщить об этом контроллеру – он также уведомит представление о загрузке и отображении шаблона. Если этот процесс отображения подразумевает использование некоторых данных модели, то контроллер также манипулирует моделью.
Классическим способом создание контроллера и процесс вызова действий включают в себя два этапа:
Код:
$controller = new UserController(/* Controller dependencies */); $controller->{action}(/* Action dependencies */);
Это означает, что контроллер несет ответственность за все, что угодно. Поэтому неудивительно, почему контроллеру необходимо вводить столько зависимостей.
Но должен ли контроллер быть вовлечен или ответственен за эффективное отображение какой-либо информации на экране? Нет. На это должна возлагаться ответственность. Чтобы достичь этого, давайте начнем разделять представление с контроллера – исходя из предпосылки отсутствия модели. Принятые шаги:
output
для отображения информации на экране в представлении. output
вида: И код:
class UserView { //.... // Display information on screen. public function output () { return $this ->load('<template-name>') ->render(array(<data-to-display>)) ; } //.... } $controller = new UserController(/* (less) controller dependencies */); $view = new UserView(/* View dependencies */); $controller->{action}(/* Action dependencies */); echo $view->output();
Достигнув пяти верхних шагов, нам удалось полностью отделить контроллер от представления.
Но есть аспект, который мы предположили ранее: мы не использовали ни одну модель. Итак, какова роль контроллера в этом созвездии? Ответ таков: нет. Контроллер должен существовать только как middlemann между некоторым местом хранения (база данных, файловая система и т. Д.) И представление. В противном случае, например, только для вывода какой-либо информации в определенном формате на экране, метод output
представления полностью достаточен.
Вещи меняются, если модель появляется на сцене. Но куда его следует вводить? В контроллере или в представлении? В обоих. Они имеют один и тот же экземпляр модели. В этот момент контроллер приобретает роль посредника – между хранением и представлением – сам по себе. Теоретическая форма:
$model = new UserModel; $controller = new UserController($model, /* Other controller dependencies */); $view = new UserView($model, /* Other view dependencies */); $controller->{action}(/* Action dependencies */); echo $view->output();
При этом контроллер может изменить состояние модели и убедиться, что она сохранена в системе хранения. Тот же экземпляр модели, соответствующий его состоянию, считывается и отображается. Контроллер передает информацию о логике отображения в представление через модель. Проблема состоит в том, что эти данные не относятся к бизнес-логике, которая, как предполагается, должна иметь только модель. Они являются только участниками логики отображения.
Чтобы избежать предоставления логики отображения логики модели, мы должны представить новый компонент на картинке: модель-образец. Вместо совместного использования объекта модели контроллер и представление будут совместно использовать экземпляр модели представления. Только эта модель получит модель как зависимость. Реализация:
$model = new UserModel; $viewModel = new UserViewModel($model, /* Other view-model dependencies */); $controller = new UserController($viewModel /* Other controller dependencies */); $view = new UserView($viewModel, /* Other view dependencies */); $controller->{action}(/* Action dependencies */); echo $view->output();
И рабочий процесс можно описать следующим образом:
output
представление считывает значения из модели представления и запрашивает модель для запроса хранилища на их основе. Модель представления не относится к модели домена, где все объекты домена находятся, и существует реальная бизнес-логика. Он также не относится к уровню сервиса, который управляет объектами домена, репозиториями и данными. Он относится к модели приложения, например, к месту, где выполняется логика приложения. Модель просмотра полностью берет на себя ответственность за получение состояния логики дисплея от контроллера и проведение ее до контроллера.
Как видно, только модель модели «затрагивает» модель. Оба, контроллер и представление были не только полностью отделены друг от друга, но и от модели. Наиболее важным аспектом этого подхода является то, что каждый из всех задействованных компонентов получает только те обязанности, которые он должен получить.
Используя этот вид разделения компонентов и контейнера инъекций зависимостей, проблема слишком большого количества зависимостей в контроллерах исчезает. И можно применить комбинацию всех вариантов, представленных в моем вопросе, в очень гибкой манере. Не имея в виду, что один из компонентов (модель, представление или контроллер) получает слишком много обязанностей.