Шаги к MVC или как правильно (или неправильно) сделать проект

Screjet

Новичок
Originally posted by Diesel 2all

Возник такой вопрос....

Кто в MVC должен заниматься обработкой ошибок?

Например газета. Есть класс модели newspaper, который занимается созданием номеров, добавлением к номеру статей, новостей и т.д. У него есть соответствующие методы: new_relase, add_article, add_news и т.д.

Модель (компонент). Например, модель статьи. Она должна знать какие ей нужны данные и что проверять. Такой подход очень удобен, когда одновременно размещается статья, новость.. етц.

имхо, компонент должен быть максимум независимым от контролера, а контролер должен иметь максимум унифицированый интерфейс. (с точки зрения ООП)
new_relase, add_article, add_news
по большому счету, это должны быть интераторы.
 

Alexandre

PHPПенсионер
Проверка заложена в отдельных классах ValidEmail, ValidString, ValidDate и т.д. Есть фабрика для создания объектов этих классов Validator.
можно и так, но проверка осуществляется в классе Модели.
Собственно фабрику можно сделать свойством класса BaseModel, можно реализовать ее на паттерне "Одиночка" или просто создавать как внутреннюю переменную метода класса при необходимости.
Логически проверка валидности данных должна быть заложена в в классе Модели. - но в принципе - кто как реализует :).
 

_RVK_

Новичок
Ладно, а кто отвечает за вывод сообщения. Это ведь уже задача View. Но кто вызывает соответствующий метод View? Модель или Контроллер?
 

Alexandre

PHPПенсионер
Вот это можно подробнее
Diesel попробую.

В ходе данного топика я вычленил для себя сл. идеи:

Контроллер- занимается обработкой входящих запросов и только. Он один на всю MVC

Контроллер - анализирует запрос и :
сюреализует класс, соответствующей модеи или дефалтовый класс
проверит права на выполнение данного метода
вызывает конкретный метод класса Модели

соответствие что и когда вызывать определенно в конфиге.

Класс Модели - производная от класса baseModel()
Функционально: изменяет данные в Предметной области.

По окончанию отработки метода класса Модели - возвращается КОД ВОЗВРАТА, приуспешном это 0 (как правило)

Далее Контроллер анализирует КОД ВОЗВРАТА и сюреализует соответствующий класс Представление

Далее, в соответствии с конфигом - Контроллер вызывает соответствующий КОДу метод Представления

Класс Представление, является производным от $baseView. Функциональность Класса Представления: отображать предметную область. Соответствующий метод - отображает соответствующую часть предметной области.

Далее класс Представление возвращает Контроллеру сформированный им HTML, который Контроллер отправляет в выходной поток.

Все бы хорошо, но возникает ситуация, когда необходимо отработать нескольким классам Представлений одновременно.

В настоящий момент я как раз решаю проблему - как объединить несколько классов представлений в один целый поток.
эта проблема не только в Шаблонах, но и в самой модели данных.

Diesel - более понятней объяснить не смогу -
наверно только спьяну. короче стучись в аську

-~{}~ 17.11.04 14:28:

Модель или Контроллер?
у меня Контроллер, хотя я хотел сделать чтоб эту функцию выполняла Модель.

Возможно в ближайшее время - это будет все-таки Модель
 

[DAN]

Старожил PHPClub
>Все бы хорошо, но возникает ситуация, когда необходимо отработать нескольким классам Представлений одновременно.
А в чем проблема? Пусть отрабатывают. Последовательно принимать от них html и формировать конечную страницу, отдаваемую клиенту.
Если вызов представления зависит от кода, возвращаемого Моделью, то ничто не мешает этой Модели возвращать некий набор кодов (я так понимаю, они все равно используются как информация для Представления).
 

Screjet

Новичок
Ладно, а кто отвечает за вывод сообщения. Это ведь уже задача View. Но кто вызывает соответствующий метод View? Модель или Контроллер?
Компонент (модуль). Он имеет свой собственный интерфейс для работы с видом (шаблоном) и так же имеет интерфейс для внешнего запроса на вывод.

По сути каждый компонент есть максимум независимая еденица, которая имеет собственные методы (объекты) MVC.

