mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-19 14:36:52 +01:00
137 lines
12 KiB
Plaintext
137 lines
12 KiB
Plaintext
Кращі практики MVC
|
||
==================
|
||
Недивлячись на те, що MVC відомий практично кожному веб-розробнику, його
|
||
використання у реальних проектах часто викликає труднощі. Головна ідея
|
||
MVC — **повторне використання коду та розділення проблем**. У даному розділі
|
||
будуть описані загальні принципи, які допоможуть слідувати MVC у вашому додатку.
|
||
|
||
Допустимо, що веб-додаток складається із декількох піддодатків, таких як
|
||
|
||
* front end: та частина сайту, яку бачать користувачі;
|
||
* back end: адміністративна частина сайту, яка дозволяє керувати додатком.
|
||
Доступ до неї зазвичай обмежений;
|
||
* консоль: додаток, який складається із набору консольних команд та запускається у вікні терміналу або як завдання cron-у;
|
||
* 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> |