Custom annotation in symfony 3 controller
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) { // ... }}
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 **/}