8000 Improving the exception message when the bundle name is wrong for the… · symfony/symfony@f9b88c6 · GitHub
[go: up one dir, main page]

Skip to content

Commit f9b88c6

Browse files
committed
Improving the exception message when the bundle name is wrong for the controller in a route
Usually, it is wrong because you've chosen the wrong bundle name in your _controller syntax. But this also tries to imply that you *might* be missing your bundle initialization in AppKernel (though I think this is much much less common).
1 parent 8b54211 commit f9b88c6

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php

Lines changed: 48 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 or is not enabled in your kernel!',
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, 0, $e);
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,33 @@ public function build($controller)
100117

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

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php

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

110+
/**
111+
* @expectedException
112+
* @dataProvider getInvalidBundleNameTests
113+
*/
114+
public function testInvalidBundleName($bundleName, $suggestedBundleName)
115+
{
116+
$parser = $this->createParser();
117+
118+
try {
119+
$parser->parse($bundleName);
120+
} catch (\Exception $e) {
121+
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws a \InvalidArgumentException if the bundle does not exist');
122+
123+
if (false === $suggestedBundleName) {
124+
// make sure we don't have a suggestion
125+
$this->assertNotContains('Did you mean', $e->getMessage());
126+
} else {
127+
$this->assertContains(sprintf('Did you mean "%s"', $suggestedBundleName), $e->getMessage());
128+
}
129+
}
130+
}
131+
132+
public function getInvalidBundleNameTests()
133+
{
134+
return array(
135+
array('FoodBundle:Default:index', 'FooBundle:Default:index'),
136+
array('CrazyBundle:Default:index', false),
137+
);
138+
}
139+
110140
private function createParser()
111141
{
112142
$bundles = array(
@@ -121,6 +151,10 @@ private function createParser()
121151
->expects($this->any())
122152
->method('getBundle')
123153
->will($this->returnCallback(function ($bundle) use ($bundles) {
154+
if (!isset($bundles[$bundle])) {
155+
throw new \InvalidArgumentException(sprintf('Invalid bundle name "%s"', $bundle));
156+
}
157+
124158
return $bundles[$bundle];
125159
}))
126160
;

0 commit comments

Comments
 (0)
0