イベントとイベントリスニング


symfony プログラムの実行中に、多数のイベント通知がトリガーされます。プログラムはこれらの通知をリッスンし、それに応じて任意のコードを実行できます。

Symfony 自体によって提供される内部イベントは、KernelEvents クラスで定義されます。サードパーティのバンドルやクラス ライブラリも多数のイベントをトリガーし、独自のプログラムで カスタム イベントをトリガーすることもできます。

この記事に示されているすべての例では、一貫性を考慮して、同じ KernelEvents::EXCEPTION イベントを使用しています。独自のプログラムでは、任意のイベントを使用したり、同じサブスクライバー内で複数のイベントを混合したりすることもできます。

イベント リスナーの作成

イベントを監視する最も一般的な方法は、イベント リスナーを登録することです :

// src/AppBundle/EventListener/ExceptionListener.phpnamespace AppBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; class ExceptionListener{
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        // You get the exception object from the received event
        // 你可以从接收到的事件中,取得异常对象
        $exception = $event->getException();
        $message = sprintf(
            'My Error says: %s with code: %s',
            $exception->getMessage(),
            $exception->getCode()
        );         // Customize your response object to display the exception details
        // 自定义响应对象,来显示异常的细节
        $response = new Response();
        $response->setContent($message);         // HttpExceptionInterface is a special type of exception that
        // holds status code and header details
        // HttpExceptionInterface是一个特殊类型的异常,持有状态码和头信息的细节
        if ($exception instanceof HttpExceptionInterface) {
            $response->setStatusCode($exception->getStatusCode());
            $response->headers->replace($exception->getHeaders());
        } else {
            $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
        }         // Send the modified response object to the event
        // 发送修改后的响应对象到事件中
        $event->setResponse($response);
    }}


すべてのイベントは、「わずかに異なるタイプ」の $event オブジェクトを受け取る必要があります。 kernel.Exception イベントの場合、このオブジェクトは GetResponseForExceptionEvent です。各「イベント リスナー」によって受信される「イベント オブジェクト」のタイプを理解するには、KernelEvents、またはリッスンする特定のイベントのドキュメントを参照してください。


クラスが作成されたので、あとはそれをサービスとして登録し、特別な「タグ」を使用してこれを Symfony に伝えるだけです。これは「リスナー」です。 kernel.Exception イベントの場合:

YAML:# app/config/services.ymlservices:
    app.exception_listener:
        class: AppBundle\EventListener\ExceptionListener
        tags:
            - { name: kernel.event_listener, event: kernel.exception }
xml:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">     <services>
        <service id="app.exception_listener"            class="AppBundle\EventListener\ExceptionListener">             <tag name="kernel.event_listener" event="kernel.exception" />
        </service>
    </services></container>
php:// app/config/services.php$container
    ->register('app.exception_listener', 'AppBundle\EventListener\ExceptionListener')
    ->addTag('kernel.event_listener', array('event' => 'kernel.exception'));

にはオプションのタグ属性 method があり、「どのメソッドを使用するかを定義します」イベントがトリガーされたときに実行されます。」デフォルトでは、メソッド名は on "CamelCase イベント名" です。イベントが kernel.Exception の場合、デフォルトの実行メソッドは onKernelException() です。

もう 1 つのオプションのタグ属性は priority です。そのデフォルト値は 0 です。これは、モニター (モニター) が実行される順序を制御するために使用されます。サーバーの優先順位が高いほど、より早く実行されます)。これは、リスナーが他のリスナーよりも先に実行されることを確認したい場合に便利です。 Symfony の内部リスナーの優先順位の範囲は -255 から 255 ですが、独自のリスナーは任意の正または負の整数を使用できます。

イベント サブスクリプションを作成する

イベントをリッスンする別の方法は、イベント サブスクライバーイベント サブスクリプションです。これは、リッスンするための 1 つ以上のメソッドを定義するクラスです。 1 つ以上のイベントに。イベント リスニングとの主な違いは、サブスクライバーがどのイベントをリッスンしているかを常に知っていることです。

