Недивлячись на те, що MVC відомий практично кожному веб-розробнику, його використання у реальних проектах часто викликає труднощі. Головна ідея MVC — повторне використання коду та розділення проблем. У даному розділі будуть описані загальні принципи, які допоможуть слідувати MVC у вашому додатку.
Допустимо, що веб-додаток складається із декількох піддодатків, таких як
Піддодатки можуть бути реалізовані у вигляді модулів або як додаток, який містить код, загальний для декількох піддодатків.
Моделі представляють структури даних, які
використовуться у додатку, і часто є спільними для кількох піддодатків.
Наприклад, модель 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-додатку контролери зазвичай дуже тонкі та містять тільки декілька десятків рядків коду. У той же час, моделі дуже товсті та містять більшу частину коду, повʼязану із обробкою даних, так як структура даних та бізнес-логіка, які там міститься, зазвичай доволі специфічні для конкретного додатку. Логіка контролеру, навпаки, доволі типова та може бути винесена у базові класи.