Введение в MVC онлайн урок

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

MVC - не только архитектура программного обеспечения, но и концепция разработки. Я не говорю, что данная статья вам расскажет все секреты MVC, но первоначальное понимание получить точно можно. А дальше http://pogugli.com/?74600

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

1 www.ourstore.com/books/list/fantasy

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

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

Контроллер

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

1
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 - это наша модель, и часть кода:

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

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

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

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

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

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

Модель

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

1
class Book extends AppModel {

}

?>

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

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

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

Вид

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

1














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

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

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

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

MVC (Mодель-Представление-Контроллер) - это широко используемая техника разработки (паттерн).

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

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

Модели, Представления, Контроллеры - это специальные необходимые части веб-приложения.

Ключевые принципы MVC:

Модели - ответственны за данные приложения и доступ к базе данных;

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

Представления (другими словами, HTML шаблоны) - просто выводят данные, полученные от контроллера.

Прямой связи между представлениями и моделями не существует.

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

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

Давайте, для примера, взглянем на коммерческий веб-сайт:

Как правило, он состоит, как минимум, из нескольких основных модулей:
- Модуль Products (Товары), который отвечает за отображение товаров, поиск и отображение;
- Модуль Cart (Корзина), который отвечает за оформление и обработку заказов;
- Модуль Users (Пользователи) – отвечает за регистрацию пользователей и управление аккаунтами.

В терминах MVC это приложение имеет следующую структуру:

Класс ProductsController с методами (функциями) index (показать список товаров),
show (показывает один товар), search (искать по товарам). Эти методы называются actions (экшенами).
Этот контроллер взаимодействует с классом Product (моделью), который будет содержать методы для
доступа и управления данными продукта, например getProductsList, search, getProductById,
save, delete и т.д.

ProductsController содержит также методы для админки. Например, admin_edit – для
редактирования товара или admin_view- для просмотра товара в админке.

Cтруктура модулей Cart и Users подобна структуре модуля Products.

Использование такой типовой структуры позволяет нам разделять код различных
логических частей или “модулей” нашего приложения для того, чтобы увеличить
продуктивность, а также избежать ошибок.
Мы можем быть уверены, если это модель Products, то она не содержит в себе код для управления пользователями и наоборот.
Кроме того, таким образом, мы разделяем PHP, HTML, JS и SQL коды.

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

Давайте рассмотрим, как обрабатываются запросы в MVC.

Для MVC приложения требуется, чтобы URL был построен по определенной форме.

Касательно примера коммерческого сайта, который мы упомянули выше, если мы хотим
попасть на страницу списка продуктов, нам необходимо перейти по следующему URL:
http://your-site.com/products

В данном случае, products - это имя контроллера, а название action – это index, по
умолчанию. Если мы хотим просмотреть определенный продукт, это будет
http://your-site.com/products/view/11.

Полагаем, вы уже видели подобные URL.
Такие URL называются User Friendly (т.е. удобный для пользователя URL), или ЧПУ (человеко понятный урл).

Поэтому здесь product – это название контроллера, а название представления и экшена - это index.
В URL, 11 - это параметр для action. В данном случае это будет id товара.

Собственно, контроллер - это часть приложения, которая ответственна за определенные
участки. К примеру, Users, Products, Pages – будут разными контроллерами. Все операции,
которые могут быть произведены в приложении, реализуются в контроллерах как public методы.

К примеру, Users контроллер будет содержать методы register, login, logout и т.д.
Все данные, которые отображаются пользователю, передаются из контроллера во views, т.е. в
HTML шаблоны. Как правило, каждый метод контроллера имеет соответствующее представление.

Рассмотрим, как обрабатываются запросы на MVC веб-сайте.

Это довольно просто.

1. С помощью специального файла.htaccess все запросы, которые не являются
файловыми запросами, перенаправляются к файлу index.php.

2. Следующий шаг - это вызов диспетчера. Диспетчер парсит URL для того, чтобы получить
контроллер и название action. Другие параметры также получены от запроса. Это
может быть, к примеру, код языка.