特定のサブスクライバでは、異なるメソッドが同じイベントをリッスンできます。メソッドが実行される順序は、各メソッドの priority パラメータによって定義されます (優先度が高いほど、メソッドがより早く呼び出されます)。サブスクライバーの詳細については、「EventDispatcher コンポーネント」を参照してください。

次の例は、いくつかのメソッドを定義し、同じ kernel.Exception イベントをリッスンするイベント サブスクリプションを示しています:

// src/AppBundle/EventSubscriber/ExceptionSubscriber.phpnamespace AppBundle\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;use Symfony\Component\HttpKernel\KernelEvents; class ExceptionSubscriber implements EventSubscriberInterface{
    public static function getSubscribedEvents()
    {
        // return the subscribed events, their methods and priorities
        // 返回被订阅的事件,以及它们的方法和属性
        return array(
           KernelEvents::EXCEPTION => array(
               array('processException', 10),
               array('logException', 0),
               array('notifyException', -10),
           )
        );
    }     public function processException(GetResponseForExceptionEvent $event)
    {
        // ...
    }     public function logException(GetResponseForExceptionEvent $event)
    {
        // ...
    }     public function notifyException(GetResponseForExceptionEvent $event)
    {
        // ...
    }}

あとは、このクラスを追加するだけです。サービスとして登録し、kernel.event_subscriber をタグ付けして、これがイベント サブスクライバーであることを Symofny に伝えます。

PHP:// app/config/services.php$container
    ->register(
        'app.exception_subscriber',
        'AppBundle\EventSubscriber\ExceptionSubscriber'
    )
    ->addTag('kernel.event_subscriber');
XML:<!-- app/config/services.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">     <services>
        <service id="app.exception_subscriber"            class="AppBundle\EventSubscriber\ExceptionSubscriber">             <tag name="kernel.event_subscriber"/>
        </service>
    </services></container>
YAML:# app/config/services.ymlservices:
    app.exception_subscriber:
        class: AppBundle\EventSubscriber\ExceptionSubscriber
        tags:
            - { name: kernel.event_subscriber }

イベントを要求し、タイプ

を確認します。

単一のページで複数のリクエスト (マスター リクエスト、次に複数のサブリクエスト) を生成できます。通常は テンプレートにコントローラーを埋め込む方法)。 Symfony コア イベントの場合、イベントが「メイン」リクエストであるか「サブ」リクエストであるかを確認することができます:

// src/AppBundle/EventListener/RequestListener.phpnamespace AppBundle\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent;use Symfony\Component\HttpKernel\HttpKernel;use Symfony\Component\HttpKernel\HttpKernelInterface; class RequestListener{
    public function onKernelRequest(GetResponseEvent $event)
    {
        if (!$event->isMasterRequest()) {
            // don't do anything if it's not the master request
            // 如果不是主请求,就什么也不做
            return;
        }         // ...
    }}

特定の動作 (real request など) これを確認すると、次のような可能性があります。サブリクエストリスナーで行う必要はありません。

リッスンまたはサブスクライブ

同じプログラムで使用すると、リスナーとサブスクライバーの境界があいまいになる場合があります。どちらを使用するかを決めるのは、多くの場合、個人の好みになります。ただし、それぞれに独自の利点があります。

  • イベントに関連するコンテンツはサービス定義ではなくクラスに存在するため、サブスクライバーは再利用が簡単です。これにより、Symfony は内部でサブスクライバーを使用することになります;

  • #リスナーは、バンドルが特定の「オプション値」に基づいて条件付きでオンまたはオフにできるため、より柔軟です。

  • イベント リスナーのデバッグ

コマンド ラインを使用すると、「どのリスナーがイベント ディスパッチャーに登録されているか」を確認できます。すべてのイベントとそのリスナーを表示するには、次を実行します:

##
1
$  php bin/console debug:event-dispatcher
##

イベント名を指定すると、この特定のイベントに登録されたリスナーを取得できます:

##
1
$  php bin/console debug:event-dispatcher kernel.exception