Разделение кода. Модель MVC

09.08.2019

Концепция MVC (Model-View-Controller: модель-вид-контроллер) очень часто упоминается в мире веб программирования в последние годы. Каждый, кто хоть как-то связан с разработкой веб приложений, так или иначе сталкивался с данным акронимом. Сегодня мы разберёмся, что такое - концепция MVC, и почему она стала популярной.

Древнейшая история

MVC — это не шаблон проекта, это конструкционный шаблон, который описывает способ построения структуры нашего приложения, сферы ответственности и взаимодействие каждой из частей в данной структуре.

Впервые она была описана в 1979 году, конечно же, для другого окружения. Тогда не существовало концепции веб приложения. Tim Berners Lee (Тим Бернерс Ли) посеял семена World Wide Web (WWW) в начале девяностых и навсегда изменил мир. Шаблон, который мы используем сегодня, является адаптацией оригинального шаблона к веб разработке.

Бешеная популярность данной структуры в веб приложениях сложилась благодаря её включению в две среды разработки, которые стали очень популярными: Struts и Ruby on Rails. Эти две среды разработки наметили пути развития для сотен рабочих сред, созданных позже.

MVC для веб приложений

Идея, которая лежит в основе конструкционного шаблона MVC, очень проста: нужно чётко разделять ответственность за различное функционирование в наших приложениях:

Приложение разделяется на три основных компонента, каждый из которых отвечает за различные задачи. Давайте подробно разберём компоненты на примере.

Контроллер (Controller)

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

Модель (Model)

Модель - это данные и правила, которые используются для работы с данными, которые представляют концепцию управления приложением. В любом приложении вся структура моделируется как данные, которые обрабатываются определённым образом. Что такое пользователь для приложения — сообщение или книга? Только данные, которые должны быть обработаны в соответствии с правилами (дата не может указывать в будущее, e-mail должен быть в определённом формате, имя не может быть длиннее Х символов, и так далее).

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

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

Вид (View)

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

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

Разберём пример

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

У нас есть определённый контроллер для обработки всех действий, связанных с книгами (просматривать, редактировать, создавать и так далее). Давайте назовем его books_controller.php в нашем примере. Также нам нужна модель, например, book_model.php , которая обрабатывает данные и логику, связанные с позицией в магазине. В заключение, нам нужно несколько видов для представления данных, например, список книг, страница для редактирования и так далее.

Следующий рисунок показывает, как обрабатывается запрос пользователя для просмотра списка книг по теме фэнтези :

Контроллер (books_controller.php) получает запрос пользователя (запрос HTTP GET или POST). Мы можем организовать центральный контроллер, например, index.php, который получает запрос и вызывает books_controller.php.

Контроллер проверяет запрос и параметры, а затем вызывает модель(book_model.php), запрашивая у неё список доступных книг по теме фэнтези .

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

Контроллер использует подходящий вид для представления данных пользователю . Если запрос приходит с мобильного телефона, используется вид для мобильного телефона; если пользователь использует определённое оформление интерфейса, то выбирается соответствующий вид, и так далее.

В чем преимущества?

Самое очевидное преимущество, которое мы получаем от использования концепции MVC — это чёткое разделение логики представления (интерфейса пользователя) и логики приложения.

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

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

А зачем использовать рабочую среду?

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

Рассмотрим cakePHP в качестве примера рабочей среды MVC. После установки у вас будет три основных директории:

  • cake/
  • vendors/

Папка app является местом размещения ваших файлов. Это место для разработки вашей части приложения.

В папке cake размещаются файлы cakePHP (функциональность рабочей среды).

Папка vendors служит для хранения библиотек PHP сторонних разработчиков.

Ваше рабочее пространство (директория app) имеет следующую структуру:

  • app/
    • config/
    • controllers/
    • locale/
    • models/
    • plugins/
    • tests/
    • vendors/
    • views/
    • webroot/

Вам нужно размещать ваши контроллеры в директории controllers , модели в директории models и виды в директории views !

Как только вы начнёте использовать рабочую среду, то сразу станет ясно, где размещается практически любая часть вашего приложения, которую надо создать или модифицировать. Такая организация сама по себе значительно упрощает процесс разработки и поддержки приложения.

