Chris@14: Chris@14: * Chris@14: * For the full copyright and license information, please view the LICENSE Chris@14: * file that was distributed with this source code. Chris@14: */ Chris@14: Chris@14: namespace Symfony\Component\HttpKernel\Controller; Chris@14: Chris@14: use Psr\Container\ContainerInterface; Chris@14: use Psr\Log\LoggerInterface; Chris@14: use Symfony\Component\DependencyInjection\Container; Chris@14: use Symfony\Component\HttpFoundation\Request; Chris@14: Chris@14: /** Chris@14: * A controller resolver searching for a controller in a psr-11 container when using the "service:method" notation. Chris@14: * Chris@14: * @author Fabien Potencier Chris@14: * @author Maxime Steinhausser Chris@14: */ Chris@14: class ContainerControllerResolver extends ControllerResolver Chris@14: { Chris@14: protected $container; Chris@14: Chris@14: public function __construct(ContainerInterface $container, LoggerInterface $logger = null) Chris@14: { Chris@14: $this->container = $container; Chris@14: Chris@14: parent::__construct($logger); Chris@14: } Chris@14: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: public function getController(Request $request) Chris@14: { Chris@14: $controller = parent::getController($request); Chris@14: Chris@17: if (\is_array($controller) && isset($controller[0]) && \is_string($controller[0]) && $this->container->has($controller[0])) { Chris@14: $controller[0] = $this->instantiateController($controller[0]); Chris@14: } Chris@14: Chris@14: return $controller; Chris@14: } Chris@14: Chris@14: /** Chris@14: * Returns a callable for the given controller. Chris@14: * Chris@14: * @param string $controller A Controller string Chris@14: * Chris@14: * @return mixed A PHP callable Chris@14: * Chris@14: * @throws \LogicException When the name could not be parsed Chris@14: * @throws \InvalidArgumentException When the controller class does not exist Chris@14: */ Chris@14: protected function createController($controller) Chris@14: { Chris@14: if (false !== strpos($controller, '::')) { Chris@14: return parent::createController($controller); Chris@14: } Chris@14: Chris@14: $method = null; Chris@14: if (1 == substr_count($controller, ':')) { Chris@14: // controller in the "service:method" notation Chris@14: list($controller, $method) = explode(':', $controller, 2); Chris@14: } Chris@14: Chris@14: if (!$this->container->has($controller)) { Chris@14: $this->throwExceptionIfControllerWasRemoved($controller); Chris@14: Chris@14: throw new \LogicException(sprintf('Controller not found: service "%s" does not exist.', $controller)); Chris@14: } Chris@14: Chris@14: $service = $this->container->get($controller); Chris@14: if (null !== $method) { Chris@17: return [$service, $method]; Chris@14: } Chris@14: Chris@14: if (!method_exists($service, '__invoke')) { Chris@14: throw new \LogicException(sprintf('Controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller)); Chris@14: } Chris@14: Chris@14: return $service; Chris@14: } Chris@14: Chris@14: /** Chris@14: * {@inheritdoc} Chris@14: */ Chris@14: protected function instantiateController($class) Chris@14: { Chris@14: if ($this->container->has($class)) { Chris@14: return $this->container->get($class); Chris@14: } Chris@14: Chris@14: try { Chris@14: return parent::instantiateController($class); Chris@14: } catch (\ArgumentCountError $e) { Chris@14: } catch (\ErrorException $e) { Chris@14: } catch (\TypeError $e) { Chris@14: } Chris@14: Chris@14: $this->throwExceptionIfControllerWasRemoved($class, $e); Chris@14: Chris@14: throw $e; Chris@14: } Chris@14: Chris@14: /** Chris@14: * @param string $controller Chris@14: * @param \Exception|\Throwable|null $previous Chris@14: */ Chris@14: private function throwExceptionIfControllerWasRemoved($controller, $previous = null) Chris@14: { Chris@14: if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) { Chris@14: throw new \LogicException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); Chris@14: } Chris@14: } Chris@14: }