Оглавление

Начало Основы Работа с формами Работа с БД Кэширование Расширение Yii Тестирование Специальные темы
Зачем реклама?

Лучшие практики MVC

Несмотря на то что с концепцией MVC знаком практически каждый веб-разработчик, её применение в реальных проектах часто вызывает затруднения. Главная идея MVC — повторное использование кода и разделение проблем. В данном разделе будут описаны общие принципы, которые помогут следовать MVC в вашем приложении.

Предположим, что веб-приложение состоит из нескольких подприложений, таких как:

  • front end: часть сайта, которую видят обычные пользователи;
  • back end: административная часть сайта, позволяющая управлять приложением. Доступ к ней обычно ограничен;
  • консоль: приложение, состоящее из набора консольных команд, запускаемых в окне терминала вручную или по расписанию;
  • API: предоставляет сторонним приложениям интерфейсы для интеграции с вашим приложением.

Подприложения могут быть реализованы в виде модулей или как приложение, которое содержит код, общий для нескольких подприложений.

Модель #

Модели представляют внутреннюю структуру данных приложения. Они часто являются общими для нескольких подприложений. Например, модель LoginForm может быть использована как в пользовательской, так и в административной части приложения. Модель News может использоваться консольными командами, API и front/back частями приложения. Поэтому модели

  • должны содержать свойства, представляющие конкретные данные;

  • должны включать в себя бизнес-логику (например, правила валидации), чтобы убедиться в том, что данные соответствуют предъявленным требованиям;

  • могут содержать код для работы с данными. К примеру, модель SearchForm, помимо хранения поисковых данных, может содержать метод search, который этот поиск осуществляет.

Иногда следование последнему правилу делает модель очень толстой, то есть содержащей очень много кода в одном классе. Это может привести к трудностям поддержки кода в том случае, если модель используется для выполнения различных задач. К примеру, модель News может содержать метод getLatestNews, который используется только пользовательской частью и метод getDeletedNews, который используется только административной частью. Для небольших и средних приложений это допустимо. Для крупных же приложений в целях упрощения дальнейшей поддержки кода можно сделать следующее:

  • Создать модель NewsBase, содержащую только код, общий для подприложений (пользовательской и административной частей).

  • В каждом подприложении создать модель News, наследуемую от NewsBase и определить в ней специфичные для подприложения методы.

Таким образом, если применить это к рассмотренному выше примеру, необходимо добавить модель News с методом getLatestNews в пользовательскую часть и ещё одну модель News с методом getDeletedNews в административную часть.

В общем случае, модели не должны напрямую взаимодействовать с пользователем. То есть:

  • не должны использовать $_GET, $_POST или другие подобные переменные, напрямую получаемые из запроса пользователя, так как модели могут использоваться в совершенно других подприложениях (например, в модульных тестах или API), в которых эти переменные недоступны. Все переменные, относящиеся к запросу пользователя, должны обрабатываться в контроллере;

  • не должны генерировать HTML или другой код представления, так как он может изменяться в зависимости от нужд пользователя (то есть, пользовательская часть и административная часть могут показывать новости в совершенно разном формате). Такой код должен генерироваться в представлениях.

Представление #

Представления отвечают за отображение моделей в необходимом пользователю формате. В общем случае представления

  • должны, главным образом, содержать разметку, такую как HTML, и простой PHP код, используемый для обхода, форматирования и отображения данных;

  • не должны напрямую обращаться к базе данных. Этим должны заниматься модели;

  • не должны напрямую обращаться к $_GET, $_POST и другим переменным, получаемым из запроса пользователя. Эту задачу должен выполнять контроллер. Представления должны использоваться только для оформления данных, полученных от контроллера и модели;

  • могут напрямую обращаться к свойствам и методам контроллера или моделей. Однако это должно делаться только в целях отображения данных.

Представления можно использовать повторно несколькими способами:

  • Общий шаблон: в него можно вынести разметку, общую для всех страниц. Например, шапку и подвал.

  • Части шаблона: используются внутри других шаблонов и, как правило, не используются с общим шаблоном. К примеру, часть шаблона _form.php можно использовать для отображения формы ввода модели, которая будет использоваться как при её создании, так и при редактировании.

  • Виджеты: используются в том случае, когда часть шаблона включает в себя слишком много логики. При этом логика переносится в класс виджета. Виджет, генерирующий большое количество разметки, может использовать свои шаблоны представлений.

  • Хелперы (помощники): в шаблонах часто требуется выполнять небольшие задачи, такие как форматирование данных или генерация HTML-тегов. Вместо того чтобы вставлять код напрямую в шаблоны, можно поместить его в класс-хелпер и использовать в шаблонах этот класс. Пример такого подхода можно найти в классе CHtml, который помогает генерировать часто используемый HTML код. Для того чтобы избежать явного подключения классов, хелперы можно разместить в отдельной директории, указанной в import.

Контроллер #

Контроллеры — связующее звено, соединяющее модели, представления и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Поэтому контроллер

  • может обращаться к $_GET, $_POST и другим переменным PHP, получаемым из запроса пользователя;

  • может создавать экземпляры моделей и управлять ими. К примеру, в типичном действии обновления модели контроллер может сначала создать экземпляр модели, затем заполнить его данными из $_POST и, в случае успешного сохранения модели, перенаправить браузер пользователя на страницу созданной модели. Стоит отметить, что само сохранение модели должно быть реализовано в классе модели, а не в контроллере;

  • не должен содержать SQL-запросы. Их лучше держать в моделях;

  • не должен содержать HTML и другую разметку. Её стоит вынести в представления.

В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. В то же время, модели очень толстые и содержат большую часть кода, связанную с обработкой данных, так как структура данных и бизнес-логика, содержащиеся там, обычно довольно специфичны для конкретного приложения. Логика контроллера, наоборот, довольно типична и может быть вынесена в базовые классы.


Зачем реклама?