3. Когда подходящий контроллер и названия метода контроллеров определены,
выполняется вызов метода контроллера.

4. Затем метод контроллера вызывает методы моделей для получения данных.

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

6. Наконец, пользователь получает html страницу.

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

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

И так начнем, как я уже писал в предыдущей статье, паттерн MVC подразумевает одну точку входа – index.php, через это скрипт будут проходить все запросы, через него будет работать вся логика проекта. Для того чтобы реализовать такой подход необходимо настроить сервер, подразумевается, что сайт работает на сервере apache, поэтому нам достаточно создать файл.htaccess, в котором мы укажем правила маршрутизации URL. Помимо определения точки входа, маршрутизация позволяет создавать ЧПУ(человеко-понятные урлы). То есть после правильной настройки, адреса страниц буду выглядеть вот так site.ru/article/new.
Для начала, давайте составим.htaccess, который перенаправит обработку всех страниц на скрипт index.php. Код выглядит вот так:

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?route=$1

Файл.htaccess должен лежать в корневой папке сайта, тут же необходимо создать скрипт index.php, который является точкой входа. Давайте запишем в index.php одну строку, для проверки работы перенаправления:

Echo "test";

Теперь можно проверять работу перенаправления, введите любой адрес и посмотрите, что получиться: test-mvc.web/sdf/sdf/ или test-mvc.web/sdf/sdf/2342/не важно, на экране в любом случае, должно появиться «Test». Если Вы увидели эту надпись, значит, у нас все получилось.
Продолжим, давайте для удобства создадим в корне сайта файл config.php, в котором будем задавать различные константы, облегчающие своим существование настройку сайта. Это могут быть различные пути к скриптам, подступы к базе данных и так далее. Сейчас в конфиге давайте зададим следующее:

// Задаем константы: define ("DS", DIRECTORY_SEPARATOR); // разделитель для путей к файлам $sitePath = realpath(dirname(__FILE__) . DS); define ("SITE_PATH", $sitePath); // путь к корневой папке сайта // для подключения к бд define("DB_USER", "root"); define("DB_PASS", ""); define("DB_HOST", "localhost"); define("DB_NAME", "blog_mvc");

Для того, чтобы константы и другие данные конфига мы могли использовать во всем проекте, в файле index.php необходимо подключить скрипт config.php.
Помимо подключения файла с настройками, в index.php нужно создать подключение к базе данных, подключить скрипт с ядром сайта и запустить роутер, в котором будет происходить маршрутизация.
Теперь по порядку, создание соединения с базой данных будет находиться в index.php для того, чтобы соединение открывалось только один раз. Единожды открыв соединение, мы сможем использовать его во всех контроллерах и моделях, но об этом чуть позже. Сейчас просто создадим соединение с базой. Для работы с бд я решил использовать PDO. Подробнее почитать про PDO можно .
Ядро сайта расположим в папке core и назовем скрипт core.php, тут мы напишем функцию, которая будет сама подключать, необходимы для работы классы. Такая функция очень облегчит и упростит нам работу с контролерами, моделями и тд. Поскольку, забегая вперед скажу, что каждый контролер и каждая модель будут представлять собой отдельный класс.
Помимо авто подключения классов, добавим в ядро создания хранилища (реестра), в котором будем хранить все необходимые объекты и переменные, которые могут пригодиться в любом месте проекта.
Роутер тоже подключим в индексном файле, он будет анализировать URL и подключать необходимый контроллер и экшен. Что такое контролер я писал в предыдущей статье, а информацию про экшен я пропустил умышленно, не став нагружать лишней информацией. Так что же такое экшен?
Контролер это класс, в котором заключены различные методы, при MVC подходе каждый метод будет являться экшеном. То есть экшен(action) – это метод класса, который будет обрабатывать данные и передавать их в представление (в шаблон). Может быть, пока не совсем понятно, но после примера все станет на свои места.
На данном этапе теории достаточно, давайте перейдем к практике. Приведу код файлов, работу которых, я описывал выше.
Код скрипта index.php:

