Чи може / має чи в базовому режимі пошук основних даних із Моделі у MVC?


10

Враховуючи концепцію "худих контролерів, жирових моделей" та загального визнання того, що Views можуть безпосередньо закликати Моделі, коли потрібні дані для виведення даних, чи варто розглядати обробку частин запитів "дістати та відображати" в межах Views, а не контролера? Наприклад (спроба зберегти код досить загальним):

Контролер

<?php

class Invoice extends Base_Controller {

    /**
     * Get all the invoices for this month
     */

    public function current_month() {

        // as there's no user input let's keep the controller very skinny,
        // DON'T get data from the Model here, just load the view

        $this->load->view('invoice/current_month');

    }

}

Вид

<?php

// directly retrieve current month invoices here

$invoices = $this->invoice_model->get_current_month();

// get some other display-only data, e.g. a list of users for a separate list somewhere on the page

$users = $this->user_model->get_users();

?>

<h1>This month's invoices</h1>

<ul>
<?php foreach ($invoices as $invoice) { ?>

<li><?php echo $invoice['ref']; ?></li>

<?php } ?>
</ul>

Для мене це має хоч якийсь сенс у тих випадках, коли запит по суті є лише Переглядом. Чому Контролер повинен збирати та передавати дані в Перегляд, коли він може сам їх отримати? Це залишає контролер відкритим для чисто "обробки додатків" (наприклад, обробка запитів GET / POST, управління правами доступу та дозволів тощо), а також збереження моделей для повторного використання та всіх інших хороших речей.

Якщо цей приклад було розширено, щоб дозволити користувачеві фільтрувати результати, Контролер просто оброблятиме POST з форми і передає фільтри до Перегляду, який потім знову запитуватиме дані, на цей раз за допомогою фільтрів.

Це вірний підхід до розробки програми MVC? Або я не помічаю важливої ​​частини ролі, яку повинен виконувати контролер?

Відповіді:


17

Так, це технічно можна зробити. Ні, цього не слід робити. І так, ви трохи не вистачаєте для того, для чого потрібен контролер.

Контролер є для того, щоб від'єднати вигляд від моделі. Розв'язка вигідна, тому що ви повинні розглядати вид як майже викинутий код. Оскільки ваша технологія інтерфейсу користувача змінюється, ви хочете мінімізувати переробку, необхідну для створення нового перегляду. Контролер дозволяє цю розв'язку і надає місце для вашого коду, який буде працювати за технологіями інтерфейсу користувача.

Він працює і в зворотному випадку, якщо вам потрібно додати або змінити свою модель. Всі зміни вгору за течією будуть міститися в Контролері, і ваші перегляди залишаться в спокої.

Інший ризик , що в той час як View дуже просто прямо зараз , у вас є менше гарантій , що він буде залишатися так просто на протязі всього свого життя. Зателефонувавши «Моделі» безпосередньо з (дуже простого) виду, ви трохи відкрили двері, щоб дозволити повну додаткову погану практику, коли дуже простий вид повинен стати не дуже простим. Майбутній розробник буде спокушатись робити більше дзвінків у моделі з не дуже простого перегляду, а не переробляти код і взаємодіяти з контролером.


1
Чудова відповідь, дякую. Трохи розширити сценарій "вперед"; якщо на сторінці є загальна інформація, яка є окремою від запитуваної (наприклад, користувач переглядає певний продукт, збоку відображається загальний список "останніх спеціальних пропозицій"), як / куди слід робити дзвінок offers_model->get_latest()? Додавання цього до кожного методу в контролері (як я нерозумно намагався раніше) здається непосильним і явно не СУХИМ.
Адам Вестбрук

2
@AdamWestbrook Погляньте на MVVM. Частина ViewModel може вирішити цю конкретну проблему. Ви можете додати offers_model->get_latest()до ProductViewModelбазового класу або що - щось подібне.
Zachary Yates

1
Чудово, я обов'язково загляну в MVVM, ще раз дякую.
Адам Вестбрук

Дуже гарна відповідь, буде викликати зауваження. Особисто я також великий фанат MVVM :)
Бенджамін Груенбаум

@BenjaminGruenbaum Чи використовуєте MVVM в PHP? Якщо так, ви використовуєте для цього певну рамку?
Адам Вестбрук

6

Враховуючи концепцію "худих контролерів, жирових моделей" та загальне визнання, що Views може безпосередньо закликати Моделі, коли потрібні дані для виводу

Ні. Це неправильно. Перегляд не може безпосередньо телефонувати на Моделі. Перегляди не повинні мати доступ до об'єктів Model, якщо з певних причин програміст не виставив ці об'єкти Перегляду.