Использование рабочей среды для нашего примера

Так как данный урок не имеет целью показать процесс создания приложения с помощью cakePHP, то мы покажем только код для модели, контроллера и вида с комментариями о преимуществах использования рабочей среды MVC. Код специально упрощён и непригоден для использования в реальном приложении.

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

Итак, как только пользователь нажимает кнопку, браузер запрашивает данный url:

Www.ourstore.com/books/list/fantasy

CakePHP форматирует URL по шаблону /controller/action/param1/param2 , где action - это функция, которая вызывается контроллером. В старом классическом виде url будет выглядеть так:

Www.ourstore.com/books_controller.php?action=list&category=fantasy

Контроллер

В рабочей среде cakePHP, наш контроллер будет выглядеть так:

class BooksController extends AppController {

Function list($category) {

$this->set("books", $this->Book->findAllByCategory($category));

Function add() { ... ... }

Function delete() { ... ... }

... ... } ?>

Просто, не так ли?. Данный контроллер будет сохранен как books_controller.php и размещён в /app/controllers . Он содержит список функций, которые выполняют действия для нашего примера, а также другие функции для выполнения связанных с книгами операций (добавить новую книгу, удалить книгу, и так далее).

Рабочая среда предоставляет нам множество готовых решений и нужно только сформировать список книг. Есть базовый класс, в котором уже определено базовое функционирование контроллера, таким образом, надо унаследовать свойства и функции этого класса (AppController является наследником Controller ).

Все что нужно сделать в списке действий — вызвать модель для получения данных и затем выбрать вид для представления их пользователю. Вот как это делается.

this->Book - это наша модель, и часть кода:

$this->Book->findAllByCategory($category)

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

Метод set в строке:

$this->set("books", $this->Book->findAllByCategory($category));

Контроллер передаёт данные виду. Переменная books принимает данные, возвращённые моделью, и они становятся доступными для вида.

Теперь остаётся только вывести на экран вид, но эта функция выполняется автоматически в cakePHP, если мы используем вид по умолчанию. Если мы хотим использовать другой вид, то надо явно вызвать метод render .

Модель

Модель даже ещё проще:

class Book extends AppModel {

Почему она пустая? Потому что она является наследником базового класса, который обеспечивает необходимую функциональность и нам нужно использовать соглашение об именах в CakePHP для того, чтобы рабочая среда выполняла все другие задачи автоматически. Например, cakePHP известно на основании имени, что данная модель используется в BooksController , и что она имеет доступ к таблице базы данных с именем books.

С таким определением у нас будет модель, которая может только читать, удалять или сохранять данные в базе данных.

Код сохраняем как book.php в папке /app/models .

Вид

Все, что нам нужно теперь сделать — это создать вид (по крайней мере, один) для списка действий. Вид будет иметь код HTML и несколько (как можно меньше) строк кода PHP для организации цикла по массиву книг, которые предоставляется моделью.












Название Автор Цена

Как можно заметить, вид создаёт не полноценную страницу, а лишь фрагмент HTML (таблицу в данном случае). Потому, что CakePHP обеспечивает другой способ для определения шаблона страницы, и вид вставляется в данный шаблон. Рабочая среда также обеспечивает нас некоторыми вспомогательными объектами для выполнения общих задач во время создания частей HTML страницы (вставка форм, ссылок, Ajax или JavaScript).

Сохраняем вид как list.ctp (list — это имя действия, а ctp означает шаблон CakePHP) в папке /app/views/books (потому, что это вид для действия контроллера).

Вот так выполняются все три компонента с помощью рабочей среды CakePHP!

Ну во первых конечно это модель или, другими словами, подход к разработке сайтов и приложений в сети Интернет, во вторых MVC используют для повышения эффективности работы разрабатываемых систем, а также для обеспечения безопасности и устойчивости от взлома.

MVC расшифровывается как Model- view- controller, а дословно перевести можно как Модель-Представление-Контроллер.

Несмотря на то, что модель разработки кажется новой оно уже давно себя зарекомендовала и получила повсеместное использования при разработке в том числе и сайтов. Впервые концепция MVC была описана Trygve Reenskaug в 1979 году.

Концепция MVC или из чего она состоит

Модель MVC включает в себя три компонента: Модель, Представление и Контроллер.

Самое главное конечно здесь первое – это Модель. Модель представляет собой совокупность процедур и алгоритмов обработки данных. Сама по себе Модель не содержит данных, но как правило черпает их из базы данных и обрабатывает по заранее прописанным алгоритмам. Если говорить о Web разработке, то модель будет содержать набор классов и функций, например на языке PHP.

Второй элемент – это представление View. Позволяет отобразить информацию. Если это сайт, то информация отображается в браузере. Представление при разработке сайтов содержит HTML код, в который подставляются переменные, которые берутся, нет не из модели, а из контроллера.

Итак, третий элемент – это Контроллер. Его главная функция это обеспечение связи в пользователем и моделью. Также может содержать PHP код.

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

Для примера рассмотрим модель MVC для новостного сайта

Пользователь попадает на страницу сайта. Ему отображается страница по умолчанию с определенным списком новостей. Информация для формирования новостей берется из базы данных.

Когда пользователь набрал определенную страницу в адресной строке браузера, запрос передается контроллеру, при этом запускается функция, которая его обрабатывает и подгружает Модель.

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

Представление, получив массив или объект с новостями подгружает определенный код HTML, CSS, если нужно и jаvascriptи отображает все это пользователю.

Эта модель используется в многих системах управления и Фреймворках, одним из которых является CodeIgniter, который недавно приобрел вторую жизнь.

Таким образом, используя модель MVC можно без проблем составить систему администрирования для сайта , Интернет-приложение. Так фреймфорк CodeIgniter использует именно эту модель.

Model-View-Controller (MVC , «Модель-Представление-Контроллер», «Модель-Вид-Контроллер») - схема разделения данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер - таким образом, что модификация каждого компонента может осуществляться независимо .

Энциклопедичный YouTube