// включим отображение всех ошибок error_reporting (E_ALL); // подключаем конфиг include ("/config.php"); // Соединяемся с БД $dbObject = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS); // подключаем ядро сайта include (SITE_PATH . DS . "core" . DS . "core.php"); // Загружаем router $router = new Router($registry); // записываем данные в реестр $registry->set ("router", $router); // задаем путь до папки контроллеров. $router->setPath (SITE_PATH . "controllers"); // запускаем маршрутизатор $router->start();

Скрипт core.php:

// Загрузка классов "на лету" function __autoload($className) { $filename = strtolower($className) . ".php"; // определяем класс и находим для него путь $expArr = explode("_", $className); if(empty($expArr) OR $expArr == "Base"){ $folder = "classes"; }else{ switch(strtolower($expArr)){ case "controller": $folder = "controllers"; break; case "model": $folder = "models"; break; default: $folder = "classes"; break; } } // путь до класса $file = SITE_PATH . $folder . DS . $filename; // проверяем наличие файла if (file_exists($file) == false) { return false; } // подключаем файл с классом include ($file); } // запускаем реестр (хранилище) $registry = new Registry;

Класс хранилища Registry.php, будет находиться в папке /classes/

// Класс хранилища Class Registry { private $vars = array(); // запись данных function set($key, $var) { if (isset($this->vars[$key]) == true) { throw new Exception("Unable to set var `" . $key . "`. Already set."); } $this->vars[$key] = $var; return true; } // получение данных function get($key) { if (isset($this->vars[$key]) == false) { return null; } return $this->vars[$key]; } // удаление данных function remove($var) { unset($this->vars[$key]); } }

Код файла router.php, который находиться в папке /classes/

// класс роутера Class Router { private $registry; private $path; private $args = array(); // получаем хранилище function __construct($registry) { $this->registry = $registry; } // задаем путь до папки с контроллерами function setPath($path) { $path = trim($path, "/\\"); $path .= DS; // если путь не существует, сигнализируем об этом if (is_dir($path) == false) { throw new Exception ("Invalid controller path: `" . $path . "`"); } $this->path = $path; } // определение контроллера и экшена из урла private function getController(&$file, &$controller, &$action, &$args) { $route = (empty($_GET["route"])) ? "" : $_GET["route"]; unset($_GET["route"]); if (empty($route)) { $route = "index"; } // Получаем части урла $route = trim($route, "/\\"); $parts = explode("/", $route); // Находим контроллер $cmd_path = $this->path; foreach ($parts as $part) { $fullpath = $cmd_path . $part; // Проверка существования папки if (is_dir($fullpath)) { $cmd_path .= $part . DS; array_shift($parts); continue; } // Находим файл if (is_file($fullpath . ".php")) { $controller = $part; array_shift($parts); break; } } // если урле не указан контролер, то испольлзуем поумолчанию index if (empty($controller)) { $controller = "index"; } // Получаем экшен $action = array_shift($parts); if (empty($action)) { $action = "index"; } $file = $cmd_path . $controller . ".php"; $args = $parts; } function start() { // Анализируем путь $this->getController($file, $controller, $action, $args); // Проверка существования файла, иначе 404 if (is_readable($file) == false) { die ("404 Not Found"); } // Подключаем файл include ($file); // Создаём экземпляр контроллера $class = "Controller_" . $controller; $controller = new $class($this->registry); // Если экшен не существует - 404 if (is_callable(array($controller, $action)) == false) { die ("404 Not Found"); } // Выполняем экшен $controller->$action(); } }

Теперь необходимо создать папки для хранения контроллеров, шаблонов и моделей – в корне создадим три папки controllers, views и models. И создадим несколько тестовых файлов /controllers/index.php, /views/index/index.php и /models/model_users.php, а теперь заполним файлы:
Для контроллера:

// контролер Class Controller_Index Extends Controller_Base { // шаблон public $layouts = "first_layouts"; // экшен function index() { $model = new Model_Users(); $userInfo = $model->getUser(); $this->template->vars("userInfo", $userInfo); $this->template->view("index"); } }

