MVC для веб: проще некуда

В этой статье мы рассмотрим архитектурный паттерн MVC (Model, View, Controller) в применении к веб-разработке, «в чистом виде», без привлечения каких-то дополнительных, не относящихся к MVC структур и паттернов. Мы будем продвигаться от простого к сложному, поэтому пока не станем рассматривать, например, дальнейшее развитие MVC – паттерн HMVC (Hierarchical MVC). Хотя HMVC, несомненно, намного более интересен для разработки веб-приложений, но его применение не отменяет необходимости понимания «обычного» MVC.

Статья в Википедии (а именно туда, видимо, чаще всего попадают те, кто только начинает изучать MVC), изобилует неточностями и туманными формулировками, само определение, по сути, является неверным, а приведенная схема просто напросто не соответствует той, которая применяется в веб вообще и при разработке на PHP – в особенности.

Наиболее корректное определение паттерна MVC я обнаружил тут:

Шаблон проектирования MVC предполагает разделение данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: Модель, Представление и Контроллер – таким образом, что модификация каждого компонента может осуществляться независимо.

Уточним, что термин «компонент» в данном случае не имеет никакой связи с компонентами некоторых популярных CMS или фреймворков, а компоненты Битрикса, например вообще строятся из всех трёх составляющих MVC.
В приведённом определении под компонентом следует понимать некую отдельную часть кода, каждая из которых играет одну из ролей Контроллера, Модели или Представления, где Модель служит для извлечения и манипуляций данными приложения, Представление отвечает за видимое пользователю отображение этих данных (то есть, в применении к вебу, формирует отдаваемый сервером браузеру пользователя HTML/CSS), а Контроллер управляет всем этим оркестром.

Давайте рассмотрим классическую схему веб-приложения:

Рисунок 1



На этом и последующем рисунках пунктирными линиями показана управляющая информация (такая, например, как ID запрашиваемой записи блога или товара в магазине), а сплошными – собственно данные приложения (которые могут храниться в БД, или в виде файлов на диске, или даже, возможно, в оперативной памяти – этот вопрос лежит за пределами паттерна MVC). В применении к вебу запрос и ответ ходят по HTTP, поэтому можно условно считать, что на этом рисунке пунктиром обозначены заголовки HTTP-запроса и ответа, а сплошными линиями – их тела.

Получив Запрос 1, Контроллер его анализирует, и в зависимости от результатов обработки может выдать следующие варианты ответа (почему ответ имеет номер 4, станет понятно из следующих рисунков):

1. Сразу выдать ответ об ошибке (например, при запросе несуществующей страницы отдать только HTTP-заголовок «404 Not found»)

2. Если поступивший Запрос 1 признан корректным, то, в зависимости от того, является он запросом на просмотр или на модификацию данных, Контроллер вызывает соответствующий метод Модели, такой как Save или Load (Запрос 2 на Рис.2).

Рисунок 2



Важное замечание: концепция MVC не только не привязана к какому-то конкретному языку программирования, она также не привязана и к используемой парадигме программирования. То есть, вы вполне можете проектировать своё приложение по MVC, при этом не применяя ООП, и спроектировать Модель Товар для интернет-магазина таким образом:

<?

mixed Product_Load (int $id) { ... }
// возвращает ассоциативный массив с данными о Товаре либо FALSE при неудаче

bool Product_Save (array $data) { ... }
// возвращает TRUE при удачном сохранении данных $data, либо FALSE при неудаче

?>


Итак, в зависимости от полученного от Модели Ответа 2 Контроллер решает, какое из Представлений вызвать для формирования итогового ответа на изначальный Запрос 1:

3.1. В случае неудачи – Представление для сообщения об ошибке
3.2. В случае успеха – Представление для отображения запрашиваемых данных либо сообщения об их успешном сохранении (если Запрос 1 был на изменение данных).

Рисунок 3



Вопрос о том, кто должен проверять на валидность и права доступа входные данные (Контроллер или Модель), является предметом достаточно многочисленных споров, поскольку паттерн MVC не описывает таких деталей. Это значит, что в этом вопросе выбор за вами (или за вас его сделали авторы вашего любимого фрейvворка или CMS).
Мы в своей практике придерживаемся такого подхода:
Контроллер проверяет входные данные на предмет «общей» (т.е. независящей от конкретного запроса) корректности, соответствие требованиям Модели к валидности сохраняемых данных проверяет соответствующий метод Модели, а права доступа – метод Access отдельного класса User.

Для вызова Представления в PHP иногда проектируется специальный класс (а то и несколько классов), например, View (это часто встречается в описаниях MVC в реализации того или иного фреймворка), однако это не является требованием MVC.
Также файлы Представлений часто называют шаблонами, а при использовании так называемых шаблонизаторов роль Представления играет сам шаблонизатор, а шаблоны (т.е. файлы, содержащие непосредственно HTML-разметку) в некоторых фреймворках называют layouts.

