This example shows us how we create a custom annotation for constollers and their methods. The annotation we will create is called @Model and it has three properties as shown below.


Annotation class


declare(strict_types=1);

namespace App\Annotation;

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

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

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

Model class


This is optional.


declare(strict_types=1);

namespace App\Model;

class Country
{
// Whatever
}

Controller


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 }


Result


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

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