Symfonyの初期化可能なコントローラーと注釈の操作

ずいぶん前に、Symfonyでコントローラー初期化メカニズムを実装するタスクに直面しました。 コントローラアクションの各呼び出しの前のいくつかのデフォルトアクションのパフォーマンス。 最初に思い付いたのは、 kernel.controllerイベントのEventListenerを追加することです。 このイベントでは、 初期化コントローラーメソッドが呼び出されます(存在する場合)。 私は数年前からこの方法を使用しています。



先日私が考えたのは、アクションの前に、異なるコントローラーに対して異なるメソッドを実行し、いくつかのメソッドを連続して実行し、それらのいくつかを異なるパラメーターで何度も実行する必要がある場合はどうでしょうか? この記事では、注釈を使用してこの問題をどのように解決したかを説明します。 この記事は、アノテーションを使用したことがない人にとっても役立つと思います。



まず、コントローラーの初期化メカニズムを実装する方法を示します。



最初に、初期化が必要なコントローラーをキャッチするのに役立つインターフェースを作成します。



<?php namespace MyBundle\Controller; interface InitializableControllerInterface { }
      
      





次に、初期化するkernel.controllerイベントのEventListenerを作成します。



 <?php namespace MyBundle\EventListener; use MyBundle\Controller\InitializableControllerInterface; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; class KernelControllerListener { // ,    kernel.controller public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); //     InitializableControllerInterface if (is_array($controller) && $controller[0] instanseof InitializableControllerInterface) { //     } } }
      
      





そして、そのためのサービス構成(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="my_bundle.kernel_controller_listener" class="MyBundle\EventListener\KernelControllerListener"> <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" /> </service> </services> </container>
      
      





原則として、これですでに十分ですが、コントローラーの初期化をより柔軟にしたいので、注釈を使用します。



実際、特にDoctrineアノテーションリーダーを使用している場合、アノテーションの操作は非常に簡単です。 まず、コントローラーの初期化メソッドに適用するアノテーションクラスを作成します。



 <?php namespace MyBundle\Annotation; /** * @Annotation * @Target({"METHOD"}) * *   @Annotation  ,       , *  @Target({"METHOD"}) -         . */ class Init { //  : /** * @var array * *    */ public $args = []; /** * @var int * *   ( ,    ) */ public $priority = 0; }
      
      





入力データ型を介してDoctrineを制御するために注釈パラメーターの型を指定することをお勧めします。



これで、コントローラーで注釈を使用できます。



 <?php namespace MyBundle\Controller; use MyBundle\Annotation\Init; use MyBundle\Controller\InitializableControllerInterface; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class MyController extends Controller implements InitializableControllerInterface { /** * @Init(args = {"test"}, priority = 200) * *     (initialize("test");)     */ public function initialize($value) { // ... -  ... } }
      
      





KernelControllerListenerに注釈処理を追加するだけです。



 <?php namespace MyBundle\EventListener; use Doctrine\Common\Annotations\Reader; use MyBundle\Annotation\Init; use MyBundle\Controller\InitializableControllerInterface; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; class KernelControllerListener { protected $annotationReader; //      public function __construct(Reader $annotationReader) { $this->annotationReader = $annotationReader; } public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); if (is_array($controller) && $controller[0] instanceof InitializableControllerInterface) { //     $reflector = new \ReflectionClass($controller[0]); //       $methods = $reflector->getMethods(\ReflectionMethod::IS_PUBLIC); $initMethods = []; //    ,     @Init foreach ($methods as $method) { //     $annotations = $this->annotationReader->getMethodAnnotations($method); foreach ($annotations as $annotation) { //   - ,            if ($annotation instanceof Init) { $initMethods[] = [ 'method' => $method, 'args' => $annotation->args, 'priority' => $annotation->priority ]; } } } //         usort($initMethods, function($a, $b) { return $b['priority'] - $a['priority']; }); foreach ($initMethods as $initMethod) { $method = $initMethod['method']; //     ,        if (count($initMethod['args'])) { $method->invokeArgs($controller[0], $initMethod['args']); } else { $method->invoke($controller[0]); } } } } }
      
      





また、サービス構成を補完します。



 <?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="my_bundle.kernel_controller_listener" class="MyBundle\EventListener\KernelControllerListener"> <argument type="service" id="annotation_reader" /> <!--      --> <tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" /> </service> </services> </container>
      
      





以上です。 私のすべてのコードはGitHubで見ることができます。建設的な批判をうれしく思います。



こちらもご覧ください:




All Articles