чи слід розглянути питання про обробку частин запитів "дістати і відобразити" в межах перегляду, а не в контролері?

Це в основному стирає Контролер і перемагає точку їх наявності.

Чому Контролер повинен збирати та передавати дані в Перегляд, коли він може сам їх отримати?

Контролер не збирає дані. Модель здійснює збір даних. Контролер вирішує, чи слід передавати ці дані перегляду. Перегляд просто представляє дані.

Якщо цей приклад було розширено, щоб дозволити користувачеві фільтрувати результати, Контролер просто оброблятиме POST з форми і передає фільтри до Перегляду, який потім знову запитуватиме дані, на цей раз за допомогою фільтрів.

Ні.

Контролер перевіряє, чи дані POSTed є дійсними, потім він передає ці дані як параметри Моделі, яка б потім запитала джерело даних і повертала дані, а Контролер передає їх у Вигляд.

Це вірний підхід до розробки програми MVC? Або я не помічаю важливої ​​частини ролі, яку повинен виконувати контролер?

Контролер працює як обробник запитів браузера. Диспетчер відправляє запит на дію контролера, який, у свою чергу, поширює запит на Моделі. Моделі містять всю логіку бізнесу (це жирна частина) і повертають дані контролеру. Потім контролер може спростити та відрегулювати дані, щоб представництву було легше їх представити.

Суть Погляду полягає в тому, щоб роз'єднати структуру та залежність між презентацією HTML та DataSource. Хоча це може бути складно. Перегляди не завжди представляють дані, які надходили безпосередньо від моделі. Контролер часто додає додаткові дані, які є релевантними.

Я впевнений, що на MVC багато навчальних посібників. Я рекомендую прочитати деякі з них.


Дякую Метью. Для уточнення, до цих пір я завжди знімав Вигляд і Модель з Контролером, як прочитано та запропоновано. Однак, починаючи з читання про збереження «худих» контролерів, мені просто було цікаво, що слід / що могло б перенести з них, здається, що процес думки, який привів мене до цього питання, був надто далеко на крок або два!
Адам Вестбрук

Коли ви починаєте отримувати Моделі, використовувані багатьма контролерами. Потреба в тому, щоб вони були жирними, стає дуже зрозумілою. Коли View починає містити багато PHP, тоді ви знаєте, що ваш контролер стоншується. Коли ваші контролери дуже жирні. Іншим контролерам важко змусити працювати таким же чином (наприклад, додавши послугу API).
Реакційний

3

Я вважав ваше запитання дуже цікавим, оскільки я нещодавно зіткнувся з тим самим питанням, вивчаючи Python.

У той час як наведені відповіді доводять переконливий аргумент, я думав, що додам ще одну думку, на яку я зіткнувся, в якій погляд отримує стан моделі, не проходячи через контролер.

MVC

Важливо зазначити, що і вид, і контролер залежать від моделі. Однак модель не залежить ні від виду, ні від контролера. Це одна з ключових переваг розлуки. Цей поділ дозволяє будувати та випробовувати модель незалежно від візуальної презентації. Розділення між представленням та контролером є вторинним для багатьох застосунків багатого клієнта, і фактично багато систем інтерфейсу користувача реалізують ролі як один об'єкт. З іншого боку, у веб-додатках дуже чітко визначено поділ між представленням (браузер) та контролером (компоненти сервера, що обробляють HTTP-запит).

Model-View-Controller - це основна модель дизайну для відділення логіки інтерфейсу користувача від бізнес-логіки. На жаль, популярність шаблону призвела до низки дефектних описів. Зокрема, термін "контролер" використовувався для позначення різних речей у різних контекстах. На щастя, поява веб-додатків допомогла вирішити деяку неоднозначність, оскільки поділ між представленням та контролером настільки очевидний.

У прикладному програмуванні в Smalltalk-80: Як користуватися Model-View-Controller (MVC) [Burbeck92], Стів Бербек описує два варіанти MVC: пасивну модель та активну модель.

Пасивна модель використовується, коли один контролер виключно маніпулює моделлю. Контролер модифікує модель, а потім повідомляє думку про те, що модель змінилася і повинна бути оновлена ​​(див. Малюнок 2). Модель у цьому сценарії повністю не залежить від погляду та контролера, а це означає, що модель не може повідомити про зміни у своєму стані. Приклад цього є протокол HTTP. У браузері немає простого способу отримання асинхронних оновлень з сервера. Веб-переглядач відображає подання та відповідає на введення користувача, але він не виявляє змін у даних на сервері. Тільки коли користувач явно вимагає оновлення, сервер допитується про зміни.

MVC - пасивна модель

Мені не вдається сказати, яка з думок є "правильною", і якщо чесно, я трохи більше плутаюсь, прочитавши відповіді тут і пов’язану статтю.

