Я хотел бы затронуть тему правильной архитектуры приложений на PHP. Статья будет посвящена паттерну проектирования MVC. Написать про MVC меня сподвиг именно тот факт, что понимание этого паттерна является ключевым в становлении PHP-программиста. Так что если вы новичок и хотите начать писать программы правильно, читайте дальше.
Теория
Если коротко, то MVC (model view controller) это такой способ написания программы, когда код отвечающий за вывод данных, пишется в одном месте, а код который эти данные формирует, пишется в другом месте. В итоге получается так, что если вам надо подправить вывод вы сразу знаете в каком месте искать. Сейчас все популярные фреймворки используют такую архитектуру.
Также стоит упомянуть тот факт, что существует два лагеря: один пишет логику в контроллерах, второй в моделях. В тех фреймворках, которые знаю я (yii, laravel) логику пишут в контроллерах, а модели являются просто экземплярами ORM. У yii кстати в мануале написано, что писать логику надо в моделях, а потом они сами в примерах пишут её в контроллерах, довольно забавно.
Что такое MVC? Краткое и простое объяснение
С бизнес-логикой определились, пишем в контроллерах. Также в методах контроллера происходит вызов моделей, которые у нас по сути экземпляры ORM, чтобы с их помощью получить данные из базы над которыми будут производить изменения. Конечный результат отправляется в виды. Виды cодержат HTML-разметку и небольшие вставки PHP-кода для обхода, форматирования и отображения данных.
Ещё можно упомянуть, что есть два вида MVC Page Controller и Front Controller. Page Controller’ом пользуются редко, его подход заключается в использовании нескольких точек входа (запросы к сайту осуществляются к нескольким файлам), и внутри каждой точки входа свой код отображения. Мы будем писать Front Controller с одной точкой входа.
Практика
Начать надо с настройки сервера для переадресации на нашу единую точку входа. Если у нас apache, то в файле .htaccess пишем следующее
RewriteEngine on RewriteCond % !-f RewriteCond % !-d RewriteRule .* index.php [L]
Дальше в папке нашего проекта создаём папку, которую можно назвать App например. В ней будет следующее содержимое.
Наш Service Locator. Файл App.php
public static function bootstrap() < static::$router = new AppRouter(); static::$kernel = new AppKernel(); static::$db = new AppDb(); >public static function loadClass ($className) < $className = str_replace(‘\’, DIRECTORY_SEPARATOR, $className); require_once ROOTPATH.DIRECTORY_SEPARATOR.$className.’.php’; >public function handleException (Throwable $e) < if($e instanceof AppExceptionsInvalidRouteException) < echo static::$kernel->launchAction(‘Error’, ‘error404’, [$e]); >else< echo static::$kernel->launchAction(‘Error’, ‘error500’, [$e]); > > >
Сервис локатор нужен чтобы хранить в нём компоненты нашего приложения. Поскольку у нас простое mvc приложение, то мы не используем паттерн registry (как например в yii сделано). А просто сохраняем компоненты приложения в статические свойства, чтобы обращаться к ним было проще. Ещё App регистрирует автозагрузчик классов и обработчик исключений.
Что такое MVC за 4 минуты
Роутер. Файл Router.php
$route = is_null($route) ? $_SERVER[‘REQUEST_URI’] : $route; $route = explode(‘/’, $route); array_shift($route); $result[0] = array_shift($route); $result[1] = array_shift($route); $result[2] = $route; return $result; > >
В простом mvc приложении роутер содержит всего один метод. Он парсит адрес из $_SERVER[‘REQUEST_URI’]. Я ещё не сказал, что все наши ссылки на страницы сайта должны быть вида www.ourwebsite.com/%controller%/%action%, где %controller% — имя файла контроллера, а %action% — имя метода контроллера, который будет вызван.
Файл Db.php
getPDOSettings(); $this->pdo = new PDO($settings[‘dsn’], $settings[‘user’], $settings[‘pass’], null); > protected function getPDOSettings() < $config = include ROOTPATH.DIRECTORY_SEPARATOR.’Config’.DIRECTORY_SEPARATOR.’Db.php’; $result[‘dsn’] = «:host=;dbname=;charset=»; $result[‘user’] = $config[‘user’]; $result[‘pass’] = $config[‘pass’]; return $result; > public function execute($query, array $params=null) < if(is_null($params))< $stmt = $this->pdo->query($query); return $stmt->fetchAll(); > $stmt = $this->pdo->prepare($query); $stmt->execute($params); return $stmt->fetchAll(); > >
Этот класс юзает файл конфига, который возврашает массив при подключении
Файл Config/Db.php
‘mysql’, ‘host’ => ‘localhost’, ‘dbname’ => ‘gotlib’, ‘charset’ => ‘utf8’, ‘user’ => ‘root’, ‘pass’ => » ];
Наше ядро. Файл Kernel.php
resolve(); echo $this->launchAction($controllerName, $actionName, $params); > public function launchAction($controllerName, $actionName, $params) < $controllerName = empty($controllerName) ? $this->defaultControllerName : ucfirst($controllerName); if(!file_exists(ROOTPATH.DIRECTORY_SEPARATOR.’Controllers’.DIRECTORY_SEPARATOR.$controllerName.’.php’)) < throw new AppExceptionsInvalidRouteException(); >require_once ROOTPATH.DIRECTORY_SEPARATOR.’Controllers’.DIRECTORY_SEPARATOR.$controllerName.’.php’; if(!class_exists(«\Controllers\».ucfirst($controllerName))) < throw new AppExceptionsInvalidRouteException(); >$controllerName = «\Controllers\».ucfirst($controllerName); $controller = new $controllerName; $actionName = empty($actionName) ? $this->defaultActionName : $actionName; if (!method_exists($controller, $actionName)) < throw new AppExceptionsInvalidRouteException(); >return $controller->$actionName($params); > >
Ядро обращается к роутеру, а потом запускает действия контроллера. Ещё ядро может кинуть исключение, если нет нужного контроллера или метода.
Файл Controller.php
Ещё нам нужно создать базовый класс для наших контроллеров, чтобы потом наследоваться от него. Наследовать методы нужно для того, чтобы вы могли рендерить (сформировать вывод) виды. Методы рендеринга поддерживают использование лэйаутов — шаблонов, которые содержат общие для всех видов компоненты, например футер и хэдер.
public function render ($viewName, array $params = []) < $viewFile = ROOTPATH.DIRECTORY_SEPARATOR.’Views’.DIRECTORY_SEPARATOR.$viewName.’.php’; extract($params); ob_start(); require $viewFile; $body = ob_get_clean(); ob_end_clean(); if (defined(NO_LAYOUT))< return $body; >return $this->renderLayout($body); > >
Файл index.php
Не забываем создать индексный файл в корне:
launch();
Создаём контроллеры и виды
Работа с нашим приложением (можно даже сказать минифреймворком) теперь сводится к созданию видов и контроллеров. Пример контроллера следующий (в папке Controllers):
render(‘Home’); > >
Пример вида(в папке Views):
В папке Views/Layout создаём Layout.php:
Обо мне Обо мне Портфолио Блог
Если решите пользоваться кодом приложения, которое описал я, не забудьте создать контроллер Error с методами error404 и error500. Класс для работы с бд, описанный мной, подходит для написания запросов руками, вместо него можно подключить ORM и вас будут настоящие модели.
- Разработка веб-сайтов
- PHP
Источник: habr.com
Общие сведения ASP.NET Core MVC
ASP.NET MVC является многофункциональной платформой для создания веб-приложений и API-интерфейсов с помощью структуры проектирования Model-View-Controller.
Шаблон MVC
Структура архитектуры MVC разделяет приложение на три основных группы компонентов: модели, представлении и контроллеры. Это позволяет реализовать принципы разделения задач. Согласно этой структуре запросы пользователей направляются в контроллер, который отвечает за работу с моделью для выполнения действий пользователей и (или) получение результатов запросов. Контроллер выбирает представление для отображения пользователю со всеми необходимыми данными модели.
На следующей схеме показаны три основных компонента и существующие между ними связи.
Такое распределение обязанностей позволяет масштабировать приложение в контексте сложности, так как проще писать код, выполнять отладку и тестирование компонента (модели, представления или контроллера) с одним заданием. Гораздо труднее обновлять, тестировать и отлаживать код, зависимости которого находятся в двух или трех этих областях. Например, логика пользовательского интерфейса, как правило, подвергается изменениям чаще, чем бизнес-логика. Если код представления и бизнес-логика объединены в один объект, содержащий бизнес-логику, объект необходимо изменять при каждом обновлении пользовательского интерфейса. Это часто приводит к возникновению ошибок и необходимости повторно тестировать бизнес-логику после каждого незначительного изменения пользовательского интерфейса.
Представление и контроллер зависят от модели. Однако сама модель не зависит ни от контроллера, ни от представления. Это является одним из ключевых преимуществ разделения. Такое разделение позволяет создавать и тестировать модели независимо от их визуального представления.
Функции модели
Модель в приложении MVC представляет состояние приложения и бизнес-логику или операций, которые должны в нем выполняться. Бизнес-логика должна быть включена в состав модели вместе с логикой реализации для сохранения состояния приложения. Как правило, строго типизированные представления используют типы ViewModel, предназначенные для хранения данных, отображаемых в этом представлении. Контроллер создает и заполняет эти экземпляры ViewModel из модели.
Функции представления
Представления отвечают за представление содержимого через пользовательский интерфейс. Они используют обработчик представленийRazor для внедрения .NET кода в разметку HTML. Представления должны иметь минимальную логику, которая должна быть связана с представлением содержимого. Если есть необходимость выполнять большую часть логики в представлении для отображения данных из сложной модели, рекомендуется воспользоваться компонентом представления, ViewModel или шаблоном представления, позволяющими упростить представление.
Функции контроллера
Контроллеры — это компоненты для управления взаимодействием с пользователем, работы с моделью и выбора представления для отображения. В приложении MVC представление служит только для отображения информации. Обработку введенных данных, формирование ответа и взаимодействие с пользователем обеспечивает контроллер. В структуре MVC контроллер является начальной отправной точкой и отвечает за выбор рабочих типов моделей и отображаемых представлений (именно этим объясняется его название — он контролирует, каким образом приложение отвечает на конкретный запрос).
Контроллеры не должны быть чересчур сложными из-за слишком большого количества обязанностей. Чтобы не перегружать логику контроллера, перенесите бизнес-логику из контроллера в модель предметной области.
Если ваш контроллер часто выполняет одни и те же виды действий, переместите эти действия в фильтры.
ASP.NET Core MVC
ASP.NET Core MVC представляет собой упрощенную, эффективно тестируемую платформу с открытым исходным кодом, оптимизированную для использования с ASP.NET Core.
ASP.NET Core MVC предоставляет основанный на шаблонах способ создания динамических веб-сайтов с четким разделением задач. Она обеспечивает полный контроль разметки, поддерживает согласованную с TDD разработку и использует новейшие веб-стандарты.
Маршрутизация
Платформа ASP.NET Core MVC создана на основе маршрутизации ASP.NET Core — мощного компонента сопоставления URL-адресов, который позволяет создавать приложения с понятными и поддерживающими поиск URL-адресами. Вы можете определять шаблоны именования URL-адресов приложения, эффективно работающие для оптимизации для поисковых систем (SEO) и для создания ссылок, независимо от способа организации файлов на веб-сервере. Вы можете определять маршруты с помощью понятного синтаксиса шаблонов маршрутов, который поддерживает ограничения значений маршрутов, значения по умолчанию и необязательные значения.
Маршрутизация на основе соглашений позволяет глобально определять форматы URL-адресов, которые принимает приложение, и как каждый из этих форматов сопоставляется с определенным методом действия на заданном контроллере. При поступлении входящего запроса модуль маршрутизации выполняет синтаксический анализ URL-адреса и соотносит его с одним из определенных форматов URL-адресов, а затем вызывает метод действия связанного контроллера.
routes.MapRoute(name: «Default», template: «//»);
Маршрутизация атрибутов используется для указания сведений о маршрутизации путем добавления атрибутов, определяющих маршруты приложения, к контроллерам и действиям. Это означает, что определения маршрутов помещаются рядом с контроллером и действием, с которым они связаны.
[Route(«api/[controller]»)] public class ProductsController : Controller < [HttpGet(«»)] public IActionResult GetProduct(int id) < . >>
Привязка модели
ASP.NET Core привязка модели MVC преобразует данные запроса клиента (значения форм, данные маршрута, параметры строки запроса, заголовки HTTP), в объекты, которые может обрабатывать контроллер. В результате логике контроллера не требуется определять данные входящего запроса — данные просто доступны в виде параметров для методов действий.
public async Task Login(LoginViewModel model, string returnUrl = null)
Проверка модели
ASP.NET MVC поддерживает возможность проверки, дополняя модель объекта атрибутами проверки заметок к данным. Атрибуты проверки проверяются на стороне клиента до размещения значений на сервере, а также на сервере перед выполнением действия контроллера.
using System.ComponentModel.DataAnnotations; public class LoginViewModel < [Required] [EmailAddress] public string Email < get; set; >[Required] [DataType(DataType.Password)] public string Password < get; set; >[Display(Name = «Remember me?»)] public bool RememberMe < get; set; >>
public async Task Login(LoginViewModel model, string returnUrl = null) < if (ModelState.IsValid) < // work with the model >// At this point, something failed, redisplay form return View(model); >
Платформа обрабатывает проверку данных запроса на клиенте и на сервере. Логика проверки, указанная в типах модели, добавляется в готовые для просмотра представления в виде ненавязчивых заметок и реализуется в браузере с помощью подключаемого модуля jQuery Validation.
Внедрение зависимостей
ASP.NET Core имеет встроенную поддержку внедрения зависимостей (DI). В ASP.NET MVC Core контроллеры могут запрашивать необходимые служб через свои конструкторы, предоставляя им возможность следовать принципу явных зависимостей.
Фильтры
Фильтры помогают разработчикам решать общие задачи, такие как обработка исключений или авторизация. Фильтры активируют пользовательскую логику предварительной и завершающей обработки для методов действий и могут быть настроены для запуска в определенные моменты в конвейерном выполнении определенного запроса. Фильтры могут применяться к контроллерам или действиям в виде атрибутов (или могут выполняться глобально). В состав платформы входит несколько фильтров (например, Authorize ). [Authorize] является атрибутом, который используется для создания фильтров авторизации MVC.
[Authorize] public class AccountController : Controller
Области
Области позволяют секционировать большое ASP.NET Core веб-приложение MVC на небольшие функциональные группы. Область является структурой MVC внутри приложения.
В проекте MVC логические компоненты, такие как модель, контроллер и представление, находятся в разных папках, и для создания связи между этими компонентами MVC использует соглашения об именовании. Крупное приложение может быть целесообразно разделить на отдельные высокоуровневые области функциональности. Например, приложение электронной коммерции с несколькими бизнес-подразделениями, такими как извлечение, выставление счетов и поиск и т. д. Каждый из этих единиц имеет собственные представления логических компонентов, контроллеры и модели.
Веб-API
Помимо того, что ASP.NET Core MV прекрасно подходит для создания веб-сайтов, эта платформа располагает мощной поддержкой для построения веб-API. Создавайте службы, доступные для широкого круга клиентов, включая браузеры и мобильные устройства.
Платформа включает поддержку согласования содержимого HTTP со встроенной поддержкой форматирования данных в формате JSON или XML. Пишите пользовательские модули форматирования для добавления поддержки собственных форматов.
Используйте функции создания ссылок для поддержки гипермедиа. Легко включайте поддержку общего доступа к ресурсам независимо от источника (CORS) для совместного использования веб-API в нескольких веб-приложениях.
Тестирование
Благодаря используемым интерфейсам и внедрению зависимостей платформа хорошо подходит для модульного тестирования. Кроме того, с помощью таких компонентов, как TestHost и поставщик InMemory для Entity Framework, можно быстро и просто выполнять интеграционные тесты. Узнайте больше о тестировании логики контроллеров.
Razor обработчик представлений
ASP.NET Core представления MVC используют обработчик представленийRazor для отрисовки представлений. Razor— это компактный, экспрессивный и гибкий язык разметки шаблона для определения представлений с помощью внедренного кода C#. Razor используется для динамического создания веб-содержимого на сервере. Серверный код можно полностью комбинировать с содержимым и кодом на стороне клиента.
С помощью обработчика представлений Razor можно определить макеты, частичные представления и заменяемые разделы.
Строго типизированные представления
Razor представления в MVC могут быть строго типизированы на основе модели. Контроллеры передают строго типизированную модель в представления для поддержки в них IntelliSense и проверки типов.
Например, следующее представление отображает модель типа IEnumerable :
Вспомогательные функции тегов
Вспомогательные функции тегов позволяют коду на стороне сервера участвовать в создании и отрисовке HTML-элементов в Razor файлах. Вспомогательные функции тегов используются для определения настраиваемых тегов (например, ) или для изменения поведения существующих тегов (например, ). Вспомогательные функции тегов привязываются к определенным элементам на основе имени элемента и его атрибутов. Они предоставляют преимущества отрисовки на стороне сервера, сохраняя при этом возможности редактирования HTML.
Существует множество встроенных вспомогательных функций тегов для общих задач — например, для создания форм, ссылок, загрузки ресурсов и т. д. Кроме того, огромное количество функций доступно в общедоступных репозиториях GitHub и в качестве пакетов NuGet. Вспомогательные функции тегов разрабатываются на C# и предназначены для HTML-элементов на основе имени элемента, имени атрибута или родительского тега. Например, встроенную функцию LinkTagHelper можно использовать для создания ссылки на действие AccountsController для Login :
С помощью EnvironmentTagHelper можно включать в приложения различные сценарии (например, необработанные или минифицированные) для конкретной среды выполнения (разработки, промежуточной или производственной):
Вспомогательные функции тегов предоставляют удобные для HTML возможности разработки и полнофункциональные среды IntelliSense для создания HTML и Razor разметки. Большинство встроенных вспомогательных функций тегов работают с существующими HTML-элементами и предоставляют для них атрибуты на стороне сервера.
Компоненты представлений
Компоненты представлений позволяют упаковывать логику отрисовки и повторно использовать ее в приложении. Они аналогичны частичным представлениям, но имеют связанную логику.
Совместимая версия
Метод SetCompatibilityVersion позволяет приложению принимать или отклонять потенциально критические изменения в поведении, появившиеся в ASP.NET Core MVC 2.1 или более поздних версий.
Дополнительные ресурсы
- MyTested.AspNetCore.Mvc — библиотека Fluent Testing для ASP.NET Core MVC: строго типизированная библиотека модульного тестирования, предоставляющая текучий интерфейс для тестирования приложений MVC и веб-API. (Не поддерживается и не обслуживается Майкрософт. )
- Компоненты Razor для предварительной визуализации и интеграции ASP.NET Core
- Использование внедрения зависимостей в ASP.NET Core
Источник: learn.microsoft.com
Что такое MVC
Рассказываю об одном из самых удобных паттернов построения приложений на любом языке и в любой области.
Что такое паттерн?
Рядом с аббревиатурой MVC почти всегда фигурирует англицизм – паттерн. Это слово означает «шаблон», и этот перевод отлично подходит в нашем случае, так как MVC как раз описывает некую пошаговую модель поведения разработчика.