Не вполне понятен предыдущий абзац? Забейте, поскольку у нас каждое Представление – это просто отдельный PHP-файл, а сам PHP устроен так, что в случае, если мы используем для выполнения Запроса 3 инструкцию include, Ответ 3 и Ответ 4 (помните, что это ответ на Запрос 1?) отдаются браузеру автоматически, средствами самого PHP.

Давайте рассмотрим пример.

У нас есть два варианта Представления (шаблоны), в которых

<!-- HTML.header --> будет означать HTML-код, предворяющий в формируемом веб-документе основной контент (т.е. содержит тег doctype, контейнер head, код шапки страницы, и т.п.), а <!-- HTML.footer --> – примерно то же, только для подвала страницы.

Листинг 1. Шаблон product.tpl.php отображает данные о Товаре (которые к моменту его вызова уже содержит объект $product):




<!-- HTML.header -->

<h1><?=$product->Title;?></h1>
<p>Цена:<b class="price"><?=$product->Price;?></b></p>
<p class="description"><?=$product->Description;?></p>

<!-- HTML.footer -->



Листинг 2. Шаблон error.tpl.php отображает сообщение об ошибке (которое содержится в переменной $error):




<!-- HTML.header -->

<h1 class="error">Ошибка: <?=$error;?></h1>

<!-- HTML.footer -->



Листинг 3. Контроллер product.php, служащий для отобоажения Товара, будет выглядеть примерно так:



<?

include 'product.class.php'; // в этом файле декларируются методы Модели Товар

// определение этой функции в контроллере, конечно, неправильно
// в данном случае она здесь только для наглядности
function Error ($error) {
	// выводит сообщение об ошибке и завершает работу контроллера, примерно так:
	header('Правильный статус ошибки, например, 400 или 404');
	$error = 'Соответствующее ошибке сообщение пользователю, например, Страницы не существует';
	include 'error.tpl.php';  // шаблон для отображения ошибки
	exit;	
}

if (!$id = ...) // проверка "общей" валидности Запроса 1
	error(...);

// проверка прав доступа
if (!$user->Access(...))
	error(403);

if (!$product = Product::Load($id))  // Запрос 2 и анализ Ответа 2
	error('Тут скорее всего случилась ошибка БД');

include 'product.tpl.php';  // Запрос 3 и Ответы 3 и 4

?>


Те, кто любит красивый и оптимизированный код могут заметить, что блоки HTML.header и HTML.footer дублируются в обоих шаблонах (они же Представления) error.tpl.php и product.tpl.php, и наверняка захотят вынести их в Контроллер product.save.php:

<!-- HTML.header -->
<?

// Основной код контролера из Листинга 3

?>
<!-- HTML.footer -->


…. и нарушить таким образом основное правило MVC – разделяйте Контроллер, Модель и Представление.

Тем не менее, дублирующийся код – однозначное Зло. Что же делать?
Мы должны перейти от MVC к HMVC!
Но это – тема отдельной статьи.

