diff --git a/src/SolutionProviders/RouteNotDefinedSolutionProvider.php b/src/SolutionProviders/RouteNotDefinedSolutionProvider.php new file mode 100644 index 00000000..cbaa523e --- /dev/null +++ b/src/SolutionProviders/RouteNotDefinedSolutionProvider.php @@ -0,0 +1,53 @@ +getMessage(), $matches); + } + + public function getSolutions(Throwable $throwable): array + { + preg_match(self::REGEX, $throwable->getMessage(), $matches); + + $missingRoute = $matches[1] ?? null; + + $suggestedRoute = $this->findRelatedRoute($missingRoute); + + if ($suggestedRoute) { + return [ + BaseSolution::create("{$missingRoute} was not defined.") + ->setSolutionDescription("Did you mean `{$suggestedRoute}`?"), + ]; + } + + return [ + BaseSolution::create("{$missingRoute} was not defined.") + ->setSolutionDescription('Are you sure that the route is defined'), + ]; + } + + protected function findRelatedRoute(string $missingRoute): ?string + { + Route::getRoutes()->refreshNameLookups(); + + return StringComparator::findClosestMatch(array_keys(Route::getRoutes()->getRoutesByName()), $missingRoute); + } +} diff --git a/tests/Solutions/RouteNotDefinedSolutionProviderTest.php b/tests/Solutions/RouteNotDefinedSolutionProviderTest.php new file mode 100644 index 00000000..0fd3c8b2 --- /dev/null +++ b/tests/Solutions/RouteNotDefinedSolutionProviderTest.php @@ -0,0 +1,47 @@ +canSolve($this->getRouteNotDefinedException()); + + $this->assertTrue($canSolve); + } + + /** @test */ + public function it_can_recommend_changing_the_route_name() + { + Route::get('/test', 'TestController@typo')->name('test.typo'); + + /** @var \Facade\IgnitionContracts\Solution $solution */ + $solution = app(RouteNotDefinedSolutionProvider::class)->getSolutions($this->getRouteNotDefinedException())[0]; + + $this->assertTrue(Str::contains($solution->getSolutionDescription(), 'Did you mean `test.typo`?')); + } + + /** @test */ + public function it_wont_recommend_another_route_if_the_names_are_too_different() + { + Route::get('/test', 'TestController@typo')->name('test.typo'); + + /** @var \Facade\IgnitionContracts\Solution $solution */ + $solution = app(RouteNotDefinedSolutionProvider::class)->getSolutions($this->getRouteNotDefinedException('test.is-too-different'))[0]; + + $this->assertFalse(Str::contains($solution->getSolutionDescription(), 'Did you mean')); + } + + protected function getRouteNotDefinedException(string $route = 'test.typoo'): InvalidArgumentException + { + return new InvalidArgumentException("Route [{$route}] not defined."); + } +}