Главный (основной) модуль (типа контролер) как раз занимается организацией работы остальных (подчиненных) компонентов, т.е. по сути основа. У него так же может быть вывод, обобщенные проверки и т.д.

(Для себя придумал определение: модуль = это самый старший компонент, который собирает в себе остальные компоненты).
 

_RVK_

Новичок
Замечательно! Сразу видно что определенной концепции не существует и каждый понимает MVC как ему удобнее :)

Как я уже сказал, у меня была попытка повесить обработку ошибок на Модель. Причем делал я примерно так же как Alexandre. Но, как заметил Screjet,
модуль (типа контролер) как раз занимается организацией работы остальных
Поэтому Контроллер должен решать, какой метод вызывать в той, или иной ситуации, метод Model или View. Или нет? Или Модель может сама вызывать View без посреднечества Контроллера?

И еще, речь не только о Выводе ошибок. В некоторых случаях нужно записать в лог, в БД или перейти на другую страницу, отправить email.... Это все действия по обработке ошибок, и их что, тоже должна выполнять Модель?
 

wrapper

Guest
Дизель, напиши рабочий код. И сам увидишь где в нем будет место для обработки ошибок - в модели или контроллере. Хочешь посоветоваться - покажи этот код. А так все демагогия. Devil is in details.
 

Макс

Старожил PHPClub
Diesel
О каких ошибках идет речь ?
Ошибка заполнения формы или ошибка приложения (например БД лежит).
Первыми должна заниматься модель, вторыми - собственный ErrorHandler (который к MVC отношения, наверное, не имеет, хотя возможно контроллер бужет делать некоторые базовые проверки).
Именно ErrorHandler отвечает за ведение лога-ошибок, отсілку письма и т.п.
 

Screjet

Новичок
Поэтому Контроллер должен решать, какой метод вызывать в той, или иной ситуации, метод Model или View. Или нет?
Ситуацию (события) определяет компонент и может сообщать об этом контролеру или самостоятельно обрабатывать события.
Или Модель может сама вызывать View без посреднечества Контроллера?
Не может, точнее не должно такого быть. Управлением выводом должно быть всегда извне, по команде.
 

_RVK_

Новичок
Макс
Про ErrorHandler не говорим, у меня он стандпртный, и таким будет всегда.
С обработкой данных тоже уже определились, это задача Модели, которая возвращает код ошибки.
Но теперь пользователю нужно сообщить о факте возникновения ошибки, будь то база упала, или формат данных неверный. Кто должен этим заниматься, вот в чем вопрос. Долна ли модель сама сформировать сообщение и отдать его классу, ответственному за вывод этого сообщения, или это должен сделать контроллер, на основании кода ошибки, полученного от модели.

