Skip to content

Commit 524e148

Browse files
committed
Throw a sensible exception when controller has been removed
1 parent 22a6a7e commit 524e148

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

src/Symfony/Component/HttpKernel/Controller/ContainerControllerResolver.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,28 @@ protected function createController($controller)
6363
return parent::createController($controller);
6464
}
6565

66+
$method = null;
6667
if (1 == substr_count($controller, ':')) {
6768
// controller in the "service:method" notation
68-
list($service, $method) = explode(':', $controller, 2);
69+
list($controller, $method) = explode(':', $controller, 2);
70+
}
71+
72+
if (!$this->container->has($controller)) {
73+
$this->throwExceptionIfControllerWasRemoved($controller);
74+
75+
throw new \LogicException(sprintf('The controller "%s" do not exists.', $controller));
76+
}
6977

70-
return array($this->container->get($service), $method);
78+
$service = $this->container->get($controller);
79+
if (null !== $method) {
80+
return array($service, $method);
7181
}
7282

73-
if ($this->container->has($controller) && method_exists($service = $this->container->get($controller), '__invoke')) {
74-
// invokable controller in the "service" notation
75-
return $service;
83+
if (!method_exists($service, '__invoke')) {
84+
throw new \LogicException(sprintf('The controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller));
7685
}
7786

78-
throw new \LogicException(sprintf('Unable to parse the controller name "%s".', $controller));
87+
return $service;
7988
}
8089

8190
/**
@@ -94,10 +103,19 @@ protected function instantiateController($class)
94103
} catch (\TypeError $e) {
95104
}
96105

97-
if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$class])) {
98-
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"?', $class), 0, $e);
99-
}
106+
$this->throwExceptionIfControllerWasRemoved($class, $e);
100107

101108
throw $e;
102109
}
110+
111+
/**
112+
* @param string $controller
113+
* @param \Exception|\Throwable|null $previous
114+
*/
115+
private function throwExceptionIfControllerWasRemoved($controller, $previous = null)
116+
{
117+
if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) {
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);
119+
}
120+
}
103121
}

src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class ContainerControllerResolverTest extends ControllerResolverTest
2323
public function testGetControllerService()
2424
{
2525
$container = $this->createMockContainer();
26+
$container->expects($this->once())
27+
->method('has')
28+
->with('foo')
29+
->will($this->returnValue(true));
2630
$container->expects($this->once())
2731
->method('get')
2832
->with('foo')
@@ -175,6 +179,57 @@ public function testNonInstantiableControllerWithCorrespondingService()
175179
$this->assertSame(array($service, 'action'), $controller);
176180
}
177181

182+
/**
183+
* @expectedException \LogicException
184+
* @expectedExceptionMessage Controller "app.my_controller" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?
185+
*/
186+
public function testExceptionWhenUsingRemovedControllerService()
187+
{
188+
$container = $this->getMockBuilder(Container::class)->getMock();
189+
$container->expects($this->at(0))
190+
->method('has')
191+
->with('app.my_controller')
192+
->will($this->returnValue(false))
193+
;
194+
195+
$container->expects($this->atLeastOnce())
196+
->method('getRemovedIds')
197+
->with()
198+
->will($this->returnValue(array('app.my_controller' => true)))
199+
;
200+
201+
$resolver = $this->createControllerResolver(null, $container);
202+
203+
$request = Request::create('/');
204+
$request->attributes->set('_controller', 'app.my_controller');
205+
$resolver->getController($request);
206+
}
207+
208+
/**
209+
* @expectedException \LogicException
210+
* @expectedExceptionMessage The controller "app.my_controller" cannot be called without a method name. Did you forget an "__invoke" method?
211+
*/
212+
public function testExceptionWhenUsingControllerWithoutAnInvokeMethod()
213+
{
214+
$container = $this->getMockBuilder(Container::class)->getMock();
215+
$container->expects($this->once())
216+
->method('has')
217+
->with('app.my_controller')
218+
->will($this->returnValue(true))
219+
;
220+
$container->expects($this->once())
221+
->method('get')
222+
->with('app.my_controller')
223+
->will($this->returnValue(new ImpossibleConstructController('toto', 'controller')))
224+
;
225+
226+
$resolver = $this->createControllerResolver(null, $container);
227+
228+
$request = Request::create('/');
229+
$request->attributes->set('_controller', 'app.my_controller');
230+
$resolver->getController($request);
231+
}
232+
178233
/**
179234
* @dataProvider getUndefinedControllers
180235
*/
@@ -197,9 +252,9 @@ public function testGetControllerOnNonUndefinedFunction($controller, $exceptionN
197252
public function getUndefinedControllers()
198253
{
199254
return array(
200-
array('foo', \LogicException::class, '/Unable to parse the controller name "foo"\./'),
255+
array('foo', \LogicException::class, '/The controller "foo" do not exists\./'),
201256
array('oof::bar', \InvalidArgumentException::class, '/Class "oof" does not exist\./'),
202-
array('stdClass', \LogicException::class, '/Unable to parse the controller name "stdClass"\./'),
257+
array('stdClass', \LogicException::class, '/The controller "stdClass" do not exists\./'),
203258
array(
204259
'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::bar',
205260
\InvalidArgumentException::class,

0 commit comments

Comments
 (0)