|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\HttpKernel\Controller; |
|
13 |
|
14 use Symfony\Component\HttpKernel\Log\LoggerInterface; |
|
15 use Symfony\Component\HttpFoundation\Request; |
|
16 |
|
17 /** |
|
18 * ControllerResolver. |
|
19 * |
|
20 * This implementation uses the '_controller' request attribute to determine |
|
21 * the controller to execute and uses the request attributes to determine |
|
22 * the controller method arguments. |
|
23 * |
|
24 * @author Fabien Potencier <fabien@symfony.com> |
|
25 * |
|
26 * @api |
|
27 */ |
|
28 class ControllerResolver implements ControllerResolverInterface |
|
29 { |
|
30 private $logger; |
|
31 |
|
32 /** |
|
33 * Constructor. |
|
34 * |
|
35 * @param LoggerInterface $logger A LoggerInterface instance |
|
36 */ |
|
37 public function __construct(LoggerInterface $logger = null) |
|
38 { |
|
39 $this->logger = $logger; |
|
40 } |
|
41 |
|
42 /** |
|
43 * Returns the Controller instance associated with a Request. |
|
44 * |
|
45 * This method looks for a '_controller' request attribute that represents |
|
46 * the controller name (a string like ClassName::MethodName). |
|
47 * |
|
48 * @param Request $request A Request instance |
|
49 * |
|
50 * @return mixed|Boolean A PHP callable representing the Controller, |
|
51 * or false if this resolver is not able to determine the controller |
|
52 * |
|
53 * @throws \InvalidArgumentException|\LogicException If the controller can't be found |
|
54 * |
|
55 * @api |
|
56 */ |
|
57 public function getController(Request $request) |
|
58 { |
|
59 if (!$controller = $request->attributes->get('_controller')) { |
|
60 if (null !== $this->logger) { |
|
61 $this->logger->warn('Unable to look for the controller as the "_controller" parameter is missing'); |
|
62 } |
|
63 |
|
64 return false; |
|
65 } |
|
66 |
|
67 if (is_array($controller) || (is_object($controller) && method_exists($controller, '__invoke'))) { |
|
68 return $controller; |
|
69 } |
|
70 |
|
71 if (false === strpos($controller, ':') && method_exists($controller, '__invoke')) { |
|
72 return new $controller; |
|
73 } |
|
74 |
|
75 list($controller, $method) = $this->createController($controller); |
|
76 |
|
77 if (!method_exists($controller, $method)) { |
|
78 throw new \InvalidArgumentException(sprintf('Method "%s::%s" does not exist.', get_class($controller), $method)); |
|
79 } |
|
80 |
|
81 return array($controller, $method); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Returns the arguments to pass to the controller. |
|
86 * |
|
87 * @param Request $request A Request instance |
|
88 * @param mixed $controller A PHP callable |
|
89 * |
|
90 * @throws \RuntimeException When value for argument given is not provided |
|
91 * |
|
92 * @api |
|
93 */ |
|
94 public function getArguments(Request $request, $controller) |
|
95 { |
|
96 if (is_array($controller)) { |
|
97 $r = new \ReflectionMethod($controller[0], $controller[1]); |
|
98 } elseif (is_object($controller)) { |
|
99 $r = new \ReflectionObject($controller); |
|
100 $r = $r->getMethod('__invoke'); |
|
101 } else { |
|
102 $r = new \ReflectionFunction($controller); |
|
103 } |
|
104 |
|
105 return $this->doGetArguments($request, $controller, $r->getParameters()); |
|
106 } |
|
107 |
|
108 protected function doGetArguments(Request $request, $controller, array $parameters) |
|
109 { |
|
110 $attributes = $request->attributes->all(); |
|
111 $arguments = array(); |
|
112 foreach ($parameters as $param) { |
|
113 if (array_key_exists($param->getName(), $attributes)) { |
|
114 $arguments[] = $attributes[$param->getName()]; |
|
115 } elseif ($param->getClass() && $param->getClass()->isInstance($request)) { |
|
116 $arguments[] = $request; |
|
117 } elseif ($param->isDefaultValueAvailable()) { |
|
118 $arguments[] = $param->getDefaultValue(); |
|
119 } else { |
|
120 if (is_array($controller)) { |
|
121 $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]); |
|
122 } elseif (is_object($controller)) { |
|
123 $repr = get_class($controller); |
|
124 } else { |
|
125 $repr = $controller; |
|
126 } |
|
127 |
|
128 throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->getName())); |
|
129 } |
|
130 } |
|
131 |
|
132 return $arguments; |
|
133 } |
|
134 |
|
135 /** |
|
136 * Returns a callable for the given controller. |
|
137 * |
|
138 * @param string $controller A Controller string |
|
139 * |
|
140 * @return mixed A PHP callable |
|
141 */ |
|
142 protected function createController($controller) |
|
143 { |
|
144 if (false === strpos($controller, '::')) { |
|
145 throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller)); |
|
146 } |
|
147 |
|
148 list($class, $method) = explode('::', $controller); |
|
149 |
|
150 if (!class_exists($class)) { |
|
151 throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); |
|
152 } |
|
153 |
|
154 return array(new $class(), $method); |
|
155 } |
|
156 } |