Контроллеры. Разделение кода. Модель MVC

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, согласно которой :

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

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

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

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

    Модель

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

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

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

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

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

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

    Контроллер

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Контроллеры

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

    В инфраструктуре ASP.NET MVC Framework контроллеры являются классами.NET, которые содержат логику, требуемую для обработки запроса. Роль контроллера заключается в инкапсуляции логики приложения. Другими словами, контроллеры отвечают за обработку входящих запросов, выполнение операций над моделью предметной области и выбор представлений для визуализации пользователю.

    Пример приложения

    Для целей этой и следующих статей мы создадим новый проект MVC по имени ControllersAndActions с использованием шаблона Empty (Пустой), отметив флажок MVC в разделе Add folders and core references for (Добавить папки и основные ссылки для), а также проект модульного тестирования под названием ControllersAndActions.Tests. Модульные тесты, которые будут создаваться, не требуют имитированных реализаций, поэтому пакет Moq устанавливать не придется, но нужно установить пакет MVC, чтобы тесты имели доступ к базовым классам контроллеров.

    В окне консоли диспетчера пакетов NuGet среды Visual Studio введите следующую команду:

    Install-Package Microsoft.Aspnet.Mvc -version 5.0.0 -projectname ControllersAndActions.Tests

    После создания проекта выберите пункт ControllersAndActions Properties (Свойства ControllersAndActions) в меню Project (Проект) среды Visual Studio, в открывшемся диалоговом окне перейдите на вкладку Web (Веб) и отметьте переключатель Specific Page (Определенная страница) в категории Start Action (Начальное действие). Вводить какое-либо значение не нужно - достаточно только выбора переключателя.

    Понятие контроллера

    Вы сталкивались со случаями использования контроллеров почти во всех предшествующих статьях, посвященных ASP.NET MVC. Наступило время заглянуть "за кулисы".

    Создание контроллера с помощью интерфейса IController

    В MVC Framework классы контроллеров должны реализовать интерфейс IController из пространства имен System.Web.Mvc , показанный в примере ниже:

    Using System.Web.Routing; namespace System.Web.Mvc { public interface IController { void Execute(RequestContext requestContext); } }

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

    Как видите, интерфейс IController очень прост. Его единственный метод Execute() вызывается, когда запрос направляется этому классу контроллера. Инфраструктура MVC Framework выясняет, на какой класс ориентирован запрос, за счет чтения значения свойства controller, сгенерированного данными маршрутизации, или через специальные классы маршрутизации.

    Создавать классы контроллеров можно путем реализации интерфейса IController, однако поскольку этот интерфейс является низкоуровневым, потребуется проделать немало работы, чтобы получить, в конечном счете, что-нибудь полезное. Тем не менее, интерфейс IController полезен для демонстрации оперирования контроллеров и с этой целью в папке Controllers создается новый файл класса по имени BasicController.cs, содержимое которого приведено в примере ниже:

    Using System.Web.Mvc; using System.Web.Routing; namespace ControllersAndActions.Controllers { public class BasicController: IController { public void Execute(RequestContext requestContext) { string controller = (string)requestContext.RouteData.Values["controller"]; string action = (string)requestContext.RouteData.Values["action"]; requestContext.HttpContext.Response.Write(string.Format("Контроллер: {0}, Метод действия: {1}", controller, action)); } } }

    Методу Execute() интерфейса IController передается объект RequestContext , предоставляющий информацию о текущем запросе и маршруте, который ему соответствует (и приводит к вызову данного контроллера для обработки этого запроса). В классе RequestContext определены два свойства, описанные в таблице ниже:

    Объект HttpContextBase предоставляет доступ к набору объектов, описывающих текущий запрос, которые называются объектами контекста; мы еще вернемся к ним позже. Объект RouteData описывает маршрут. Важные свойства класса RouteData перечислены в таблице ниже:

    В статье Настройка системы маршрутизации было показано, как использовать типы RouteBase и IRouteHandler для настройки системы маршрутизации. В рассматриваемом примере с помощью свойства Values получаются значения переменных сегментов controller и action, которые затем записываются в ответ.

    Часть проблемы, возникающей при создании специальных контроллеров, связана с отсутствием доступа к таким средствам, как представления. Это означает, что придется работать на более низком уровне, чем и объясняется запись содержимого напрямую в ответ клиенту. Свойство HttpContextBase.Response возвращает объект HttpResponseBase , который позволяет конфигурировать и добавлять содержимое к ответу, предназначенному для отправки клиенту. Это еще одна точка соприкосновения между платформой ASP.NET и инфраструктурой MVC Framework.

    Если запустить приложение и перейти на URL вида /Basic/Index, то специальный контроллер сгенерирует вывод, показанный на рисунке ниже:

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

    Классы с именами, заканчивающимися на Base

    При обработке запросов инфраструктура MVC Framework полагается на платформу ASP.NET, что имеет большой смысл, т.к. эта платформа является проверенной и многофункциональной реализацией, которая тесно интегрируется с сервером приложений IIS. Проблема заключается в том, что классы, применяемые платформой ASP.NET для предоставления информации о запросах, не очень хорошо подходят для модульного тестирования - основного преимущества использования MVC Framework.

    В Microsoft решили ввести возможность тестирования, поддерживая при этом совместимость с существующими приложениями ASP.NET Web Forms, так что в результате появились классы Base . Эти классы так называются из-за того, что они имеют те же самые имена, как у основных классов платформы ASP.NET, за которыми следует слово Base.

    Так, например, платформа ASP.NET предоставляет контекстную информацию о текущем запросе и ряде ключевых служб приложения через объект HttpContext. Соответствующим ему классом Base является HttpContextBase, экземпляр которого передается методу Execute(), определенному в интерфейсе IController (в последующих примерах будут продемонстрированы и другие классы Base). В первоначальных классах и классах Base определены одни и те же свойства и методы, но классы Base всегда абстрактны , а это значит, что их легко применять для модульного тестирования.

    Иногда вы получите экземпляр одного из первоначальных классов ASP.NET, такого как HttpContext. В таком случае необходимо создать дружественный к MVC класс Base, подобный HttpContextBase. Это делается с использованием одного из классов Wrapper , которые имеют такие же имена, как первоначальные классы, дополненные словом Wrapper, например, HttpContextWrapper . Классы Wrapper являются производными от классов Base и имеют конструкторы, которые принимают экземпляры первоначальных классов:

    Первоначальные классы, классы Base и классы Wrapper определены в пространстве имен System.Web, поэтому платформа ASP.NET может гладко поддерживать приложения MVC Framework и более старые приложения Web Forms.

    Создание контроллера за счет наследования от класса Controller

    Как было продемонстрировано в предыдущем примере, инфраструктура MVC Framework допускает практически неограниченную настройку и расширение. Чтобы обеспечить любой требуемый вид обработки запросов и генерации результатов, можно реализовать интерфейс IController. Вам не нравятся методы действий? Вы не хотите беспокоиться по поводу визуализированных представлений? В таком случае можете взять дело в свои руки и реализовать лучший, быстрый и более элегантный способ обработки запросов. Либо же вы можете воспользоваться средствами, предлагаемыми командой разработчиков MVC Framework из Microsoft, и унаследовать свои контроллеры от класса System.Web.Mvc.Controller .

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

    Методы действий

    Поведение контроллера разнесено по множеству методов (вместо реализации в виде единственного метода Execute()). Каждый метод действия отображается на соответствующий URL и вызывается с параметрами, извлеченными из входящего запроса.

    Результаты действий

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

    Фильтры

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

    Если только вы не имеете дело со специфичным требованием, то лучшим подходом к созданию контроллеров будет их наследование от класса Controller, что, как и можно было ожидать, делает среда Visual Studio, когда создает новый класс в ответ на выбор пункта меню Add --> Scaffold (Добавить --> Шаблон).

    В примере ниже приведен код простого контроллера под названием DerivedController, созданного подобным образом. Он сгенерирован с применением варианта MVC 5 Controller - Empty (Контроллер MVC 5 - Пустой) с несколькими простыми изменениями, предназначенными для установки свойства ViewBag и выбора представления:

    Using System; using System.Web; using System.Web.Mvc; namespace ControllersAndActions.Controllers { public class DerivedController: Controller { public ActionResult Index() { ViewBag.Message = "Привет из контроллера DerivedController метода действия Index"; return View("MyView"); } } }

    Класс Controller также обеспечивает связь с системой представлений Razor. В этом примере мы возвращаем результат вызова метода View(), которому в качестве параметра передается имя представления для визуализации клиенту. Чтобы создать это представление, создайте папку Views/Derived, щелкните на ней правой кнопкой мыши и выберите в контекстном меню пункт Add --> MVC 5 View Page (Razor) (Добавить --> Страница представления MVC 5 (Razor)). Укажите в качестве имени MyView.cshtml и щелкните на кнопке ОК для создания файла представления.

    Приведите содержимое файла в соответствие с примером:

    @{ ViewBag.Title = "Index"; } MyView Сообщение от контроллера: « @ViewBag.Message »

    После запуска приложения и перехода на URL вида /Derived/Index этот метод действия вызывается, а представление MyView визуализируется:

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

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

    Вы можеть быть даже слышали о шаблонах проектирования и даже листали эти прекрасные книги:

    • Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидесс «Приемы объектно ориентированного проектирования. Паттерны проектирования»;
    • М. Фаулер «Архитектура корпоративных программных приложений».
    А многие, не испугавшись огромных руководств и документаций, пытались изучить какой-либо из современных фреймворков и столкнувшись со сложностью понимания (в силу наличия множества архитектруных концепций хитро увязанных между собой) отложили изучение и применение современных интсрументов в «долгий ящик».

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

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

    1. Теория Шаблон MVC описывает простой способ построения структуры приложения, целью которого является отделение бизнес-логики от пользовательского интерфейса. В результате, приложение легче масштабируется, тестируется, сопровождается и конечно же реализуется.

    Рассмотрим концептуальную схему шаблона MVC (на мой взгляд - это наиболее удачная схема из тех, что я видел):

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

    Типичную последовательность работы MVC-приложения можно описать следующим образом:

  • При заходе пользователя на веб-ресурс, скрипт инициализации создает экземпляр приложения и запускает его на выполнение.
    При этом отображается вид, скажем главной страницы сайта.
  • Приложение получает запрос от пользователя и определяет запрошенные контроллер и действие. В случае главной страницы, выполняется действие по умолчанию (index ).
  • Приложение создает экземпляр контроллера и запускает метод действия,
    в котором, к примеру, содержаться вызовы модели, считывающие информацию из базы данных.
  • После этого, действие формирует представление с данными, полученными из модели и выводит результат пользователю.
  • Модель - содержит бизнес-логику приложения и включает методы выборки (это могут быть методы ORM), обработки (например, правила валидации) и предоставления конкретных данных, что зачастую делает ее очень толстой, что вполне нормально.
    Модель не должна напрямую взаимодействовать с пользователем. Все переменные, относящиеся к запросу пользователя должны обрабатываться в контроллере.
    Модель не должна генерировать HTML или другой код отображения, который может изменяться в зависимости от нужд пользователя. Такой код должен обрабатываться в видах.
    Одна и та же модель, например: модель аутентификации пользователей может использоваться как в пользовательской, так и в административной части приложения. В таком случае можно вынести общий код в отдельный класс и наследоваться от него, определяя в наследниках специфичные для подприложений методы.

    Вид - используется для задания внешнего отображения данных, полученных из контроллера и модели.
    Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.
    Не должны напрямую обращаться к базе данных. Этим должны заниматься модели.
    Не должны работать с данными, полученными из запроса пользователя. Эту задачу должен выполнять контроллер.
    Может напрямую обращаться к свойствам и методам контроллера или моделей, для получения готовых к выводу данных.
    Виды обычно разделяют на общий шаблон, содержащий разметку, общую для всех страниц (например, шапку и подвал) и части шаблона, которые используют для отображения данных выводимых из модели или отображения форм ввода данных.

    Контроллер - связующее звено, соединяющее модели, виды и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Контроллер не должен содержать SQL-запросов. Их лучше держать в моделях. Контроллер не должен содержать HTML и другой разметки. Её стоит выносить в виды.
    В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. Чего, не скажешь о Stupid Fat Controllers (SFC) в CMS Joomla. Логика контроллера довольно типична и большая ее часть выносится в базовые классы.
    Модели, наоборот, очень толстые и содержат большую часть кода, связанную с обработкой данных, т.к. структура данных и бизнес-логика, содержащаяся в них, обычно довольно специфична для конкретного приложения.

    1.1. Front Controller и Page Controller В большинстве случае, взаимодействие пользователя с web-приложением проходит посредством переходов по ссылкам. Посмотрите сейчас на адресную строку браузера - по этой ссылке вы получили данный текст. По другим ссылкам, например, находящимся справа на этой странице, вы получите другое содержимое. Таким образом, ссылка представляет конкретную команду web-приложению.

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

    Рассмотрим два варианта адресной строки, по которым показывается какой-то текст и профиль пользователя.

    Приблизительный код обработки в таком случае:
    switch($_GET["action"]) { case "about" : require_once("about.php"); // страница "О Нас" break; case "contacts" : require_once("contacts.php"); // страница "Контакты" break; case "feedback" : require_once("feedback.php"); // страница "Обратная связь" break; default: require_once("page404.php"); // страница "404" break; }
    Думаю, почти все так раньше делали.

    С использованием движка маршрутизации URL вы сможете для отображения той же информации настроить приложение на прием таких запросов:
    http://www.example.com/contacts/feedback

    Здесь contacts представляет собой контроллер, а feedback - это метод контроллера contacts, отображающий форму обратной связи и т.д. Мы еще вернемся к этому вопросу в практической части.

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

    2. Практика Для начала создадим следующую структуру файлов и папок:


    Забегая вперед, скажу, что в папке core будут храниться базовые классы Model, View и Controller.
    Их потомки будут храниться в директориях controllers, models и views. Файл index.php это точка в хода в приложение. Файл bootstrap.php инициирует загрузку приложения, подключая все необходимые модули и пр.

    Будем идти последовательно; откроем файл index.php и наполним его следующим кодом:
    ini_set("display_errors", 1); require_once "application/bootstrap.php";
    Тут вопросов возникнуть не должно.

    Следом, сразу же перейдем к фалу bootstrap.php :
    require_once "core/model.php"; require_once "core/view.php"; require_once "core/controller.php"; require_once "core/route.php"; Route::start(); // запускаем маршрутизатор
    Первые три строки будут подключать пока что несуществующие файлы ядра. Последние строки подключают файл с классом маршрутизатора и запускают его на выполнение вызовом статического метода start.

    2.1. Реализация маршрутизатора URL Пока что отклонимся от реализации паттерна MVC и займемся мрашрутизацией. Первый шаг, который нам нужно сделать, записать следующий код в .htaccess :
    RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule .* index.php [L]
    Этот код перенаправит обработку всех страниц на index.php , что нам и нужно. Помните в первой части мы говорили о Front Controller?!

    Маршрутизацию мы поместим в отдельный файл route.php в директорию core. В этом файле опишем класс Route, который будет запускать методы контроллеров, которые в свою очередь будут генерировать вид страниц.

    Содержимое файла route.php

    class Route { static function start() { // контроллер и действие по умолчанию $controller_name = "Main"; $action_name = "index"; $routes = explode("/", $_SERVER["REQUEST_URI"]); // получаем имя контроллера if (!empty($routes)) { $controller_name = $routes; } // получаем имя экшена if (!empty($routes)) { $action_name = $routes; } // добавляем префиксы $model_name = "Model_".$controller_name; $controller_name = "Controller_".$controller_name; $action_name = "action_".$action_name; // подцепляем файл с классом модели (файла модели может и не быть) $model_file = strtolower($model_name).".php"; $model_path = "application/models/".$model_file; if(file_exists($model_path)) { include "application/models/".$model_file; } // подцепляем файл с классом контроллера $controller_file = strtolower($controller_name).".php"; $controller_path = "application/controllers/".$controller_file; if(file_exists($controller_path)) { include "application/controllers/".$controller_file; } else { /* правильно было бы кинуть здесь исключение, но для упрощения сразу сделаем редирект на страницу 404 */ Route::ErrorPage404(); } // создаем контроллер $controller = new $controller_name; $action = $action_name; if(method_exists($controller, $action)) { // вызываем действие контроллера $controller->$action(); } else { // здесь также разумнее было бы кинуть исключение Route::ErrorPage404(); } } function ErrorPage404() { $host = "http://".$_SERVER["HTTP_HOST"]."/"; header("HTTP/1.1 404 Not Found"); header("Status: 404 Not Found"); header("Location:".$host."404"); } }


    Замечу, что в классе реализована очень упрощенная логика (несмотря на объемный код) и возможно даже имеет проблемы безопасности. Это было сделано намерено, т.к. написание полноценного класса маршрутизации заслуживает как минимум отдельной статьи. Рассмотрим основные моменты…

    В элементе глобального массива $_SERVER["REQUEST_URI"] содержится полный адрес по которому обратился пользователь.
    Например: example.ru/contacts/feedback

    С помощью функции explode производится разделение адреса на составлющие. В результате мы получаем имя контроллера, для приведенного примера, это контроллер contacts и имя действия, в нашем случае - feedback .

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

    Таким образом, при переходе, к примеру, по адресу:
    example.com/portfolio
    или
    example.com/portfolio/index
    роутер выполнит следующие действия:

  • подключит файл model_portfolio.php из папки models, содержащий класс Model_Portfolio;
  • подключит файл controller_portfolio.php из папки controllers, содержащий класс Controller_Portfolio;
  • создаст экземпляр класса Controller_Portfolio и вызовет действие по умолчанию - action_index, описанное в нем.
  • Если пользователь попытается обратиться по адресу несуществующего контроллера, к примеру:
    example.com/ufo
    то его перебросит на страницу «404»:
    example.com/404
    То же самое произойдет если пользователь обратится к действию, которое не описано в контроллере.2.2. Возвращаемся к реализации MVC Перейдем в папку core и добавим к файлу route.php еще три файла: model.php, view.php и controller.php


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

    Содержимое файла model.php
    class Model { public function get_data() { } }
    Класс модели содержит единственный пустой метод выборки данных, который будет перекрываться в классах потомках. Когда мы будем создавать классы потомки все станет понятней.

    Содержимое файла view.php
    class View { //public $template_view; // здесь можно указать общий вид по умолчанию. function generate($content_view, $template_view, $data = null) { /* if(is_array($data)) { // преобразуем элементы массива в переменные extract($data); } */ include "application/views/".$template_view; } }
    Не трудно догадаться, что метод generate предназначен для формирования вида. В него передаются следующие параметры:

  • $content_file - виды отображающие контент страниц;
  • $template_file - общий для всех страниц шаблон;
  • $data - массив, содержащий элементы контента страницы. Обычно заполняется в модели.
  • Функцией include динамически подключается общий шаблон (вид), внутри которого будет встраиваться вид
    для отображения контента конкретной страницы.

    В нашем случае общий шаблон будет содержать header, menu, sidebar и footer, а контент страниц будет содержаться в отдельном виде. Опять же это сделано для упрощения.

    Содержимое файла controller.php
    class Controller { public $model; public $view; function __construct() { $this->view = new View(); } function action_index() { } }
    Метод action_index - это действие, вызываемое по умолчанию, его мы перекроем при реализации классов потомков.

    2.3. Реализация классов потомков Model и Controller, создание View"s Теперь начинается самое интересное! Наш сайт-визитка будет состоять из следущих страниц:
  • Главная
  • Услуги
  • Портфолио
  • Контакты
  • А также - страница «404»
  • Для каждой из страниц имеется свой контроллер из папки controllers и вид из папки views. Некоторые страницы могут использовать модель или модели из папки models.


    На предыдущем рисунке отдельно выделен файл template_view.php - это шаблон, содержащий общую для всех страниц разметку. В простейшем случае он мог бы выглядеть так:
    Главная
    Для придания сайту презентабельного вида сверстаем CSS шаблон и интегририруем его в наш сайт путем изменения структуры HTML-разметки и подключения CSS и JavaScript файлов:

    В конце статьи, в разделе «Результат», приводится ссылка на GitHub-репозиторий с проектом, в котором проделаны действия по интеграции простенького шаблона.

    2.3.1. Создадаем главную страницу Начнем с контроллера controller_main.php , вот его код:
    class Controller_Main extends Controller { function action_index() { $this->view->generate("main_view.php", "template_view.php"); } }
    В метод generate экземпляра класса View передаются имена файлов общего шаблона и вида c контентом страницы.
    Помимо индексного действия в контроллере конечно же могут содержаться и другие действия.

    Файл с общим видом мы рассмотрели ранее. Рассмотрим файл контента main_view.php :
    Добро пожаловать!

    ОЛОЛОША TEAM - команда первоклассных специалистов в области разработки веб-сайтов с многолетним опытом коллекционирования мексиканских масок, бронзовых и каменных статуй из Индии и Цейлона, барельефов и изваяний, созданных мастерами Экваториальной Африки пять-шесть веков назад...


    Здесь содержиться простая разметка без каких либо PHP-вызовов.
    Для отображения главной странички можно воспользоваться одним из следующих адресов:

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

    2.3.2. Создадаем страницу «Портфолио» В нашем случае, страница «Портфолио» - это единственная страница использующая модель.
    Модель обычно включает методы выборки данных, например:
  • методы нативных библиотек pgsql или mysql;
  • методы библиотек, реализующих абстракицю данных. Например, методы библиотеки PEAR MDB2;
  • методы ORM;
  • методы для работы с NoSQL;
  • и др.
  • Для простоты, здесь мы не будем использовать SQL-запросы или ORM-операторы. Вместо этого мы сэмулируем реальные данные и сразу возвратим массив результатов.
    Файл модели model_portfolio.php поместим в папку models. Вот его содержимое:
    class Model_Portfolio extends Model { public function get_data() { return array(array("Year" => "2012", "Site" => "http://DunkelBeer.ru", "Description" => "Промо-сайт темного пива Dunkel от немецкого производителя Löwenbraü выпускаемого в России пивоваренной компанией "CАН ИнБев"."), array("Year" => "2012", "Site" => "http://ZopoMobile.ru", "Description" => "Русскоязычный каталог китайских телефонов компании Zopo на базе Android OS и аксессуаров к ним."), // todo); } }

    Класс контроллера модели содержится в файле controller_portfolio.php , вот его код:
    class Controller_Portfolio extends Controller { function __construct() { $this->model = new Model_Portfolio(); $this->view = new View(); } function action_index() { $data = $this->model->get_data(); $this->view->generate("portfolio_view.php", "template_view.php", $data); } }
    В переменную data записывается массив, возвращаемый методом get_data , который мы рассматривали ранее.
    Далее эта переменная передается в качестве параметра метода generate , в который также передаются: имя файла с общим шаблон и имя файла, содержащего вид c контентом страницы.

    Вид содержащий контент страницы находится в файле portfolio_view.php .
    Портфолио

    Все проекты в следующей таблице являются вымышленными, поэтому даже не пытайтесь перейти по приведенным ссылкам.
    ГодПроектОписание


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

    2.3.3. Создаем остальные страницы Остальные страницы создаются аналогично. Их код досутпен в репозитории на GitHub, ссылка на который приводится в конце статьи, в разделе «Результат».3. Результат А вот что получилось в итоге:

    Скриншот получившегося сайта-визитки



    Ссылка на GitHub: https://github.com/vitalyswipe/tinymvc/zipball/v0.1

    А вот в этой версии я набросал следующие классы (и соответствующие им виды):

    • Controller_Login в котором генерируется вид с формой для ввода логина и пароля, после заполнения которой производится процедура аутентификации и в случае успеха пользователь перенаправляется в админку.
    • Contorller_Admin с индексным действием, в котором проверяется был ли пользователь ранее авторизован на сайте как администратор (если был, то отображается вид админки) и действием logout для разлогинивания.
    Аутентификация и авторизация - это другая тема, поэтому здесь она не рассматривается, а лишь приводится ссылка указанная выше, чтобы было от чего оттолкнуться.4. Заключение Шаблон MVC используется в качестве архитектурной основы во многих фреймворках и CMS, которые создавались для того, чтобы иметь возможность разрабатывать качественно более сложные решения за более короткий срок. Это стало возможным благодаря повышению уровня абстракции, поскольку есть предел сложности конструкций, которыми может оперировать человеческий мозг.

    Но, использование веб-фреймворков, типа Yii или Kohana, состоящих из нескольких сотен файлов, при разработке простых веб-приложений (например, сайтов-визиткок) не всегда целесообразно. Теперь мы умеем создавать красивую MVC модель, чтобы не перемешивать Php, Html, CSS и JavaScript код в одном файле.

    Данная статья является скорее отправной точкой для изучения CMF, чем примером чего-то истинно правильного, что можно взять за основу своего веб-приложения. Возможно она даже вдохновила Вас и вы уже подумываете написать свой микрофреймворк или CMS, основанные на MVC. Но, прежде чем изобретать очередной велосипед с «блекджеком и шлюхами», еще раз подумайте, может ваши усилия разумнее направить на развитие и в помощь сообществу уже существующего проекта?!

    P.S.: Статья была переписана с учетом некоторых замечаний, оставленных в комментариях. Критика оказалась очень полезной. Судя по отклику: комментариям, обращениям в личку и количеству юзеров добавивших пост в избранное затея написать этот пост оказалось не такой уж плохой. К сожалению, не возможно учесть все пожелания и написать больше и подробнее по причине нехватки времени… но возможно это сделают те таинственные личности, кто минусовал первоначальный вариант. Удачи в проектах!

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

    Теги: Добавить метки

    В номере

      защитный элемент - Водяной знак: традиции и инновации

      место встречи - Это деньги завтрашнего дня

      точка зрения - Премьеры и тенденции

      ноу-хау - Двуликая защита

      ноу-хау - Весь секрет в линзах

      документ - Канадский паспорт: искусство технологий

      разработки - Защитные волокна: новые возможности

      марки - Изразцы, никель и стихи Бродского

      знаки истории - Открытки: путь от «почтовой телеграммы» до агитационного плаката

      экскурсия - Армянские драмы: деньги иллюстрируют историю

    Просто проверить, сложно повторить

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

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

    Просветленные технологии

    Водяной знак, наблюдаемый в бумаге в проходящем свете, остается наиболее популярным защитным признаком у населения. При этом он технологичен, а опыт производства бумаги с водяными знаками исчисляется более чем семью столетиями. Именно поэтому за последние годы благодаря появлению новых технологий изготовления формных изделий этот защитный признак получил новое развитие. Многотоновые водяные знаки практически во всех модернизированных банкнотах уступили свое место водяным знакам, полученным за счет комбинирования многотоновых и филигранных знаков. А в настоящее время активно внедряется технология получения водяных знаков за счет сложных многоуровневых филиграней. Журнал «Водяной знак» неоднократно рассказывал об этих водяных знаках. Эта технология дает возможность получить не только контрастные светлые участки знака, но и изображения с высокой, нетипичной для водяных знаков линиатурой.

    Защитные нити, как и контролируемые на просвет водяные знаки, имеют, в отличие от последних, не столь давнюю историю – чуть больше полутора веков. Однако они прочно обосновались на верхнем уровне защитных технологий. Это связано как с хорошей технологичностью изготовления бумаги с защитными нитями, так и с их широчайшими возможностями выступать в качестве носителя различных защитных признаков и эффектов. При кажущихся неоспоримых преимуществах по сравнению с водяными знаками значительно более высокая стоимость самих защитных нитей снижает эффективность их использования, особенно на низких номиналах, где, как правило, применяются наиболее простые и, соответственно, более дешевые варианты нитей. Именно поэтому одним из направлений развития защитных нитей на Гознаке стало получение в бумаге прозрачного окна большой площади за счет введения при отливе бумаги широкой прозрачной полимерной ленты с последующим использованием стандартных печатных технологий для получения защитных эффектов в области окна. Поскольку полимерная пленка, из которой изготавливается лента, относится к массово выпускаемой продукции и не содержит эксклюзивных защитных признаков, ее стоимость существенно ниже стоимости нитей, имеющих цветопеременные, оптически-переменные и другие высокотехнологичные признаки. При этом аналогичные высокозащищенные оптически-переменные признаки можно получить с использованием традиционных печатных технологий, что делает это техническое решение более эффективным.

    Именно такой подход был реализован в памятной банкноте «Сочи 2014». В прозрачном окне, полученном за счет введения широкой полимерной ленты в бумагу во время отлива, выполнен металлографским способом оптически-переменный защитный элемент «Зебра». При рассматривании на просвет и плавном повороте банкноты можно увидеть, как изображение снежинки в окне меняется с негативного на позитивное.

    А что, если не вводить полимерную ленту для получения оптически-переменного признака, контролируемого на просвет? Или, по-другому, как получить в бумаге оптически-переменный элемент, контролируемый на просвет, с использованием традиционных банкнотных технологий? Именно такая задача была поставлена перед сотрудниками Дирекции по защитным технологиям и специалистами НИИ Гознака в 2014 году. Цель очевидна: избавиться от «дополнительного» элемента – широкой полимерной ленты и сложной технологии ее введения в бумагу, т. е. сделать защитное решение еще более эффективным.

    Задача оказалась очень сложной, поскольку, с одной стороны, на конечный результат влияло большое количество факторов, а, с другой стороны, основные факторы оказались не только тесно связаны друг с другом, но и находились в противоречии друг с другом. Пришлось искать нестандартные решения. К концу 2014 года после проведенной научно-исследовательской работы была доказана принципиальная возможность получения таких защитных элементов. В 2015 году ФГУП «Гознак» выпущена рекламная банкнота «Русский Авангард», представленная заместителем генерального директора по науке и развитию А. Б. Курятниковым во втором номере журнала «Водяной знак» за 2015 год. В рекламной банкноте реализован защитный элемент «Силуэт» – оптически переменный элемент, видимый в проходящем свете и выполненный с использованием традиционных полиграфических банкнотных технологий в полупрозрачном окне, полученном с использованием традиционной технологии изготовления банкнотной бумаги. В настоящее время проводится работа так как по совершенствованию технологии получения полупрозрачного окна, и по оптимизации дизайна печатных элементов.

    Игра в кубики

    MVC, MVC+, HMC… Эти аббревиатуры названий защитных признаков, разработанных во ФГУП «Гознак», регулярно появляются на страницах журнала начиная с 2004 года. И если собрать все статьи, написанные на эту тему, получится целая история рождения, становления и развития одного из самых эффективных, на наш взгляд, защитных направлений. Особенность этого направления заключается в том, что для воспроизведения защитных элементов используется комбинация в виде согласованных по геометрическим параметрам линий, отпечатанных офсетным и металлографским способами печати.

    Появившийся в модернизированных банкнотах Банка России защитный признак MVC Moire Variable Color – был предназначен, в первую очередь, для защиты от копирования. Напомним, как работает признак: на изначально однородном поле при наклоне банкноты появляются муаровые цветные полосы. На копии этот оптически-переменный эффект отсутствует, т. е. или цветные муаровые полосы не появляются, или обнаруживаются сразу, и картина остается без изменений при любых наклонах и поворотах банкноты. Потенциал этого признака оказался гораздо выше первоначально предполагаемого благодаря высокой стойкости к имитациям, технологичности, износостойкости и возможностям его дальнейшей модернизации. Простота его реализации в банкнотах городской серии модернизации 2004 г. и ожидаемые специалистами Гознака в связи с этим скорые имитации заставили модернизировать этот защитный признак в направлении создания более сложной для воспроизведения фальшивомонетчиками муаровой картины, обусловленной применением нелинейной структуры линий и применением комбинации бескрасочного тиснения и красочной металлографской печати. Так появилась следующая генерация оптически-переменного признака MVC+. Этот защитный элемент имеет две согласованные между собой области. В нижней области рисунок муара виден под любым углом, а в верхней области, как и в случае MVC, он появляется только под определенным углом. Очень важно знать, что при наклоне банкноты рисунок муара верхней и нижней частей должен образовать одну неразрывную картину без смещения муаровых линий на границе этих двух областей. Кроме того, этот защитный признак усилен кассовым уровнем защиты. При рассматривании элемента MVC+ под воздействием УФ-излучения можно наблюдать точно такой же муарообразующий эффект, как и при дневном свете. Защитный элемент MVC+ применен в банкнотах Банка России номиналом 1000 и 5000 рублей модернизации 2010 года.

    Параллельно с MVC+ велись разработки нового защитного элемента, обладающего большим визуальным эффектом. И к 2010 году был создан новый защитный признак HMC (Hidden Multi Color), который стал еще более эффективным защитным элементом в этой серии признаков. Благодаря изменению геометрических параметров офсетных и металлографских линий при наклоне банкноты изначально однородное поле разбивается на отдельные фрагменты, окрашенные в разные цвета. В качестве цветных фрагментов используются цифры, текстовые символы, геометрические фигуры, любые произвольные области. Обычно применяется не более 2–3 цветов. Важной особенностью этого защитного признака является возможность дополнительной проверки его подлинности. Если запомнить цвета, видимые при наклоне банкноты, а потом развернуть банкноту в ее плоскости на 180 градусов, то можно увидеть совершенно другие цвета фрагментов. Этот эффект получен благодаря специальной форме линий и использованию уникального оборудования для изготовления металлографских форм. Как и у элемента MVC+, у защитного элемента HMC существует дополнительный кассовый уровень проверки подлинности: под воздействием УФ-излучения можно увидеть точно такие же оптически-переменные эффекты, как и при дневном свете. Защитный элемент HMC был внедрен в защитный комплекс банкноты Банка России номиналом 500 рублей модификации 2010 года.

    Для получения защитных элементов серии MVC – HMC используются металлографские линии с достаточно большой глубиной рельефа. В условиях очень высокого давления при металлографской печати бумага деформируется, принимая форму профиля металлографских линий. Образующийся при этом рельеф возникает и на лицевой, и на оборотной стороне печатного листа. Если рельеф лицевой стороны «работает» в защитных признаках серии MVC – HMC, то оборотный рельеф до недавнего времени не использовался. Специалисты Гознака предложили интересное решение – создание оптически-переменных элементов и на лицевой, и на оборотной стороне банкноты при металлографской печати только с лицевой стороны. Такой элемент был разработан и реализован на рекламной банкноте «195 лет Гознака». Подробное описание этого элемента, получившего название CHMC (Сombined HMC) приведено в журнале «Водяной знак» №3 за 2013 г. Кроме получения оптически-переменных признаков на двух сторонах банкноты за счет использования важной технологической особенности офсетной печатной машины – обеспечения точной приводки печати лицевой и оборотной сторон, – получен элемент для контроля совмещения лицевой и оборотной сторон. Таким образом, CHMC – это «три в одном», т. е. оптические признаки с обеих сторон банкноты и элемент для контроля совмещения лицевой и оборотной сторон. Важной особенностью этого элемента является то, что на лицевой и оборотной сторонах банкноты можно получать независимо как MVC, так и HMC или их комбинации. Так, на рекламной банкноте «Русский Авангард» на лицевой стороне применен элемент HMC, а на оборотной – комбинация MVC и HMC.

    Для получения наилучшего визуального эффекта при создании признаков серии MVC – HMC, особенно HMC, необходимо использовать при печати офсетных линий яркие контрастные цвета. Идеальный случай – применять цвета CMY. Однако часто при модернизации банкнот заказчик не разрешает менять цвета или использовать такие яркие цвета для офсетной печати. Поэтому приходится идти на компромисс между дизайном и визуальным эффектом. Особенно это актуально для элемента HMC. Именно для таких «сложных» в цветовом отношении банкнот были разработаны двух- и даже однокрасочные оптически-переменные элементы HMC. При этом однокрасочный элемент формально является двухкрасочным, поскольку в качестве второй краски используется пробел, т. е. цвет бумаги. Поэтому при наклоне банкноты цвет не меняется, появляется позитивное или негативное изображение.

    Кроме того, любой из элементов серии MVC – HMC может быть дополнен скрытым или латентным изображением.

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

    Развитие оптически-переменных защитных элементов серии MVC – HMC продолжается. Есть новые идеи. И вполне возможно, что в новой рекламной банкноте или каком-либо тиражном изделии в скором времени появится новая реализация защитного признака, основанного на комбинации офсетной и металлографской печати.

    Концепция 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!



Просмотров