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).
This commit is contained in:
parent
8b54211471
commit
f9b88c6b9a
@ -46,6 +46,7 @@ class ControllerNameParser
|
||||
*/
|
||||
public function parse($controller)
|
||||
{
|
||||
$originalController = $controller;
|
||||
if (3 != count($parts = explode(':', $controller))) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
|
||||
}
|
||||
@ -54,8 +55,24 @@ class ControllerNameParser
|
||||
$controller = str_replace('/', '\\', $controller);
|
||||
$bundles = array();
|
||||
|
||||
// this throws an exception if there is no such bundle
|
||||
foreach ($this->kernel->getBundle($bundle, false) as $b) {
|
||||
try {
|
||||
// this throws an exception if there is no such bundle
|
||||
$allBundles = $this->kernel->getBundle($bundle, false);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$message = sprintf(
|
||||
'The "%s" (from the _controller value "%s") does not exist or is not enabled in your kernel!',
|
||||
$bundle,
|
||||
$originalController
|
||||
);
|
||||
|
||||
if ($alternative = $this->findAlternative($bundle)) {
|
||||
$message .= sprintf(' Did you mean "%s:%s:%s"?', $alternative, $controller, $action);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($message, 0, $e);
|
||||
}
|
||||
|
||||
foreach ($allBundles as $b) {
|
||||
$try = $b->getNamespace().'\\Controller\\'.$controller.'Controller';
|
||||
if (class_exists($try)) {
|
||||
return $try.'::'.$action.'Action';
|
||||
@ -100,4 +117,33 @@ class ControllerNameParser
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unable to find a bundle that defines controller "%s".', $controller));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a bundle that is *similar* to the given bundle name
|
||||
*
|
||||
* @param string $nonExistentBundleName
|
||||
* @return string
|
||||
*/
|
||||
private function findAlternative($nonExistentBundleName)
|
||||
{
|
||||
$bundleNames = array_map(function ($b) {
|
||||
return $b->getName();
|
||||
}, $this->kernel->getBundles());
|
||||
|
||||
$alternative = null;
|
||||
$shortest = null;
|
||||
foreach ($bundleNames as $bundleName) {
|
||||
// if there's a partial match, return it immediately
|
||||
if (false !== strpos($bundleName, $nonExistentBundleName)) {
|
||||
return $bundleName;
|
||||
}
|
||||
|
||||
$lev = levenshtein($nonExistentBundleName, $bundleName);
|
||||
if ($lev <= strlen($nonExistentBundleName) / 3 && ($alternative === null || $lev < $shortest)) {
|
||||
$alternative = $bundleName;
|
||||
}
|
||||
}
|
||||
|
||||
return $alternative;
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +107,36 @@ class ControllerNameParserTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException
|
||||
* @dataProvider getInvalidBundleNameTests
|
||||
*/
|
||||
public function testInvalidBundleName($bundleName, $suggestedBundleName)
|
||||
{
|
||||
$parser = $this->createParser();
|
||||
|
||||
try {
|
||||
$parser->parse($bundleName);
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws a \InvalidArgumentException if the bundle does not exist');
|
||||
|
||||
if (false === $suggestedBundleName) {
|
||||
// make sure we don't have a suggestion
|
||||
$this->assertNotContains('Did you mean', $e->getMessage());
|
||||
} else {
|
||||
$this->assertContains(sprintf('Did you mean "%s"', $suggestedBundleName), $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getInvalidBundleNameTests()
|
||||
{
|
||||
return array(
|
||||
array('FoodBundle:Default:index', 'FooBundle:Default:index'),
|
||||
array('CrazyBundle:Default:index', false),
|
||||
);
|
||||
}
|
||||
|
||||
private function createParser()
|
||||
{
|
||||
$bundles = array(
|
||||
@ -121,6 +151,10 @@ class ControllerNameParserTest extends TestCase
|
||||
->expects($this->any())
|
||||
->method('getBundle')
|
||||
->will($this->returnCallback(function ($bundle) use ($bundles) {
|
||||
if (!isset($bundles[$bundle])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid bundle name "%s"', $bundle));
|
||||
}
|
||||
|
||||
return $bundles[$bundle];
|
||||
}))
|
||||
;
|
||||
|
Reference in New Issue
Block a user