Для отображения(/views/index/index.php)

Test view
id:
name:

И модель:

// модель Class Model_Users{ public function getUser(){ return array("id"=>1, "name"=>"test_name"); } }

Как вы могли заметить, класс контролера наследуется от родительского класса Controller_Base. Это сделано, для того, чтобы упростить класс контролера. Поскольку нам еще необходимо подключать класс для работы с шаблонами, его подключение вынесено в Controller_Base.
Приведу его код, он расположен в папке /classes/ и называется controller_base.php:

// абстрактый класс контроллера Abstract Class Controller_Base { protected $registry; protected $template; protected $layouts; // шаблон public $vars = array(); // в конструкторе подключаем шаблоны function __construct($registry) { $this->registry = $registry; // шаблоны $this->template = new Template($this->layouts, get_class($this)); } abstract function index(); }

Теперь осталось только разобраться с шаблонами. В абстрактном классе Controller_Base мы вызываем класс Template и передаем ему имя шаблона и имя контроллера.
Код класса Template, который лежит тут /classes/ и называется template.php

// класс для подключения шаблонов и передачи данных в отображение Class Template { private $template; private $controller; private $layouts; private $vars = array(); function __construct($layouts, $controllerName) { $this->layouts = $layouts; $arr = explode("_", $controllerName); $this->controller = strtolower($arr); } // установка переменных, для отображения function vars($varname, $value) { if (isset($this->vars[$varname]) == true) { trigger_error ("Unable to set var `" . $varname . "`. Already set, and overwrite not allowed.", E_USER_NOTICE); return false; } $this->vars[$varname] = $value; return true; } // отображение function view($name) { $pathLayout = SITE_PATH . "views" . DS . "layouts" . DS . $this->layouts . ".php"; $contentPage = SITE_PATH . "views" . DS . $this->controller . DS . $name . ".php"; if (file_exists($pathLayout) == false) { trigger_error ("Layout `" . $this->layouts . "` does not exist.", E_USER_NOTICE); return false; } if (file_exists($contentPage) == false) { trigger_error ("Template `" . $name . "` does not exist.", E_USER_NOTICE); return false; } foreach ($this->vars as $key => $value) { $$key = $value; } include ($pathLayout); } }

Если вы внимательно прочитали код, то наверняка поняли, что для отображения на страницах у нас используется шаблон first_layouts и вьюха(отображение) index.php – ее код я приводил чуть выше. Все что нам осталось, это создать файл шаблона first_layouts. Расположим его в папке /views/layouts/first_layouts.php
Шаблон будет содержать вот такой код:

header

footer

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

В данной статье мы разберемся с понятием MVC, и как, на примере, можно применить это в PHP.

Понятие MVC

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

Шаблон MVC хорошо применять при создании сложных проектов, где необходимо отделить работу php программиста (или разделить группу программистов на отделы), дизайнера, верстальщика, и т.д.

Шаблон MVC разделяет представление, данные, и обработку действий пользователя на три отдельных компонента:

MVC Модель (Model). Модель предоставляет данные (обычно для View), а также реагирует на запросы (обычно от контроллера), изменяя своё состояние.

MVC Представление (View). Отвечает за отображение информации (пользовательский интерфейс).

MVC Поведение (Controller). Интерпретирует данные, введённые пользователем, и информирует модель и представление о необходимости соответствующей реакции.

Для наглядности схемы действия шаблона MVC, ниже предоставлена иллюстрация.

Такие компоненты как представление и поведение зависят от модели, но никак не влияют на нее. Модель может иметь несколько представлений. Может быть, концепция MVCсложная для понимания, но если ее осмыслить, она становиться незаменимой при разработке приложений на PHP.

MVC в PHP

Особенностью при использовании MVC в PHP, является то, что существует одна точка входа в php приложение, которая, например, достигается следующим образом. Создается index.php через который будут обрабатываться все запросы, для этого создаем в папке с индексом файл.htaccess и помещаем в него такой код:

RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?route=$1