  • 1 / 5

    Концепция MVC была описана Трюгве Реенскаугом в 1978 году , работавшем в научно-исследовательском центре «Xerox PARC » над языком программирования «Smalltalk ». Позже, Стив Бурбек реализовал шаблон в Smalltalk-80 .

    Впоследствии, шаблон проектирования стал эволюционировать. Например, была представлена иерархическая версия HMVC ; MVA, MVVM .

    После внедрения компанией Apple технологии WebObjects, реализованных на Objective-C, стало популяризировать шаблон и в вебе [ ] .

    Когда WebObjects портировали на Java, шаблон стал популярен и там. Более поздние фреймворки вроде Spring (октябрь 2002 года) всё ещё имеют реализацию MVC [ ] .

    Дальнейший виток популярности привнесло развитие фреймворков, ориентированных на быструю развёртку, на языках Python и Ruby, Django и Rails, соответственно [ ] . На момент 2017 года, фреймворки с MVC заняли заметные позиции по отношению к остальным фреймворкам без этого шаблона .

    Различия описания концепции шаблона

    С развитием объектно-ориентированного программирования и понятия о шаблонах проектирования - был создан ряд модификаций концепции MVC, которые при реализации у разных авторов могут отличаться от оригинальной. Так, например, Эриан Верми в 2004 году описал пример обобщённого MVC .

    В предисловии к диссертации «Naked objects » Ричарда Поусона (Richard Pawson), - Трюгве Реенскауг упоминает свою неопубликованную наиболее раннюю версию MVC, согласно которой :

    • Модель относилась к «разуму» пользователя;
    • Под представлением имелся в виду редактор, позволяющий пользователю просматривать и обновлять информацию;
    • Контроллер являлся инструментом для связывания представлений воедино и применялся пользователем для решения его задач.

    Назначение

    Основная цель применения этой концепции состоит в отделении бизнес-логики (модели ) от её визуализации (представления , вида ). За счёт такого разделения повышается возможность повторного использования кода . Наиболее полезно применение данной концепции в тех случаях, когда пользователь должен видеть те же самые данные одновременно в различных контекстах и/или с различных точек зрения. В частности, выполняются следующие задачи:

