Я использую шаблон MVC в своем веб-приложении, построенном на PHP.
Я всегда изо всех сил пытаюсь определить, нужен ли мне новый выделенный контроллер для набора действий или я должен поместить их в уже существующий контроллер.
Есть ли хорошие правила, которым нужно следовать при создании контроллеров?
Например, я могу иметь:
AuthenticationController
с действиями:
index()
отобразить форму входа.submit()
обрабатывать отправку формы.logout()
, само за себя.
ИЛИ
LoginController
с действиями:
index()
отобразить форму входа.submit()
обрабатывать отправку формы.
LogoutController
с действием:
index()
обрабатывать выход.
ИЛИ
AccountController
с действиями:
loginGet()
отобразить форму входа.loginPost()
обрабатывать отправку формы входа.logoutGet()
обрабатывать выход.registerGet()
отобразить регистрационную форму.registerPost()
обрабатывать отправку формы.И любые другие действия, связанные с учетной записью.
Ответы:
Чтобы найти правильную группу для контроллеров, подумайте о тестировании .
(Даже если вы на самом деле не проводите никакого тестирования, размышления о том, как вы будете проводить тестирование ваших контроллеров, дадут вам очень хорошее представление о том, как их структурировать.)
An
AuthenticationController
не является тестируемым сам по себе, потому что он содержит только функциональные возможности для входа и выхода, но ваш тестовый код должен будет каким-то образом создать поддельные учетные записи для целей тестирования, прежде чем он сможет протестировать успешный вход в систему. Вы можете обойти тестируемую подсистему и перейти непосредственно к своей модели для создания учетных записей тестирования, но тогда у вас будет хрупкий тест в ваших руках: если модель изменится, вам придется изменять не только код, который тестирует модель, но также и код, который тестирует контроллер, хотя интерфейс и поведение контроллера остались неизменными. Это неразумно.A
LoginController
не подходит по тем же причинам: вы не можете протестировать его, не создав сначала учетные записи, и есть еще больше вещей, которые вы не можете протестировать, например, например, запрет повторных входов в систему, но затем разрешение пользователю войти в систему после выхода из системы. (Поскольку этот контроллер не имеет функции выхода из системы.)An
AccountController
предоставит вам все необходимое для проведения тестирования: вы можете создать тестовую учетную запись и затем попытаться войти в нее, вы можете удалить учетную запись, а затем убедиться, что вы больше не можете войти в систему, вы можете изменить пароль и убедиться, что Для входа в систему необходимо использовать правильный пароль и т. д.В заключение: для того, чтобы написать даже самый маленький набор тестов, вам нужно сделать все функциональные возможности
AccountController
доступными для него. Подразделение его на более мелкие контроллеры, по-видимому, приводит к тому, что контроллеры с ограниченными возможностями не обладают достаточной функциональностью для проведения надлежащего теста. Это очень хороший признак того, что функциональностьAccountController
является самым маленьким подразделением, которое имеет смысл.И вообще, подход «думать о тестировании» будет работать не только в этом конкретном сценарии, но и в любом подобном сценарии, с которым вы столкнетесь в будущем.
источник
Ответ не так очевиден
Пожалуйста, позвольте мне прояснить несколько вещей, прежде чем я сделаю какие-либо ответные заявления. Прежде всего:
Что такое контроллер?
Контроллер является частью системы, которая контролирует запрос - после отправки. Таким образом, мы можем определить его как некоторый набор действий, связанных с ... чем?
Какова сфера действия контроллера?
И это более или менее важно, когда у нас будет какой-либо ответ. Что вы думаете? Это контроллер вещей (например, Учетная запись) или контроллер действий? Конечно, это контроллер какой-то модели или более абстрактная вещь, которая обеспечивает действия над ней.
Ответ...
Нет, аутентификация - это процесс. Не иди этим путем.
Тоже самое. Логин - действие. Лучше не создавать контроллер действий (у вас нет соответствующей модели).
Неплохо, но я не уверен, стоит ли строить этот контроллер низкого уровня (контроллер - это сама абстракция). В любом случае, создание методов с помощью * Get или * Post неясно.
Любое предложение?
Да, учтите это:
AccountController:
И связанная с ним модель, оф класс аккаунта. Это даст вам возможность переместить пару модель-контроллер в другое место (если это будет необходимо) и создать четкий код (очевидно, что
login()
означает метод). Привязка к модели действительно известна, особенно с CRUD-приложениями, и, возможно, это способ для вас.источник
Контроллеры обычно создаются для определенного ресурса (класс сущности, таблица в базе данных), но также могут быть созданы для группировки действий, которые отвечают за определенную часть приложения. В ваших примерах это будет контроллер, который управляет безопасностью приложения:
Примечание : не помещайте действия, связанные с безопасностью, и действия профиля пользователя в один контроллер; это может иметь смысл, поскольку они связаны с пользователем, но один должен обрабатывать аутентификацию, а другой должен обрабатывать обновления электронной почты, имени и т. д.
С контроллерами, созданными для ресурсов (скажем
Task
), у вас будут обычные действия CRUD :Конечно, у вас есть возможность добавить связанные ресурсы на тот же контроллер. Например, у вас есть сущность
Business
, а у каждой есть несколькоBusinessService
сущностей. Контроллер для этого может выглядеть так:Этот подход имеет смысл, когда связанные дочерние объекты не могут существовать без родительского объекта.
Вот мои рекомендации:
Subscription
объект, который имеет доступность на основе ограниченного числа записей, вы можете добавить новое действие к названному контроллеруuse()
, единственная цель которого - вычитать одну запись изSubscription
)Некоторые ресурсы для дальнейшего чтения здесь .
источник
Я вижу два антагонистических дизайна "силы" (которые не являются исключительными для контроллеров):
С точки зрения сплоченности все три действия (вход в систему, выход из системы, регистрация) связаны между собой, но вход и выход из системы намного больше, чем регистрация. Они связаны семантически (одно является инверсией другого) и, вполне возможно, также будут использовать одни и те же сервисные объекты (их реализации также взаимосвязаны).
Моим первым инстинктом было бы сгруппировать вход и выход в один контроллер. Но если реализации контроллера входа в систему и выхода из системы не так просты (например, в логине есть капча, больше методов аутентификации и т. Д.), У меня не будет проблем с разделением их на LoginController и LogoutController для обеспечения простоты. Где лежит этот порог сложности (когда вы должны начать разделять контроллер), немного личное.
Также помните, что независимо от того, что вы изначально разрабатываете свой код, вы можете (и должны) реорганизовать его по мере его изменения. В этом случае довольно типично начать с простого проектирования (иметь один AuthenticationController), и со временем вы получите больше требований, которые усложнят код. Как только он пересекает порог сложности, вы должны реорганизовать его на два контроллера.
Кстати, ваш код предполагает, что вы выходите из системы с помощью запроса GET. Это плохая идея, поскольку HTTP GET должен быть нулевым (он не должен изменять состояние приложения).
источник
Вот несколько практических правил:
Упорядочить по теме или теме, с именем контроллера, являющимся названием темы.
Помните, что имя контроллера будет отображаться в URL, видимом для ваших пользователей, поэтому желательно, чтобы оно имело смысл для них.
В ситуации, которую вы упоминаете (аутентификация), команда MVC уже написала для вас контроллер. Откройте Visual Studio 2013, а затем нажмите
AccountController.cs содержит все методы для управления учетными записями пользователей:
Таким образом, они организованы по теме «Учетные записи пользователей и аутентификация», с видимым названием темы «Учетная запись».
источник
терминология
Я считаю, что ошибочно называть класс, содержащий некоторые связанные с HTTP методы, «контроллером».
Контроллер - это метод, который обрабатывает запрос, но не класс, содержащий такие методы . Так
index()
,submit()
,logout()
являются контроллерами.Класс, содержащий методы такого типа, называется «контроллер» только потому, что он представляет собой группу контроллеров и играет роль пространства имен «нижнего уровня». На языке FP (например, Haskell) это был бы просто модуль. Хорошей практикой является сохранение классов «контроллеров» в состоянии без возможности сохранения состояния на языках ООП, за исключением ссылок на сервисы и другие вещи всей программы.
Ответ
С разборкой терминологии возникает вопрос: «Как разделить контроллеры на пространства имен / модули?». Я думаю, что ответ таков: контроллеры внутри одного пространства имен / модуля должны иметь дело с однотипными данными . Например,
UserController
имеет дело прежде всего с экземплярамиUser
класса, но иногда затрагивает другие связанные вещи, если требуется.Так
login
,logout
и другие подобные действия, в основном дело с сессией, он , вероятно , лучше всего поместить их внутрьSessionController
, иindex
контроллер, который просто выводит форму, должен быть помещен вLoginPageController
, так как он , очевидно , имеет дело с страницей входа. Имеет смысл объединить рендеринг HTML и управление сеансами в один класс, что нарушит SRP и, возможно, множество других хороших практик.Основной принцип
Если вам трудно решить, куда поместить фрагмент кода, начните с данных (и типов), с которыми вы имеете дело.
источник