В предоставленном коде, первой строкой, проверяется существование запрашиваемого файла, и если его нет, то идет перенаправление на index.php, иначе даже запросы картинок сайта будут перенаправляться на индекс. Последняя строка кода преобразовывает запросы вида index.php?route=chat/index у вид index.php/chat/index. Если у вас нет возможности использовать ModRewrite в своем приложении, то вам придется делать переадресацию вручную.

PHP Модель

Данные о PHP модели содержаться в ее атрибутах и могут быть изменены только через специальные функции. Модель может содержать в себе несколько представлений. Как правило, phpмодель это класс работающий с БД, конкретнее: запись, чтение, удаление. Естественно чтение информации с БД может быть реализовано несколькими представлениями (функциями). Как пример модель статей на сайте: можно получить конкретную статью из БД, список последних, популярных, какой-то категории… это все представления модели. Для наглядности ниже предоставлен пример php модели.

PHP контролер (Поведение)

PHP контролеры получают запросы пользователей, которые мы направляли через index.php, и в соответствии с ними, корректируют работу модели. Правильнее сказать контролируют работу php приложения.

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

Представление отслеживает изменение в модели и создает или меняет интерфейс php приложения.

List of Datas

firstname ?>

lastname?>

Как работает данный PHP MVC шаблон?

При обращении пользователем по нужному url выбирается соответственный контролер, который обращается к представлению и модели, и выводится информация. Другими словами контролер в mvc есть связующим звеном модели и представления.

Преимущества MVC шаблона при создании PHP приложения

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

MVC пример

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

Еще одна схема работы MVC шаблона на PHP, она более чем доступна для понимания.

Добрый день, уважаемые коллеги. В этой статье я бы хотел рассказать о своем аналитическом понимании различий паттернов MVC, MVP и MVVM. Написать эту статью меня побудило желание разобраться в современных подходах при разработке крупного программного обеспечения и соответствующих архитектурных особенностях. На текущем этапе своей карьерной лестницы я не являюсь непосредственным разработчиком, поэтому статья может содержать ошибки, неточности и недопонимание. Заинтригованы, как аналитики видят, что делают программисты и архитекторы? Тогда добро пожаловать под кат.

Ссылки
Первое, с чего я бы хотел начать - это ссылки на внешние материалы, которыми я руководствовался в процессе написания этой статьи:
Введение
Во времена, когда солнце светило ярче, а трава была зеленее, на тот момент команда студентов, как автор этой статьи, разрабатывали программное обеспечение, писав сотни строк кода непосредственно в интерфейсе продукта. Иногда использовались сервисы и менеджеры для работы с данными и тогда решение получалось с использованием паттерна Document-View. Поддержка такого кода требовала колоссальных затрат, т. к. нового разработчика надо обучить (рассказать), какой код за что в продукте отвечает, и ни о каком модульном тестировании и речи не было. Команда разработки - это 4 человека, которые сидят в одной комнате.
Прошло время, менялась работа. Разрабатываемые приложения становились больше и сложнее, из одной сплоченной команды разработчиков стало много разных команд разработчиков, архитекторов, юзабилистов, дизайнеров и PMов. Теперь каждый ответственен за свою область: GUI, бизнес-логика, компоненты. Появился отдел анализа, тестирования, архитектуры. Стоимость разработки ПО возросла в сотни и даже тысячи раз. Такой подход к разработке требует наличие стойкой архитектуры, которая бы синхронизировала разные функциональные области продукта между собой.
Паттерны
Учитывая цель уменьшения трудозатрат на разработку сложного программного обеспечения, предположим, что необходимо использовать готовые унифицированные решения. Ведь шаблонность действий облегчает коммуникацию между разработчиками, позволяет ссылаться на известные конструкции, снижает количество ошибок.
По словам Википедии , паттерн (англ. design pattern) - повторимая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста.

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

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

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

Модель обладает следующими признаками:

  • Модель - это бизнес-логика приложения;
  • Модель обладает знаниями о себе самой и не знает о контроллерах и представлениях;
  • Для некоторых проектов модель - это просто слой данных (DAO, база данных, XML-файл);
  • Для других проектов модель - это менеджер базы данных, набор объектов или просто логика приложения;