    1. К одной модели можно присоединить несколько видов , при этом не затрагивая реализацию модели . Например, некоторые данные могут быть одновременно представлены в виде электронной таблицы , гистограммы и круговой диаграммы ;
    2. Не затрагивая реализацию видов , можно изменить реакции на действия пользователя (нажатие мышью на кнопке, ввод данных) - для этого достаточно использовать другой контроллер ;
    3. Ряд разработчиков специализируется только в одной из областей: либо разрабатывают графический интерфейс , либо разрабатывают бизнес-логику . Поэтому возможно добиться того, что программисты, занимающиеся разработкой бизнес-логики (модели ), вообще не будут осведомлены о том, какое представление будет использоваться.

    Концепция

    Концепция MVC позволяет разделить модель, представление и контроллер на три отдельных компонента:

    Модель

    Модель предоставляет данные и методы работы с ними: запросы в базу данных, проверка на корректность. Модель не зависит от представления - не знает как данные визуализировать - и контроллера - не имеет точек взаимодействия с пользователем -, просто предоставляя доступ к данным и управлению ими.

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

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

    Представление

    Представление отвечает за получение необходимых данных из модели и отправляет их пользователю. Представление не обрабатывает введённые данные пользователя [ ] .

    Представление может влиять на состояние модели сообщая модели об этом.

    Контроллер

    Контроллер обеспечивает «связи» между пользователем и системой. Контролирует и направляет данные от пользователя к системе и наоборот. Использует модель и представление для реализации необходимого действия.

    Функциональные возможности и расхождения

    Поскольку MVC не имеет строгой реализации, то реализован он может быть по-разному. Нет общепринятого определения, где должна располагаться бизнес-логика. Она может находиться как в контроллере, так и в модели. В последнем случае, модель будет содержать все бизнес-объекты со всеми данными и функциями.

    Некоторые фреймворки жестко задают где должна располагаться бизнес-логика, другие не имеют таких правил.

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

    Интернационализация и форматирование данных также не имеет четких указаний по расположению.

    Условно-обязательные модификации

    Для реализации схемы «Model-View-Controller» используется достаточно большое число шаблонов проектирования (в зависимости от сложности архитектурного решения), основные из которых - «наблюдатель », «стратегия », «компоновщик » :

    Наиболее типичная реализация - в которой вид отделён от модели путём установления между ними протокола взаимодействия, использующего «аппарат событий» (обозначение «событиями» определённых ситуаций, возникающих в ходе выполнения программы, - и рассылка уведомлений о них всем тем, кто подписался на получение): при каждом особом изменении внутренних данных в модели (обозначенном как «событие»), она оповещает о нём те зависящие от неё представления, которые подписаны на получение такого оповещения - и представление обновляется. Так используется шаблон «наблюдатель »;

    При обработке реакции пользователя - представление выбирает, в зависимости от реакции, нужный контроллер , который обеспечит ту или иную связь с моделью. Для этого используется шаблон «стратегия », или вместо этого может быть модификация с использованием шаблона «команда »;

    Для возможности однотипного обращения с подобъектами сложно-составного иерархического вида - может использоваться шаблон «компоновщик ». Кроме того, могут использоваться и другие шаблоны проектирования - например, «фабричный метод », который позволит задать по умолчанию тип контроллера для соответствующего вида.

    Наиболее частые ошибки

    Начинающие программисты очень часто трактуют архитектурную модель MVC как пассивную модель MVC: модель выступает исключительно совокупностью функций для доступа к данным, а контроллер содержит бизнес-логику . В результате - код моделей по факту является средством получения данных из СУБД , а контроллер - типичным модулем , наполненным бизнес-логикой (см. «скрипт » в терминологии веб-программирования). В результате такого понимания - MVC-разработчики стали писать код, который Pádraic Brady (известный в кругах сообщества «Zend Framework ») охарактеризовал как «ТТУК» («Толстые, тупые, уродливые контроллеры»; Fat Stupid Ugly Controllers):

    Среднестатистический ТТУК получал данные из БД (используя уровень абстракции базы данных, делая вид, что это модель) или манипулировал, проверял, записывал, а также передавал данные в Представление. Такой подход стал очень популярен потому, что использование таких контроллеров похоже на классическую практику использования отдельного php-файла для каждой страницы приложения.

    Но в объектно-ориентированном программировании используется активная модель MVC, где модель - это не только совокупность кода доступа к данным и