wrapper я этого кода уже столько написал! Показать могу.
1. Вот вариант когда контроллер занимается и проверкой данных, и обработкой ошибки.
Метод add_relase просто выполняет запрос.
PHP:
   switch ($_POST['action']) {
        case 'add':
            if (!checkdate($_POST['M'],$_POST['D'],$_POST['Y']) || ($time = mktime(0,0,0,$_POST['M'],$_POST['D'],$_POST['Y']))<=0)  {
               $log->location(PHP_SELF,'err_format_date');
               exit;
            }
            $np->add_relase($time,$_POST['number']);
            $log->location(PHP_SELF,'relase_added');
            exit;
        break;
...

2. Вот вариант когда контроллер не проверяет данныe но проверяет возвращаемое значение метода Модели
Метод add_relase выполняет проверку формата даты, и в случае ошибки возвращает false. Можно организовать и другие проверки, и возвращать другие коды <1
PHP:
   switch ($_POST['action']) {
        case 'add':
            if (!$np->add_relase($time,$_POST['number']))  {
               $log->location(PHP_SELF,'err_format_date');
               exit;
            }
            $log->location(PHP_SELF,'relase_added');
            exit;
        break;
...
3. И наконец вариант когда контроллер не проверяет данныe и ему наплевать на то что вернул метод
Метод add_relase выполняет проверку формата даты, и в случае ошибки сам определяет что делать. В этом случае он вызывает метод location объекта $log
PHP:
   switch ($_POST['action']) {
        case 'add':
            $np->add_relase($time,$_POST['number']))
            $log->location(PHP_SELF,'relase_added');
            exit;
        break;
...
Я показал 3 примера. Какой из них наиболее правильный с точки зрения MVC? Лично я считаю что лучше всего патерну соответствует 2й вариант, но Alexandre вот говорит что:
"я хотел сделать чтоб эту функцию выполняла Модель"
 

Screjet

Новичок
Почему бы объекту release самому не заниматься проверкой/записью/логом и проч.? В моей схеме компонент может делать все кроме вывода. Вывод только по заказу верхнего объекта (родителя).

В итоге все очень красиво: вначале все обработки, а в конце сам вывод.
 

Макс

Старожил PHPClub
Diesel
1. Я считаю что для ошибок приложения (например если база упала или что-то похожее) надо создать свой небольшой модуль:
http://www.example.com/?module=error&code=$code
(можно передавать код, а можно просто текст ошибки)
И в случае ошибки приложения просто делать редирект на этот УРЛ указав код/текст ошибки

2. Ошибки ввода юзера.
Во-первых, все таки модель должна иметь возможность указать контроллеру, какое представление вызвать:
PHP:
$view = $controller->loadView($model->getViewCode()); // создаем представлени, получив его "код"/идентификтор  из модели
$view->setData($model->getData()); // передаем данные из модели в представление
$view->display(); // выводим в броузер
это псевдокод, а не реальный скрипт.
В чем суть ?
Модель возвращает данные. Не важно какие данные (текст, список строк из таблицы или массив ошибок с данными из формы). Нам это знать совершенно не надо: мы получили данные и направили их представлению. Главное чтобы модель правильно указала, какое представление загрузить.
То есть, в твоем случае, модель формирует текст ошибки и указывает какое представление загрузить, а представление выводит это сообщение.
 

Alexandre

PHPПенсионер
А в чем проблема? Пусть отрабатывают. Последовательно принимать от них html и формировать конечную страницу, отдаваемую клиенту.
[DAN] не все так просто, если шаблонизирование не вложенное, то все просто, а если есть вложенность шаблонов, то возникает куча косяков или получается всек сложно "в плане написания шаблонов"
признаюсь - пока эту часть я не реализовал.

-~{}~ 17.11.04 18:56:

В некоторых случаях нужно записать в лог, в БД или перейти на другую страницу, отправить email.... Это все действия по обработке ошибок, и их что, тоже должна выполнять
Diesel хороший вопрос:
если есть логика обработки ошибок, то данные действия выполняются в классе Модель
если логики нет то это может выполнить и Контроллер.

Пол моей схеме - Модель возвращает КОД возврата, а Контроллер - на основании КОДа - уже выполняет сл. шаг:
вызывает соответствующее Представление.

Обработку ошибок можно отнести в соотв. методы Представления. (ну если ошибка отображаема)

хотя можно вызвать и неотображаемый метод Представления.

У меня логикой заложено, что на один метод Модели - может быть выполненно несколько методов Представления. Один из них может быть и запись в лог... - хотя все спорно это :)

-~{}~ 17.11.04 19:00:

Долна ли модель сама сформировать сообщение и отдать его классу, ответственному за вывод этого сообщения, или это должен сделать контроллер, на основании кода ошибки, полученного от модели.
сорри если повторюсь
если ошибка зависит от данных (Модели) , то (у меня) ее отображает Представление.

Собственно - у меня есть класс Представление состоит из двух слоев (назову таким термином )
слой - Источника данных
слой - шаблонов
здесь еще один уровень логики о котором я умолчал...

но об этом в др. раз :);)
 

wrapper

Guest
2 Дизель
из 3-х предложенных вариантов наиболее приемлемый 2-й
а в остальном - слушай Макса :)

-~{}~ 17.11.04 19:40:

2 Скрежет

>Почему бы объекту release самому не заниматься проверкой/записью/логом и проч.?

проверкой - да
записью - возможно
логом - сомнительно, например если ты захочешь еще время выполнения измерять, вызовы таймера тоже распихаешь по всем своим классам? ИМХО его лучше вынести выше, т.е. туда где у тебя вызывается Обьект->save()
 

Screjet

