Custom annotation in symfony 3 controller
For Symfony 3.4.*
public function onKernelController(FilterControllerEvent $event){
if (!is_array($controllers = $event->getController())) {
return;
}
list($controller, $methodName) = $controllers;
$reflectionClass = new \ReflectionClass($controller);
// Controller
$reader = new \Doctrine\Common\Annotations\AnnotationReader();
$classAnnotation = $reader->getClassAnnotation($reflectionClass, AnnotationClass::class);
// Method
$reflectionMethod = $reflectionClass->getMethod($methodName);
$methodAnnotation = $reader->getMethodAnnotation($reflectionMethod, AnnotationClass::class);
if(!($classAnnotation || $methodAnnotation)){
return;
}
/** TODO CODE HERE **/
}
You need to make a custom annotation and then a listener that injects the annotation reader and handles the kernel.controller event:
Annotation
/**
* @Annotation
*/
class CheckRequest
{
}
Service Definition
services:
controller_check_request:
class: AppBundle\EventListener\ControllerCheckRequestListener
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController}
arguments:
- "@annotation_reader"
Listener:
namespace AppBundle\EventListener;
use AppBundle\Annotation\CheckRequest;
use Doctrine\Common\Annotations\Reader;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ControllerCheckRequestListener
{
/** @var Reader */
private $reader;
/**
* @param Reader $reader
*/
public function __construct(Reader $reader)
{
$this->reader = $reader;
}
/**
* {@inheritdoc}
*/
public function onKernelController(FilterControllerEvent $event)
{
if (!is_array($controllers = $event->getController())) {
return;
}
$request = $event->getRequest();
$content = $request->getContent();
list($controller, $methodName) = $controllers;
$reflectionClass = new \ReflectionClass($controller);
$classAnnotation = $this->reader
->getClassAnnotation($reflectionClass, CheckRequest::class);
$reflectionObject = new \ReflectionObject($controller);
$reflectionMethod = $reflectionObject->getMethod($methodName);
$methodAnnotation = $this->reader
->getMethodAnnotation($reflectionMethod, CheckRequest::class);
if (!($classAnnotation || $methodAnnotation)) {
return;
}
if ($request->getContentType() !== 'json' ) {
return $event->setController(
function() {
return new JsonResponse(['success' => false]);
}
);
}
if (empty($content)) {
throw new BadRequestHttpException('Content is empty');
}
$data = json_decode($content, true);
if ($request->getContentType() !== 'json' ) {
return $event->setController(
function() {
return new JsonResponse(['success' => false]);
}
);
}
}
}
Notice that instead of returning the response, you set the entire controller with $event->setController();
, and you also must return
when making that call.
Then in your controller you can set it on the entire class:
use AppBundle\Annotation\CheckRequest;
/**
* @CheckRequest
*/
class YourController extends Controller
{
}
or individual methods/actions:
use AppBundle\Annotation\CheckRequest;
class TestController extends Controller
{
/**
* @Route("/", name="index")
* @CheckRequest
*/
public function indexAction(Request $request)
{
// ...
}
}