002 Полное MVC приложение
Вся сложная работа по дирижированию работой MVC в Phalcon обычно выполняется с помощью Phalcon\Mvc\Application. Этот компонент инкапсулирует все сложные операции, требуемые в фоновом режиме, отвечает за создание каждого необходимого компонента и интеграцию его с проектом, позволяя паттерну MVC работать как положено.
Следующий код начальной загрузки является типичным для Phalcon приложения:
<?php use Phalcon\Mvc\Application; // Регистрация автозагрузчиков // ... // Регистрация сервисов // ... // Обработка запроса $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo 'Exception: ', $e->getMessage(); }
Основная работа контроллера происходит при вызове метода handle()
:
<?php $response = $application->handle();
Ручная обработка
Если вы не желаете использовать Phalcon\Mvc\Application, код выше должен быть изменен следующим образом:
<?php // Получить сервис 'router' $router = $di['router']; $router->handle(); $view = $di['view']; $dispatcher = $di['dispatcher']; // Посылаем обработанные параметры маршрута в диспетчер $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); // Запускаем отображение вид $view->start(); // Доставляем запрос $dispatcher->dispatch(); // Отображаем соответствующие виды $view->render( $dispatcher->getControllerName(), $dispatcher->getActionName(), $dispatcher->getParams() ); // Заканчиваем отображение вида $view->finish(); $response = $di['response']; // Передаем вывод из вида в ответ $response->setContent( $view->getContent() ); // Отсылаем ответ $response->send();
Следующая доработка компонента view в Phalcon\Mvc\Application, делает его пригодным для Rest API:
<?php use Phalcon\Http\ResponseInterface; // Получение сервиса 'router' $router = $di['router']; $router->handle(); $dispatcher = $di['dispatcher']; // Передача обработанных параметров маршрута в диспетчер $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); // Доставка запроса $dispatcher->dispatch(); // Получение значения, которое вернуло последнее выполненное действие $response = $dispatcher->getReturnedValue(); // Проверка является ли возвращенное значение объектом 'response' if ($response instanceof ResponseInterface) { // Send the response $response->send(); }
Еще один вариант, который перехватывает исключения произведенные в диспетчере, пересылаемые в другие действия последовательно:
<?php use Phalcon\Http\ResponseInterface; // Получение сервиса 'router' $router = $di['router']; $router->handle(); $dispatcher = $di['dispatcher']; // Передача обработанных параметров маршрута диспетчеру $dispatcher->setControllerName( $router->getControllerName() ); $dispatcher->setActionName( $router->getActionName() ); $dispatcher->setParams( $router->getParams() ); try { // Доставка запроса $dispatcher->dispatch(); } catch (Exception $e) { // Произошло исключение, доставка контроллеру/методу предназначенному для этого // Передача обработанных параметров маршрута диспетчеру $dispatcher->setControllerName('errors'); $dispatcher->setActionName('action503'); // доставка запроса $dispatcher->dispatch(); } // Получение возвращаемого значения из последнего выполненного действия $response = $dispatcher->getReturnedValue(); // Проверка является ли возвращенное значение объектом 'response' if ($response instanceof ResponseInterface) { // Send the response $response->send(); }
Хотя реализация выше является более подробной, чем код необходимый при использовании Phalcon\Mvc\Application, она предлагает альтернативу начальной загрузки вашего приложения. В зависимости от ваших нужд, вы можете захотеть иметь полный контроль над тем, что должно быть создано или нет, или заменить определенные компоненты своими для расширения функциональности по умолчанию.
Одномодульные и многомодульные приложения
С помощью этого компонента можно запускать разные типы MVC приложений:
Одномодульное приложение
Отдельные приложения MVC состоят только из одного модуля. Пространства имен можно использовать, но не обязательно. Такое приложение будет иметь следующую файловую структуру:
single/
app/
controllers/
models/
views/
public/
css/
img/
js/
Если не используется пространство имён, то в качестве файла загрузки MVC можно использовать следующий подход:
<?php use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $loader = new Loader(); $loader->registerDirs( [ '../apps/controllers/', '../apps/models/', ] ); $loader->register(); $di = new FactoryDefault(); // Регистрация view компонента $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/views/'); return $view; } ); $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); }
Если же используются пространства имён, то инициализация приложения может быть реализована следующим образом:
<?php use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\Mvc\Dispatcher; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $loader = new Loader(); // Использование автозагрузчика с префиксами пространств имён $loader->registerNamespaces( [ 'Single\Controllers' => '../apps/controllers/', 'Single\Models' => '../apps/models/', ] ); $loader->register(); $di = new FactoryDefault(); // Регистрация пространства имён по умолчанию для контроллеров $di->set( 'dispatcher', function () { $dispatcher = new Dispatcher(); $dispatcher->setDefaultNamespace('Single\Controllers'); return $dispatcher; } ); // Регистрация компонента представлений $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/views/'); return $view; } ); $application = new Application($di); try { $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); }
Многомодульное приложение
Многомодульное приложение использует один и тот же корень документа для нескольких модулей. В этом случае можно использовать следующую файловую структуру:
multiple/
apps/
frontend/
controllers/
models/
views/
Module.php
backend/
controllers/
models/
views/
Module.php
public/
css/
img/
js/
Каждый каталог в apps/
имеет свою собственную структуру MVC. Module.php
присутствует для настройки конкретных параметров каждого модуля, таких как автозагрузчики или пользовательские службы:
<?php namespace Multiple\Backend; use Phalcon\Loader; use Phalcon\Mvc\View; use Phalcon\DiInterface; use Phalcon\Mvc\Dispatcher; use Phalcon\Mvc\ModuleDefinitionInterface; class Module implements ModuleDefinitionInterface { /** * Регистрация специфичного автозагрузчика для модуля */ public function registerAutoloaders(DiInterface $di = null) { $loader = new Loader(); $loader->registerNamespaces( [ 'Multiple\Backend\Controllers' => '../apps/backend/controllers/', 'Multiple\Backend\Models' => '../apps/backend/models/', ] ); $loader->register(); } /** * Регистрация специфичных сервисов для модуля */ public function registerServices(DiInterface $di) { // Registering a dispatcher $di->set( 'dispatcher', function () { $dispatcher = new Dispatcher(); $dispatcher->setDefaultNamespace('Multiple\Backend\Controllers'); return $dispatcher; } ); // Регистрация компонента представлений $di->set( 'view', function () { $view = new View(); $view->setViewsDir('../apps/backend/views/'); return $view; } ); } }
Для загрузки многомодульных MVC приложений можно использовать такой файл автозагрузки:
<?php use Phalcon\Mvc\Router; use Phalcon\Mvc\Application; use Phalcon\Di\FactoryDefault; $di = new FactoryDefault(); // Указываем маршруты для модулей $di->set( 'router', function () { $router = new Router(); $router->setDefaultModule('frontend'); $router->add( '/login', [ 'module' => 'backend', 'controller' => 'login', 'action' => 'index', ] ); $router->add( '/admin/products/:action', [ 'module' => 'backend', 'controller' => 'products', 'action' => 1, ] ); $router->add( '/products/:action', [ 'controller' => 'products', 'action' => 1, ] ); return $router; } ); // Создание приложения $application = new Application($di); // Регистрация установленных модулей $application->registerModules( [ 'frontend' => [ 'className' => 'Multiple\Frontend\Module', 'path' => '../apps/frontend/Module.php', ], 'backend' => [ 'className' => 'Multiple\Backend\Module', 'path' => '../apps/backend/Module.php', ] ] ); try { // Обработка запроса $response = $application->handle(); $response->send(); } catch (\Exception $e) { echo $e->getMessage(); }
Если вы желаете хранить конфигурацию модуля в загрузочном файле, можно использовать анонимную функцию для регистрации модуля:
<?php use Phalcon\Mvc\View; // Создание компонента представлений $view = new View(); // Установка опций для компонента представлений // ... // Регистрация установленных модулей $application->registerModules( [ 'frontend' => function ($di) use ($view) { $di->setShared( 'view', function () use ($view) { $view->setViewsDir('../apps/frontend/views/'); return $view; } ); }, 'backend' => function ($di) use ($view) { $di->setShared( 'view', function () use ($view) { $view->setViewsDir('../apps/backend/views/'); return $view; } ); } ] );
Когда Phalcon\Mvc\Application зарегистрирует модули, каждый сопоставленный маршрут должен возвращать существующий модуль. Каждый зарегистрированный модуль должен иметь соответствующий класс и функцию для настройки самого модуля. Каждое определение класса модуля обязательно должно реализовать два метода: registerAutoloaders()
и registerServices()
, они будут автоматически вызваны Phalcon\Mvc\Application при выполнении модуля.
События приложения
Phalcon\Mvc\Application может отправлять события в EventsManager (если он присутствует). События вызываются с типом application
. Поддерживаются следующие события:
Название события | Вызывается |
---|---|
boot |
Выполняется, когда приложение обрабатывает первый запрос |
beforeStartModule |
До инициализации зарегистрированного модуля |
afterStartModule |
После инициализации зарегистрированного модуля |
beforeHandleRequest |
До выполнения цикла диспетчера |
afterHandleRequest |
После выполнения цикла диспетчера |
Следующий пример демонстрирует, как прикрепить слушателей к этому компоненту:
<?php use Phalcon\Events\Event; use Phalcon\Events\Manager as EventsManager; $eventsManager = new EventsManager(); $application->setEventsManager($eventsManager); $eventsManager->attach( 'application', function (Event $event, $application) { // ... } );