<?php/* * This file is part of the Symfony framework. * * (c) Fabien Potencier <fabien@symfony.com> * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */namespace Sensio\Bundle\FrameworkExtraBundle\EventListener;use Doctrine\Common\Annotations\Reader;use Symfony\Component\HttpKernel\Event\FilterControllerEvent;use Symfony\Component\HttpKernel\KernelEvents;use Symfony\Component\EventDispatcher\EventSubscriberInterface;use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;use Doctrine\Common\Util\ClassUtils;/** * The ControllerListener class parses annotation blocks located in * controller classes. * * @author Fabien Potencier <fabien@symfony.com> */class ControllerListener implements EventSubscriberInterface{ /** * @var Reader */ protected $reader; /** * Constructor. * * @param Reader $reader An Reader instance */ public function __construct(Reader $reader) { $this->reader = $reader; } /** * Modifies the Request object to apply configuration information found in * controllers annotations like the template to render or HTTP caching * configuration. * * @param FilterControllerEvent $event A FilterControllerEvent instance */ public function onKernelController(FilterControllerEvent $event) { $controller = $event->getController(); if (!is_array($controller) && method_exists($controller, '__invoke')) { $controller = array($controller, '__invoke'); } if (!is_array($controller)) { return; } $className = class_exists('Doctrine\Common\Util\ClassUtils') ? ClassUtils::getClass($controller[0]) : get_class($controller[0]); $object = new \ReflectionClass($className); $method = $object->getMethod($controller[1]); $classConfigurations = $this->getConfigurations($this->reader->getClassAnnotations($object)); $methodConfigurations = $this->getConfigurations($this->reader->getMethodAnnotations($method)); $configurations = array(); foreach (array_merge(array_keys($classConfigurations), array_keys($methodConfigurations)) as $key) { if (!array_key_exists($key, $classConfigurations)) { $configurations[$key] = $methodConfigurations[$key]; } elseif (!array_key_exists($key, $methodConfigurations)) { $configurations[$key] = $classConfigurations[$key]; } else { if (is_array($classConfigurations[$key])) { if (!is_array($methodConfigurations[$key])) { throw new \UnexpectedValueException('Configurations should both be an array or both not be an array'); } $configurations[$key] = array_merge($classConfigurations[$key], $methodConfigurations[$key]); } else { // method configuration overrides class configuration $configurations[$key] = $methodConfigurations[$key]; } } } $request = $event->getRequest(); foreach ($configurations as $key => $attributes) { $request->attributes->set($key, $attributes); } } protected function getConfigurations(array $annotations) { $configurations = array(); foreach ($annotations as $configuration) { if ($configuration instanceof ConfigurationInterface) { if ($configuration->allowArray()) { $configurations['_'.$configuration->getAliasName()][] = $configuration; } elseif (!isset($configurations['_'.$configuration->getAliasName()])) { $configurations['_'.$configuration->getAliasName()] = $configuration; } else { throw new \LogicException(sprintf('Multiple "%s" annotations are not allowed.', $configuration->getAliasName())); } } } return $configurations; } public static function getSubscribedEvents() { return array( KernelEvents::CONTROLLER => 'onKernelController', ); }}