Комментарии 102

    +13
    Я ничего плохого сказать не хочу, но новизна такой статьи истекла лет 10 тому назад (на самом деле, много больше, но лет 10 назад как раз все это активно обсуждалось).
    А если тут, на хабре, вбить в поиск MVC, то можно узреть over9000 топиков про этот паттерн во всем мыслимых и немыслимых вариантах.
      –3
      :)
      эта статья есть попытка показать, где MVC, а где «варианты»…
      ибо некоторые «варианты» на самом деле искажают, а местами сильно искажают то, что декларируется в MVC
        –2
        ну, или, выражаясь другими словами — по своей практике возникло ощущение, что за 10 лет MVC оброс таким количеством «вспомогательных» элементов и «вариантов», что самое время ещё раз напомнить, где MVC, а где «дальнейшее развитие»…
        0
        Тривия.
        Для преодоления дублирования используются лейауты — общие представления, контекстно содержащие в себе конкретные представления. Никакого нарушения.
          0
          я как раз имею в виду продолжение об этом написать, можете рассказать или направить, что же такое лейауты и какое они имеют место в MVC?
            0
            MVC — архитектурный паттерн, layout — вариант реализации (в данном случае, отображения или V в MVC). Т.е., layout не имеет никакого отношения к MVC, но вместе получается лучше, чем дублирование шапки и подвала в каждой вьюхе.
          0
          В меру моего понимания MVC методы или функции типа load/save относятся не к модели, а к контроллеру. Как раз потому что их наличие в модели может не позволить изменять модель без изменения контроллера при изменении способа хранения (скажем на такой, в котором эти методы не имеют смысла, например в памяти процесса). Модель, по-моему, не должна знать ничего о том как она хранится, это забот контроллера получить экземпляр модели (полностью или только необходимого фрагмента — не суть).

          С другой стороны, обычно модель это не только (а то и не столько) данные, а и логика предметной области о чем в посте не упомянуто и может сложиться впечатление, что вся логика должна быть в контроллере.
            –1
            header('Правильный статус ошибки, например, 400 или 404');
            $error = 'Соответствующее ошибке сообщение пользователю, например, Страницы не существует';


            Это так-то вы разделяете Контроллер и Представление?
            Не знаю, как принято у вас в PHP, но в приличных языках тот, кто указывает, какой шаблон генерировать для Представления, как это делаете и вы:
            include 'error.tpl.php'; // шаблон для отображения ошибки

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

            Не пишите статью о HMVC, оставьте это кому-то с лучшим пониманием деталей применения MVC.
              –1
              может, Вы приведёте примеры статей кого-то с лучшим пониманием MVC? можно даже не обязательно Ваших
                +1
                Здесь есть интересная статья о MVC. В контексте PHP.
                  0
                  Спасибо, роскошная статья, обязательно её попользую при следующих своих творчествах, если они состоятся
                • НЛО прилетело и опубликовало эту надпись здесь
                    0
                    кстати, для начального изучения MVC это как раз плохой пример…
                    очень надеюсь, что напишу более развёрнутую статью по этому поводу…
                    а стрелка на схеме «Данные от Представления к Модели» — просто катастрофически не по MVC
                      0
                      А чего катастрофического? Представление может вызывать методы модели, не изменяющие (или изменяющие по принципу lazy load) её состояния, в том числе и передавать параметры. Например, банальный вывод первых десяти элементов в коллекции с помощью метода $collection->getItem($i); $i в данном случае будет данными, передаваемыми от представления к модели.
                        0
                        > Представление может вызывать методы модели
                        При таком подходе можно считать, что модель вполне может самостоятельно обрабатывать параметры HTTP-запроса.
                        И что HTML-код очень удобно держать в методе Модели Show (чем многие перескакивающие с классических ЯП на web страдают)…
                        Можно как угодно модифицировать, дополнять, обрезать MVC, просто не следует это называть MVC.
                          0
                          Обмен данными между моделью и представлением по инициативе представления — это именно классический MVC. Представление получает сообщение об изменение модели и запрашивает у неё нужные ему данные.
                            0
                            А зачем тогда контроллер нужен?
                              0
                              «Конвертировать» действия пользователя в изменения состояния модели.
                                0
                                Можете набросать схему, которая будет соответствовать правильному в вашем понимании MVC для такой задачи:
                                Просмотр списка товаров, формат представления списка («плитка», таблица кратко, таблица подробно) является настройкой конкретного пользователя.
                                ?
                                  0
                                  Коллекция/массив «товары». Представление с «контролом» «список», поддерживающее три вида. Контроллер.
                                  Контроллер формирует коллекцию (читает из БД, файла, ещё откуда-то)и передает её представлению. Оно формирует три варианта списка методами типа getName(), getDescription(), getImage() и т. п.
                                    –1
                                    Что ж, ваше «Контроллер формирует коллекцию (читает из БД ..)» прекрасно иллюстрирует ваше понимание MVC и объясняет, почему вы так яростно спорите с очевидными вещами.
                                      0
                                      И кто же по вашему должен формировать модель в памяти процесса и отвечать за её персистентность между запросами? Она сама себя? Или представление? Приведите хоть одно авторитетное определение, где сказано, что в модели должна быть не только бизнес-логика, но и логика хранения данных (что общеговоря нарушает принцип инственной отвественности, как впопулярно паттерне ActiveRec? bcgjkmpetvv d MVC, когдводномклассе совмещаютсяи бизнес-логика, и логика хранения)? Модель вообще, может существовать без какого-либо хранилища, только на время жизни процесса, а то и меньше. И временем её жизни управляет контроллер (больше некому).
                                        –1
                                        почитайте авторитетов самостоятельно, я эту статью написал для тех, кто хочет разобраться, что такое MVC, а не для тех, которые жаждут, чтобы их высочество или величество в чём-то убедили…
                                        таких, как вы, убеждать бессмысленно…
                                          0
                                          В чем убеждать? В выдуманной вами интерпретации MVC? Создатели MVC для вас достаточно авторитетны?
                                          The view manages the graphical and/or textual output to the portion of the bitmapped display that is allocated to its application. The controller interprets the mouse and keyboard inputs from the user, commanding the model and/or the view to change as appropriate. Finally, the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller).


                                          Черным по-белому сказано, что модель управляет поведением и данными предметной области, но вовсе не их хранением. А за управление моделью и её состоянием отвечает контроллер.
                                            –1
                                            Вам осталась самая малость — указать, в чём приведённое мной определение противоречит приведённому вами
                                              0
                                              а стрелка на схеме «Данные от Представления к Модели» — просто катастрофически не по MVC

                                              responds to requests for information about its state (usually from the view)

                                              Действительно не видите?

                                                0
                                                А вы это видите?
                                                «В этой статье мы рассмотрим архитектурный паттерн MVC (Model, View, Controller) в применении к веб-разработке».
                                                Расскажите, каким образом в вашем понимании View, который на клиенте, может напрямую обратиться к Model (которая на сервере)?
                                                  0
                                                  В процессе формирования. <?= $model->getItem(1); ?>
                                                    –1
                                                    Вопрос был «Расскажите, каким образом в вашем понимании View, который на клиенте, может напрямую обратиться к Model (которая на сервере)?»
                                                    Разжую, раз вы не желаете осмыслить вопрос:
                                                    Веб-страница на клиенте (Представление), нажимается ссылка «Следующие 10 товаров».
                                                    Каким образом Представление вызовет напрямую ваш метод Модели $model->getItem(2)?
                                                      0
                                                      Нельзя считать страницу на клиенте представлением — она его часть, как и шаблон на сервере, как и шаблонизатор на нем. При нажатии ссылки представление на клиенте сформирует запрос к контроллеру, тот восстановит модель, а потом передаст её представлению на сервере, где оно вызовет методы модели для получения данных (возможно с параметрами), а потом отдаст клиенту.
                                                        –1
                                                        > представление на клиенте сформирует запрос к контроллеру, тот восстановит модель, а потом передаст её представлению на сервере
                                                        Статья именно об этом
                                                        > на сервере, где оно [Представление?] вызовет методы модели для получения данных
                                                        Статья так же о том, что это плохая практика.
                                                        Пожалуйста, можете проектировать через одно место, только не говорите, что этому учит MVC.
                                                        Если только Вы не говорите об HMVC, но тогда будьте любезны обратить внимание на фразу «пока не станем рассматривать, например, дальнейшее развитие MVC – паттерн HMVC»
                                                          0
                                                          Статья именно об этом

                                                          Тогда непонятно чем вас удивило «Контроллер формирует коллекцию (читает из БД ..)»
                                                          Статья так же о том, что это плохая практика.

                                                          Это не плохая практика, а нормальная, имхо. Как раз создание суррогатных DTO (массивов, переменных) для передачи данных от модели к серверной части представления считаю плохой в большинстве случаев, как увеличивающую связанность модели с контроллером и контроллера с представлением, уменьшая связанность модели и представления. Проще говоря, больше нужно будет исправлений в код вносить скажем, решим добавить поле. При «моем подходе» изменения только в модель и представление вносить, а при вашем ещё и в контроллер. Иногда это оправдано, но в общем случае — нет, имхо.
                                                            –1
                                                            При подходе, о котором эта статья, при добавлении поля в БД нужно будет вносить изменения только в Представление.
                                                            Ладно, я понял, что вы прочитали статью и всё в ней поняли.
                                                            Удачи… и внимания и большего понимания при чтении!..
                0
                Мне вот интересно, а на основании чего вы определяете «правильность» определения MVC? С какими авторитетными источниками вы сравниваете?

                А то, например, статья, на которую вы ссылаетесь, в части .net полностью неверна (да и банально устарела, учитывая наличие «честного» asp.net MVC, про который там не слова).
                  –2
                  Определил я правильность, изучив 100500 определений и пояснений авторов разной степени авторитетности.
                  Приведённое мой определение является непротиворечивым как внутренне, так и внешне (по крайней мере по отношению к тем системам, которые придерживаются именно MVC, пусть и с теми или иными сопутствующими механизмами).

                  > в части .net полностью неверна
                  Эту статью я написал с одной целью — показать, что есть MVC, а что есть её интерпретации, развития или вариации с комбинациями. Примитивный код на PHP приведён для того, чтобы показать, что MVC — это совсем не «богатая» система классов типа Controller, View, Layout и прочих, коих легион, и многие из которых действительно полезны, а что MVC — это образ мышления при проектировании веб-приложения.
                  И если в .NET какая-то другая MVC (в чём я, кстати, сомневаюсь) — значит, там вовсе не MVC

                  Комментарии в стиле «а вот там не так, а вот у этого по-другому» говорят о том, что статья как раз актуальна, ибо там, где действительно «не так» — либо там не MVC, либо комментатор так и не уловил, где там MVC, а где другие, смежные паттерны
                    +4
                    Определил я правильность, изучив 100500 определений и пояснений авторов разной степени авторитетности.

                    Цитаты в студию.

                    MVC — это образ мышления при проектировании веб-приложения.

                    Нет. MVC — это архитектурный шаблон, не более.

                    И если в .NET какая-то другая MVC (в чём я, кстати, сомневаюсь) — значит, там вовсе не MVC

                    либо там не MVC, либо комментатор так и не уловил, где там MVC, а где другие, смежные паттерны

                    Вариант, что вы ошибаетесь, вы вовсе не рассматриваете?

                    Вы не замечаете, что ваше определение рекурсивно? «Я считаю, что мое определение MVC верно, потому что оно совпадает с моим представлением об MVC».
                      –2
                      > Цитаты в студию
                      Видите ли, эта статья предназначена тем, кто только начинает изучать MVC, дабы они не погрязли в том обилии материала, где от MVC одно название. Поэтому я привёл то определение (заметьте, не моё), которое даёт максимально ясное понимание MVC. Цитат, которые запутают новичков, Вы от меня не дождётесь, ладно?

                      >> MVC — это образ мышления при проектировании веб-приложения.
                      >> MVC — это архитектурный шаблон, не более
                      э?..

                      > Вариант, что вы ошибаетесь, вы вовсе не рассматриваете?
                      в данном случае (что приведённое мной определение абсолютно верное) — полностью исключено

                      > ваше определение рекурсивно
                      чем писать столько букав, приведите определение, которое Вы считаете верным, будет проще обсуждать
                        +1
                        Поэтому я привёл то определение (заметьте, не моё), которое даёт максимально ясное понимание MVC.

                        … и которое бессмысленно, потому что не дает определения ни одного из компонентов.

                        э?..

                        Вы невнимательные. И, видимо, не знаете, что такое design pattern.

                        определение, которое Вы считаете верным

                        Определение чего? «Классического» MVC? «Современного», которое Model2?

                        А вообще — PoEAA, страница 330.
                          0
                          понятно, спасибо
                      0
                      Как минимум вы упустили в своем определении логику предметной области (бизнес-логику). Данные у вас есть, пользовательский интерфейс есть, управляющая логика есть, а где предметная?

                      Ну и плюс по вашему объяснению далее получается, что представление не зависит от модели, хотя в классическом MVC это не так. Представление не должно воздействовать на модель (изменять её состояние), но вполне может получать данные от неё напрямую.
                        –1
                        это не моё определение

                        > управляющая логика есть, а где предметная?
                        В Модели, из определения этого разве не ясно? Пруф был дан (ещё раз спасибо rsvasilyev/) выше

                        > представление не зависит от модели, хотя в классическом MVC это не так
                        > Представление… вполне может получать данные от неё напрямую
                        Правильный MVC — это когда три компонента максимально независимы, а Модель и Представление взаимодействую только через Котроллер, а точнее, Контроллер «ими взаимодействует».
                        Подскажите, откуда Вы черпаете «классику»?
                          0
                          Не ясно. Из определения ясно, что данные в модели, пользовательский интерфейс в представлении, а управляющая логика в контроллере.

                          Из Smalltalk. Там представления подписываются на сообщения модели self changed, а потом сами получают от модели нужные им данные. В классическом MVC только модель не зависит от контроллеров и представлений, а они зависят друг от друга и от модели.
                            0
                            давайте рассуждать логически?
                            Контроллер — это управляющая Моделью и Представлением логика…
                            Представление — это представление (да-с)…
                            Модель — это манипулирование данными…
                            Вы реально думаете, что при таком определении нечто, именуемое бизнес-логикой, может быть в Контроллере или Представлении?
                              0
                              Если модель — это манипулирование данными, а контроллер управляет моделью, то получается, что контроллер управляет данными (через посредника). Именно поэтому выходит, что «нечто, именуемое бизнес-логикой», оказывается в контроллере.

                              А по факту «классический MVC» плохо ложится на web именно потому, что в нем нет событий, а есть линейная обработка (привет, Model2, который сейчас большая часть людей, включая вас, знает под именем MVC).
                                0
                                В правильном MVC есть события, их обрабатывает Контроллер, точнее, он в ответ на событие вызывает соответствующий метод Модели.
                                Он, возможно, и управляет данными, но не манипулирует ими, манипулирует Модель.
                                Может, расскажите уже, что за мифическая модель2? Судя по Вашим комментариям — какая-то майкрософтовская ересь
                                  0
                                  В правильном MVC есть события, их обрабатывает Контроллер, точнее, он в ответ на событие вызывает соответствующий метод Модели.

                                  События. В http. Конечно.

                                  Может, расскажите уже, что за мифическая модель2?

                                  Ну то есть вы с первоисточниками все-таки незнакомы.

                                  Ну да, «майкрософтовская ересь»… реализованная, правда, в Java, но какие мелочи.

                                  en.wikipedia.org/wiki/Model_2
                                    0
                                    Вообще в процессе обработки http никто не мешает генерировать события, да и сами http-запросы во многом можно считать событиями пользовательского интерфейса. И формировать ответ вовсе не обязательно линейно (логически). Можно, скажем, сформировать DOM «рекурсивно», а потом просто экспортировать его в строку.
                                      0
                                      Вообще в процессе обработки http никто не мешает генерировать события

                                      Никто не мешает. Посмотрите на asp.net webforms, там так и сделано.
                                        0
                                        :) Я не настолько высокоуровневые события имел ввиду. А просто событийную связь между контроллером, представлениями и моделью. Скажем, при изменение модели генерируется событие, на которые подписаны логгер и хранилище (тоже своего рода представления).
                                          0
                                          Это не «своего рода представления», не надо путать публику. Это совсем другого рода взаимосвязь.
                                            0
                                            > при изменение модели генерируется событие
                                            да не генерируется в вебе событие при изменении Модели, Модель изменяется по событию, ну, блин, чего Вы сочиняете?

                                            > своего рода представления
                                            своего рода Вы можете насочинять и Контроллеров, и Слоёв, и Наблюдателей — только это будут своего (Вашего) рода, а не MVC-шные…
                                            Так и пишите в следующий раз — «в моего рода MVC ...»
                                              0
                                              Вот именно поэтому в вебе и не используется классический MVC.
                                                0
                                                Именно потому я и рекомендую (для того статья) для начала разобраться, что такое MVC, а потому его (возможно) обвешивать другими паттернами, или применять другие, если такой «умный», хоть PoEAA-ми — главное, не называть PoEAA MVC и наоборот
                                                  0
                                                  Разбираться лучше по первоисточникам.
                                                    0
                                                    Вот именно, что сначала нужно разобраться что такое MVC вообще, а лишь потом его обычные особенности в вебе.
                                                  0
                                                  Всё зависит лишь от выбранного способа взаимодействия модели и представления. Выберем передачу событиями — будут события генерироваться. Выберем параметрами из контролера — будут из контроллера. Классический способ — событиями, для веба он обычно избыточен, поскольку редко бывают нужны связи один-ко-многим между моделью и представлением.
                                            0
                                            Да, смишно…
                                            На схеме частный случай MVC…
                                            Давайте теперь изобретём новую религию на основе того, что контроллер может иногда напрямую вызывать Представление (в статье это ф-ция Error)?
                                              +1
                                              Это в вашей голове контроллер может иногда напрямую вызывать представления. А в asp.net mvc контроллер всегда создает представление (если представление является результатом ответа контроллера).

                                              Что возвращает нас к вопросу: что же на самом деле такое MVC, и что сейчас под этим понимают. А для этого надо знать историю возникновения этого паттерна, и понимать, что появился он в rich interface, а не в вебе, а сейчас адаптирован к вебу — с соответствующими переделками.

                                              (впрочем, в вашем коде контроллер тоже напрямую вызывает представление, и не только в Error)
                                                0
                                                Не надо путать…
                                                «напрямую вызывает Представление» — имеется в виду, без обращения к Модели (ф-цмя Error)…
                                                Это частный случай, а общий — Представление всегда вызывается Контроллером, как правило, что отобрадения результатов взаимодействия Контроллера с Моделью…
                                                Но да, кому-то может захотеться вызывать Представление из Модели… Это плохой MVC, неправильный
                                                  +1
                                                  А у вас и нет никакого обращения к модели, у вас идет include 'product.tpl.php';, то есть прямой рендер представления, которое потом внутри себя обращается к модели.

                                                  Ну и да, вы начинаете себе противоречить — то контроллер иногда вызывает представление, то всегда…

                                                  А вот из модели представление не вызывается никогда, здесь вы правы… за исключением того факта, что в классическом MVC представление наблюдает (шаблон Observer) за моделью, и изменения в модели провоцируют изменения в представлении; чего у вас нет.
                                                    0
                                                    у меня есть обращение к Модели Контроллером:
                                                    $product = Product::Load($id)

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

                                                    > шаблон Observe
                                                    это другой шаблон… Вы вольны его использовать, только не говорите, что этот шаблон — часть шаблона MVC, это сильно неправда
                                                      0
                                                      у меня есть обращение к Модели Контроллером:
                                                      $product = Product::Load($id)

                                                      И что?

                                                      у меня (да, можете считать, что только у меня) Контроллер всегда вызывает Представление,

                                                      Тогда не надо было писать «Давайте теперь изобретём новую религию на основе того, что контроллер может иногда напрямую вызывать Представление».

                                                      Вы вольны его использовать, только не говорите, что этот шаблон — часть шаблона MVC, это сильно неправда

                                                      Вы, видимо, не понимаете, что это шаблоны разных уровней. Скажите, вы уже прочитали Фаулера, на которого я вам дал ссылку?
                                                    0
                                                    Вызывать представление из модели неправильно, а вот сообщить представлению, что модель изменилась — правильно. В веб-приложениях это зачастую делает контроллер, но классический случай — модель сама извещает всех, кто заинтересовался в её изменениях.
                                                      0
                                                      и снова я попрошу источник Вашей «классики» — где описан паттерн, где Модель оповещает кого угодно, кроме Контроллера, её вызвавшего?
                                                        0
                                                        Так PoEAA же.
                                                          0
                                                          ахха… точно!
                                                          0
                                                          Что значит «кроме»? Кого угодно, кто подписался на её события.
                                                            0
                                                            Я Вам русским языком объясняю, что патерн Наблюдатель — ни хорош, ни плох, просто это другой паттерн, не относящийся напрямую к паттерну MVC
                                                              0
                                                              Это наиболее распространенный для классического MVC способ реализации. Могут быть и другие способы реализации, но суть остается в том, что модель уведомляет свои представления о своем изменении. В вебе, ввиду того, что представление не существует постоянно, а формируется на миллисекунды и как правило только одно на запрос, эту функцию обычно берет на себя контроллер.
                                                                0
                                                                хм… кажется, именно об этом моя статья?
                                                    0
                                                    Контроллер вызывает представление практически всегда. В статье это include или error (тоже сводящаяся к include).

                                                    Кстати, у вас же представление напрямую взаимодействует с моделью в строках вида <?=$product->Price;?>. Оно прямо зависит от модели. Измените что-то в ней и нужно будет менять представление.
                                                      0
                                                      видимо, это вопрос религии, но моя религия в том, что Контроллер совсем всегда вызывает Представление (или его суррогат, когда сам Контроллер отдаёт HTTP-заголовок 404), и наоборот — Представление вызывает только Контроллер, а никак не Модель…
                                                      На практике для сокращения кода часто пытаются в метод Модели типа Product->Show(product_id) запихнуть вызов Представления Моделью, но это неправильное кун-фу (ИМХО)
                                                        0
                                                        Не совсем всегда. Скажем, если результат нас вообще не интересует. Но это редкий, конечно, случай и часто нарушение стандартов, но бывает.

                                                        — Модель никого не вызывает (кроме посылки сообщений в классике, но в традиционном вебе очень редко это используется, поскольку представления формируются обычно с нуля на каждый запрос).
                                                        — Контроллер вызывает модель и представление. Иногда модель не нужна. Очень редко не нужно и представление.
                                                        — Представление обычно вызывает модель (как правило только свойства или геттеры, не изменяющие свойства) и иногда — контроллер.

                                                        MVC запрещены только вызовы моделью представлений и контроллеров.

                                                          0
                                                          > Модель никого не вызывает
                                                          TRUE

                                                          > кроме посылки сообщений в классике
                                                          нет, не в классике, а в интерпретации…
                                                          ибо в классике Модель ничего не делает, пока её не дёрнут, а в ответ на дёрганье даёт ответ — тому, кому дёрнул…
                                                          Чтобы была MVC, дёргать нужно Контроллером — далее по паттерну

                                                          > Контроллер вызывает модель и представление
                                                          TRUE

                                                          > Иногда модель не нужна
                                                          TRUE

                                                          > Очень редко не нужно и представление
                                                          Условно TRUE. Ибо ответ 4 Контроллер по-хорошему всё равно должен дать, пусть в виде кода ошибки HTTP, или в виде переадресации 30x. Это слегка искажённое, но Представление

                                                          > Представление обычно вызывает модель
                                                          FALSE в начальном MVC (в интерпретациях можно встретить и более другие утверждения)
                                                          Событие, которое генерирует тот, кто взаимодействует с итоговым Представлением (обычно пользователь), отдаётся на обработку соответствующему Контроллеру

                                                            0
                                                            ибо в классике Модель ничего не делает, пока её не дёрнут, а в ответ на дёрганье даёт ответ — тому, кому дёрнул…

                                                            Да ну? Дайте же нам уже, наконец, точный источник этой классики.
                                                              0
                                                              так в статье есть определение, с источником…
                                                              теперь Ваша очередь опровергать, более авторитетным источником
                                                                0
                                                                Легко. PoEAA — существенно более авторитетный источник, чем некий Сергей Рогачев из Перми. Ну и плюс к этому опубликована она в 2002, а не в 2007-ом, что тоже наводит на мысли.
                                                                  +1
                                                                  Кстати. В статье, на которую вы ссылаетесь, модель не «дергает» контроллер — она тоже посылает события представлению.

                                                                  image
                                                                    0
                                                                    Кстати, в статье правильное определение, а картинка — плохая…
                                                                    Зря Вы её сюда запостили…
                                                                    Очередное увеличение энтропии…
                                                                    Вы плохой… глупый…
                                                                      0
                                                                      Ну тогда вернемся к началу.

                                                                      В каком «классическом» определении (точная цитата, источник) написано, что «Модель ничего не делает, пока её не дёрнут, а в ответ на дёрганье даёт ответ — тому, кому дёрнул»?

                                                                      А определение (процитированное вами) не имеет смысла, потому что не указывает направление зависимостей.
                                                                        0
                                                                        Мы уже пришли к концу
                                                                        Досвидос
                                                                          0
                                                                          Ну да, признаться, что вы не знаете, что такое PoEAA, вы просто не можете (равно как и признаться, что у вас нет ни одного источника, подтверждающего ваши высказывания). Зато перейти на личности — легко.

                                                                          Зачет, что я могу сказать.
                                                                0
                                                                нет, не в классике, а в интерпретации…
                                                                ибо в классике Модель ничего не делает, пока её не дёрнут, а в ответ на дёрганье даёт ответ — тому, кому дёрнул…

                                                                Самая что ни на есть классика MVC Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller (MVC) by Steve Burbeck, Ph.D. 1987, 1992:
                                                                Thus a model may notify any dependent views that it has changed by simply sending the message self changed. The view (and any other objects that are registered as dependents of the model) receives the message update: with the model object as the argument.

                                                                Событие, которое генерирует тот, кто взаимодействует с итоговым Представлением (обычно пользователь), отдаётся на обработку соответствующему Контроллеру

                                                                Представление (в случае веба — браузер) посылает событие пользовательского интерфейса контроллеру, тот вызывает метод(ы) модели. Если в результате модель изменила свое состояние, то она посылает сообщение представлениям через некий диспетчер (как — вопрос десятый, может реализация паттерна Наблюдатель, может системная очередь сообщений Windows, может захардкоженный вызов метода диспетчера), который посылает сообщения представлениям со ссылкой на объект модели, который представление анализирует и собственно представляет (обновляет текущее).
                                                      0
                                                      В правильном MVC модель так же генерирует события, на которые подписываются представления. Скажем, контроллер сообщает модели «пользователь изменил поле ввода „первое слагаемое“на такое-то», а модель в ответ сообщает представлению «я изменилась», после чего представление получает значение поля сумма от модели и выводит его.

                                                      Это от Sun, из Java.
                                                        0
                                                        Sun — голова…
                                                        Только я про то же:
                                                        3.2. В случае успеха – Представление для отображения запрашиваемых данных либо сообщения об их успешном сохранении (если Запрос 1 был на изменение данных).
                                                          0
                                                          У вас не модель сообщает представлению о своем изменении, а контроллер решает, что наверное этот запрос был запросом на изменение данных.
                                                            0
                                                            Нет, у меня Модель отвечает на запрос, а кто вызвал — тот и решает…
                                                            Модели всё равно, кто её вызвал, но правильно, когда её вызывает Контроллер (он для этого и введён в схему MVC):

                                                            mixed Product_Load (int $id) {… }
                                                            // возвращает ассоциативный массив с данными о Товаре либо FALSE при неудаче

                                                            bool Product_Save (array $data) {… }
                                                            // возвращает TRUE при удачном сохранении данных $data, либо FALSE при неудаче
                                                              0
                                                              В моем понимании модель тут массив $data, а функции Product_* лишь обертки для логики контроллера.
                                                                0
                                                                нет, массив не управляет данными, это есть результат управления данными (результат метода «Запросить данные» Модели), а функции Product_ * (методы Product::*) — это и есть Модель.
                                                                Похоже, моя статья совсем не зря
                                                                  0
                                                                  Модель не может быть функциями. Модель — это объект.
                                                                    0
                                                                    нет, Модель — это часть кода, которая манипулирует данными…
                                                                    Это может быть функцией, методом (объекта или класса), просто скриптом:
                                                                    если бы в PHP можно было вызывать
                                                                    include 'product.load.php?id=...'
                                                                    

                                                                    product.load.php был бы частью Модели (вместе с подобными гипотетическими product.save.php и.т.п)
                                                                      0
                                                                      Я, в отличие от вас, могу предоставить цитату, подтверждающую свое утверждение.
                                                                      The model is an object that represents some information about the domain.

                                                                      (PoEAA)
                                                                        0
                                                                        хорошо, пусть PoEAA
                                                                        при чём тут MVC, если Вы про PoEAA?
                                                                          +1
                                                                          При том, что PoEAA — это книжка такая, в которой на странице 330 описан паттерн MVC.
                                                                        0
                                                                        Модель это прежде всего данные, к ней могут относиться функции, иногда даже функции без данных (состояния), но это частные случаи. Плюс во многих современных языках совокупность взаимосвязанных данных и функций называют объектом. :)
                                                                      0
                                                                      Управление данными — задача контроллера. Нет? Задача модели, как ни странно, моделировать предметную область, а в ней обычно нет понятий «загрузить» и «сохранить». Скажем в бухгалтерии нельзя загрузить или сохранить документ, его можно создать и уничтожить, провести или сторнировать, подписать и отправить контрагенту, но вот нет понятия «сохранить» (если не иметь в виду передачу в архив на хранение). «загрузить» и «сохранить» это чисто управляющая логика, не имеющая к бизнес-логике никакого отношения.
                                                                        0
                                                                        Вы еще про persistence ignorance расскажите, да.
                                                                          0
                                                                          Ну вот, всю интригу испортили :)
                                                        0
                                                        Из «вашего» определения следует, что модель — это данные, а управляет им контроллер.
                                                          0
                                                          Нет, из не моего определения следует, что Модель управляет данными, а Моделью управляет Контроллер.
                                                          Это очень просто.
                                                          Команду «Фас» даёт человек, а зубами по этой команде управляет собака.
                                                          Тут человек — Контроллер, а собака — Модель.
                                                          Философствования на тему того, что человек управляет зубами собаки, считаю признаком ;)
                                                            0
                                                            Откуда это следует? Названы три сущности (данные, пользовательский интерфейс и управляющая логика) и названы три компонента (модель, представление и контроллер). Даже если допустить, что соотносятся они не прямо, то бизнес-логика не названа вообще. Её просто нет в этом определении.
                                                              0
                                                              Именно так… Её нет в этом определении, и это пичалька, потому что в результате этого неопределения возникают Тупые Жирные Контроллеры…
                                                              Издержки свободы восприятия простых определений…

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

                                            Самое читаемое