Skip to content

Commit fd9f738

Browse files
committed
Improving the exception message when the bundle name is wrong for the controller in a route
1 parent 1318914 commit fd9f738

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

Controller/ControllerNameParser.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public function __construct(KernelInterface $kernel)
4646
*/
4747
public function parse($controller)
4848
{
49+
$originalController = $controller;
4950
if (3 != count($parts = explode(':', $controller))) {
5051
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
5152
}
@@ -54,8 +55,24 @@ public function parse($controller)
5455
$controller = str_replace('/', '\\', $controller);
5556
$bundles = array();
5657

57-
// this throws an exception if there is no such bundle
58-
foreach ($this->kernel->getBundle($bundle, false) as $b) {
58+
try {
59+
// this throws an exception if there is no such bundle
60+
$allBundles = $this->kernel->getBundle($bundle, false);
61+
} catch (\InvalidArgumentException $e) {
62+
$message = sprintf(
63+
'The "%s" (from the _controller value "%s") does not exist!',
64+
$bundle,
65+
$originalController
66+
);
67+
68+
if ($alternative = $this->findAlternative($bundle)) {
69+
$message .= sprintf(' Did you mean "%s:%s:%s"?', $alternative, $controller, $action);
70+
}
71+
72+
throw new \InvalidArgumentException($message);
73+
}
74+
75+
foreach ($allBundles as $b) {
5976
$try = $b->getNamespace().'\\Controller\\'.$controller.'Controller';
6077
if (class_exists($try)) {
6178
return $try.'::'.$action.'Action';
@@ -100,4 +117,27 @@ public function build($controller)
100117

101118
throw new \InvalidArgumentException(sprintf('Unable to find a bundle that defines controller "%s".', $controller));
102119
}
120+
121+
private function findAlternative($nonExistentBundleName)
122+
{
123+
$bundleNames = array_map(function ($b) {
124+
return $b->getName();
125+
}, $this->kernel->getBundles());
126+
127+
$alternative = null;
128+
$shortest = null;
129+
foreach ($bundleNames as $bundleName) {
130+
// if there's a partial match, return it immediately
131+
if (false !== strpos($bundleName, $nonExistentBundleName)) {
132+
return $bundleName;
133+
}
134+
135+
$lev = levenshtein($nonExistentBundleName, $bundleName);
136+
if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) {
137+
$alternative = $bundleName;
138+
}
139+
}
140+
141+
return $alternative;
142+
}
103143
}

Tests/Controller/ControllerNameParserTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,18 @@ public function getMissingControllersTest()
107107
);
108108
}
109109

110+
public function testInvalidBundleName()
111+
{
112+
$parser = $this->createParser();
113+
114+
try {
115+
$parser->parse('FooFakeBundle:Fake:index');
116+
$this->fail('->parse() throws a \InvalidArgumentException if the bundle does not exist');
117+
} catch (\Exception $e) {
118+
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws a \InvalidArgumentException if the bundle does not exist');
119+
}
120+
}
121+
110122
private function createParser()
111123
{
112124
$bundles = array(
@@ -121,6 +133,10 @@ private function createParser()
121133
->expects($this->any())
122134
->method('getBundle')
123135
->will($this->returnCallback(function ($bundle) use ($bundles) {
136+
if (!isset($bundles[$bundle])) {
137+
throw new \InvalidArgumentException(sprintf('Invalid bundle name "%s"', $bundle));
138+
}
139+
124140
return $bundles[$bundle];
125141
}))
126142
;

0 commit comments

Comments
 (0)