Повний текст статті тут .


Правильно, і інша річ, яка додає плутанини, - це клієнт-сервер, на який оригінальний MVC SmallTalk насправді не враховувався. У клієнт-сервері (наприклад, з javascript) є клієнтсько-орієнтовані моделі, погляди та контролери на клієнті, а також орієнтовані на домени погляди та контролери на сервері, хоча сервер також виконує деяку орієнтацію на презентацію, додаючи плутанину. Крім того, іноді ми хочемо, щоб представлення домену мали деяку стійкість, а це означає, що параметри подання формують власну модель, що не обов'язково є частиною доменної моделі.
Ерік Ейдт

Дякую за посилання, я знав, що я не злий з цього приводу! Це, по суті, те, про що я пішов, перш ніж зайняти ідею трохи надто далеко, доки модель не залежатиме ні від чого, що має значення, як / де вона має доступ? Я ще не вирішив, який підхід я буду використовувати у своїй наступній розробці, але це безумовно допомагає.
Адам Вестбрук

1

Ще одна річ, яку слід врахувати, це те, що, здається, ви завантажили user_modelта invoice_modelдозволу представнику доступу до них. Щоб це надійно працювало, ви, ймовірно, автоматично завантажуєте всі свої моделі (тому що $this->load->model()на виду просто виглядає неправильно, чи не так ...)

Це зайво роздуває ваш стек, завантажуючи купу речей, до яких ніколи не звикнути. Частина причини наявності декількох моделей полягає в тому, щоб ви могли інкапсулювати пов'язану логіку і завантажувати лише те, що вам потрібно для даної задачі.

Це схоже на CodeIgniter. Я зробив багато розробок CI, і я можу поділитися з особистого досвіду, що ви дійсно не хочете завантажувати більше, ніж потрібно насправді. Спробуйте додати $this->output->enable_profiler(TRUE);в конструктор контролера та поспілкуватися з автоматичними завантаженнями (включаючи подібні помічники database): ви, ймовірно, побачите значну зміну часу завантаження та виконання, але особливо у розподілі пам'яті.


1
Хороші бали, ви праві, що це базується на CI, хоча для ясності я видалив деякі конкретні синтаксиси. Я ввійшов у звичку «автозавантажувати» майже все здебільшого за час та із сухих причин, здавалось, трохи шалено мав багато того самого load->modelу більшості контролерів та методів. Не використання належної функції автозавантаження - це одне з речей, які мені найбільше не подобається щодо зворотної сумісності CI, але це зовсім інша дискусія ...
Адам Вестбрук

0

Коротка відповідь полягає в тому, що форма вашого зразка коду оманливо інтуїтивно зрозуміла. Здавалося б, це простий шлях на розум.


Завдання №1

Ваші Modelта Viewоб’єкти будуть щільно з'єднані.

Якщо вам коли-небудь доведеться додавати або видаляти методи в Model, можливо, вам доведеться відповідно змінити View.

Принципово, MVC походить із моделей командування та спостерігача . Вам потрібно незалежну "Модель", якою керують через інтерфейс / API , до якого Controllerможе підключитися (тобто делегувати).

Часто це означає введення Model та Viewінстанцій у Controllerта збереження їх як властивості зазначеного Controller. Потім, використовуючи метод Controller(тобто команда) як робочу область, передайте дані в a View з Model ( після того, як `Модель закінчила оновлення стану програми ).

Попутний дані (масиви, Iterable об'єктів, безвідносно) продовжує сшивающий між Modelі Viewвипадками втратити . Якщо ви введете Modelекземпляр у програму View, див. Проблему №1 вище.

Пам'ятайте, що Viewsможуть бути HTML, JSON, Text, XML, заголовки HTTP, YAML або майже що-небудь, дотримуючись методології передачі стану представлення (REST) .

Таким чином, ключовим у розумінні того, як керувати відносинами між Modelі Viewsполягає в тому, щоб побачити відносини такими, якими вони є, один-багатьом (потенційно)! Саме це і було розроблено схемою спостерігача .

Хоча для більшості налаштувань одночасно слід зайнятися одним переглядом, ніщо не заважає архітектурній схемі MVC оновлювати декілька представлень одночасно! Робота з традиційними веб-програмами CRUD змушує людей думати однозначно , але це найменший приклад того, як може працювати шаблон спостерігача ( один - багато хто - інший ).

Таким чином, якщо у вас був один Modelі кілька Views, потенційний головний біль від оновлення всього Views'коду реалізації, оскільки ви щось змінили в Model'sAPI / методах, зараз стає гострим .

Передайте дані Views , а не екземпляри Models .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.