Новичок
wrapper,
[оффтоп]
Мы, видимо, о разных логах говорим. Я говорил о логах событий, а ты о логах дебага. Дебаг и отладка не очень относится к теме.

Вообще время измеряю только общее (для события/операции) и радуюсь скорости выполнения:)
[/оффтоп]

У меня логикой заложено, что на один метод Модели - может быть выполненно несколько методов Представления.
Это как? Долго думал над твоей идеей, но так и не понял смысла :)
 

_RVK_

Новичок
Макс
Я считаю что для ошибок приложения (например если база упала или что-то похожее) надо создать свой небольшой модуль:
http://www.example.com/?module=error&code=$code
(можно передавать код, а можно просто текст ошибки)
Да, именно так, только у меня не модуль а класс, объект которого смотрит в $_GET['code'] и берет сообщение из массива по полученному ключу. Далее записывает сообщение во внутреннее свойство. В самом конце Контроллер отдает все сообщения в Представление.

Я говорил о логах событий, а ты о логах дебага
В чем разница? Ошибка это тоже событие.
А логирование на модель не повесишь. Я вот в лог записываю данные __LINE__ и __FILE__. Чтож их мне в каждом методе передавать?

Вообщем я тут подумал и вот что понял:
1. Модель должна сама обрабатывать поступившие данные, и контролировать успешность их обработки.
2. В случае ошибки, она должна возвратить false.
3. Но код ошибки (сисловой или символьный) сохранить в свойстве класса.
4. Если контроллер, посчитает что в этом случае нужно уточнить код ошибки, он всегда может его посмотреть.
Вывод: Другими словами Контроллер должен выбирать, что именно предпринять в случае тои или иной ошибки, а задача модели только сообщить о факте её возникновения.
 

Alexandre

PHPПенсионер
2. В случае ошибки, она должна возвратить false.
3. Но код ошибки (сисловой или символьный) сохранить в свойстве класса.
4. Если контроллер, посчитает что в этом случае нужно уточнить код ошибки, он всегда может его посмотреть
Diesel в принципе у меня так и реализованно, т.е. почти так:
Код возвращается цифровой.
Описание Ошибки возвращается в св-ве ErrDescdiption
Хотя принципиально, что возвращается - не важно. Главное - что оно есть.
Почему у меня возвращается цифровой код - просто мне так проще реализовывать логику Приложения.
У меня логикой заложено, что на один метод Модели - может быть выполненно несколько методов Представления.
Это как? Долго думал над твоей идеей, но так и не понял смысла
Смысл в том, что Представление отражает кусок предметной области. А если необходимо отразить одновременно два куска предметной области, например: карзина и прайс - это два разных Представления.

В общем - отображение на страницы строится из кирпичеков Представлений.
 

Screjet

Новичок
В чем разница? Ошибка это тоже событие.
Скорее это исключительная ситуация, в результате которой прекращается дальнейшая обработка данных, но не прекращаются этапы проверки остальных поступивших данных. Думаю, при пользовательской ошибке не редиректишь его на readme, не высылаешь письмо вебмастеру, а просто уточняешь где пользователь ошибся. Хотя реализация обработки ошибки в бОльшей степени зависит от параноидности програмера, эту обработку можно довести до абсурда:)
Я вот в лог записываю данные __LINE__ и __FILE__. Чтож их мне в каждом методе передавать?
Можешь уточнить, в каких случаях вообще должен вестись лог?

Alexandre,
Как тебе идея, когда представление выполняет ф-ции схемы (основы) и несет инфу о всех включаемых моделях (агрегация)? Как тебе идейка о наследовании представлений? :)
 

_RVK_

Новичок
Можешь уточнить, в каких случаях вообще должен вестись лог
Как я упоминал, может быть 3 реакции на событие(плюс их комбинации).
1. Вывести сообщение.
2. Записать в лог.
3. Переправить на другую страницу.

Когда писать лог, это дело программиста. Я, обычно, проверяю все операции с БД, и в случае ошибки записываю в лог функцией [m]error_log[/m]. Но т.к. Модель почти всегда выполняет именно операции с БД, то мне нужно будет при вызове каждого метода передавать в параметрах по крайней мере __LINE__. Это неудобно.
 
Сверху