如何在Symfony中为控制器类和方法创建一个自定义注解

208 阅读1分钟

这个例子向我们展示了我们如何为constollers及其方法创建一个自定义注解。我们将创建的注解叫做@Model ,它有三个属性,如下所示。

注释类

declare(strict_types=1);

namespace App\Annotation;

/**
 * @Annotation
 */
class Model
{
    /**
     * @var string
     */
    public $namespace;

    /**
     * @var int
     */
    public $version;

    /**
     * @var array
     */
    public $types;
}

模型类

这是可选的:

declare(strict_types=1);

namespace App\Model;

class Country
{
    // Whatever
}

控制器

declare(strict_types=1);

namespace App\Controller;

use App\Annotation\Model;
...

/**
 * @Route("/countries")
 * @Model
 */
class CountryController
{
    /**
     * @Route(....)
     * @Model(
     *     namespace="App\Model\Country",
     *     version=1,
     *     types={"json","xml"}
     * )
     */
    public function getAll(): Response
    {
        // ...
    }
}

ModelAnnotationListener

declare(strict_types=1);

namespace App\Event\Listener;

use App\Annotation\Model as ModelAnnotation;
use Doctrine\Common\Annotations\Reader;
use ReflectionClass;
use ReflectionException;
use RuntimeException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

class ModelAnnotationListener
{
    private $annotationReader;

    public function __construct(Reader $annotationReader)
    {
        $this->annotationReader = $annotationReader;
    }

    public function onKernelController(FilterControllerEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            return;
        }

        $controllers = $event->getController();
        if (!is_array($controllers)) {
            return;
        }

        $this->handleAnnotation($controllers);
    }

    private function handleAnnotation(iterable $controllers): void
    {
        list($controller, $method) = $controllers;

        try {
            $controller = new ReflectionClass($controller);
        } catch (ReflectionException $e) {
            throw new RuntimeException('Failed to read annotation!');
        }

        $this->handleClassAnnotation($controller);
        $this->handleMethodAnnotation($controller, $method);
    }

    private function handleClassAnnotation(ReflectionClass $controller): void
    {
        $annotation = $this->annotationReader->getClassAnnotation($controller, ModelAnnotation::class);

        if ($annotation instanceof ModelAnnotation) {
            print_r($annotation);
        }
    }

    private function handleMethodAnnotation(ReflectionClass $controller, string $method): void
    {
        $method = $controller->getMethod($method);
        $annotation = $this->annotationReader->getMethodAnnotation($method, ModelAnnotation::class);

        if ($annotation instanceof ModelAnnotation) {
            print_r($annotation);
        }
    }
}
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    App\Event\:
        resource: '../../src/Event'

    App\Event\Listener\ModelAnnotationListener:
        tags:
            - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

结果

App\Annotation\Model Object
(
    [namespace] => 
    [version] => 
    [types] => 
)

App\Annotation\Model Object
(
    [namespace] => App\Model\Country
    [version] => 1
    [types] => Array
        (
            [0] => json
            [1] => xml
        )
)