    Паттерн Model-View-Controller (MVC) , открытый в в конце 1970-х, представляет собой шаблон проектирования архитектуры программного обеспечения, основной задачей которого является отделение функций работы с данными от их представления. Теоретически, грамотно спроектированное MVC-приложение позволит фронтенд и бэкенд разработчикам в ходе работы не вмешиваться в зоны ответственности друг друга, то есть фронтенд-разработчику не понадобиться что-либо знать о «кухне» своего бэкенд-коллеги и наоборот.

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

    В этой статье мы рассмотрим базовые принципы MVC, начав с определения паттерна и продолжив его применением в небольшом примере. Эта статья будет прежде всего полезна тем, кто ещё никогда не сталкивался с этим паттерном в жизни, а также, возможно, и тем, кто желает освежить в памяти знания об MVC.

    Понимание MVC

    Как уже было сказано, название паттерна происходит от аббревиатуры трёх слов: Model (модель), View (представление) и Controller (контроллер) . Вкратце принцип работы паттерна можно проиллюстрировать одной схемой ( можно найти на Википедии):

    Эта схема наглядно показывает однонаправленность потока информации в паттерне, а также описывает роли каждого компонента.

    Модель

    Модель используется для доступа и манипулирования данными. В большинстве случаев модель — это то, что используется для доступа к хранилищу данных (например, базе данных). Модель предоставляет интерфейс для поиска данных, их создания, модификации и удаления из хранилища. В контексте паттерна MVC модель является посредником между представлением и контроллером.

    Крайне важной чертой модели является то, что технически она не имеет никаких знаний ни о том, что происходит с данными в контроллере и представлении. Модель никогда не должна делать или ожидать каких-либо запросов в/из других компонентов паттерна.

    Тем не менее, всегда помните, что модель — это не просто шлюз доступа к базе данных или другой системе, который только и занимается что передачей данных туда-сюда. Модель — это нечто вроде пропускного пункта к данным. Модель в большинстве случаев является самой сложной частью системы, отчасти из-за того, что сама по себе модель есть связующее звено для всех остальных частей.

    Представление

    Представление — это то, где данные, полученные от модели, выводятся в нужном виде. В традиционных веб-приложениях, разработанных в рамках MVC-паттерна, представление — это часть системы, где выполняется генерация HTML-кода. Представление также отвечает за получение действий от пользователя с тем чтобы отправить их контроллеру. Например, представление отображает кнопку в пользовательском интерфейсе, а после её нажатия вызывает соответствующее действие контроллера.

    Существуют некоторые заблуждения относительно предназначения представления, особенно в среде веб-разработчиков, которые только начинают строить свои приложения с использованием MVC. Одним из наиболее часто нарушаемых правил является то, что представление никоим образом не должно общаться с моделью , а все данные, получаемые представлением должны поступать только от контроллера . На практике же разработчики часто игнорируют эту концепцию, стоящую в основах MVC-паттерна. В статье Fabio Cevasco наглядно показан этот сбивающий с толку подход к MVC на примере фреймворка CakePHP, одним из многих нестандартных MVC-фреймворков:

    Крайне важно понимать, что для того, чтобы получить правильную MVC-архитектуру, не должно быть никаких прямых взаимодействий между представлениями и моделями. Вся логика обмена данными между ними должна быть реализована в контроллерах.

    Помимо этого, существует распространённое заблуждение о том, что представление — это просто темплейт-файл. Как заметил Tom Butler, это заблуждение имеет огромный масштаб из-за того, что многие разработчики с самого начала неправильно понимают структуру MVC, после чего начинают вливать эти «знания» дальше, массы начинающих разработчиков. В действительности представление — это гораздо больше, чем просто темплейт, однако много фреймворков, построенных на базе MVC-паттерна, настолько исказили концепцию представления, что уже всем пофигу, насколько правильными являются их приложения с точки зрения MVC-паттерна.

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

    Контроллер

    Контроллер — это последняя часть связки MVC. Задачей контроллера является получение данных от пользователя и манипуляция моделью. Именно контроллер, и только он, является той частью системы, которая взаимодействует с пользователем.

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

