Mvc простыми словами. Введение в MVC онлайн урок

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

Реклама Коротко о паттерне MVC

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

Модель

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

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

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

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

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

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

Контроллер

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

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

Реклама Спецификации игры Сапер

Достаточно теории. Теперь перейдем к практике. Для демонстрации паттерна MVC мы напишем несложную игру: Сапер. Правила игры достаточно простые:

  • Игровое поле представляет собой прямоугольную область, состоящую из клеток. В некоторых клетках случайным образом расположены мины, но игрок о них не знает;
  • Игрок может щелкнуть по любой клетке игрового поля левой или правой кнопками мыши;
  • Щелчок левой кнопки мыши приводит к тому, что клетка будет открыта. При этом, если в клетке находится мина, то игра завершается проигрышем. Если в соседних клетках, рядом с открытой, расположены мины, то на открытой клетке отобразится счетчик с числом мин вокруг. Если же мин вокруг открытой клетки нет, то каждая соседняя клетка будет открыта по тому же принципу. То есть клетки будут открываться до тех пор, пока либо не упрутся в границу игрового поля, либо не дойдут до уже открытых клеток, либо рядом с ними не окажется мина;
  • Щелчок правой кнопки мыши позволяет делать пометки на клетках. Щелчок на закрытой клетке помечает ее флажком, который блокирует ее состояние и предотвращает случайное открытие. Щелчок на клетке, помеченной флажком, меняет ее пометку на вопросительный знак. В этом случае клетка уже не блокируется и может быть открыта левой кнопкой мыши. Щелчок на клетке с вопросительным знаком возвращает ей закрытое состояние без пометок;
  • Победа определяется состоянием игры, при котором на игровом поле открыты все клетки, за исключением заминированных.
  • Пример того, что у нас получится приведен ниже:

    UML-диаграммы игры Сапер

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

    Диаграмма Состояний игровой клетки

    Любая клетка на игровом поле может находиться в одном из 4 состояний:

  • Клетка закрыта;
  • Клетка открыта;
  • Клетка помечена флажком;
  • Клетка помечена вопросительным знаком.
  • Здесь мы определили лишь состояния, значимые для Представления. Поскольку мины в процессе игры не отображаются, то и в базовом наборе соответствующего состояния не предусмотрено. Определим возможные переходы из одного состояния клетки в другое с помощью UML Диаграммы Состояний:

    Диаграмма Классов игры Сапер

    Поскольку мы решили создавать наше приложение на основе паттерна MVC, то у нас будет три основных класса: MinesweeperModel , MinesweeperView и MinesweeperController , а также вспомогательный класс MinesweeperCell для хранения состояния клетки. Рассмотрим их диаграмму классов:

    Организация архитектуры довольно проста. Здесь мы просто распределили задачи по каждому классу в соответствии с принципами паттерна MVC:

  • В самом низу иерархии расположен класс игровой клетки MinesweeperCell . Он хранит позицию клетки, определяемую рядом row и столбцом column игрового поля; одно из состояний state , которые мы описали в предыдущем подразделе; информацию о наличии мины в клетке (mined) и счетчик мин в соседних клетках counter . Кроме того, у него есть два метода: nextMark() для циклического перехода по состояниям, связанным с пометками, появляющимися в результате щелчка правой кнопкой мыши, а также open() , который обрабатывает событие, связанное с щелчком левой кнопкой мыши;
  • Чуть выше расположен класс Модели MinesweeperModel . Он является контейнером для игровых клеток MinesweeperCell . Его первый метод startGame() подготавливает игровое поле для начала игры. Метод isWin() делает проверку игрового поля на состояние выигрыша и возвращает истину, если игрок победил, иначе возвращается ложь. Для проверки проигрыша предназначен аналогичный метод isGameOver() . Методы openCell() и nextCellMark() всего лишь делегируют действия соответствующим клеткам на игровом поле, а метод getCell() возвращает запрашиваемую игровую клетку;
  • Класс Представления MinesweeperView включает следующие методы: syncWithModel() - обеспечивает перерисовку Представления для отображения актуального состояния игрового поля в Модели; getGameSettings() - возвращает настройки игры, заданные пользователем; createBoard() - создает игровое поле на основе данных Модели; showWinMessage() и showGameOverMessage() соответственно отображают сообщения о победе и проигрыше;
  • И наконец класс Контроллера MinesweeperController . В нем определено всего три метода на каждое возможное действие игрока: startNewGame() отвечает за нажатие на кнопке "Новая игра" в интерфейсе Представления; onLeftClick() и onRightClick() обрабатывают щелчки по игровым клеткам левой и правой кнопками мыши соответственно.
  • Реализация игры Сапер на Python

    Пришло время заняться реализацией нашего проекта. В качестве языка разработки выберем Python. Тогда класс Представления будем писать на основе модуля tkinter .

    Но начнем с Модели.

    Модель MinsweeperModel

    Реализация модели на языке Python выглядит следующим образом:

    MIN_ROW_COUNT = 5 MAX_ROW_COUNT = 30 MIN_COLUMN_COUNT = 5 MAX_COLUMN_COUNT = 30 MIN_MINE_COUNT = 1 MAX_MINE_COUNT = 800 class MinesweeperCell: # Возможные состояния игровой клетки: # closed - закрыта # opened - открыта # flagged - помечена флажком # questioned - помечена вопросительным знаком def __init__(self, row, column): self.row = row self.column = column self.state = "closed" self.mined = False self.counter = 0 markSequence = [ "closed", "flagged", "questioned" ] def nextMark(self): if self.state in self.markSequence: stateIndex = self.markSequence.index(self.state) self.state = self.markSequence[ (stateIndex + 1) % len(self.markSequence) ] def open(self): if self.state != "flagged": self.state = "opened" class MinesweeperModel: def __init__(self): self.startGame() def startGame(self, rowCount = 15, columnCount = 15, mineCount = 15): if rowCount in range(MIN_ROW_COUNT, MAX_ROW_COUNT + 1): self.rowCount = rowCount if columnCount in range(MIN_COLUMN_COUNT, MAX_COLUMN_COUNT + 1): self.columnCount = columnCount if mineCount < self.rowCount * self.columnCount: if mineCount in range(MIN_MINE_COUNT, MAX_MINE_COUNT + 1): self.mineCount = mineCount else: self.mineCount = self.rowCount * self.columnCount - 1 self.firstStep = True self.gameOver = False self.cellsTable = for row in range(self.rowCount): cellsRow = for column in range(self.columnCount): cellsRow.append(MinesweeperCell(row, column)) self.cellsTable.append(cellsRow) def getCell(self, row, column): if row < 0 or column < 0 or self.rowCount $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. Подборка полезных ссылок по сабжу В статье очень часто затрагивается тема веб-фреймворков - это очень обширная тема, потому что даже микрофреймворки состоят из многих компонентов хитро увязанных между собой и потребовалась бы не одна статья, чтобы рассказать об этих компонентах. Тем не менее, я решил привести здесь небольшую подборку ссылок (по которым я ходил при написаниие этой статьи), которые так или иначе касаются темы фреймворков.

    Теги:

    • php
    • framework
    • cmf
    • mvc
    • site
    Добавить метки

    В паттерне "Модель - представление - контроллер " модель представляет данные приложения и связанную с ними бизнес-логику. Модель может быть представлена одним объектом или сложным графом связанных объектов. В приложении для плат­формы Java ЕЕ данные инкапсулируются в объектах предметной области, часто раз­вертываемых в EJB-модуле. Данные передаются в БД и из нее в объектах передачи данных (ОТО), и к ним обращаются с помощью объектов доступа к данным (ОАО).

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

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

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

    Контроллер и представление расположены на веб­-уровне. Представление, вероятнее всего, будет создано из JavaServer Faces (JSF) или JavaServer Pages (JSP) с помощью языка выражений (EL). Контроллер обыч­но представляет собой сервлет, получающий НТТР-запросы от пользователя.

    Часто MVC сочетается с другими паттернами, такими как "Команда" (или "Действие"), "Стратегия", "Компоновщик" и " ".

    Впервые этот паттерн упоминался еще до создания Интернета в современном виде, в статье, опубликованной в декабре 1979 года работавшим тогда в компании Xeror SmallTalk-программистом Трюгве Реенскауг .

    И хотя элементы MVC этого паттерна были описаны более 35 лет назад, они удивительно точно соответствуют современному их использованию в веб-прило­жениях.

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

    Диаграмма паттерна MVC

    Паттерн MVC существует в множестве разных форм. Две наиболее известные обычно называются тип I и тип II .

    Типы паттерна MVC:
    • MVC тип I . Этот тип представляет собой странично-ориентированный подход,при котором представление и контроллер существуют в виде одной сущности, именуемой "представление - контроллер". При этом подходе логика контрол­лера реализуется в представлении, таком кaк JSF. Все выполняемые контрол­лером задания, включая извлечение атрибутов и параметров НТТР-запроса, вызов бизнес-логики и управление НТТР-сеансом, встроены в представление с помощью скриптлетов и библиотек тегов. Тип I сильно связывает формирование представления с последовательностью выполняемых приложением дей­ствий, затрудняя тем самым сопровождение.
    • MVC тип II . Проблемы с сопровождением в типе I преодолены в типе II благо­даря вынесению логики контроллера из представления в сервлет, при этом визуализация данных остается представлению.

    Главное различие между типом I и типом II - в местонахождении логики кон­троллера: в типе I она в представлении, а в типе II - в сервлете.

    Многие фреймворки, такие как Spring MVC , Struts , Grails и Wicket , реализуют свою собственную версию паттерна MVC типа II. Например, Spring MVC включает концепцию сервлета-диспетчера, взаимодействующего с НТТР-запросами и выпол­няющего делегирование контроллеру, а также содержит представление (и преобра­зователь представления) и обработчики.

    Следующий рисунок демонстрирует диаграмму реализации паттерна MVC в Spring.

    Диаграмма реализации паттерна MVC в Spring

    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 была первоначально разработана для персональных компьютеров, она была адаптирована и широко используется веб-разработчиками из-за точного разграничения задач и возможности повторного использования кода. Схема стимулирует развитие модульных систем, что позволяет разработчикам быстро обновлять, добавлять или удалять функционал.

    В этой статье я опишу основные принципы, а также рассмотрю определение схемы построения и простой MVC PHP пример.

    Что такое MVC

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

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

    Модель

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

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

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

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

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

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

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

    «Чтобы правильно применять архитектуру MVC, между «Моделью» и «Представлением» не должно быть никакого взаимодействия: вся логика обрабатывается «Контроллером».

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

    Компоненту «Представление » никогда не передаются данные непосредственно «Контроллером ». Между «Представлением » и «Контроллером » нет прямой связи — они соединяются с помощью «Модели ».

    Контроллер

    Его задача заключается в обработке данных, которые пользователь вводит и обновлении «Модели ». Это единственная часть схемы, для которой необходимо взаимодействие пользователя.

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

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

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

    MVC в PHP

    Напишем на PHP веб-приложение, архитектура которого основана MVC . Давайте начнем с примера каркаса: