Chris@14
|
1 <?php
|
Chris@14
|
2
|
Chris@14
|
3 /*
|
Chris@14
|
4 * This file is part of the Symfony package.
|
Chris@14
|
5 *
|
Chris@14
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@14
|
7 *
|
Chris@14
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@14
|
9 * file that was distributed with this source code.
|
Chris@14
|
10 */
|
Chris@14
|
11
|
Chris@14
|
12 namespace Symfony\Component\HttpKernel\Controller;
|
Chris@14
|
13
|
Chris@14
|
14 use Psr\Container\ContainerInterface;
|
Chris@14
|
15 use Psr\Log\LoggerInterface;
|
Chris@14
|
16 use Symfony\Component\DependencyInjection\Container;
|
Chris@14
|
17 use Symfony\Component\HttpFoundation\Request;
|
Chris@14
|
18
|
Chris@14
|
19 /**
|
Chris@14
|
20 * A controller resolver searching for a controller in a psr-11 container when using the "service:method" notation.
|
Chris@14
|
21 *
|
Chris@14
|
22 * @author Fabien Potencier <fabien@symfony.com>
|
Chris@14
|
23 * @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
Chris@14
|
24 */
|
Chris@14
|
25 class ContainerControllerResolver extends ControllerResolver
|
Chris@14
|
26 {
|
Chris@14
|
27 protected $container;
|
Chris@14
|
28
|
Chris@14
|
29 public function __construct(ContainerInterface $container, LoggerInterface $logger = null)
|
Chris@14
|
30 {
|
Chris@14
|
31 $this->container = $container;
|
Chris@14
|
32
|
Chris@14
|
33 parent::__construct($logger);
|
Chris@14
|
34 }
|
Chris@14
|
35
|
Chris@14
|
36 /**
|
Chris@14
|
37 * {@inheritdoc}
|
Chris@14
|
38 */
|
Chris@14
|
39 public function getController(Request $request)
|
Chris@14
|
40 {
|
Chris@14
|
41 $controller = parent::getController($request);
|
Chris@14
|
42
|
Chris@17
|
43 if (\is_array($controller) && isset($controller[0]) && \is_string($controller[0]) && $this->container->has($controller[0])) {
|
Chris@14
|
44 $controller[0] = $this->instantiateController($controller[0]);
|
Chris@14
|
45 }
|
Chris@14
|
46
|
Chris@14
|
47 return $controller;
|
Chris@14
|
48 }
|
Chris@14
|
49
|
Chris@14
|
50 /**
|
Chris@14
|
51 * Returns a callable for the given controller.
|
Chris@14
|
52 *
|
Chris@14
|
53 * @param string $controller A Controller string
|
Chris@14
|
54 *
|
Chris@14
|
55 * @return mixed A PHP callable
|
Chris@14
|
56 *
|
Chris@14
|
57 * @throws \LogicException When the name could not be parsed
|
Chris@14
|
58 * @throws \InvalidArgumentException When the controller class does not exist
|
Chris@14
|
59 */
|
Chris@14
|
60 protected function createController($controller)
|
Chris@14
|
61 {
|
Chris@14
|
62 if (false !== strpos($controller, '::')) {
|
Chris@14
|
63 return parent::createController($controller);
|
Chris@14
|
64 }
|
Chris@14
|
65
|
Chris@14
|
66 $method = null;
|
Chris@14
|
67 if (1 == substr_count($controller, ':')) {
|
Chris@14
|
68 // controller in the "service:method" notation
|
Chris@14
|
69 list($controller, $method) = explode(':', $controller, 2);
|
Chris@14
|
70 }
|
Chris@14
|
71
|
Chris@14
|
72 if (!$this->container->has($controller)) {
|
Chris@14
|
73 $this->throwExceptionIfControllerWasRemoved($controller);
|
Chris@14
|
74
|
Chris@14
|
75 throw new \LogicException(sprintf('Controller not found: service "%s" does not exist.', $controller));
|
Chris@14
|
76 }
|
Chris@14
|
77
|
Chris@14
|
78 $service = $this->container->get($controller);
|
Chris@14
|
79 if (null !== $method) {
|
Chris@17
|
80 return [$service, $method];
|
Chris@14
|
81 }
|
Chris@14
|
82
|
Chris@14
|
83 if (!method_exists($service, '__invoke')) {
|
Chris@14
|
84 throw new \LogicException(sprintf('Controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller));
|
Chris@14
|
85 }
|
Chris@14
|
86
|
Chris@14
|
87 return $service;
|
Chris@14
|
88 }
|
Chris@14
|
89
|
Chris@14
|
90 /**
|
Chris@14
|
91 * {@inheritdoc}
|
Chris@14
|
92 */
|
Chris@14
|
93 protected function instantiateController($class)
|
Chris@14
|
94 {
|
Chris@14
|
95 if ($this->container->has($class)) {
|
Chris@14
|
96 return $this->container->get($class);
|
Chris@14
|
97 }
|
Chris@14
|
98
|
Chris@14
|
99 try {
|
Chris@14
|
100 return parent::instantiateController($class);
|
Chris@14
|
101 } catch (\ArgumentCountError $e) {
|
Chris@14
|
102 } catch (\ErrorException $e) {
|
Chris@14
|
103 } catch (\TypeError $e) {
|
Chris@14
|
104 }
|
Chris@14
|
105
|
Chris@14
|
106 $this->throwExceptionIfControllerWasRemoved($class, $e);
|
Chris@14
|
107
|
Chris@14
|
108 throw $e;
|
Chris@14
|
109 }
|
Chris@14
|
110
|
Chris@14
|
111 /**
|
Chris@14
|
112 * @param string $controller
|
Chris@14
|
113 * @param \Exception|\Throwable|null $previous
|
Chris@14
|
114 */
|
Chris@14
|
115 private function throwExceptionIfControllerWasRemoved($controller, $previous = null)
|
Chris@14
|
116 {
|
Chris@14
|
117 if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) {
|
Chris@14
|
118 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
|
119 }
|
Chris@14
|
120 }
|
Chris@14
|
121 }
|