Представление (View)
В обязанности Представления входит отображение данных полученных от Модели. Однако, представление не может напрямую влиять на модель. Можно говорить, что представление обладает доступом «только на чтение» к данным.

Представление обладает следующими признаками:

  • В представлении реализуется отображение данных, которые получаются от модели любым способом;
  • В некоторых случаях, представление может иметь код, который реализует некоторую бизнес-логику.
Примеры представления: HTML-страница, WPF форма, Windows Form.
Различия MVP & MVVM & MVP
Наиболее распространенные виды MVC-паттерна, это:
  • Model-View-Controller
  • Model-View-Presenter
  • Model-View-View Model

Рассмотрим и сравним каждый из них.

Model-View-Presenter

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

Признаки презентера:

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

Реализация:
Каждое представление должно реализовывать соответствующий интерфейс. Интерфейс представления определяет набор функций и событий, необходимых для взаимодействия с пользователем (например, IView .ShowErrorMessage(string msg)). Презентер должен иметь ссылку на реализацию соответствующего интерфейса, которую обычно передают в конструкторе.
Логика представления должна иметь ссылку на экземпляр презентера. Все события представления передаются для обработки в презентер и практически никогда не обрабатываются логикой представления (в т.ч. создания других представлений).

Пример использования: Windows Forms.

Model-View-View Model


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

Признаки View-модели:

  • Двухсторонняя коммуникация с представлением;
  • View-модель - это абстракция представления. Обычно означает, что свойства представления совпадают со свойствами View-модели / модели
  • View-модель не имеет ссылки на интерфейс представления (IView). Изменение состояния View-модели автоматически изменяет представление и наоборот, поскольку используется механизм связывания данных (Bindings)
  • Один экземпляр View-модели связан с одним отображением.

Реализация:
При использовании этого паттерна, представление не реализует соответствующий интерфейс (IView).
Представление должно иметь ссылку на источник данных (DataContex), которым в данном случае является View-модель. Элементы представления связаны (Bind) с соответствующими свойствами и событиями View-модели.
В свою очередь, View-модель реализует специальный интерфейс, который используется для автоматического обновления элементов представления. Примером такого интерфейса в WPF может быть INotifyPropertyChanged.

Пример использования: WPF

Model-View-Controller

Основная идея этого паттерна в том, что и контроллер и представление зависят от модели, но модель никак не зависит от этих двух компонент.

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

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

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

Пример использования: MVC ASP.NET

Резюме
Реализация MVVM и MVP-паттернов, на первый взгляд, выглядит достаточно простой схожей. Однако, для MVVM связывание представления с View-моделью осуществляется автоматически, а для MVP - необходимо программировать
MVC, по-видимому, имеет больше возможностей по управлению представлением.
Общие правила выбора паттерна
MVVM
  • Используется в ситуации, когда возможно связывание данных без необходимости ввода специальных интерфейсов представления (т.е. отсутствует необходимость реализовывать IView);
  • Частым примером является технология WPF.
MVP
  • Используется в ситуации, когда невозможно связывание данных (нельзя использовать Binding);
  • Частым примером может быть использование Windows Forms.
MVC
  • Используется в ситуации, когда связь между представление и другими частями приложения невозможна (и Вы не можете использовать MVVM или MVP);
  • Частым примером использования может служить ASP.NET MVC.
Заключение
В заключении, автор этой статьи хотел бы отметить, что строго придерживаться только одному паттерну - не всегда лучший выбор. Например, представьте, что Вы хотели бы использовать MVVM для разработки приложений с использованием Windows Forms через свойство контролов Bindings. Ваша цель - это отделить представление от бизнес логики и логики, которая их связывает. Приложение должно быть легко тестируемым и поддерживаемым, а для аналитиков - понятным (ведь на вопрос «в чем измеряется работа жесткого диска» существует единственный правильный ответ - в Джоулях (абстрактный пример Модели -> Представления)).

Большое спасибо за уделенное время, приятного чтения!




Top