Файл Module.php
, расположенный внутри корневого каталога модуля, является своего рода точкой входа модуля.
Класс Module
, который определяется в этом файле, загружается компонентом Zend\ModuleManager
при загрузке
всех модулей приложения.
С этим классом можно сделать одну полезную вещь - зарегистрировать обработчики событий. Если помните из главы Как работает веб-сайт, у приложения есть жизненный цикл, представленный событиями. Вы можете написать функцию-обработчик событий (или класс) и зарегистрировать ее в точке входа модуля. Когда вызывается событие, будет вызван ваш метод-обработчик (или же класс), позволяющий вам сделать что-то полезное.
Зачем мне регистрировать обработчик событий?
Вот несколько практических примеров обработки событий, которые могут вам пригодиться:
- Обрабатывать событие Route для того, чтобы использовать безопасное соединение HTTPS.
- Когда ваш сайт находится в режиме обслуживания, обрабатывать событие Route для перехвата всех запросов и перенаправления пользователя.
- Обрабатывать событие Dispatch, чтобы перенаправить пользователя на другую страницу. Например, если пользователь не аутентифицирован, перенаправить его на страницу входа.
- Обрабатывать событие Dispatch для переопределения шаблона лэйаута по умолчанию для всех контроллеров, принадлежащих модулю.
- Обрабатывать событие Dispatch Error для сообщения об исключении или ошибке и/или их логирования.
- Обрабатывать событие Render для изменения содержимого получившейся веб-страницы..
Существует два способа зарегистрировать обработчик событий внутри класса Module
: либо с помощью метода init()
класса Module
, либо с помощью
его другого метода, onBootstrap()
. Разница между ними в том, что init()
вызывается раньше, чем onBootstrap()
, до инициализации всех
модулей, в то время как onBootstrap()
вызывается тогда, когда все модули инициализированы. В последующих примерах мы используем метод init()
.
Чтобы показать, как подписаться на событие, создадим обработчик, который будет реагировать на событие Dispatch и устанавливать другой шаблон лэйаута для всех контроллеров модуля:
<?php
namespace YourCompanyModule;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;
class Module
{
// Метод "init" вызывается при запуске приложения и
// позволяет зарегистрировать обработчик событий.
public function init(ModuleManager $manager)
{
// Получаем менеджер событий.
$eventManager = $manager->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Регистрируем метод-обработчик.
$sharedEventManager->attach(__NAMESPACE__, 'dispatch',
[$this, 'onDispatch'], 100);
}
// Обработчик события.
public function onDispatch(MvcEvent $event)
{
// Получаем контроллер, к которому был отправлен HTTP-запрос.
$controller = $event->getTarget();
// Получаем полностью определенное имя класса контроллера.
$controllerClass = get_class($controller);
// Получаем имя модуля контроллера.
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
// Переключаем лэйаут только для контроллеров, принадлежащих нашему модулю.
if ($moduleNamespace == __NAMESPACE__) {
$viewModel = $event->getViewModel();
$viewModel->setTemplate('layout/layout2');
}
}
// ...
}
Во фрагменте кода выше мы добавляем в класс Module
метод init()
. В этом методе мы регистрируем обработчик события (строка 17)
с помощью метода attach()
, предоставляемого классом Zend\EventManager\SharedEventManager
. Метод attach()
принимает четыре
аргумента: ID компонента, являющегося источником события, имя события ("dispatch"), обработчик события (метод текущего класса
onDispatch()
) и приоритет (100)).
Метод onDispatch()
вызывается при событии Dispatch. В этом методе мы проверяем (строка 32), отправлен ли HTTP-запрос
контроллеру, принадлежащему нашему модулю, и, если это так, переключаем шаблон лэйаута (строка 34).
В этом примере мы покажем, как зарегистрировать обработчик событий, благодаря которому ваш сайт всегда будет использовать HTTPS-соединение для всех веб-страниц:
<?php
namespace YourCompanyModule;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;
class Module
{
// Метод "init" вызывается при запуске приложения и
// позволяет зарегистрировать обработчик событий.
public function init(ModuleManager $manager)
{
// Получаем менеджер событий.
$eventManager = $manager->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Регистрируем метод-обработчик.
$sharedEventManager->attach(__NAMESPACE__, 'route',
[$this, 'onRoute'], 100);
}
// Обработчик события.
public function onRoute(MvcEvent $event)
{
if (php_sapi_name() == "cli") {
// Не выполняем перенаправление на HTTPS в консольном режиме.
return;
}
// Получаем URI запроса
$uri = $event->getRequest()->getUri();
$scheme = $uri->getScheme();
// Если схема - не HTTPS, перенаправляем на тот же URI, но
// со схемой HTTPS.
if ($scheme != 'https'){
$uri->setScheme('https');
$response=$event->getResponse();
$response->getHeaders()->addHeaderLine('Location', $uri);
$response->setStatusCode(301);
$response->sendHeaders();
return $response;
}
}
// ...
}
В этом коде мы регистрируем метод обработчика события, который вызывается при событии Route.
Внутри обработчика мы сначала проверяем, работает ли наш сайт в консольном режиме. В этом режиме мы не выполняем перенаправление на HTTPS.
После этого мы извлекаем из HTTP-запроса URI и проверяем, является ли текущая схема HTTPS или нет. Если нет, мы перенаправляем пользователя на тот же URL, но со схемой HTTPS.
С помощью данной процедуры можно легко отслеживать все происходящие на сайте исключения. Сообщать об исключениях или ошибках довольно важно, так как это позволяет сделать сайт более стабильным и безопасным, а также улучшить взаимодействие с пользователем.
<?php
namespace YourCompanyModule;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;
class Module
{
// Метод "init" вызывается при запуске приложения и
// позволяет зарегистрировать обработчик событий.
public function init(ModuleManager $manager)
{
// Получаем менеджер событий.
$eventManager = $manager->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Регистрируем метод-обработчик.
$sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH_ERROR,
[$this, 'onError'], 100);
$sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_RENDER_ERROR,
[$this, 'onError'], 100);
}
// Обработчик события.
public function onError(MvcEvent $event)
{
// Получаем информацию об исключении.
$exception = $event->getParam('exception');
if ($exception!=null) {
$exceptionName = $exception->getMessage();
$file = $exception->getFile();
$line = $exception->getLine();
$stackTrace = $exception->getTraceAsString();
}
$errorMessage = $event->getError();
$controllerName = $event->getController();
// Подготавливаем сообщение эл. почты.
$to = 'admin@yourdomain.com';
$subject = 'Your Website Exception';
$body = '';
if(isset($_SERVER['REQUEST_URI'])) {
$body .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n\n";
}
$body .= "Controller: $controllerName\n";
$body .= "Error message: $errorMessage\n";
if ($exception!=null) {
$body .= "Exception: $exceptionName\n";
$body .= "File: $file\n";
$body .= "Line: $line\n";
$body .= "Stack trace:\n\n" . $stackTrace;
}
$body = str_replace("\n", "<br>", $body);
// Посылаем эл. сообщение об ошибке.
mail($to, $subject, $body);
}
// ...
}
В данном фрагменте мы регистрируем обработчик событий, который будет вызываться при каждой
ошибке отправки запроса (при несоответствии маршрута или исключении) и ошибке визуализации.
Внутри метода обработчика onError()
мы извлекаем информацию об исключении/ошибке и посылаем
ее в виде электронного сообщения на адрес по вашему выбору.