За последние 24 часа нас посетили 16174 программиста и 1552 робота. Сейчас ищут 943 программиста ...

Вопрос по MVC

Тема в разделе "PHP для новичков", создана пользователем VLK, 7 июл 2014.

  1. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Вроде как понятен принцип MVC, а с другой стороны не понятно зачем разделять Controller и Model, а если разделять, то кто за что отвечает, есть небольшие примеры в интернете, например http://habrahabr.ru/post/150267/ но из них это не понятно, меня интересует пример с базой данных, может кто подскажет, приведет пример на псевдокоде (или как там это называется).

    Допустим есть регистрация пользователя из данных всего логин и пароль, кто за что должен отвечать, последовательность действий такая:
    Или ситуация попроще, заход на страницу, которую могут видеть только зарегистрированные пользователи:
     
  2. nskrazor

    nskrazor Новичок

    С нами с:
    19 июн 2014
    Сообщения:
    25
    Симпатии:
    0
    Адрес:
    Новосибирск
    Объясняю на пальцах.. MVC - представляет собой бизнес модель, это некий стандарт, по которому последующим поколениям кодеров после тебя будет проще ориентироваться.
    За меня лучше скажет википедия.
    Т.е. в контроллере только обработка данных, получаем мы данные в модели, в контроллере обрабатываем. Вот схема.
    [​IMG]
    Приведу пример из своего самописного(MVC) велосипеда.
    Всю партянку кидать не буду, просто разбор с комментариями, момента регистрации.
    Модель
    В модели у нас будут только методы, которые каким либо образом получают данные(обычно это любого рода запросы к бд)
    Код (PHP):
    1. //наследуем основную модель, в которой реализовано подключение к дб(можно использовать singleton) и набор функций для работы с дб
    2. class Model_User extends baseModel {
    3.  
    4.     //таблица с которой работаем(для удобства)
    5.     private $table = 'users';
    6.  
    7.     function __construct() {
    8.             parent::__construct();
    9.     }
    10.    
    11.     //поиск пользователя по user_id
    12.     public function getUser($login) {
    13.        return $this->getRow("SELECT * FROM ?n WHERE user_id=?s LIMIT 1",$this->table ,$login);
    14.     }
    15.    
    16.    //добавление нового пользователя
    17.     public function addUser($array) {
    18.         $this->query("INSERT INTO ?n SET ?u",$this->table, $array);
    19.     }
    20.  
    21. }
    22.  
    Контроллер(здесь у нас будет только обработка данных и получение данных от юзера, никаких запросов к бд
    Код (PHP):
    1. class Ctrl_User extends BaseController{
    2.  
    3.     //методы-действия, все методы с приставкой Action, будут обработаны по соответствующей ссылке http://site/user/register
    4.     //где user - это соответствующий контроллер, а register - соответствующий метод, по умолчанию метод будет ActionIndex
    5.     function ActionRegister() {
    6.            #проверки post данных и.т.п.
    7.  
    8.             # Если нет ошибок, то добавляем в БД нового пользователя
    9.  
    10.             if(empty($this->errors))
    11.  
    12.             {
    13.                //формируем массив данных
    14.                 $data = array('username' => $login,
    15.                               'password' => $password,
    16.                               'reg_date' => time());
    17.                 //$this->model реализует доступ к соответствующей модели
    18.                 $this->model->addUser($data);
    19.  
    20.             }
    21.  
    22.  
    23.         }
    24.        //так как я использую шаблонизатор twig вместо традиционного view, таким образом происходит отправка на рендер в шаблон
    25.        $template->render(array(
    26.             'errors' => $this->errors
    27.         ));
    28.     }
    29. }
    30.  
    В общем как-то так..
     
  3. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    В модели лучше реализовать как можно больше бизнес-логики, т.е. не только чтение их из базы, но и все необходимые расчёты, всю логику. Контроллер должен, грубо говоря, просто запрашивать у модели данные, необходимые расчёты, при необходимости передавать ей ввод от пользователя, передавать в представления полученные у модели результаты. Но не должен содержать сам никакую другую логику. таким образом, вы всегда знаете, где искать, к примеру, ошибку. Или что расширять, чтоб добавить функционал.
     
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Сурикат рекомендует не делать MVC самоцелью и бескомпромиссной догмой.
    Далее - "модель" это не набор методов, получающих данные из БД и файликов. Модель - это и есть сами данные, ребят. Мыслим в контексте информационного потока:
    1) Модель - способ внутренней организации и хранения информации. Есть у нас пачка информации, мы можем ее держать в БД, в XML, в JSON, в текстовичке со своей собственной странной разметкой, в шаред-мемори, и, даже в облигациях газпрома. В любом случае данные будут одни и те же. НО, механизмы хранения и способы организации будут сильно отличаться. Это и есть "определиться с моделью".
    2) Контроллер - средства обработки информации, шлюз между моделью и вьюхой. Работающий в обе стороны, да. Берет у модели, жует, отдает вьюхе. Потом берет у вьюхи, жует, отдает модели.
    3) Вьюха - способ внешней организации и представления информации, ее выдачи и ввода.

    То есть модель - то, как видит данные нашего проекта машина, вью - как видят ее со стороны. Контроллер - как первое превращается во второе и наоборот.

    Просто добавьте слово "данных" в каждый из трех пунктов,и все сразу станет прозрачным :
    1) Модель данных.
    2) Контроллер/обработчик данных.
    3) Представление/выдача данных.

    В данном концепте, к слову, вьюха - не всегда страничка браузера или форма. Вьюхой так же является какой-нибудь API, плюющийся JSON'ами во всех, кто к нему обращается. Пропорции количества моделей-вьюх-контроллеров не должны быть 1:1:1. На весь проект может быть, грубо, 100 контроллеров, 30 вьюх и одна-единственная модель. То есть MVC - это не про резать все на тортики по 3 куска каждый. Это про соблюдать логику в архитектуре.

    Далее, у людей случается приступ паники, когда они понимают, что НЕ МОГУТ ОТДЕЛИТЬ ПРЕДСТАВЛЕНИЕ ОТ ЛОГИКИ!!111слезы!11БОЛЬ!!11111один!!111страдания11!!!!!Гнев1111разраз

    Но это не нужно делать любой ценой. Если у вас во вьюхе есть цикл(!!!!боль!!11сжечь!!11слезы!1!!), в котором вы генерите табличку(!!!еретик!1111сжечь!!!!), не спешите вскрывать себе вены - вы не нарушили закон, не опозорили свою честь, не стали причиной катаклизмов, радикальные программисты ислама не объявят вам DDOS-джихад. Все нормально. Вы делаете архитектуру своего проекта, а не она вас. Если в вашем случае требуется такой подход - вперед.

    З.Ы. Про будущие поколения программистов, которым будет легче понять ваш код, конечно интересно и тешит самолюбие, но открою вам страшную тайну... На ваш код(и на мой тоже, разумеется) всем плевать и никто никогда не будет его ковырять и запиливать, если, конечно, вы не наймете его на работу. Только тссс...
     
  5. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    хорошо сказано:
    и
    в контексте ООП приложения, данные должны представлять собой максимально простой объект, хранящий необходимый набор свойств. Если для сохранения приходится записывать файл или данные в таблицы, то это может делать функция-хелпер. Мы привыкли к MySQL в вебе, но реляционные базы данных очень и очень далеки от объектов, именно поэтому приходится городить непонятно к чему относящийся огород методов для работы с базой, а-ля ActiveRecord. NoSQL-субд сохраняют и отдают объекты "как есть".
    Еще есть вариант, "толстая модель", когда класс модели описывает методы для взаимодействия с базой. В этой ситуации надо помнить, что модель не должна изменять данные: только извлекать и сохранять.
    В модели не должно быть ничего, заточенного под определенный контроллер. Любая модель должна быть совместима с любым контроллером, а вот представления - только с конкретными методами контроллеров.
     
  6. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    upd. нет ничего неправильного в представлении брать данные непосредственно из модели.
     
  7. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Кстати да. Вообще, эти вот разделения и так далее нужны не для мифического признания, а просто чтобы через месяц перерыва можно было вернуться и не сломать ногу. Но если вьюха для генерации таблицы может просто выдернуть данные из БД напрямую - нафига городить оверхеды и костыли ради "максимально четкого разделения"?

    Делать надо не как у соседа, а как в твоем случае вернее. MVC - не закон, а рекомендация. Только и всего.
     
  8. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    https://yadi.sk/d/gqhcFS30WCCyF
    Вот такое для примера накрутил, мини MVC главные действия это регистрация и авторизация пользователя, скажите, правильно ли я все сделал?

    PS из кода убрано все лишнее, нет маршрутизатора в привычном виде

    один controller - user, он отвечает за работу с пользователями (регистрация, авторизация), для него предусмотрено 2 model, register_model и login_model (при этом НЕТ user_model, ну а для чего?), ну и куча view под соответствующее происшествие.
     
  9. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Тогда же получится, что всё интересное перенесётся в контроллер, и он станет толстым и уродливым... http://yii.kz/mvc-tolstaya-model-tonkiy-kontroller. Я стараюсь (когда не лень), чтоб у меня в конроллере вообще не было больших функций, и они состояли только из обращения к функциям модели и передачи результатов работы вьюхе
     
  10. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    верно. Статья годная, идея - тоже. Опять же одна из предпосылок - сложная реляционная структура из множества таблиц, для хранения в общем-то плоских объектов. Однако в этом случае логика оказывается именно в контроллерах (как и должно быть по первородной MVC), а модель можно заюзать (гипотетически) в других приложениях. Дело в том, что чужие контроллеры никому не нужны, а чужая модель может пригодиться - именно как данные, а логика по обработке данных уже своя.
    с этим я не соглашусь. Модель самолета - это не самолет, и модель на подиуме - это не человек в жизни. Модель только демонстрирует, чтО есть и как оно выглядит. Она ничего не делает, ну это ИМХО, толстую модель умные дядьки придумали, но запихнуть всю в конце концов ПРОГРАММУ в один компонент и называть это MVC как-то не честно.
     
  11. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Что?????

    Какой еще оверхед? Логика должна быть отделена от представления. Никаких запросов из представления.
    Не хочешь использовать MVC не надо. Путать людей то же не надо.
     
  12. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Посмотрите пожалуйста что я наворотил и скажите то или не то
     
  13. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Не, плодить целый класс ради функции login я бы не стал. К тому же, модель, по идее, не должна взаимодействовать с $_POST напрямую. Как бы я сам реализовал - надо подумать. Но у меня бы, скорее всего, был класс User_Model, отвечающий за регистрацию пользователя, ну и выполняющий ещё какие-нибудь функции, которые мне от него нужны. Может над ним ещё один класс Authorization_Provider, который бы занимался непосредственно проблемами авторизации
     
  14. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Тут в укороченном виде, в полноценном было бы на много больше кода, ну может с login и нет, но вот с регистрацией точно.

    т.е. я в controller должен вытащить значения из $_POST (прогнать через trim и т.п.) и передать их в model?
     
  15. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.156
    Симпатии:
    1.771
    Адрес:
    :сердА
    Это вот то, о чем я говорил в самом начале. Догматы...
     
  16. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    Не нужно возводить в абсолют это разеделение.
    Логика представления может и должна быть в представлении. Логика модели может и должна быть в модели. Толстая модель, тонкий контроллер или наоборот — зависит от конкретного проекта или задачи в рамках проекта, единственно верного выбора между этими вариантами не существует.
    Абстрагируйтесь от Postов. Задача модели — отдать данные по запросу контроллера. Задача контроллера — запросить нужные данные у модели и передать результат их обработки во вьюху.
    Первый серьёзный проект на Yii/ZF/Symphony расставит всё в голове на свои места. Прикладные вещи сложно объяснять на пальцах.
     
  17. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Ну какие еще догматы. ТС спрашивает как правильно реализовать MVC вы же вместо того что бы направить советуете черт знает что.
    И еще какой то оверхед приплели, он же помешен на оптимизации не травмируйте человека.

    Все верно. Как писать не правильно он и без нас разберется.
     
  18. krocos

    krocos Активный пользователь

    С нами с:
    30 июн 2014
    Сообщения:
    10
    Симпатии:
    0
    Контроллер служит как бы диспетчером в приложении. Говоря кому что делать, генерирует события для листнеров, манипулирует контейнером обратной зависимости.
    Модель представляет слой абстракции над данными. Которыми (данными) могут пользоваться разнообразные модули, слушатели и сам контроллер.
    Вид - это только шаблоны, никакой сложной логики. Это только обертка, куда вставляются данные чтобы их показать пользователю.

    И вот например псевдо-код авторизации:
    - Пользователь запрашивает страницу на сайте по определенному адресу
    - Апач (ну или что угодно) запускает наш контроллер
    - Контроллер спрашивает у валидаторов, нормально ли введены данные от пользователя и если да, продолжаем
    - Контроллер спрашивает у модели "Пользователь", есть ли такой пользователь в БД и если да, продолжаем
    - Контроллер выстреливает событие "Пользователь заходит", на которое откликаются соответствующие листнеры типо логгера входа, модуля, который выдает пользователю всякие нотификации и тп
    - Контроллер просит ВИД отрендерить (вставить данные в шаблон так сказать :) шаблон который надо показать (при удачной регистрации шаблон страницы, а при неудачной, - форму логина с ошибками)
    - Контроллер возвращает пользователю ответ (в виде отрендереного html)
     
  19. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Столько приведено терминов MVC (я надеюсь вы хоть не сами их писали, а откуда то копировали), но оно не вносит ясность, все это вода, тут как говориться лучше один раз увидеть, чем 100 раз услышать, я даже код написал, загрузил на сервер, может лучше было бы отредактировать этот код, так, как должна выглядеть MVC (я как понимаю если там что то и надо делать, так это пару строк перенести) и вопрос будет исчерпан.
    Да и на будущее, у не знающих как будет выглядеть MVC будет пример в виде живого кода, а не терминология.
     
  20. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    плюну хорошим ответом на SO

    забавно как сюда вплелись ещё пару паттернов :)
     
  21. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    валидатор как я понимаю это например прогон через preg_match, а так же проверка допустим длинны (min/max), где все эти действия происходят на месте, в Контроллере или в Модели?

    И где происходит вытаскивание данных из $_POST в переменные (массив) для дальнейшей работы в Контроллере или в Модели?
     
  22. Zuldek

    Zuldek Старожил

    С нами с:
    13 май 2014
    Сообщения:
    2.381
    Симпатии:
    344
    Адрес:
    Лондон, Тисовая улица, дом 4, чулан под лестницей
    Каким образом модель связана с обработкой пользовательских данных?
     
  23. Luge

    Luge Старожил

    С нами с:
    2 фев 2007
    Сообщения:
    4.680
    Симпатии:
    1
    Адрес:
    Минск
    Очень много зависит от конечной архитектуры и твоего видения структуры.

    Пойми, MVC — это парадигма, первоначальная идея от которой ты потом оттолкнёшься. Не обязательно всегда строго следовать принципу построения. Существуют уйма приложений у которых своё видение MVC и это абсолютно не мешает им развивать свой проект и работать с комьюнити. Кстати, MVC, MVP, MVVC, MVVM и ещё парочка.

    тут хорошо написали выше про добавление слова «данные». Если совсем академически подходить к вопросу, то контроллер получает из модели Http данные из $_POST, проводит валидации (хэлпер, модель, отдельные валидаторы. Тоже, кстати, интересный вопрос архитектуры). И скармливает какой-нибудь модели User для добавления данных в базу. Вызываем вьюху для вывода ответа пользователю или редиректим дальше.

    Модель — это вовсе не обязательно только база данных. База, кэш, сессии — для любого типа данных могут быть свои модели.
    Точно так же вьюхи — вывод html в браузер, запись на диск/ftp, ajax ответы, api (json, xmlrpc, soap), крон
     
  24. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    Luge снова с нами, ура!
     
  25. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Так это я и пытаюсь выяснить :)
    И что подразумевается под словом "обработка", одно дело вытащить (переписать) интересующие данные из $_POST в собственный массив, при этом по необходимости очистить от тегов и выполнить trim, и совсем другое дело проверять через БД (например есть такой пользователь или нет).

    т.е. например если у нас идет регистрация пользователя, то это происходит так:
    Код (PHP):
    1. class reg_controller {
    2.     
    3.     function index() {
    4.         
    5.         $view = new reg_view();
    6.         $model = new reg_model(); 
    7.         // модель отвечающая за регистрацию
    8.         // в ней все методы отвечающие за регистрацию
    9.         
    10.         $data = $model->get_data(); // метод находится в model (reg_model)
    11.         // get_data вытаскивает из $_POST интересующие нас переменные
    12.         // прогоняет их через strip_tags() и trim() и возвращает в виде массива
    13.         
    14.         $result = $model->filter($data); // метод находится в model (reg_model)
    15.         // filter прогоняет через фильтр данные проверяет, длину и preg_match
    16.         // возвращает true / false
    17.         
    18.         if (!$result) {
    19.             $view->load_view('failed'); // шаблон с сообщением что данные заполнены не верно
    20.             return;
    21.         }
    22.         
    23.         $result = $model->db_filter($data); // метод находится в model (reg_model)
    24.         // db_filter проверяет нет ли БД такого пользователя
    25.         // возвращает true / false
    26.         
    27.         if (!$result) {
    28.             $view->load_view('failed'); // шаблон с сообщением что данные заполнены не верно
    29.             return;
    30.         }
    31.         
    32.         $model->add_db($data); // метод находится в model (reg_model)
    33.         // add_db добавляет в БД нового пользователя
    34.         
    35.         $view->load_view('success'); // шаблон с сообщение об успехе
    36.         return;
    37.         
    38.     }
    39.     
    40. } 
    так?