mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-21 15:36:53 +01:00
143 lines
12 KiB
Plaintext
143 lines
12 KiB
Plaintext
Лучшие практики MVC
|
||
===================
|
||
|
||
Несмотря на то что с концепцией MVC знаком практически каждый веб-разработчик, её
|
||
применение в реальных проектах часто вызывает затруднения. Главная идея
|
||
MVC — **повторное использование кода и разделение проблем**. В данном разделе
|
||
будут описаны общие принципы, которые помогут следовать MVC в вашем приложении.
|
||
|
||
Предположим, что веб-приложение состоит из нескольких подприложений, таких как:
|
||
|
||
* front end: часть сайта, которую видят обычные пользователи;
|
||
* back end: административная часть сайта, позволяющая управлять приложением.
|
||
Доступ к ней обычно ограничен;
|
||
* консоль: приложение, состоящее из набора консольных команд, запускаемых
|
||
в окне терминала вручную или по расписанию;
|
||
* API: предоставляет сторонним приложениям интерфейсы для интеграции с вашим
|
||
приложением.
|
||
|
||
Подприложения могут быть реализованы в виде [модулей](/doc/guide/basics.module)
|
||
или как приложение, которое содержит код, общий для нескольких подприложений.
|
||
|
||
|
||
Модель
|
||
------
|
||
|
||
[Модели](/doc/guide/basics.model) представляют внутреннюю структуру данных приложения.
|
||
Они часто являются общими для нескольких подприложений.
|
||
Например, модель `LoginForm` может быть использована как в пользовательской, так
|
||
и в административной части приложения. Модель `News` может использоваться
|
||
консольными командами, API и front/back частями приложения. Поэтому модели
|
||
|
||
* должны содержать свойства, представляющие конкретные данные;
|
||
|
||
* должны включать в себя бизнес-логику (например, правила валидации), чтобы убедиться в том,
|
||
что данные соответствуют предъявленным требованиям;
|
||
|
||
* могут содержать код для работы с данными. К примеру, модель `SearchForm`,
|
||
помимо хранения поисковых данных, может содержать метод `search`, который этот поиск
|
||
осуществляет.
|
||
|
||
Иногда следование последнему правилу делает модель очень
|
||
толстой, то есть содержащей очень много кода в одном классе. Это может привести
|
||
к трудностям поддержки кода в том случае, если модель используется для выполнения
|
||
различных задач. К примеру, модель `News` может содержать метод `getLatestNews`,
|
||
который используется только пользовательской частью и метод `getDeletedNews`,
|
||
который используется только административной частью. Для небольших и средних
|
||
приложений это допустимо. Для крупных же приложений в целях упрощения
|
||
дальнейшей поддержки кода можно сделать следующее:
|
||
|
||
* Создать модель `NewsBase`, содержащую только код, общий для подприложений
|
||
(пользовательской и административной частей).
|
||
|
||
* В каждом подприложении создать модель `News`, наследуемую от `NewsBase` и
|
||
определить в ней специфичные для подприложения методы.
|
||
|
||
Таким образом, если применить это к рассмотренному выше примеру, необходимо
|
||
добавить модель `News` с методом `getLatestNews` в пользовательскую часть и
|
||
ещё одну модель `News` с методом `getDeletedNews` в административную часть.
|
||
|
||
В общем случае, модели не должны напрямую взаимодействовать с пользователем. То есть:
|
||
|
||
* не должны использовать `$_GET`, `$_POST` или другие подобные переменные, напрямую
|
||
получаемые из запроса пользователя, так как модели могут использоваться в
|
||
совершенно других подприложениях (например, в модульных тестах или API), в
|
||
которых эти переменные недоступны. Все переменные, относящиеся к запросу
|
||
пользователя, должны обрабатываться в контроллере;
|
||
|
||
* не должны генерировать HTML или другой код представления, так как он
|
||
может изменяться в зависимости от нужд пользователя (то есть, пользовательская часть
|
||
и административная часть могут показывать новости в совершенно разном формате).
|
||
Такой код должен генерироваться в представлениях.
|
||
|
||
|
||
Представление
|
||
-------------
|
||
|
||
[Представления](/doc/guide/basics.view) отвечают за отображение моделей в
|
||
необходимом пользователю формате. В общем случае представления
|
||
|
||
* должны, главным образом, содержать разметку, такую как HTML, и простой PHP код,
|
||
используемый для обхода, форматирования и отображения данных;
|
||
|
||
* не должны напрямую обращаться к базе данных. Этим должны заниматься модели;
|
||
|
||
* не должны напрямую обращаться к `$_GET`, `$_POST` и другим переменным, получаемым
|
||
из запроса пользователя. Эту задачу должен выполнять контроллер. Представления
|
||
должны использоваться только для оформления данных, полученных от контроллера и модели;
|
||
|
||
* могут напрямую обращаться к свойствам и методам контроллера или моделей.
|
||
Однако это должно делаться только в целях отображения данных.
|
||
|
||
|
||
Представления можно использовать повторно несколькими способами:
|
||
|
||
* Общий шаблон: в него можно вынести разметку, общую для всех страниц.
|
||
Например, шапку и подвал.
|
||
|
||
* Части шаблона: используются внутри других шаблонов и, как правило, не
|
||
используются с общим шаблоном. К примеру, часть шаблона `_form.php` можно
|
||
использовать для отображения формы ввода модели, которая будет использоваться
|
||
как при её создании, так и при редактировании.
|
||
|
||
* Виджеты: используются в том случае, когда часть шаблона включает в себя слишком
|
||
много логики. При этом логика переносится в класс виджета. Виджет, генерирующий
|
||
большое количество разметки, может использовать свои шаблоны представлений.
|
||
|
||
* Хелперы (помощники): в шаблонах часто требуется выполнять небольшие задачи, такие как
|
||
форматирование данных или генерация HTML-тегов. Вместо того чтобы вставлять
|
||
код напрямую в шаблоны, можно поместить его в класс-хелпер и использовать в шаблонах
|
||
этот класс. Пример такого подхода можно найти в классе [CHtml], который помогает генерировать
|
||
часто используемый HTML код. Для того чтобы избежать явного подключения классов,
|
||
хелперы можно разместить в [отдельной директории, указанной в import](/doc/guide/basics.namespace).
|
||
|
||
|
||
Контроллер
|
||
----------
|
||
|
||
[Контроллеры](/doc/guide/basics.controller) — связующее звено, соединяющее
|
||
модели, представления и другие компоненты в рабочее приложение. Контроллер отвечает
|
||
за обработку запросов пользователя. Поэтому контроллер
|
||
|
||
* может обращаться к `$_GET`, `$_POST` и другим переменным PHP, получаемым из
|
||
запроса пользователя;
|
||
|
||
* может создавать экземпляры моделей и управлять ими. К примеру, в типичном действии
|
||
обновления модели контроллер может сначала создать экземпляр модели, затем
|
||
заполнить его данными из `$_POST` и, в случае успешного сохранения модели, перенаправить
|
||
браузер пользователя на страницу созданной модели. Стоит отметить, что само сохранение
|
||
модели должно быть реализовано в классе модели, а не в контроллере;
|
||
|
||
* не должен содержать SQL-запросы. Их лучше держать в моделях;
|
||
|
||
* не должен содержать HTML и другую разметку. Её стоит вынести в представления.
|
||
|
||
|
||
В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и
|
||
содержат только несколько десятков строк кода. В то же время, модели очень толстые
|
||
и содержат большую часть кода, связанную с обработкой данных, так как структура
|
||
данных и бизнес-логика, содержащиеся там, обычно довольно специфичны для конкретного
|
||
приложения. Логика контроллера, наоборот, довольно типична и может быть вынесена
|
||
в базовые классы.
|
||
|
||
<div class="revision">$Id: basics.best-practices.txt 2795 2010-12-31 00:22:33Z alexander.makarow $</div> |