    Очень важно запомнить, что что контроллер начинает свою работу только в результате взаимодействия пользователя с представлением, которое вызывает соответствующую функцию контроллера. Самая распространённая ошибка среди разработчиков заключается в том, что контроллер рассматривается просто как шлюз между представлением и моделью. В результате чего контроллер наделяется теми функциями, который должны выполняться представлением (кстати, вот откуда растут ноги у идеи, что представление — это просто темплейт-файл). Вдобавок ко всему многие вообще сваливают всю логику обработки данных, забывая о том, для чего в паттерне MVC предназначена модель.

    MVC в PHP

    Предлагаю попробовать реализовать описанное выше в небольшом приложении. Начнём с того, что создадим классы модели, представления и контроллера:

    string = "MVC + PHP = Awesome!"; } } controller = $controller; $this->

    " . $this->model->string . "

    "; } } model = $model; } }

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

    output();

    Как видите, контроллер не обладает никакой функциональностью, поскольку пользователь никак не взаимодействует с приложением. Вся функциональность помещена в представление, поскольку наше приложение предназначено исключительно для вывода данных.

    Давайте немного расширим приложение, добавив немного интерактивности, чтобы увидеть, как работает контроллер:

    string = “MVC + PHP = Awesome, click here!”; } } controller = $controller; $this->model = $model; } public function output() { return "

    model->string . "

    "; } } model = $model; } public function clicked() { $this->model->string = “Updated Data, thanks to MVC and PHP!” } }

    И в завершение немного модернизируем связующий код:

    {$_GET["action"]}(); } echo $view->output();

    Итоги

    В этой небольшой статье мы рассмотрели основные концепции шаблона проектирования MVC и разработали простенькое приложение на его базе, хотя конечно, нам ещё очень далеко до того, чтобы использовать это в реальной жизни. В следующей статье мы рассмотрим основные затруднения, с которыми вы столкнётесь, если плотнее займётесь построением архитектуры приложения на базе MVC-паттерна. Stay tuned!

    По всему интернет-миру разбросаны миллионы веб-приложений. Есть совсем простые, есть такие, что сам «архитектор матрицы ногу сломит». Но их объединяет одно — MVC .

    Самый популярный архитектурный паттерн в мире среди веб-приложений — модель-представление-контроллер (Model View Controller или просто MVC). Впервые, он был использован ещё в конце 70-х двадцатого века, в приложениях на языке Smalltalk . А затем, его приютили программисты Java и расшарили для всего мира и всех языков программирования. PHP не стал исключением. Сегодня, только малая часть программистов, коллекционирующих раритетный PHP-код может себе позволить не смотреть в сторону MVC.

    Таким популярным он стал неспроста. Он просто рождён для создания гибких и масштабируемых приложений, которые легко сопровождать и достраивать.
    Цель нашего тьюториала — показать на простом примере, как работает паттерн MVC.

    Чтобы выполнить задания, вам потребуются следующие программы:

    Примечания:

    • Мы предполагаем, что у вас есть базовые знания PHP.

    Паттерн MVC

    Теперь обо всём по порядку. Сначала раскроем великую тайну аббревиатуры, в которой, очевидно, отражается тот факт, что приложение будет представлять собой три взаимодействующие части:

    • Модель отвечает за управление данными, она сохраняет и извлекает сущности, используемые приложением, как правило, из базы данных и содержит логику, реализованную в приложении.
    • Представление несет ответственность за отображение данных, которые даёт контроллер. С представлением тесно связано понятие шаблона, который позволяет менять внешний вид показываемой информации. В веб-приложении представление часто реализуется в виде HTML-страницы.
    • Контроллер связывает модель и представление. Он получает запрос от клиента, анализирует его параметры и обращается к модели для выполнения операций над данными запроса. От модели поступают уже скомпонованные объекты. Затем они перенаправляются в представление, которое передаёт сформированную страницу контроллеру, а он, в свою очередь, отправляет её клиенту.

    Схематично потоки данных в этой модели можно представить так:

    Вход в реальность

    Давайте наконец сформулируем реальную задачу. Пусть нам заказали построить сайт социальной сети. В этой гигантской задаче есть маленькая подзадача: используя имеющуюся базу друзей, обеспечить просмотр их полного списка, а также детальную информацию по каждому другу.

    Мы не будем сейчас рассматривать архитектуру всей социальной сети. Мы возьмём только маленькую подзадачку, представим всю её серьёзность и применим к ней паттерн MVC.

    Как только мы начинаем его использовать, то сразу задумываемся — а как бы нам расположить скрипты нашего решения так, что бы всё было под рукой? Для этого, разместим каждый из трёх разделов нашей MVC-системы по отдельным папкам и, таким образом, получим простую структуру каталогов, в которой легко найти то, что нам нужно. Кроме того, эти три папки поместим в каталог lib, и вынесем его выше корневого веб-каталога www:

    /lib --/controller ---- FrendCnt.php --/model ---- Frend.php ---- FrendList.php --/view ---- frendlist.php ---- frendone.php /www -- index.php -- .htaccess

    Вынесение каталога lib (содержащего движок нашего сайта) из веб-каталога даёт нам бОльшую защищённость, делая нашу систему недоступной для посягательств шаловливых ручонок взломщиков.

    Контроллер

    Теперь обо всём по порядку. Начнём с контроллера , так как он первый из трёх компонентов паттерна встречает клиентский запрос, разбирает его на элементы, инициализирует объекты модели. После обработки данных моделью, он принимает её ответ и отправляет его на уровень представления.

    В нашем простом примере, контроллер будет сконцентрирован в одном классе FrendCnt . Подробнее его опишем позже.А сейчас немного о точке входа в веб-приложение — это, конечно, будет файл index.php . В нём, мы определим точку отсчёта для подключения наших скриптов. Создадим экземпляр контроллера, и вызовем у него метод, который начнёт обрабатывать HTTP-запрос и определит что делать дальше.

    Листинг №1 (файл index.php):

    $baseDir = dirname(__FILE__) . "/.."; include_once($baseDir . "/lib/controller/FriendCnt.php"); $controller = new FriendCnt(); $controller->invoke();

    Теперь о контроллере. У нас — это класс FriendCnt . Вы уже заметили, что экземпляр этого класса создаётся в index.php . Он имеет только один метод invoke() , который вызывается сразу после создания экземпляра. В конструкторе контроллера, создаётся объект на основе класса модели — FrendList (список друзей) для оперирования с данными.

    В функции invoke() , на основе пришедшего HTTP-запроса, принимается решение: какие данные потребуются от модели. Затем происходит вызов метода извлекающего данные. Далее происходит подключение шаблонов для отображения, которым передаются данные из контроллера. Обратите внимание, что контроллер ничего не знает о базе данных или о том, как страница генерится.

    Листинг №2 (файл контроллера FriendCnt.php):

    Require_once($baseDir . "/lib/model/FriendList.php"); class FriendCnt { public $oFriendList; public function __construct() { $this->oFriendList = new FriendList(); } public function invoke() { global $baseDir; $oFriendList = $this->oFriendList; if(isset($_GET["key"])) { $oFriendList->setKey($_GET["key"]); $oFriend = $oFriendList->fetch(); include $baseDir . "/lib/view/friendone.php"; }else { $aFriend = $oFriendList->fetch(); include $baseDir . "/lib/view/friendlist.php"; } } }

    Модель и сущности

    Модель — это образ реальности, из которой взято только то, что нужно для решения задачи. Модель концентрируется на логике решения основной задачи. Многие называют это бизнес-логикой, на ней лежит большая ответственность:

    • Сохранение, удаление, обновление данных приложения. Это реализуется через операции с базой данных или через вызов внешних веб-сервисов.
    • Инкапсуляция всей логики приложения. Абсолютно вся логика приложения без исключений должна быть сконцентрирована в модели. Не нужно какую-то часть бизнес-логики выносить в контроллер или представление.

    У нас к модели относятся два скрипта, в каждом из которых определён свой класс. Центральный класс FriendList и класс-сущность Friend . В центральном классе, происходит манипуляция с данными: получение данных от контроллера и их обработка. Класс-сущность служит контейнером для переноса данных между моделью и представлением, а также определяет их формат. При хорошей реализации паттерна MVC, классы сущности не должны упоминаться в контроллере, и они не должны содержать какую-либо бизнес-логику. Их цель - только хранение данных.
    В классе FriendList , работающем со списком друзей, мы создали функцию, которая моделирует взаимодействие этого класса с базой данных. Метод getFriendList() возвращает массив из объектов, созданных на основе класса Friend . Для обеспечения удобства работы с данными, также была создана функция, индексирующая массив объектов. Контроллеру оказались доступны только два метода: setKey() — устанавливает поле ключа, по которому возвращаются детальные данные о друге; fetch() — возвращает или конкретный объект или весь список друзей.

    Листинг №3 (файл модели FriendList.php):

    Require_once($baseDir . "/lib/model/Friend.php"); class FriendList { private $oneKey; private function getFriendList() { return array(new Friend("Александр", "1985", "[email protected]"), new Friend("Юрий", "1987", "[email protected]"), new Friend("Алексей", "1989", "[email protected]"),); } private function getIndexedList() { $list = array(); foreach($this->getFriendList() as $val) { $list[$val->getKey()] = $val; } return $list; } public function setKey($key) { $this->oneKey = $key; } public function fetch() { $aFriend = $this->getIndexedList(); return ($this->oneKey) ? $aFriend[$this->oneKey] : $aFriend; } }

    В зависимости от реализации объектов Сущности, данные о ней, могут быть оформлены в виде XML-документа или JSON-объекта.

    Листинг №4 (файл сущности Friend.php):

    Class Friend { private $key; private $name; private $yearOfBirth; private $email; public function __construct($name, $yearOfBirth, $email) { $this->key = md5($name . $yearOfBirth . $email); $this->name = $name; $this->yearOfBirth = $yearOfBirth; $this->email = $email; } public function getKey() { return $this->key; } public function getName() { return $this->name; } public function getYearOfBirth() { return $this->yearOfBirth; } public function getEmail() { return $this->email; } }

    Представление

    Теперь нам нужно представить данные в наилучшем свете для пользователя.

    Настал черёд поговорить о Представлении. В зависимости от задачи, данные могут быть переданы представлению в разных форматах: простые объекты, XML-документы, JSON-объекты и т.д. В нашем случае передаётся объект или массив объектов. При это мы не побеспокоились о выводе базового слоя — то, что относится к футеру и хедеру генерируемой страницы, этот код повторяется в обоих файлах представления. Но для нашего небольшого примера это не важно.

    Главное здесь показать, что представление отделено от контроллера и модели. При этом контроллер занимается передачей данных от модели к представлению.

    В нашем примере представление содержит только два файла: для отображения детальной информации о друге и для отображения списка друзей.

    Листинг №5 (файл для вывода списка друзей friendlist.php):

    Мои друзья

    Имя Год рождения
    getKey() ?>"> getName() ?> getYearOfBirth() ?>

    Листинг №6 (файл для вывода списка друзей friendone.php):

    <?php echo $oFriend->getName() ?> : Мой друг getName() . "
    "; echo "Год рождения: " . $oFriend->getYearOfBirth() . "
    "; echo "Email: " . $oFriend->getEmail() . "
    "; ?> Список

    Если вы перенесёте весь этот код на веб-сервер, то в результате вы получите микро-сайт не на две страницы (если судить по количеству файлов представления), а уже на четыре. На первой будет показан список друзей, а на остальных трёх — детальная информация по каждому другу.

    Мы могли бы реализовать детальный просмотр с помощью AJAX, тогда бы у нас была всего одна страница, и мы формировали бы часть представления через JSON-объекты непосредственно на компьютерах клиентов. Существует куча вариантов на этот счёт.

    Это упрощённый пример веб-приложения на основе паттерна MVC. Но уже на нём можно увидеть массу возможностей. К плюсам мы уже отнесли гибкость и масштабируемость. Дополнительными плюсами будут — возможности стандартизации кодирования, лёгкость обнаружения и исправления ошибок, быстрое вхождение в проект новых разработчиков. Кроме того, вы можете в своём приложении изменять способ хранения сущностей, используя для этого сторонние веб-сервисы и облачные базы данных. Из минусов можно привести только небольшое увеличение объёма скриптов. А так, сплошные плюсы. Так-что пользуетесь на здоровье.

    Здесь лежат файлы проекта, качайте сравнивайте:

    Ну как? Какие мысли? Комментируем, не стесняемся.

Похожие статьи