Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

События

Событие — сообщение «сейчас произошло то-то», на которое может отозваться любой код. Обработка запроса в Laminas — цепочка таких событий: определить маршрут, вызвать контроллер, вывести шаблон, отправить ответ. К каждому шагу можно подключить слушателя — функцию, которая выполнится в этот момент.

Этапы запроса

СобытиеКогда происходит
MvcEvent::EVENT_BOOTSTRAPПриложение собрано
MvcEvent::EVENT_ROUTEОпределяется маршрут
MvcEvent::EVENT_DISPATCHВызывается контроллер
MvcEvent::EVENT_DISPATCH_ERRORОшибка: нет маршрута или исключение
MvcEvent::EVENT_RENDERВыводится шаблон
MvcEvent::EVENT_FINISHОтвет готов к отправке

Первый слушатель

Слушателей подключают в методе onBootstrap() класса модуля — файл module/Blog/src/Module.php. Laminas вызывает этот метод сам при каждом запросе:

// module/Blog/src/Module.php
use Laminas\Mvc\MvcEvent;
 
public function onBootstrap(MvcEvent $event): void
{
    $events = $event->getApplication()->getEventManager();
 
    $events->attach(MvcEvent::EVENT_FINISH, function (MvcEvent $e) {
        $e->getResponse()->getHeaders()->addHeaderLine('X-Frame-Options', 'DENY');
    });
}

Метод attach() принимает имя события и функцию. Теперь к каждому ответу сайта добавляется заголовок X-Frame-Options: его видно в инструментах разработчика браузера на вкладке сети.

Что доступно слушателю

Слушатель получает объект MvcEvent с данными запроса:

МетодЧто возвращает
getRequest(), getResponse()Запрос и ответ
getRouteMatch()Сработавший маршрут и его параметры
getApplication()->getServiceManager()Контейнер сервисов
getParam('exception')Исключение (в событии ошибки)

Приоритет

Третий аргумент attach() — приоритет. Чем он больше, тем раньше вызывается слушатель; по умолчанию он равен 1.

$events->attach(MvcEvent::EVENT_DISPATCH_ERROR, function (MvcEvent $e) {
    $exception = $e->getParam('exception');
 
    if ($exception !== null) {
        error_log($exception->getMessage());
    }
}, 100);

Слушатель с приоритетом 100 запишет текст исключения в журнал PHP раньше, чем встроенный слушатель покажет страницу ошибки.

Свои события

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

// module/Blog/src/Service/PostService.php
namespace Blog\Service;
 
use Blog\Model\Post;
use Blog\Model\PostTable;
use Laminas\EventManager\EventManagerInterface;
 
class PostService
{
    public function __construct(
        private PostTable $posts,
        private EventManagerInterface $events,
    ) {}
 
    public function create(Post $post): void
    {
        $this->posts->save($post);
 
        $this->events->trigger('post.created', $this, ['post' => $post]);
    }
}

Фабрика выдаёт сервису собственный менеджер событий и помечает его именем класса:

// module/Blog/src/Service/PostServiceFactory.php
public function __invoke(ContainerInterface $container): PostService
{
    $events = $container->get('EventManager');
    $events->setIdentifiers([PostService::class]);
 
    return new PostService($container->get(PostTable::class), $events);
}

Подписываются на такое событие через общий менеджер — в onBootstrap():

$shared = $events->getSharedManager();
 
$shared->attach(PostService::class, 'post.created', function ($e) {
    error_log('Новая статья: ' . $e->getParam('post')->title);
});

Первый аргумент — метка источника, второй — имя события. Если в действии add вызвать $this->postService->create($post) вместо $this->posts->save($post), после каждой новой статьи в журнале появится строка. Отправку писем или сброс кеша добавляют таким же слушателем, не меняя сам сервис.

Частая ошибка

Слушатели из onBootstrap() выполняются при каждом запросе и для всех страниц сайта. Запрос к базе или чтение файлов внутри них замедляют всё приложение. Держите слушателей короткими, а сервисы получайте из контейнера внутри функции-слушателя: тогда они создадутся, только когда действительно понадобятся.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.