From 11e4d77f1a88eab579c607f2080d5dcdd1e7ead9 Mon Sep 17 00:00:00 2001 From: Ruben Van Assche Date: Wed, 12 Jun 2024 12:17:40 +0200 Subject: [PATCH 1/4] Solutions refactor --- composer.json | 5 +- phpstan-baseline.neon | 5 - src/Commands/stubs/runnable-solution.stub | 2 +- src/Commands/stubs/solution-provider.stub | 2 +- src/Commands/stubs/solution.stub | 2 +- .../CannotExecuteSolutionForNonLocalIp.php | 6 +- src/Exceptions/InvalidConfig.php | 6 +- src/Exceptions/ViewExceptionWithSolution.php | 4 +- .../Controllers/ExecuteSolutionController.php | 2 +- src/Http/Requests/ExecuteSolutionRequest.php | 6 +- src/IgnitionServiceProvider.php | 4 +- src/Renderers/ErrorPageRenderer.php | 2 +- src/Solutions/GenerateAppKeySolution.php | 46 ------ src/Solutions/LivewireDiscoverSolution.php | 53 ------- .../MakeViewVariableOptionalSolution.php | 142 ------------------ src/Solutions/RunMigrationsSolution.php | 53 ------- .../DefaultDbNameSolutionProvider.php | 35 ----- ...enericLaravelExceptionSolutionProvider.php | 63 -------- ...rectValetDbCredentialsSolutionProvider.php | 67 --------- .../InvalidRouteActionSolutionProvider.php | 79 ---------- .../LazyLoadingViolationSolutionProvider.php | 41 ----- .../MissingAppKeySolutionProvider.php | 25 --- .../MissingColumnSolutionProvider.php | 35 ----- .../MissingImportSolutionProvider.php | 55 ------- ...ssingLivewireComponentSolutionProvider.php | 42 ------ .../MissingMixManifestSolutionProvider.php | 25 --- .../MissingViteManifestSolutionProvider.php | 56 ------- .../OpenAiSolutionProvider.php | 38 ----- .../RouteNotDefinedSolutionProvider.php | 52 ------- ...RunningLaravelDuskInProductionProvider.php | 33 ---- .../SailNetworkSolutionProvider.php | 30 ---- .../SolutionProviderRepository.php | 99 ------------ .../TableNotFoundSolutionProvider.php | 35 ----- ...ndefinedLivewireMethodSolutionProvider.php | 49 ------ ...efinedLivewirePropertySolutionProvider.php | 53 ------- .../UndefinedViewVariableSolutionProvider.php | 110 -------------- ...nknownMariadbCollationSolutionProvider.php | 34 ----- ...UnknownMysql8CollationSolutionProvider.php | 34 ----- .../UnknownValidationSolutionProvider.php | 78 ---------- .../ViewNotFoundSolutionProvider.php | 116 -------------- .../LaravelSolutionTransformer.php | 4 +- .../SuggestCorrectVariableNameSolution.php | 43 ------ src/Solutions/SuggestImportSolution.php | 30 ---- .../SuggestLivewireMethodNameSolution.php | 35 ----- .../SuggestLivewirePropertyNameSolution.php | 35 ----- .../SuggestUsingCorrectDbNameSolution.php | 28 ---- .../SuggestUsingMariadbDatabaseSolution.php | 26 ---- .../SuggestUsingMysql8DatabaseSolution.php | 26 ---- .../UseDefaultValetDbCredentialsSolution.php | 62 -------- src/Support/Composer/Composer.php | 15 -- src/Support/Composer/ComposerClassMap.php | 127 ---------------- src/Support/Composer/FakeComposer.php | 24 --- src/Support/LivewireComponentParser.php | 80 ---------- src/Support/StringComparator.php | 65 -------- src/Views/ViewExceptionMapper.php | 2 +- tests/ExceptionSolutionTest.php | 80 ---------- .../AlwaysFalseSolutionProvider.php | 20 --- .../Exceptions/AlwaysTrueSolutionProvider.php | 20 --- .../ExecuteSolutionControllerTest.php | 2 + ...InvalidRouteActionSolutionProviderTest.php | 48 ------ ...zyLoadingViolationSolutionProviderTest.php | 26 ---- .../MakeViewVariableOptionalSolutionTest.php | 37 ----- .../MergeConflictSolutionProviderTest.php | 20 --- ...ixManifestNotFoundSolutionProviderTest.php | 20 --- .../RouteNotDefinedSolutionProviderTest.php | 36 ----- ...elDuskInProductionSolutionProviderTest.php | 22 --- .../OpenAiSolutionProviderTest.php | 23 --- ...inedLivewireMethodSolutionProviderTest.php | 20 --- ...edLivewirePropertySolutionProviderTest.php | 39 ----- ...wnMariadbCollationSolutionProviderTest.php | 21 --- ...ownMysql8CollationSolutionProviderTest.php | 21 --- .../UndefinedPropertySolutionProviderTest.php | 35 ----- .../UnknownValidationSolutionProviderTest.php | 47 ------ .../ViewNotFoundSolutionProviderTest.php | 37 ----- ...teManifestNotFoundSolutionProviderTest.php | 51 ------- tests/Support/ComposerClassMapTest.php | 12 -- tests/Support/Models/Car.php | 15 -- .../Components/TestLivewireComponent.php | 32 ---- .../Controllers/GitConflictController.php | 21 --- .../stubs/Controllers/TestTypoController.php | 10 -- 80 files changed, 26 insertions(+), 2915 deletions(-) delete mode 100644 src/Solutions/GenerateAppKeySolution.php delete mode 100644 src/Solutions/LivewireDiscoverSolution.php delete mode 100644 src/Solutions/MakeViewVariableOptionalSolution.php delete mode 100644 src/Solutions/RunMigrationsSolution.php delete mode 100644 src/Solutions/SolutionProviders/DefaultDbNameSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/GenericLaravelExceptionSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/IncorrectValetDbCredentialsSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/LazyLoadingViolationSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingAppKeySolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingColumnSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingImportSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingLivewireComponentSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingMixManifestSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/OpenAiSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/RouteNotDefinedSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/RunningLaravelDuskInProductionProvider.php delete mode 100644 src/Solutions/SolutionProviders/SailNetworkSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/SolutionProviderRepository.php delete mode 100644 src/Solutions/SolutionProviders/TableNotFoundSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UndefinedViewVariableSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php delete mode 100644 src/Solutions/SolutionProviders/ViewNotFoundSolutionProvider.php delete mode 100644 src/Solutions/SuggestCorrectVariableNameSolution.php delete mode 100644 src/Solutions/SuggestImportSolution.php delete mode 100644 src/Solutions/SuggestLivewireMethodNameSolution.php delete mode 100644 src/Solutions/SuggestLivewirePropertyNameSolution.php delete mode 100644 src/Solutions/SuggestUsingCorrectDbNameSolution.php delete mode 100644 src/Solutions/SuggestUsingMariadbDatabaseSolution.php delete mode 100644 src/Solutions/SuggestUsingMysql8DatabaseSolution.php delete mode 100644 src/Solutions/UseDefaultValetDbCredentialsSolution.php delete mode 100644 src/Support/Composer/Composer.php delete mode 100644 src/Support/Composer/ComposerClassMap.php delete mode 100644 src/Support/Composer/FakeComposer.php delete mode 100644 src/Support/LivewireComponentParser.php delete mode 100644 src/Support/StringComparator.php delete mode 100644 tests/ExceptionSolutionTest.php delete mode 100644 tests/Exceptions/AlwaysFalseSolutionProvider.php delete mode 100644 tests/Exceptions/AlwaysTrueSolutionProvider.php delete mode 100644 tests/Solutions/InvalidRouteActionSolutionProviderTest.php delete mode 100644 tests/Solutions/LazyLoadingViolationSolutionProviderTest.php delete mode 100644 tests/Solutions/MakeViewVariableOptionalSolutionTest.php delete mode 100644 tests/Solutions/MergeConflictSolutionProviderTest.php delete mode 100644 tests/Solutions/MixManifestNotFoundSolutionProviderTest.php delete mode 100644 tests/Solutions/RouteNotDefinedSolutionProviderTest.php delete mode 100644 tests/Solutions/RunningLaravelDuskInProductionSolutionProviderTest.php delete mode 100644 tests/Solutions/SolutionProviders/OpenAiSolutionProviderTest.php delete mode 100644 tests/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProviderTest.php delete mode 100644 tests/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProviderTest.php delete mode 100644 tests/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProviderTest.php delete mode 100644 tests/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProviderTest.php delete mode 100644 tests/Solutions/UndefinedPropertySolutionProviderTest.php delete mode 100644 tests/Solutions/UnknownValidationSolutionProviderTest.php delete mode 100644 tests/Solutions/ViewNotFoundSolutionProviderTest.php delete mode 100644 tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php delete mode 100644 tests/Support/ComposerClassMapTest.php delete mode 100644 tests/Support/Models/Car.php delete mode 100644 tests/stubs/Components/TestLivewireComponent.php delete mode 100644 tests/stubs/Controllers/GitConflictController.php delete mode 100644 tests/stubs/Controllers/TestTypoController.php diff --git a/composer.json b/composer.json index 8a180171..a4de8d49 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,9 @@ "ext-json": "*", "ext-mbstring": "*", "illuminate/support": "^10.0|^11.0", - "spatie/flare-client-php": "^1.5", - "spatie/ignition": "^1.14", + "spatie/error-solutions": "dev-main", + "spatie/flare-client-php" : "dev-solutions-refactor", + "spatie/ignition": "dev-solutions-refactor", "symfony/console": "^6.2.3|^7.0", "symfony/var-dumper": "^6.2.3|^7.0" }, diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index d1dfb404..6761da23 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -85,11 +85,6 @@ parameters: count: 1 path: src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php - - - message: "#^Parameter \\#1 \\$missingView of method Spatie\\\\LaravelIgnition\\\\Solutions\\\\SolutionProviders\\\\ViewNotFoundSolutionProvider\\:\\:findRelatedView\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/Solutions/SolutionProviders/ViewNotFoundSolutionProvider.php - - message: "#^Argument of an invalid type array\\|DateTimeImmutable\\|int\\|string\\|null supplied for foreach, only iterables are supported\\.$#" count: 1 diff --git a/src/Commands/stubs/runnable-solution.stub b/src/Commands/stubs/runnable-solution.stub index 37e01d79..d098fdb8 100644 --- a/src/Commands/stubs/runnable-solution.stub +++ b/src/Commands/stubs/runnable-solution.stub @@ -2,7 +2,7 @@ namespace DummyNamespace; -use Spatie\Ignition\Contracts\RunnableSolution; +use Spatie\ErrorSolutions\Contracts\RunnableSolution; class DummyClass implements RunnableSolution { diff --git a/src/Commands/stubs/solution-provider.stub b/src/Commands/stubs/solution-provider.stub index ba7e37fb..dc4c9e7b 100644 --- a/src/Commands/stubs/solution-provider.stub +++ b/src/Commands/stubs/solution-provider.stub @@ -2,7 +2,7 @@ namespace DummyNamespace; -use Spatie\Ignition\Contracts\HasSolutionsForThrowable; +use Spatie\ErrorSolutions\Contracts\HasSolutionsForThrowable; use Throwable; class DummyClass implements HasSolutionsForThrowable diff --git a/src/Commands/stubs/solution.stub b/src/Commands/stubs/solution.stub index 00e32f1f..43733bef 100644 --- a/src/Commands/stubs/solution.stub +++ b/src/Commands/stubs/solution.stub @@ -2,7 +2,7 @@ namespace DummyNamespace; -use Spatie\Ignition\Contracts\Solution; +use Spatie\ErrorSolutions\Contracts\Solution; class DummyClass implements Solution { diff --git a/src/Exceptions/CannotExecuteSolutionForNonLocalIp.php b/src/Exceptions/CannotExecuteSolutionForNonLocalIp.php index a3dc82d5..5537d95b 100644 --- a/src/Exceptions/CannotExecuteSolutionForNonLocalIp.php +++ b/src/Exceptions/CannotExecuteSolutionForNonLocalIp.php @@ -2,9 +2,9 @@ namespace Spatie\LaravelIgnition\Exceptions; -use Spatie\Ignition\Contracts\BaseSolution; -use Spatie\Ignition\Contracts\ProvidesSolution; -use Spatie\Ignition\Contracts\Solution; +use Spatie\ErrorSolutions\Contracts\BaseSolution; +use Spatie\ErrorSolutions\Contracts\ProvidesSolution; +use Spatie\ErrorSolutions\Contracts\Solution; use Symfony\Component\HttpKernel\Exception\HttpException; class CannotExecuteSolutionForNonLocalIp extends HttpException implements ProvidesSolution diff --git a/src/Exceptions/InvalidConfig.php b/src/Exceptions/InvalidConfig.php index bb1bc688..c6054e0e 100644 --- a/src/Exceptions/InvalidConfig.php +++ b/src/Exceptions/InvalidConfig.php @@ -4,9 +4,9 @@ use Exception; use Monolog\Level; -use Spatie\Ignition\Contracts\BaseSolution; -use Spatie\Ignition\Contracts\ProvidesSolution; -use Spatie\Ignition\Contracts\Solution; +use Spatie\ErrorSolutions\Contracts\BaseSolution; +use Spatie\ErrorSolutions\Contracts\ProvidesSolution; +use Spatie\ErrorSolutions\Contracts\Solution; class InvalidConfig extends Exception implements ProvidesSolution { diff --git a/src/Exceptions/ViewExceptionWithSolution.php b/src/Exceptions/ViewExceptionWithSolution.php index b2b93649..3f4b899b 100644 --- a/src/Exceptions/ViewExceptionWithSolution.php +++ b/src/Exceptions/ViewExceptionWithSolution.php @@ -2,8 +2,8 @@ namespace Spatie\LaravelIgnition\Exceptions; -use Spatie\Ignition\Contracts\ProvidesSolution; -use Spatie\Ignition\Contracts\Solution; +use Spatie\ErrorSolutions\Contracts\ProvidesSolution; +use Spatie\ErrorSolutions\Contracts\Solution; class ViewExceptionWithSolution extends ViewException implements ProvidesSolution { diff --git a/src/Http/Controllers/ExecuteSolutionController.php b/src/Http/Controllers/ExecuteSolutionController.php index 1878adea..c1dfa27f 100644 --- a/src/Http/Controllers/ExecuteSolutionController.php +++ b/src/Http/Controllers/ExecuteSolutionController.php @@ -3,7 +3,7 @@ namespace Spatie\LaravelIgnition\Http\Controllers; use Illuminate\Foundation\Validation\ValidatesRequests; -use Spatie\Ignition\Contracts\SolutionProviderRepository; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository; use Spatie\LaravelIgnition\Exceptions\CannotExecuteSolutionForNonLocalIp; use Spatie\LaravelIgnition\Http\Requests\ExecuteSolutionRequest; use Spatie\LaravelIgnition\Support\RunnableSolutionsGuard; diff --git a/src/Http/Requests/ExecuteSolutionRequest.php b/src/Http/Requests/ExecuteSolutionRequest.php index 41426957..0f662ce5 100644 --- a/src/Http/Requests/ExecuteSolutionRequest.php +++ b/src/Http/Requests/ExecuteSolutionRequest.php @@ -3,9 +3,9 @@ namespace Spatie\LaravelIgnition\Http\Requests; use Illuminate\Foundation\Http\FormRequest; -use Spatie\Ignition\Contracts\RunnableSolution; -use Spatie\Ignition\Contracts\Solution; -use Spatie\Ignition\Contracts\SolutionProviderRepository; +use Spatie\ErrorSolutions\Contracts\RunnableSolution; +use Spatie\ErrorSolutions\Contracts\Solution; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository; class ExecuteSolutionRequest extends FormRequest { diff --git a/src/IgnitionServiceProvider.php b/src/IgnitionServiceProvider.php index 0f2e2a01..946f3037 100644 --- a/src/IgnitionServiceProvider.php +++ b/src/IgnitionServiceProvider.php @@ -19,7 +19,7 @@ use Spatie\Ignition\Config\FileConfigManager; use Spatie\Ignition\Config\IgnitionConfig; use Spatie\Ignition\Contracts\ConfigManager; -use Spatie\Ignition\Contracts\SolutionProviderRepository as SolutionProviderRepositoryContract; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository as SolutionProviderRepositoryContract; use Spatie\Ignition\Ignition; use Spatie\LaravelIgnition\Commands\SolutionMakeCommand; use Spatie\LaravelIgnition\Commands\SolutionProviderMakeCommand; @@ -34,7 +34,7 @@ use Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder; use Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder; use Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer; -use Spatie\LaravelIgnition\Solutions\SolutionProviders\SolutionProviderRepository; +use Spatie\ErrorSolutions\SolutionProviderRepository; use Spatie\LaravelIgnition\Support\FlareLogHandler; use Spatie\LaravelIgnition\Support\SentReports; use Spatie\LaravelIgnition\Views\ViewExceptionMapper; diff --git a/src/Renderers/ErrorPageRenderer.php b/src/Renderers/ErrorPageRenderer.php index a0dbf1c3..3c0ccffe 100644 --- a/src/Renderers/ErrorPageRenderer.php +++ b/src/Renderers/ErrorPageRenderer.php @@ -4,7 +4,7 @@ use Spatie\FlareClient\Flare; use Spatie\Ignition\Config\IgnitionConfig; -use Spatie\Ignition\Contracts\SolutionProviderRepository; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository; use Spatie\Ignition\Ignition; use Spatie\LaravelIgnition\ContextProviders\LaravelContextProviderDetector; use Spatie\LaravelIgnition\Solutions\SolutionTransformers\LaravelSolutionTransformer; diff --git a/src/Solutions/GenerateAppKeySolution.php b/src/Solutions/GenerateAppKeySolution.php deleted file mode 100644 index b5f50c41..00000000 --- a/src/Solutions/GenerateAppKeySolution.php +++ /dev/null @@ -1,46 +0,0 @@ - 'https://laravel.com/docs/master/installation#configuration', - ]; - } - - public function getSolutionActionDescription(): string - { - return 'Generate your application encryption key using `php artisan key:generate`.'; - } - - public function getRunButtonText(): string - { - return 'Generate app key'; - } - - public function getSolutionDescription(): string - { - return ''; - } - - public function getRunParameters(): array - { - return []; - } - - public function run(array $parameters = []): void - { - Artisan::call('key:generate'); - } -} diff --git a/src/Solutions/LivewireDiscoverSolution.php b/src/Solutions/LivewireDiscoverSolution.php deleted file mode 100644 index 8087209c..00000000 --- a/src/Solutions/LivewireDiscoverSolution.php +++ /dev/null @@ -1,53 +0,0 @@ -customTitle = $customTitle; - } - - public function getSolutionTitle(): string - { - return $this->customTitle; - } - - public function getSolutionDescription(): string - { - return 'You might have forgotten to discover your Livewire components.'; - } - - public function getDocumentationLinks(): array - { - return [ - 'Livewire: Artisan Commands' => 'https://laravel-livewire.com/docs/2.x/artisan-commands', - ]; - } - - public function getRunParameters(): array - { - return []; - } - - public function getSolutionActionDescription(): string - { - return 'You can discover your Livewire components using `php artisan livewire:discover`.'; - } - - public function getRunButtonText(): string - { - return 'Run livewire:discover'; - } - - public function run(array $parameters = []): void - { - app(LivewireComponentsFinder::class)->build(); - } -} diff --git a/src/Solutions/MakeViewVariableOptionalSolution.php b/src/Solutions/MakeViewVariableOptionalSolution.php deleted file mode 100644 index c5bacea5..00000000 --- a/src/Solutions/MakeViewVariableOptionalSolution.php +++ /dev/null @@ -1,142 +0,0 @@ -variableName = $variableName; - - $this->viewFile = $viewFile; - } - - public function getSolutionTitle(): string - { - return "$$this->variableName is undefined"; - } - - public function getDocumentationLinks(): array - { - return []; - } - - public function getSolutionActionDescription(): string - { - $output = [ - 'Make the variable optional in the blade template.', - "Replace `{{ $$this->variableName }}` with `{{ $$this->variableName ?? '' }}`", - ]; - - return implode(PHP_EOL, $output); - } - - public function getRunButtonText(): string - { - return 'Make variable optional'; - } - - public function getSolutionDescription(): string - { - return ''; - } - - public function getRunParameters(): array - { - return [ - 'variableName' => $this->variableName, - 'viewFile' => $this->viewFile, - ]; - } - - /** - * @param array $parameters - * - * @return bool - */ - public function isRunnable(array $parameters = []): bool - { - return $this->makeOptional($this->getRunParameters()) !== false; - } - - /** - * @param array $parameters - * - * @return void - */ - public function run(array $parameters = []): void - { - $output = $this->makeOptional($parameters); - if ($output !== false) { - file_put_contents($parameters['viewFile'], $output); - } - } - - protected function isSafePath(string $path): bool - { - if (! Str::startsWith($path, ['/', './'])) { - return false; - } - if (! Str::endsWith($path, '.blade.php')) { - return false; - } - - return true; - } - - /** - * @param array $parameters - * - * @return bool|string - */ - public function makeOptional(array $parameters = []): bool|string - { - if (! $this->isSafePath($parameters['viewFile'])) { - return false; - } - - $originalContents = (string)file_get_contents($parameters['viewFile']); - $newContents = str_replace('$'.$parameters['variableName'], '$'.$parameters['variableName']." ?? ''", $originalContents); - - $originalTokens = token_get_all(Blade::compileString($originalContents)); - $newTokens = token_get_all(Blade::compileString($newContents)); - - $expectedTokens = $this->generateExpectedTokens($originalTokens, $parameters['variableName']); - - if ($expectedTokens !== $newTokens) { - return false; - } - - return $newContents; - } - - /** - * @param array $originalTokens - * @param string $variableName - * - * @return array - */ - protected function generateExpectedTokens(array $originalTokens, string $variableName): array - { - $expectedTokens = []; - foreach ($originalTokens as $token) { - $expectedTokens[] = $token; - if ($token[0] === T_VARIABLE && $token[1] === '$'.$variableName) { - $expectedTokens[] = [T_WHITESPACE, ' ', $token[2]]; - $expectedTokens[] = [T_COALESCE, '??', $token[2]]; - $expectedTokens[] = [T_WHITESPACE, ' ', $token[2]]; - $expectedTokens[] = [T_CONSTANT_ENCAPSED_STRING, "''", $token[2]]; - } - } - - return $expectedTokens; - } -} diff --git a/src/Solutions/RunMigrationsSolution.php b/src/Solutions/RunMigrationsSolution.php deleted file mode 100644 index da9c6585..00000000 --- a/src/Solutions/RunMigrationsSolution.php +++ /dev/null @@ -1,53 +0,0 @@ -customTitle = $customTitle; - } - - public function getSolutionTitle(): string - { - return $this->customTitle; - } - - public function getSolutionDescription(): string - { - return 'You might have forgotten to run your database migrations.'; - } - - public function getDocumentationLinks(): array - { - return [ - 'Database: Running Migrations docs' => 'https://laravel.com/docs/master/migrations#running-migrations', - ]; - } - - public function getRunParameters(): array - { - return []; - } - - public function getSolutionActionDescription(): string - { - return 'You can try to run your migrations using `php artisan migrate`.'; - } - - public function getRunButtonText(): string - { - return 'Run migrations'; - } - - public function run(array $parameters = []): void - { - Artisan::call('migrate'); - } -} diff --git a/src/Solutions/SolutionProviders/DefaultDbNameSolutionProvider.php b/src/Solutions/SolutionProviders/DefaultDbNameSolutionProvider.php deleted file mode 100644 index 01b91e4f..00000000 --- a/src/Solutions/SolutionProviders/DefaultDbNameSolutionProvider.php +++ /dev/null @@ -1,35 +0,0 @@ -getCode() !== self::MYSQL_UNKNOWN_DATABASE_CODE) { - return false; - } - - if (! in_array(env('DB_DATABASE'), ['homestead', 'laravel'])) { - return false; - } - - return true; - } - - public function getSolutions(Throwable $throwable): array - { - return [new SuggestUsingCorrectDbNameSolution()]; - } -} diff --git a/src/Solutions/SolutionProviders/GenericLaravelExceptionSolutionProvider.php b/src/Solutions/SolutionProviders/GenericLaravelExceptionSolutionProvider.php deleted file mode 100644 index 11084383..00000000 --- a/src/Solutions/SolutionProviders/GenericLaravelExceptionSolutionProvider.php +++ /dev/null @@ -1,63 +0,0 @@ -getSolutionTexts($throwable)); - } - - public function getSolutions(Throwable $throwable): array - { - if (! $texts = $this->getSolutionTexts($throwable)) { - return []; - } - - $solution = BaseSolution::create($texts['title']) - ->setSolutionDescription($texts['description']) - ->setDocumentationLinks($texts['links']); - - return ([$solution]); - } - - /** - * @param \Throwable $throwable - * - * @return array|null - */ - protected function getSolutionTexts(Throwable $throwable) : ?array - { - foreach ($this->getSupportedExceptions() as $supportedClass => $texts) { - if ($throwable instanceof $supportedClass) { - return $texts; - } - } - - return null; - } - - /** @return array */ - protected function getSupportedExceptions(): array - { - $majorVersion = LaravelVersion::major(); - - return - [ - BroadcastException::class => [ - 'title' => 'Here are some links that might help solve this problem', - 'description' => '', - 'links' => [ - 'Laravel docs on authentication' => "https://laravel.com/docs/{$majorVersion}.x/authentication", - ], - ], - ]; - } -} diff --git a/src/Solutions/SolutionProviders/IncorrectValetDbCredentialsSolutionProvider.php b/src/Solutions/SolutionProviders/IncorrectValetDbCredentialsSolutionProvider.php deleted file mode 100644 index 568ceaba..00000000 --- a/src/Solutions/SolutionProviders/IncorrectValetDbCredentialsSolutionProvider.php +++ /dev/null @@ -1,67 +0,0 @@ -isAccessDeniedCode($throwable->getCode())) { - return false; - } - - if (! $this->envFileExists()) { - return false; - } - - if (! $this->isValetInstalled()) { - return false; - } - - if ($this->usingCorrectDefaultCredentials()) { - return false; - } - - return true; - } - - public function getSolutions(Throwable $throwable): array - { - return [new UseDefaultValetDbCredentialsSolution()]; - } - - protected function envFileExists(): bool - { - return file_exists(base_path('.env')); - } - - protected function isAccessDeniedCode(string $code): bool - { - return $code === static::MYSQL_ACCESS_DENIED_CODE; - } - - protected function isValetInstalled(): bool - { - return file_exists('/usr/local/bin/valet'); - } - - protected function usingCorrectDefaultCredentials(): bool - { - return env('DB_USERNAME') === 'root' && env('DB_PASSWORD') === ''; - } -} diff --git a/src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php b/src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php deleted file mode 100644 index 6b4706fb..00000000 --- a/src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php +++ /dev/null @@ -1,79 +0,0 @@ -getMessage(), $matches)) { - return false; - } - - return Str::startsWith($throwable->getMessage(), 'Invalid route action: '); - } - - public function getSolutions(Throwable $throwable): array - { - preg_match(self::REGEX, $throwable->getMessage(), $matches); - - $invalidController = $matches[1] ?? null; - - $suggestedController = $this->findRelatedController($invalidController); - - if ($suggestedController === $invalidController) { - return [ - BaseSolution::create("`{$invalidController}` is not invokable.") - ->setSolutionDescription("The controller class `{$invalidController}` is not invokable. Did you forget to add the `__invoke` method or is the controller's method missing in your routes file?"), - ]; - } - - if ($suggestedController) { - return [ - BaseSolution::create("`{$invalidController}` was not found.") - ->setSolutionDescription("Controller class `{$invalidController}` for one of your routes was not found. Did you mean `{$suggestedController}`?"), - ]; - } - - return [ - BaseSolution::create("`{$invalidController}` was not found.") - ->setSolutionDescription("Controller class `{$invalidController}` for one of your routes was not found. Are you sure this controller exists and is imported correctly?"), - ]; - } - - protected function findRelatedController(string $invalidController): ?string - { - $composerClassMap = app(ComposerClassMap::class); - - $controllers = collect($composerClassMap->listClasses()) - ->filter(function (string $file, string $fqcn) { - return Str::endsWith($fqcn, 'Controller'); - }) - ->mapWithKeys(function (string $file, string $fqcn) { - return [$fqcn => class_basename($fqcn)]; - }) - ->toArray(); - - $basenameMatch = StringComparator::findClosestMatch($controllers, $invalidController, 4); - - $controllers = array_flip($controllers); - - $fqcnMatch = StringComparator::findClosestMatch($controllers, $invalidController, 4); - - return $fqcnMatch ?? $basenameMatch; - } -} diff --git a/src/Solutions/SolutionProviders/LazyLoadingViolationSolutionProvider.php b/src/Solutions/SolutionProviders/LazyLoadingViolationSolutionProvider.php deleted file mode 100644 index 079c4d46..00000000 --- a/src/Solutions/SolutionProviders/LazyLoadingViolationSolutionProvider.php +++ /dev/null @@ -1,41 +0,0 @@ -getPrevious()) { - return false; - } - - return $previous instanceof LazyLoadingViolationException; - } - - public function getSolutions(Throwable $throwable): array - { - $majorVersion = LaravelVersion::major(); - - return [BaseSolution::create( - 'Lazy loading was disabled to detect N+1 problems' - ) - ->setSolutionDescription( - 'Either avoid lazy loading the relation or allow lazy loading.' - ) - ->setDocumentationLinks([ - 'Read the docs on preventing lazy loading' => "https://laravel.com/docs/{$majorVersion}.x/eloquent-relationships#preventing-lazy-loading", - 'Watch a video on how to deal with the N+1 problem' => 'https://www.youtube.com/watch?v=ZE7KBeraVpc', - ]),]; - } -} diff --git a/src/Solutions/SolutionProviders/MissingAppKeySolutionProvider.php b/src/Solutions/SolutionProviders/MissingAppKeySolutionProvider.php deleted file mode 100644 index b621edb1..00000000 --- a/src/Solutions/SolutionProviders/MissingAppKeySolutionProvider.php +++ /dev/null @@ -1,25 +0,0 @@ -getMessage() === 'No application encryption key has been specified.'; - } - - public function getSolutions(Throwable $throwable): array - { - return [new GenerateAppKeySolution()]; - } -} diff --git a/src/Solutions/SolutionProviders/MissingColumnSolutionProvider.php b/src/Solutions/SolutionProviders/MissingColumnSolutionProvider.php deleted file mode 100644 index ec980ec1..00000000 --- a/src/Solutions/SolutionProviders/MissingColumnSolutionProvider.php +++ /dev/null @@ -1,35 +0,0 @@ -isBadTableErrorCode($throwable->getCode()); - } - - protected function isBadTableErrorCode(string $code): bool - { - return $code === static::MYSQL_BAD_FIELD_CODE; - } - - public function getSolutions(Throwable $throwable): array - { - return [new RunMigrationsSolution('A column was not found')]; - } -} diff --git a/src/Solutions/SolutionProviders/MissingImportSolutionProvider.php b/src/Solutions/SolutionProviders/MissingImportSolutionProvider.php deleted file mode 100644 index 31d1fc6e..00000000 --- a/src/Solutions/SolutionProviders/MissingImportSolutionProvider.php +++ /dev/null @@ -1,55 +0,0 @@ -getMessage(), $matches)) { - return false; - } - - $class = $matches[1]; - - $this->composerClassMap = new ComposerClassMap(); - - $this->search($class); - - return ! is_null($this->foundClass); - } - - /** - * @param \Throwable $throwable - * - * @return array - */ - public function getSolutions(Throwable $throwable): array - { - if (is_null($this->foundClass)) { - return []; - } - - return [new SuggestImportSolution($this->foundClass)]; - } - - protected function search(string $missingClass): void - { - $this->foundClass = $this->composerClassMap->searchClassMap($missingClass); - - if (is_null($this->foundClass)) { - $this->foundClass = $this->composerClassMap->searchPsrMaps($missingClass); - } - } -} diff --git a/src/Solutions/SolutionProviders/MissingLivewireComponentSolutionProvider.php b/src/Solutions/SolutionProviders/MissingLivewireComponentSolutionProvider.php deleted file mode 100644 index 9b9bf57b..00000000 --- a/src/Solutions/SolutionProviders/MissingLivewireComponentSolutionProvider.php +++ /dev/null @@ -1,42 +0,0 @@ -livewireIsInstalled()) { - return false; - } - - if (! $throwable instanceof ComponentNotFoundException) { - return false; - } - - return true; - } - - public function getSolutions(Throwable $throwable): array - { - return [new LivewireDiscoverSolution('A Livewire component was not found')]; - } - - public function livewireIsInstalled(): bool - { - if (! class_exists(ComponentNotFoundException::class)) { - return false; - } - if (! class_exists(LivewireComponentsFinder::class)) { - return false; - } - - return true; - } -} diff --git a/src/Solutions/SolutionProviders/MissingMixManifestSolutionProvider.php b/src/Solutions/SolutionProviders/MissingMixManifestSolutionProvider.php deleted file mode 100644 index 8b1d14de..00000000 --- a/src/Solutions/SolutionProviders/MissingMixManifestSolutionProvider.php +++ /dev/null @@ -1,25 +0,0 @@ -getMessage(), 'Mix manifest not found'); - } - - public function getSolutions(Throwable $throwable): array - { - return [ - BaseSolution::create('Missing Mix Manifest File') - ->setSolutionDescription('Did you forget to run `npm install && npm run dev`?'), - ]; - } -} diff --git a/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php b/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php deleted file mode 100644 index dd02fda4..00000000 --- a/src/Solutions/SolutionProviders/MissingViteManifestSolutionProvider.php +++ /dev/null @@ -1,56 +0,0 @@ - */ - protected array $links = [ - 'Asset bundling with Vite' => 'https://laravel.com/docs/9.x/vite#running-vite', - ]; - - public function canSolve(Throwable $throwable): bool - { - return Str::startsWith($throwable->getMessage(), 'Vite manifest not found'); - } - - public function getSolutions(Throwable $throwable): array - { - return [ - $this->getSolution(), - ]; - } - - public function getSolution(): Solution - { - /** @var string */ - $baseCommand = collect([ - 'pnpm-lock.yaml' => 'pnpm', - 'yarn.lock' => 'yarn', - ])->first(fn ($_, $lockfile) => file_exists(base_path($lockfile)), 'npm run'); - - return app()->environment('local') - ? $this->getLocalSolution($baseCommand) - : $this->getProductionSolution($baseCommand); - } - - protected function getLocalSolution(string $baseCommand): Solution - { - return BaseSolution::create('Start the development server') - ->setSolutionDescription("Run `{$baseCommand} dev` in your terminal and refresh the page.") - ->setDocumentationLinks($this->links); - } - - protected function getProductionSolution(string $baseCommand): Solution - { - return BaseSolution::create('Build the production assets') - ->setSolutionDescription("Run `{$baseCommand} build` in your deployment script.") - ->setDocumentationLinks($this->links); - } -} diff --git a/src/Solutions/SolutionProviders/OpenAiSolutionProvider.php b/src/Solutions/SolutionProviders/OpenAiSolutionProvider.php deleted file mode 100644 index c1eac517..00000000 --- a/src/Solutions/SolutionProviders/OpenAiSolutionProvider.php +++ /dev/null @@ -1,38 +0,0 @@ -store(config('cache.default')), - cacheTtlInSeconds: 60, - applicationType: 'Laravel ' . Str::before(app()->version(), '.'), - applicationPath: base_path(), - ); - - return $solutionProvider->getSolutions($throwable); - } -} diff --git a/src/Solutions/SolutionProviders/RouteNotDefinedSolutionProvider.php b/src/Solutions/SolutionProviders/RouteNotDefinedSolutionProvider.php deleted file mode 100644 index 7e1a0e9d..00000000 --- a/src/Solutions/SolutionProviders/RouteNotDefinedSolutionProvider.php +++ /dev/null @@ -1,52 +0,0 @@ -getMessage(), $matches); - } - - public function getSolutions(Throwable $throwable): array - { - preg_match(self::REGEX, $throwable->getMessage(), $matches); - - $missingRoute = $matches[1] ?? ''; - - $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/src/Solutions/SolutionProviders/RunningLaravelDuskInProductionProvider.php b/src/Solutions/SolutionProviders/RunningLaravelDuskInProductionProvider.php deleted file mode 100644 index 94053de6..00000000 --- a/src/Solutions/SolutionProviders/RunningLaravelDuskInProductionProvider.php +++ /dev/null @@ -1,33 +0,0 @@ -getMessage() === 'It is unsafe to run Dusk in production.'; - } - - public function getSolutions(Throwable $throwable): array - { - return [ - BaseSolution::create() - ->setSolutionTitle('Laravel Dusk should not be run in production.') - ->setSolutionDescription('Install the dependencies with the `--no-dev` flag.'), - - BaseSolution::create() - ->setSolutionTitle('Laravel Dusk can be run in other environments.') - ->setSolutionDescription('Consider setting the `APP_ENV` to something other than `production` like `local` for example.'), - ]; - } -} diff --git a/src/Solutions/SolutionProviders/SailNetworkSolutionProvider.php b/src/Solutions/SolutionProviders/SailNetworkSolutionProvider.php deleted file mode 100644 index 0f0b2390..00000000 --- a/src/Solutions/SolutionProviders/SailNetworkSolutionProvider.php +++ /dev/null @@ -1,30 +0,0 @@ -runningInConsole() - && str_contains($throwable->getMessage(), 'php_network_getaddresses') - && file_exists(base_path('vendor/bin/sail')) - && file_exists(base_path('docker-compose.yml')) - && env('LARAVEL_SAIL') === null; - } - - public function getSolutions(Throwable $throwable): array - { - return [ - BaseSolution::create('Network address not found') - ->setSolutionDescription('Did you mean to use `sail artisan`?') - ->setDocumentationLinks([ - 'Sail: Executing Artisan Commands' => 'https://laravel.com/docs/sail#executing-artisan-commands', - ]), - ]; - } -} diff --git a/src/Solutions/SolutionProviders/SolutionProviderRepository.php b/src/Solutions/SolutionProviders/SolutionProviderRepository.php deleted file mode 100644 index 0e5f1eff..00000000 --- a/src/Solutions/SolutionProviders/SolutionProviderRepository.php +++ /dev/null @@ -1,99 +0,0 @@ - $solutionProviders - */ - protected Collection $solutionProviders; - - /** - * @param array $solutionProviders - */ - public function __construct(array $solutionProviders = []) - { - $this->solutionProviders = Collection::make($solutionProviders); - } - - public function registerSolutionProvider(string $solutionProviderClass): SolutionProviderRepositoryContract - { - $this->solutionProviders->push($solutionProviderClass); - - return $this; - } - - public function registerSolutionProviders(array $solutionProviderClasses): SolutionProviderRepositoryContract - { - $this->solutionProviders = $this->solutionProviders->merge($solutionProviderClasses); - - return $this; - } - - public function getSolutionsForThrowable(Throwable $throwable): array - { - $solutions = []; - - if ($throwable instanceof Solution) { - $solutions[] = $throwable; - } - - if ($throwable instanceof ProvidesSolution) { - $solutions[] = $throwable->getSolution(); - } - - /** @phpstan-ignore-next-line */ - $providedSolutions = $this->solutionProviders - ->filter(function (string $solutionClass) { - if (! in_array(HasSolutionsForThrowable::class, class_implements($solutionClass) ?: [])) { - return false; - } - - if (in_array($solutionClass, config('ignition.ignored_solution_providers', []))) { - return false; - } - - return true; - }) - ->map(fn (string $solutionClass) => app($solutionClass)) - ->filter(function (HasSolutionsForThrowable $solutionProvider) use ($throwable) { - try { - return $solutionProvider->canSolve($throwable); - } catch (Throwable $e) { - return false; - } - }) - ->map(function (HasSolutionsForThrowable $solutionProvider) use ($throwable) { - try { - return $solutionProvider->getSolutions($throwable); - } catch (Throwable $e) { - return []; - } - }) - ->flatten() - ->toArray(); - - return array_merge($solutions, $providedSolutions); - } - - public function getSolutionForClass(string $solutionClass): ?Solution - { - if (! class_exists($solutionClass)) { - return null; - } - - if (! in_array(Solution::class, class_implements($solutionClass) ?: [])) { - return null; - } - - return app($solutionClass); - } -} diff --git a/src/Solutions/SolutionProviders/TableNotFoundSolutionProvider.php b/src/Solutions/SolutionProviders/TableNotFoundSolutionProvider.php deleted file mode 100644 index 7cdc393c..00000000 --- a/src/Solutions/SolutionProviders/TableNotFoundSolutionProvider.php +++ /dev/null @@ -1,35 +0,0 @@ -isBadTableErrorCode($throwable->getCode()); - } - - protected function isBadTableErrorCode(string $code): bool - { - return $code === static::MYSQL_BAD_TABLE_CODE; - } - - public function getSolutions(Throwable $throwable): array - { - return [new RunMigrationsSolution('A table was not found')]; - } -} diff --git a/src/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProvider.php b/src/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProvider.php deleted file mode 100644 index b4245eb3..00000000 --- a/src/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProvider.php +++ /dev/null @@ -1,49 +0,0 @@ - $methodName, 'component' => $component] = $this->getMethodAndComponent($throwable); - - if ($methodName === null || $component === null) { - return []; - } - - $parsed = LivewireComponentParser::create($component); - - return $parsed->getMethodNamesLike($methodName) - ->map(function (string $suggested) use ($parsed, $methodName) { - return new SuggestLivewireMethodNameSolution( - $methodName, - $parsed->getComponentClass(), - $suggested - ); - }) - ->toArray(); - } - - /** @return array */ - protected function getMethodAndComponent(Throwable $throwable): array - { - preg_match_all('/\[([\d\w\-_]*)\]/m', $throwable->getMessage(), $matches, PREG_SET_ORDER); - - return [ - 'methodName' => $matches[0][1] ?? null, - 'component' => $matches[1][1] ?? null, - ]; - } -} diff --git a/src/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProvider.php b/src/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProvider.php deleted file mode 100644 index 7642abfa..00000000 --- a/src/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProvider.php +++ /dev/null @@ -1,53 +0,0 @@ - $variable, 'component' => $component] = $this->getMethodAndComponent($throwable); - - if ($variable === null || $component === null) { - return []; - } - - $parsed = LivewireComponentParser::create($component); - - return $parsed->getPropertyNamesLike($variable) - ->map(function (string $suggested) use ($parsed, $variable) { - return new SuggestLivewirePropertyNameSolution( - $variable, - $parsed->getComponentClass(), - '$'.$suggested - ); - }) - ->toArray(); - } - - /** - * @param \Throwable $throwable - * - * @return array - */ - protected function getMethodAndComponent(Throwable $throwable): array - { - preg_match_all('/\[([\d\w\-_\$]*)\]/m', $throwable->getMessage(), $matches, PREG_SET_ORDER, 0); - - return [ - 'variable' => $matches[0][1] ?? null, - 'component' => $matches[1][1] ?? null, - ]; - } -} diff --git a/src/Solutions/SolutionProviders/UndefinedViewVariableSolutionProvider.php b/src/Solutions/SolutionProviders/UndefinedViewVariableSolutionProvider.php deleted file mode 100644 index e21f69cf..00000000 --- a/src/Solutions/SolutionProviders/UndefinedViewVariableSolutionProvider.php +++ /dev/null @@ -1,110 +0,0 @@ -getNameAndView($throwable) !== null; - } - - public function getSolutions(Throwable $throwable): array - { - $solutions = []; - - /** @phpstan-ignore-next-line */ - extract($this->getNameAndView($throwable)); - - if (! isset($variableName)) { - return []; - } - - if (isset($viewFile)) { - /** @phpstan-ignore-next-line */ - $solutions = $this->findCorrectVariableSolutions($throwable, $variableName, $viewFile); - $solutions[] = $this->findOptionalVariableSolution($variableName, $viewFile); - } - - - return $solutions; - } - - /** - * @param \Spatie\LaravelIgnition\Exceptions\ViewException $throwable - * @param string $variableName - * @param string $viewFile - * - * @return array - */ - protected function findCorrectVariableSolutions( - ViewException $throwable, - string $variableName, - string $viewFile - ): array { - return collect($throwable->getViewData()) - ->map(function ($value, $key) use ($variableName) { - similar_text($variableName, $key, $percentage); - - return ['match' => $percentage, 'value' => $value]; - }) - ->sortByDesc('match') - ->filter(fn ($var) => $var['match'] > 40) - ->keys() - ->map(fn ($suggestion) => new SuggestCorrectVariableNameSolution($variableName, $viewFile, $suggestion)) - ->map(function ($solution) { - return $solution->isRunnable() - ? $solution - : BaseSolution::create($solution->getSolutionTitle()) - ->setSolutionDescription($solution->getSolutionDescription()); - }) - ->toArray(); - } - - protected function findOptionalVariableSolution(string $variableName, string $viewFile): Solution - { - $optionalSolution = new MakeViewVariableOptionalSolution($variableName, $viewFile); - - return $optionalSolution->isRunnable() - ? $optionalSolution - : BaseSolution::create($optionalSolution->getSolutionTitle()) - ->setSolutionDescription($optionalSolution->getSolutionDescription()); - } - - /** - * @param \Throwable $throwable - * - * @return array|null - */ - protected function getNameAndView(Throwable $throwable): ?array - { - $pattern = '/Undefined variable:? (.*?) \(View: (.*?)\)/'; - - preg_match($pattern, $throwable->getMessage(), $matches); - - if (count($matches) === 3) { - [, $variableName, $viewFile] = $matches; - $variableName = ltrim($variableName, '$'); - - return compact('variableName', 'viewFile'); - } - - return null; - } -} diff --git a/src/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProvider.php b/src/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProvider.php deleted file mode 100644 index 1ae563fa..00000000 --- a/src/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProvider.php +++ /dev/null @@ -1,34 +0,0 @@ -getCode() !== self::MYSQL_UNKNOWN_COLLATION_CODE) { - return false; - } - - return str_contains( - $throwable->getMessage(), - 'Unknown collation: \'utf8mb4_uca1400_ai_ci\'' - ); - } - - public function getSolutions(Throwable $throwable): array - { - return [new SuggestUsingMariadbDatabaseSolution()]; - } -} diff --git a/src/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProvider.php b/src/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProvider.php deleted file mode 100644 index 717f6199..00000000 --- a/src/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProvider.php +++ /dev/null @@ -1,34 +0,0 @@ -getCode() !== self::MYSQL_UNKNOWN_COLLATION_CODE) { - return false; - } - - return str_contains( - $throwable->getMessage(), - 'Unknown collation: \'utf8mb4_0900_ai_ci\'' - ); - } - - public function getSolutions(Throwable $throwable): array - { - return [new SuggestUsingMysql8DatabaseSolution()]; - } -} diff --git a/src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php b/src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php deleted file mode 100644 index 653db0f2..00000000 --- a/src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php +++ /dev/null @@ -1,78 +0,0 @@ -validate(?!(Attribute|UsingCustomRule))[A-Z][a-zA-Z]+)/m'; - - public function canSolve(Throwable $throwable): bool - { - if (! $throwable instanceof BadMethodCallException) { - return false; - } - - return ! is_null($this->getMethodFromExceptionMessage($throwable->getMessage())); - } - - public function getSolutions(Throwable $throwable): array - { - return [ - BaseSolution::create() - ->setSolutionTitle('Unknown Validation Rule') - ->setSolutionDescription($this->getSolutionDescription($throwable)), - ]; - } - - protected function getSolutionDescription(Throwable $throwable): string - { - $method = (string)$this->getMethodFromExceptionMessage($throwable->getMessage()); - - $possibleMethod = StringComparator::findSimilarText( - $this->getAvailableMethods()->toArray(), - $method - ); - - if (empty($possibleMethod)) { - return ''; - } - - $rule = Str::snake(str_replace('validate', '', $possibleMethod)); - - return "Did you mean `{$rule}` ?"; - } - - protected function getMethodFromExceptionMessage(string $message): ?string - { - if (! preg_match(self::REGEX, $message, $matches)) { - return null; - } - - return $matches['method']; - } - - protected function getAvailableMethods(): Collection - { - $class = new ReflectionClass(Validator::class); - - $extensions = Collection::make((app('validator')->make([], []))->extensions) - ->keys() - ->map(fn (string $extension) => 'validate'.Str::studly($extension)); - - return Collection::make($class->getMethods()) - ->filter(fn (ReflectionMethod $method) => preg_match('/(validate(?!(Attribute|UsingCustomRule))[A-Z][a-zA-Z]+)/', $method->name)) - ->map(fn (ReflectionMethod $method) => $method->name) - ->merge($extensions); - } -} diff --git a/src/Solutions/SolutionProviders/ViewNotFoundSolutionProvider.php b/src/Solutions/SolutionProviders/ViewNotFoundSolutionProvider.php deleted file mode 100644 index 63f46b2b..00000000 --- a/src/Solutions/SolutionProviders/ViewNotFoundSolutionProvider.php +++ /dev/null @@ -1,116 +0,0 @@ -getMessage(), $matches); - } - - public function getSolutions(Throwable $throwable): array - { - preg_match(self::REGEX, $throwable->getMessage(), $matches); - - $missingView = $matches[1] ?? null; - - $suggestedView = $this->findRelatedView($missingView); - - if ($suggestedView) { - return [ - BaseSolution::create() - ->setSolutionTitle("{$missingView} was not found.") - ->setSolutionDescription("Did you mean `{$suggestedView}`?"), - ]; - } - - return [ - BaseSolution::create() - ->setSolutionTitle("{$missingView} was not found.") - ->setSolutionDescription('Are you sure the view exists and is a `.blade.php` file?'), - ]; - } - - protected function findRelatedView(string $missingView): ?string - { - $views = $this->getAllViews(); - - return StringComparator::findClosestMatch($views, $missingView); - } - - /** @return array */ - protected function getAllViews(): array - { - /** @var \Illuminate\View\FileViewFinder $fileViewFinder */ - $fileViewFinder = View::getFinder(); - - $extensions = $fileViewFinder->getExtensions(); - - $viewsForHints = collect($fileViewFinder->getHints()) - ->flatMap(function ($paths, string $namespace) use ($extensions) { - $paths = Arr::wrap($paths); - - return collect($paths) - ->flatMap(fn (string $path) => $this->getViewsInPath($path, $extensions)) - ->map(fn (string $view) => "{$namespace}::{$view}") - ->toArray(); - }); - - $viewsForViewPaths = collect($fileViewFinder->getPaths()) - ->flatMap(fn (string $path) => $this->getViewsInPath($path, $extensions)); - - return $viewsForHints->merge($viewsForViewPaths)->toArray(); - } - - /** - * @param string $path - * @param array $extensions - * - * @return array - */ - protected function getViewsInPath(string $path, array $extensions): array - { - $filePatterns = array_map(fn (string $extension) => "*.{$extension}", $extensions); - - $extensionsWithDots = array_map(fn (string $extension) => ".{$extension}", $extensions); - - $files = (new Finder()) - ->in($path) - ->files(); - - foreach ($filePatterns as $filePattern) { - $files->name($filePattern); - } - - $views = []; - - foreach ($files as $file) { - if ($file instanceof SplFileInfo) { - $view = $file->getRelativePathname(); - $view = str_replace($extensionsWithDots, '', $view); - $view = str_replace('/', '.', $view); - $views[] = $view; - } - } - - return $views; - } -} diff --git a/src/Solutions/SolutionTransformers/LaravelSolutionTransformer.php b/src/Solutions/SolutionTransformers/LaravelSolutionTransformer.php index e9bfdce2..e2acf305 100644 --- a/src/Solutions/SolutionTransformers/LaravelSolutionTransformer.php +++ b/src/Solutions/SolutionTransformers/LaravelSolutionTransformer.php @@ -2,8 +2,8 @@ namespace Spatie\LaravelIgnition\Solutions\SolutionTransformers; -use Spatie\Ignition\Contracts\RunnableSolution; -use Spatie\Ignition\Solutions\SolutionTransformer; +use Spatie\ErrorSolutions\Contracts\RunnableSolution; +use Spatie\ErrorSolutions\Solutions\SolutionTransformer; use Spatie\LaravelIgnition\Http\Controllers\ExecuteSolutionController; use Throwable; diff --git a/src/Solutions/SuggestCorrectVariableNameSolution.php b/src/Solutions/SuggestCorrectVariableNameSolution.php deleted file mode 100644 index 29024b6c..00000000 --- a/src/Solutions/SuggestCorrectVariableNameSolution.php +++ /dev/null @@ -1,43 +0,0 @@ -variableName = $variableName; - - $this->viewFile = $viewFile; - - $this->suggested = $suggested; - } - - public function getSolutionTitle(): string - { - return 'Possible typo $'.$this->variableName; - } - - public function getDocumentationLinks(): array - { - return []; - } - - public function getSolutionDescription(): string - { - return "Did you mean `$$this->suggested`?"; - } - - public function isRunnable(): bool - { - return false; - } -} diff --git a/src/Solutions/SuggestImportSolution.php b/src/Solutions/SuggestImportSolution.php deleted file mode 100644 index 3228d4af..00000000 --- a/src/Solutions/SuggestImportSolution.php +++ /dev/null @@ -1,30 +0,0 @@ -class = $class; - } - - public function getSolutionTitle(): string - { - return 'A class import is missing'; - } - - public function getSolutionDescription(): string - { - return 'You have a missing class import. Try importing this class: `'.$this->class.'`.'; - } - - public function getDocumentationLinks(): array - { - return []; - } -} diff --git a/src/Solutions/SuggestLivewireMethodNameSolution.php b/src/Solutions/SuggestLivewireMethodNameSolution.php deleted file mode 100644 index 243e465b..00000000 --- a/src/Solutions/SuggestLivewireMethodNameSolution.php +++ /dev/null @@ -1,35 +0,0 @@ -componentClass}::{$this->methodName}`"; - } - - public function getDocumentationLinks(): array - { - return []; - } - - public function getSolutionDescription(): string - { - return "Did you mean `{$this->componentClass}::{$this->suggested}`?"; - } - - public function isRunnable(): bool - { - return false; - } -} diff --git a/src/Solutions/SuggestLivewirePropertyNameSolution.php b/src/Solutions/SuggestLivewirePropertyNameSolution.php deleted file mode 100644 index a957a4e2..00000000 --- a/src/Solutions/SuggestLivewirePropertyNameSolution.php +++ /dev/null @@ -1,35 +0,0 @@ -variableName}"; - } - - public function getDocumentationLinks(): array - { - return []; - } - - public function getSolutionDescription(): string - { - return "Did you mean `$this->suggested`?"; - } - - public function isRunnable(): bool - { - return false; - } -} diff --git a/src/Solutions/SuggestUsingCorrectDbNameSolution.php b/src/Solutions/SuggestUsingCorrectDbNameSolution.php deleted file mode 100644 index 7763abbe..00000000 --- a/src/Solutions/SuggestUsingCorrectDbNameSolution.php +++ /dev/null @@ -1,28 +0,0 @@ - */ - public function getDocumentationLinks(): array - { - return [ - 'Database: Getting Started docs' => 'https://laravel.com/docs/master/database#configuration', - ]; - } -} diff --git a/src/Solutions/SuggestUsingMariadbDatabaseSolution.php b/src/Solutions/SuggestUsingMariadbDatabaseSolution.php deleted file mode 100644 index 6a80202e..00000000 --- a/src/Solutions/SuggestUsingMariadbDatabaseSolution.php +++ /dev/null @@ -1,26 +0,0 @@ - */ - public function getDocumentationLinks(): array - { - return [ - 'Database: Getting Started docs' => 'https://laravel.com/docs/master/database#configuration', - ]; - } -} diff --git a/src/Solutions/SuggestUsingMysql8DatabaseSolution.php b/src/Solutions/SuggestUsingMysql8DatabaseSolution.php deleted file mode 100644 index e991092e..00000000 --- a/src/Solutions/SuggestUsingMysql8DatabaseSolution.php +++ /dev/null @@ -1,26 +0,0 @@ - */ - public function getDocumentationLinks(): array - { - return [ - 'Database: Getting Started docs' => 'https://laravel.com/docs/master/database#configuration', - ]; - } -} diff --git a/src/Solutions/UseDefaultValetDbCredentialsSolution.php b/src/Solutions/UseDefaultValetDbCredentialsSolution.php deleted file mode 100644 index 2f57ba26..00000000 --- a/src/Solutions/UseDefaultValetDbCredentialsSolution.php +++ /dev/null @@ -1,62 +0,0 @@ -ensureLineExists('DB_USERNAME', 'root'); - $this->ensureLineExists('DB_PASSWORD', ''); - } - - protected function ensureLineExists(string $key, string $value): void - { - $envPath = base_path('.env'); - - $envLines = array_map(fn (string $envLine) => Str::startsWith($envLine, $key) - ? "{$key}={$value}".PHP_EOL - : $envLine, file($envPath) ?: []); - - file_put_contents($envPath, implode('', $envLines)); - } - - public function getRunParameters(): array - { - return []; - } - - public function getDocumentationLinks(): array - { - return [ - 'Valet documentation' => 'https://laravel.com/docs/master/valet', - ]; - } - - public function getSolutionDescription(): string - { - return 'You seem to be using Valet, but the .env file does not contain the right default database credentials.'; - } -} diff --git a/src/Support/Composer/Composer.php b/src/Support/Composer/Composer.php deleted file mode 100644 index 3a420583..00000000 --- a/src/Support/Composer/Composer.php +++ /dev/null @@ -1,15 +0,0 @@ - */ - public function getClassMap(): array; - - /** @return array */ - public function getPrefixes(): array; - - /** @return array */ - public function getPrefixesPsr4(): array; -} diff --git a/src/Support/Composer/ComposerClassMap.php b/src/Support/Composer/ComposerClassMap.php deleted file mode 100644 index 3138fdb1..00000000 --- a/src/Support/Composer/ComposerClassMap.php +++ /dev/null @@ -1,127 +0,0 @@ -composer = file_exists($autoloaderPath) - ? require $autoloaderPath - : new FakeComposer(); - - $this->basePath = app_path(); - } - - /** @return array */ - public function listClasses(): array - { - $classes = $this->composer->getClassMap(); - - return array_merge($classes, $this->listClassesInPsrMaps()); - } - - public function searchClassMap(string $missingClass): ?string - { - foreach ($this->composer->getClassMap() as $fqcn => $file) { - $basename = basename($file, '.php'); - - if ($basename === $missingClass) { - return $fqcn; - } - } - - return null; - } - - /** @return array */ - public function listClassesInPsrMaps(): array - { - // TODO: This is incorrect. Doesnt list all fqcns. Need to parse namespace? e.g. App\LoginController is wrong - - $prefixes = array_merge( - $this->composer->getPrefixes(), - $this->composer->getPrefixesPsr4() - ); - - $classes = []; - - foreach ($prefixes as $namespace => $directories) { - foreach ($directories as $directory) { - if (file_exists($directory)) { - $files = (new Finder) - ->in($directory) - ->files() - ->name('*.php'); - - foreach ($files as $file) { - if ($file instanceof SplFileInfo) { - $fqcn = $this->getFullyQualifiedClassNameFromFile($namespace, $file); - - $classes[$fqcn] = $file->getRelativePathname(); - } - } - } - } - } - - return $classes; - } - - public function searchPsrMaps(string $missingClass): ?string - { - $prefixes = array_merge( - $this->composer->getPrefixes(), - $this->composer->getPrefixesPsr4() - ); - - foreach ($prefixes as $namespace => $directories) { - foreach ($directories as $directory) { - if (file_exists($directory)) { - $files = (new Finder) - ->in($directory) - ->files() - ->name('*.php'); - - foreach ($files as $file) { - if ($file instanceof SplFileInfo) { - $basename = basename($file->getRelativePathname(), '.php'); - - if ($basename === $missingClass) { - return $namespace . basename($file->getRelativePathname(), '.php'); - } - } - } - } - } - } - - return null; - } - - protected function getFullyQualifiedClassNameFromFile(string $rootNamespace, SplFileInfo $file): string - { - $class = trim(str_replace($this->basePath, '', (string)$file->getRealPath()), DIRECTORY_SEPARATOR); - - $class = str_replace( - [DIRECTORY_SEPARATOR, 'App\\'], - ['\\', app()->getNamespace()], - ucfirst(Str::replaceLast('.php', '', $class)) - ); - - return $rootNamespace . $class; - } -} diff --git a/src/Support/Composer/FakeComposer.php b/src/Support/Composer/FakeComposer.php deleted file mode 100644 index 50118c4d..00000000 --- a/src/Support/Composer/FakeComposer.php +++ /dev/null @@ -1,24 +0,0 @@ - */ - public function getClassMap(): array - { - return []; - } - - /** @return array */ - public function getPrefixes(): array - { - return []; - } - - /** @return array */ - public function getPrefixesPsr4(): array - { - return []; - } -} diff --git a/src/Support/LivewireComponentParser.php b/src/Support/LivewireComponentParser.php deleted file mode 100644 index 5a7607f6..00000000 --- a/src/Support/LivewireComponentParser.php +++ /dev/null @@ -1,80 +0,0 @@ -componentClass = app(LivewireManager::class)->getClass($this->componentAlias); - $this->reflectionClass = new ReflectionClass($this->componentClass); - } - - public function getComponentClass(): string - { - return $this->componentClass; - } - - public function getPropertyNamesLike(string $similar): Collection - { - $properties = collect($this->reflectionClass->getProperties(ReflectionProperty::IS_PUBLIC)) - // @phpstan-ignore-next-line - ->reject(fn (ReflectionProperty $reflectionProperty) => $reflectionProperty->class !== $this->reflectionClass->name) - ->map(fn (ReflectionProperty $reflectionProperty) => $reflectionProperty->name); - - $computedProperties = collect($this->reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC)) - // @phpstan-ignore-next-line - ->reject(fn (ReflectionMethod $reflectionMethod) => $reflectionMethod->class !== $this->reflectionClass->name) - ->filter(fn (ReflectionMethod $reflectionMethod) => str_starts_with($reflectionMethod->name, 'get') && str_ends_with($reflectionMethod->name, 'Property')) - ->map(fn (ReflectionMethod $reflectionMethod) => lcfirst(Str::of($reflectionMethod->name)->after('get')->before('Property'))); - - return $this->filterItemsBySimilarity( - $properties->merge($computedProperties), - $similar - ); - } - - public function getMethodNamesLike(string $similar): Collection - { - $methods = collect($this->reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC)) - // @phpstan-ignore-next-line - ->reject(fn (ReflectionMethod $reflectionMethod) => $reflectionMethod->class !== $this->reflectionClass->name) - ->map(fn (ReflectionMethod $reflectionMethod) => $reflectionMethod->name); - - return $this->filterItemsBySimilarity($methods, $similar); - } - - protected function filterItemsBySimilarity(Collection $items, string $similar): Collection - { - return $items - ->map(function (string $name) use ($similar) { - similar_text($similar, $name, $percentage); - - return ['match' => $percentage, 'value' => $name]; - }) - ->sortByDesc('match') - ->filter(function (array $item) { - return $item['match'] > 40; - }) - ->map(function (array $item) { - return $item['value']; - }) - ->values(); - } -} diff --git a/src/Support/StringComparator.php b/src/Support/StringComparator.php deleted file mode 100644 index a1256040..00000000 --- a/src/Support/StringComparator.php +++ /dev/null @@ -1,65 +0,0 @@ - $strings - * @param string $input - * @param int $sensitivity - * - * @return string|null - */ - public static function findClosestMatch(array $strings, string $input, int $sensitivity = 4): ?string - { - $closestDistance = -1; - - $closestMatch = null; - - foreach ($strings as $string) { - $levenshteinDistance = levenshtein($input, $string); - - if ($levenshteinDistance === 0) { - $closestMatch = $string; - $closestDistance = 0; - - break; - } - - if ($levenshteinDistance <= $closestDistance || $closestDistance < 0) { - $closestMatch = $string; - $closestDistance = $levenshteinDistance; - } - } - - if ($closestDistance <= $sensitivity) { - return $closestMatch; - } - - return null; - } - - /** - * @param array $strings - * @param string $input - * - * @return string|null - */ - public static function findSimilarText(array $strings, string $input): ?string - { - if (empty($strings)) { - return null; - } - - return Collection::make($strings) - ->sortByDesc(function (string $string) use ($input) { - similar_text($input, $string, $percentage); - - return $percentage; - }) - ->first(); - } -} diff --git a/src/Views/ViewExceptionMapper.php b/src/Views/ViewExceptionMapper.php index 38727766..af648c96 100644 --- a/src/Views/ViewExceptionMapper.php +++ b/src/Views/ViewExceptionMapper.php @@ -10,7 +10,7 @@ use Illuminate\View\ViewException; use ReflectionClass; use ReflectionProperty; -use Spatie\Ignition\Contracts\ProvidesSolution; +use Spatie\ErrorSolutions\Contracts\ProvidesSolution; use Spatie\LaravelIgnition\Exceptions\ViewException as IgnitionViewException; use Spatie\LaravelIgnition\Exceptions\ViewExceptionWithSolution; use Throwable; diff --git a/tests/ExceptionSolutionTest.php b/tests/ExceptionSolutionTest.php deleted file mode 100644 index 84c37bfc..00000000 --- a/tests/ExceptionSolutionTest.php +++ /dev/null @@ -1,80 +0,0 @@ -registerSolutionProvider(AlwaysTrueSolutionProvider::class); - $repository->registerSolutionProvider(AlwaysFalseSolutionProvider::class); - - $solutions = $repository->getSolutionsForThrowable(new Exception()); - - $this->assertNotNull($solutions); - expect($solutions)->toHaveCount(1); - expect($solutions[0] instanceof BaseSolution)->toBeTrue(); -}); - -it('returns possible solutions when registered together', function () { - $repository = new SolutionProviderRepository(); - - $repository->registerSolutionProviders([ - AlwaysTrueSolutionProvider::class, - AlwaysFalseSolutionProvider::class, - ]); - - $solutions = $repository->getSolutionsForThrowable(new Exception()); - - $this->assertNotNull($solutions); - expect($solutions)->toHaveCount(1); - expect($solutions[0] instanceof BaseSolution)->toBeTrue(); -}); - -it('can suggest bad method call exceptions', function () { - if (version_compare(app()->version(), '5.6.3', '<')) { - $this->markTestSkipped('Laravel version < 5.6.3 do not support bad method call solutions'); - } - - try { - collect([])->faltten(); - } catch (Exception $exception) { - $solution = new BadMethodCallSolutionProvider(); - - expect($solution->canSolve($exception))->toBeTrue(); - } -}); - -it('can propose a solution for bad method call exceptions on collections', function () { - try { - collect([])->frist(fn ($item) => null); - } catch (Exception $exception) { - $solution = new BadMethodCallSolutionProvider(); - - expect($solution->getSolutions($exception)[0]->getSolutionDescription())->toBe('Did you mean Illuminate\Support\Collection::first() ?'); - } -}); - -it('can propose a solution for bad method call exceptions on models', function () { - try { - $user = new User(); - $user->sarve(); - } catch (Exception $exception) { - $solution = new BadMethodCallSolutionProvider(); - - expect($solution->getSolutions($exception)[0]->getSolutionDescription())->toBe('Did you mean Illuminate\Foundation\Auth\User::save() ?'); - } -}); - -it('can propose a solution for missing app key exceptions', function () { - $exception = new RuntimeException('No application encryption key has been specified.'); - - $solution = new MissingAppKeySolutionProvider(); - - expect($solution->getSolutions($exception)[0]->getSolutionActionDescription())->toBe('Generate your application encryption key using `php artisan key:generate`.'); -}); diff --git a/tests/Exceptions/AlwaysFalseSolutionProvider.php b/tests/Exceptions/AlwaysFalseSolutionProvider.php deleted file mode 100644 index 508f2b0f..00000000 --- a/tests/Exceptions/AlwaysFalseSolutionProvider.php +++ /dev/null @@ -1,20 +0,0 @@ -set('app.debug', true); config()->set('ignition.enable_runnable_solutions', true); + $this->withoutExceptionHandling(); + $this ->postJson(route('ignition.executeSolution'), solutionPayload()) ->assertSuccessful(); diff --git a/tests/Solutions/InvalidRouteActionSolutionProviderTest.php b/tests/Solutions/InvalidRouteActionSolutionProviderTest.php deleted file mode 100644 index 4c607c0d..00000000 --- a/tests/Solutions/InvalidRouteActionSolutionProviderTest.php +++ /dev/null @@ -1,48 +0,0 @@ -bind( - ComposerClassMap::class, - function () { - return new ComposerClassMap(__DIR__.'/../../vendor/autoload.php'); - } - ); -}); - -it('can solve the exception', function () { - $canSolve = app(InvalidRouteActionSolutionProvider::class)->canSolve(getInvalidRouteActionException()); - - expect($canSolve)->toBeTrue(); -}); - -it('can recommend changing the routes method', function () { - Route::get('/test', TestTypoController::class); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(InvalidRouteActionSolutionProvider::class)->getSolutions(getInvalidRouteActionException())[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean `TestTypoController`'))->toBeTrue(); -}); - -it('wont recommend another controller class if the names are too different', function () { - Route::get('/test', TestTypoController::class); - - $invalidController = 'UnrelatedTestTypoController'; - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(InvalidRouteActionSolutionProvider::class)->getSolutions(getInvalidRouteActionException($invalidController))[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean `TestTypoController`'))->toBeFalse(); -}); - -// Helpers -function getInvalidRouteActionException(string $controller = 'TestTypooController'): UnexpectedValueException -{ - return new UnexpectedValueException("Invalid route action: [{$controller}]"); -} diff --git a/tests/Solutions/LazyLoadingViolationSolutionProviderTest.php b/tests/Solutions/LazyLoadingViolationSolutionProviderTest.php deleted file mode 100644 index ec4af202..00000000 --- a/tests/Solutions/LazyLoadingViolationSolutionProviderTest.php +++ /dev/null @@ -1,26 +0,0 @@ -canSolve(new LazyLoadingViolationException(new User(), 'posts')); - - expect($canSolve)->toBeTrue(); - - $canSolve = app(LazyLoadingViolationSolutionProvider::class) - ->canSolve(new Exception('generic exception')); - - expect($canSolve)->toBeFalse(); -}); - -// Helpers -function it_can_provide_the_solution_for_lazy_loading_exceptions() -{ - $solutions = app(LazyLoadingViolationSolutionProvider::class) - ->getSolutions(new LazyLoadingViolationException(new User(), 'posts')); - - expect($solutions)->toHaveCount(1); -} diff --git a/tests/Solutions/MakeViewVariableOptionalSolutionTest.php b/tests/Solutions/MakeViewVariableOptionalSolutionTest.php deleted file mode 100644 index 195ae02c..00000000 --- a/tests/Solutions/MakeViewVariableOptionalSolutionTest.php +++ /dev/null @@ -1,37 +0,0 @@ -bind( - ComposerClassMap::class, - function () { - return new ComposerClassMap(__DIR__.'/../../vendor/autoload.php'); - } - ); -}); - -it('does not open scheme paths', function () { - $solution = getSolutionForPath('php://filter/resource=./tests/stubs/views/blade-exception.blade.php'); - expect($solution->isRunnable())->toBeFalse(); -}); - -it('does open relative paths', function () { - $solution = getSolutionForPath('./tests/stubs/views/blade-exception.blade.php'); - expect($solution->isRunnable())->toBeTrue(); -}); - -it('does not open other extensions', function () { - $solution = getSolutionForPath('./tests/stubs/views/php-exception.php'); - expect($solution->isRunnable())->toBeFalse(); -}); - -// Helpers -function getSolutionForPath($path): MakeViewVariableOptionalSolution -{ - return new MakeViewVariableOptionalSolution('notSet', $path); -} diff --git a/tests/Solutions/MergeConflictSolutionProviderTest.php b/tests/Solutions/MergeConflictSolutionProviderTest.php deleted file mode 100644 index fb5a8a8d..00000000 --- a/tests/Solutions/MergeConflictSolutionProviderTest.php +++ /dev/null @@ -1,20 +0,0 @@ -canSolve($exception); - - expect($canSolve)->toBeTrue(); -}); diff --git a/tests/Solutions/MixManifestNotFoundSolutionProviderTest.php b/tests/Solutions/MixManifestNotFoundSolutionProviderTest.php deleted file mode 100644 index e1edc92b..00000000 --- a/tests/Solutions/MixManifestNotFoundSolutionProviderTest.php +++ /dev/null @@ -1,20 +0,0 @@ -canSolve(new Exception('Mix manifest not found.')); - - expect($canSolve)->toBeTrue(); -}); - -it('can recommend running npm install and npm run dev', function () { - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(MissingMixManifestSolutionProvider::class) - ->getSolutions(new Exception('Mix manifest not found.'))[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you forget to run `npm install && npm run dev`?'))->toBeTrue(); -}); diff --git a/tests/Solutions/RouteNotDefinedSolutionProviderTest.php b/tests/Solutions/RouteNotDefinedSolutionProviderTest.php deleted file mode 100644 index c180c1b1..00000000 --- a/tests/Solutions/RouteNotDefinedSolutionProviderTest.php +++ /dev/null @@ -1,36 +0,0 @@ -canSolve(getRouteNotDefinedException()); - - expect($canSolve)->toBeTrue(); -}); - -it('can recommend changing the route name', function () { - Route::get('/test', 'TestController@typo')->name('test.typo'); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(RouteNotDefinedSolutionProvider::class)->getSolutions(getRouteNotDefinedException())[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean `test.typo`?'))->toBeTrue(); -}); - -it('wont recommend another route if the names are too different', function () { - Route::get('/test', 'TestController@typo')->name('test.typo'); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(RouteNotDefinedSolutionProvider::class)->getSolutions(getRouteNotDefinedException('test.is-too-different'))[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean'))->toBeFalse(); -}); - -// Helpers -function getRouteNotDefinedException(string $route = 'test.typoo'): RouteNotFoundException -{ - return new RouteNotFoundException("Route [{$route}] not defined."); -} diff --git a/tests/Solutions/RunningLaravelDuskInProductionSolutionProviderTest.php b/tests/Solutions/RunningLaravelDuskInProductionSolutionProviderTest.php deleted file mode 100644 index acf01960..00000000 --- a/tests/Solutions/RunningLaravelDuskInProductionSolutionProviderTest.php +++ /dev/null @@ -1,22 +0,0 @@ -canSolve($exception); - [$first_solution, $second_solution] = app(RunningLaravelDuskInProductionProvider::class)->getSolutions($exception); - - expect($canSolve)->toBeTrue(); - expect('Laravel Dusk should not be run in production.')->toBe($first_solution->getSolutionTitle()); - expect('Install the dependencies with the `--no-dev` flag.')->toBe($first_solution->getSolutionDescription()); - - expect('Laravel Dusk can be run in other environments.')->toBe($second_solution->getSolutionTitle()); - expect('Consider setting the `APP_ENV` to something other than `production` like `local` for example.')->toBe($second_solution->getSolutionDescription()); -}); - -// Helpers -function generate_dusk_exception(): Exception -{ - return new Exception('It is unsafe to run Dusk in production.'); -} diff --git a/tests/Solutions/SolutionProviders/OpenAiSolutionProviderTest.php b/tests/Solutions/SolutionProviders/OpenAiSolutionProviderTest.php deleted file mode 100644 index 77d19304..00000000 --- a/tests/Solutions/SolutionProviders/OpenAiSolutionProviderTest.php +++ /dev/null @@ -1,23 +0,0 @@ -markTestSkipped('Cannot run AI test'); - - return; - } - - config()->set('ignition.open_ai_key', env('OPEN_API_KEY')); - - $solutionProvider = new OpenAiSolutionProvider(); - - $exception = new Exception('T_PAAMAYIM_NEKUDOTAYIM expected'); - - $solutions = $solutionProvider->getSolutions($exception); - - $solution = $solutions[0]; - - expect($solution->getSolutionDescription())->toBeString(); -}); diff --git a/tests/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProviderTest.php b/tests/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProviderTest.php deleted file mode 100644 index 70b3e0da..00000000 --- a/tests/Solutions/SolutionProviders/UndefinedLivewireMethodSolutionProviderTest.php +++ /dev/null @@ -1,20 +0,0 @@ -addAlias('test-livewire-component', TestLivewireComponent::class); - - $exception = new MethodNotFoundException('chnge', 'test-livewire-component'); - - $canSolve = app(UndefinedLivewireMethodSolutionProvider::class)->canSolve($exception); - [$solution] = app(UndefinedLivewireMethodSolutionProvider::class)->getSolutions($exception); - - expect($canSolve)->toBeTrue(); - - expect($solution->getSolutionTitle())->toBe('Possible typo `Spatie\LaravelIgnition\Tests\stubs\Components\TestLivewireComponent::chnge`'); - expect($solution->getSolutionDescription())->toBe('Did you mean `Spatie\LaravelIgnition\Tests\stubs\Components\TestLivewireComponent::change`?'); -})->skip(LIVEWIRE_VERSION_3, 'Missing Livewire 3 support.'); diff --git a/tests/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProviderTest.php b/tests/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProviderTest.php deleted file mode 100644 index c6254f42..00000000 --- a/tests/Solutions/SolutionProviders/UndefinedLivewirePropertySolutionProviderTest.php +++ /dev/null @@ -1,39 +0,0 @@ -addAlias('test-livewire-component', TestLivewireComponent::class); - - $exception = new PropertyNotFoundException('compted', 'test-livewire-component'); - - $canSolve = app(UndefinedLivewirePropertySolutionProvider::class)->canSolve($exception); - [$solution] = app(UndefinedLivewirePropertySolutionProvider::class)->getSolutions($exception); - - expect($canSolve)->toBeTrue(); - - expect($solution->getSolutionTitle())->toBe('Possible typo $compted'); - expect($solution->getSolutionDescription())->toBe('Did you mean `$computed`?'); -}); - -// Helpers -function it_can_solve_an_unknown_livewire_property() -{ - FakeLivewireManager::setUp()->addAlias('test-livewire-component', TestLivewireComponent::class); - - $exception = new PropertyNotFoundException('strng', 'test-livewire-component'); - - $canSolve = app(UndefinedLivewirePropertySolutionProvider::class)->canSolve($exception); - [$firstSolution, $secondSolution] = app(UndefinedLivewirePropertySolutionProvider::class)->getSolutions($exception); - - expect($canSolve)->toBeTrue(); - - expect($firstSolution->getSolutionTitle())->toBe('Possible typo $strng'); - expect($firstSolution->getSolutionDescription())->toBe('Did you mean `$string`?'); - - expect($secondSolution->getSolutionTitle())->toBe('Possible typo $strng'); - expect($secondSolution->getSolutionDescription())->toBe('Did you mean `$stringable`?'); -} diff --git a/tests/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProviderTest.php b/tests/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProviderTest.php deleted file mode 100644 index 2bafd725..00000000 --- a/tests/Solutions/SolutionProviders/UnknownMariadbCollationSolutionProviderTest.php +++ /dev/null @@ -1,21 +0,0 @@ -getSolutions($exception); - - $solution = $solutions[0]; - - expect($solution->getSolutionDescription())->toBe("Laravel 11 changed the default collation for MySQL and MariaDB. It seems you are trying to use the MariaDB collation `utf8mb4_uca1400_ai_ci` with a MySQL database.\n\nEdit the `.env` file and use the correct database in the `DB_CONNECTION` key."); -}); diff --git a/tests/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProviderTest.php b/tests/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProviderTest.php deleted file mode 100644 index b6710024..00000000 --- a/tests/Solutions/SolutionProviders/UnknownMysql8CollationSolutionProviderTest.php +++ /dev/null @@ -1,21 +0,0 @@ -getSolutions($exception); - - $solution = $solutions[0]; - - expect($solution->getSolutionDescription())->toBe("Laravel 11 changed the default collation for MySQL and MariaDB. It seems you are trying to use the MySQL 8 collation `utf8mb4_0900_ai_ci` with a MariaDB or MySQL 5.7 database.\n\nEdit the `.env` file and use the correct database in the `DB_CONNECTION` key."); -}); diff --git a/tests/Solutions/UndefinedPropertySolutionProviderTest.php b/tests/Solutions/UndefinedPropertySolutionProviderTest.php deleted file mode 100644 index 11de96b2..00000000 --- a/tests/Solutions/UndefinedPropertySolutionProviderTest.php +++ /dev/null @@ -1,35 +0,0 @@ -canSolve(getUndefinedPropertyException()); - - expect($canSolve)->toBeTrue(); -}); - -it('cannot solve an undefined property exception when there is no similar property', function () { - $canSolve = app(UndefinedPropertySolutionProvider::class)->canSolve(getUndefinedPropertyException('balance')); - - expect($canSolve)->toBeFalse(); -}); - -it('can recommend a property name when there is a similar property', function () { - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(UndefinedPropertySolutionProvider::class)->getSolutions(getUndefinedPropertyException())[0]; - - expect($solution->getSolutionDescription())->toEqual('Did you mean Spatie\LaravelIgnition\Tests\Support\Models\Car::$color ?'); -}); - -it('cannot recommend a property name when there is no similar property', function () { - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(UndefinedPropertySolutionProvider::class)->getSolutions(getUndefinedPropertyException('balance'))[0]; - - expect($solution->getSolutionDescription())->toEqual(''); -}); - -// Helpers -function getUndefinedPropertyException(string $property = 'colro'): ErrorException -{ - return new ErrorException("Undefined property: Spatie\LaravelIgnition\Tests\Support\Models\Car::$$property "); -} diff --git a/tests/Solutions/UnknownValidationSolutionProviderTest.php b/tests/Solutions/UnknownValidationSolutionProviderTest.php deleted file mode 100644 index 3558edc1..00000000 --- a/tests/Solutions/UnknownValidationSolutionProviderTest.php +++ /dev/null @@ -1,47 +0,0 @@ -canSolve(getBadMethodCallException()); - - expect($canSolve)->toBeTrue(); -}); - -it('can recommend changing the rule', function (string $invalidRule, string $recommendedRule) { - Validator::extend('foo', fn ($attribute, $value, $parameters, $validator) => $value == 'foo'); - - Validator::extendImplicit('bar_a', fn ($attribute, $value, $parameters, $validator) => $value == 'bar'); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(UnknownValidationSolutionProvider::class)->getSolutions(getBadMethodCallException($invalidRule))[0]; - - expect($solution->getSolutionDescription())->toEqual("Did you mean `{$recommendedRule}` ?"); - expect($solution->getSolutionTitle())->toEqual('Unknown Validation Rule'); -})->with('rulesProvider'); - -// Datasets -dataset('rulesProvider', [ - ['number', 'numeric'], - ['unik', 'unique'], - ['fooo', 'foo'], - ['bar_b', 'bar_a'], -]); - -// Helpers -function getBadMethodCallException(string $rule = 'number'): BadMethodCallException -{ - $default = new BadMethodCallException('Not a validation rule exception!'); - - try { - $validator = Validator::make(['number' => 10], ['number' => "{$rule}"]); - $validator->validate(); - - return $default; - } catch (BadMethodCallException $badMethodCallException) { - return $badMethodCallException; - } catch (Exception $exception) { - return $default; - } -} diff --git a/tests/Solutions/ViewNotFoundSolutionProviderTest.php b/tests/Solutions/ViewNotFoundSolutionProviderTest.php deleted file mode 100644 index 7e760501..00000000 --- a/tests/Solutions/ViewNotFoundSolutionProviderTest.php +++ /dev/null @@ -1,37 +0,0 @@ -canSolve(getViewNotFoundException()); - - expect($canSolve)->toBeTrue(); -}); - -it('can recommend changing a typo in the view name', function () { - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(ViewNotFoundSolutionProvider::class)->getSolutions(getViewNotFoundException())[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean `php-exception`?'))->toBeTrue(); -}); - -it('wont recommend another controller class if the names are too different', function () { - $unknownView = 'a-view-that-doesnt-exist-and-is-not-a-typo'; - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(ViewNotFoundSolutionProvider::class)->getSolutions(getViewNotFoundException($unknownView))[0]; - - expect(Str::contains($solution->getSolutionDescription(), 'Did you mean'))->toBeFalse(); -}); - -// Helpers -function getViewNotFoundException(string $view = 'phpp-exceptionn'): InvalidArgumentException -{ - return new InvalidArgumentException("View [{$view}] not found."); -} diff --git a/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php b/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php deleted file mode 100644 index 4ce05353..00000000 --- a/tests/Solutions/ViteManifestNotFoundSolutionProviderTest.php +++ /dev/null @@ -1,51 +0,0 @@ -canSolve(new Exception('Vite manifest not found at: public/build/manifest.json')); - - expect($canSolve)->toBeTrue(); -}); - -it('recommends running `npm run dev` in a local environment', function () { - app()->detectEnvironment(fn () => 'local'); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(MissingViteManifestSolutionProvider::class) - ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; - - - expect(Str::contains($solution->getSolutionDescription(), 'Run `npm run dev` in your terminal and refresh the page.'))->toBeTrue(); -}); - -it('recommends running `npm run build` in a production environment', function () { - app()->detectEnvironment(fn () => 'production'); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(MissingViteManifestSolutionProvider::class) - ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; - - - expect(Str::contains($solution->getSolutionDescription(), 'Run `npm run build` in your deployment script.'))->toBeTrue(); -}); - -it('detects the package manager and adapts the recommended command', function (string $lockfile, string $command) { - app()->detectEnvironment(fn () => 'local'); - - file_put_contents(base_path($lockfile), ''); - - /** @var \Spatie\Ignition\Contracts\Solution $solution */ - $solution = app(MissingViteManifestSolutionProvider::class) - ->getSolutions(new Exception('Vite manifest not found at: public/build/manifest.json'))[0]; - - expect(Str::contains($solution->getSolutionDescription(), "Run `{$command}` in your terminal and refresh the page."))->toBeTrue(); - - unlink(base_path($lockfile)); -})->with([ - ['pnpm-lock.yaml', 'pnpm dev'], - ['yarn.lock', 'yarn dev'], - ['package-lock.json', 'npm run dev'], -]); diff --git a/tests/Support/ComposerClassMapTest.php b/tests/Support/ComposerClassMapTest.php deleted file mode 100644 index df7712af..00000000 --- a/tests/Support/ComposerClassMapTest.php +++ /dev/null @@ -1,12 +0,0 @@ -listClasses())->toBe([]); - expect($classMap->listClassesInPsrMaps())->toBe([]); - expect($classMap->searchClassMap('SomeClass'))->toBeNull(); - expect($classMap->searchPsrMaps('SomeClass'))->toBeNull(); -}); diff --git a/tests/Support/Models/Car.php b/tests/Support/Models/Car.php deleted file mode 100644 index f81128c7..00000000 --- a/tests/Support/Models/Car.php +++ /dev/null @@ -1,15 +0,0 @@ -brand = $brand; - $this->color = $color; - } -} diff --git a/tests/stubs/Components/TestLivewireComponent.php b/tests/stubs/Components/TestLivewireComponent.php deleted file mode 100644 index 98ff76d6..00000000 --- a/tests/stubs/Components/TestLivewireComponent.php +++ /dev/null @@ -1,32 +0,0 @@ -string = $title; - } - - public function render() - { - return 'nowp'; - } - - public function change() - { - $this->string = 'Ruben'; - } - - public function getComputedProperty() - { - return 'bla'; - } -} diff --git a/tests/stubs/Controllers/GitConflictController.php b/tests/stubs/Controllers/GitConflictController.php deleted file mode 100644 index 997e54f0..00000000 --- a/tests/stubs/Controllers/GitConflictController.php +++ /dev/null @@ -1,21 +0,0 @@ - 'hello', - 'someOtherVariable' => 'thingy123', - ======= - 'someOtherVariable' => 'something', - >>>>>>> another - } -} diff --git a/tests/stubs/Controllers/TestTypoController.php b/tests/stubs/Controllers/TestTypoController.php deleted file mode 100644 index a538da77..00000000 --- a/tests/stubs/Controllers/TestTypoController.php +++ /dev/null @@ -1,10 +0,0 @@ - Date: Wed, 12 Jun 2024 10:18:06 +0000 Subject: [PATCH 2/4] Fix styling --- src/IgnitionServiceProvider.php | 4 ++-- src/Renderers/ErrorPageRenderer.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IgnitionServiceProvider.php b/src/IgnitionServiceProvider.php index 946f3037..ebef3554 100644 --- a/src/IgnitionServiceProvider.php +++ b/src/IgnitionServiceProvider.php @@ -14,12 +14,13 @@ use Laravel\Octane\Events\TickReceived; use Monolog\Level; use Monolog\Logger; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository as SolutionProviderRepositoryContract; +use Spatie\ErrorSolutions\SolutionProviderRepository; use Spatie\FlareClient\Flare; use Spatie\FlareClient\FlareMiddleware\AddSolutions; use Spatie\Ignition\Config\FileConfigManager; use Spatie\Ignition\Config\IgnitionConfig; use Spatie\Ignition\Contracts\ConfigManager; -use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository as SolutionProviderRepositoryContract; use Spatie\Ignition\Ignition; use Spatie\LaravelIgnition\Commands\SolutionMakeCommand; use Spatie\LaravelIgnition\Commands\SolutionProviderMakeCommand; @@ -34,7 +35,6 @@ use Spatie\LaravelIgnition\Recorders\LogRecorder\LogRecorder; use Spatie\LaravelIgnition\Recorders\QueryRecorder\QueryRecorder; use Spatie\LaravelIgnition\Renderers\IgnitionExceptionRenderer; -use Spatie\ErrorSolutions\SolutionProviderRepository; use Spatie\LaravelIgnition\Support\FlareLogHandler; use Spatie\LaravelIgnition\Support\SentReports; use Spatie\LaravelIgnition\Views\ViewExceptionMapper; diff --git a/src/Renderers/ErrorPageRenderer.php b/src/Renderers/ErrorPageRenderer.php index 3c0ccffe..c0aa160a 100644 --- a/src/Renderers/ErrorPageRenderer.php +++ b/src/Renderers/ErrorPageRenderer.php @@ -2,9 +2,9 @@ namespace Spatie\LaravelIgnition\Renderers; +use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository; use Spatie\FlareClient\Flare; use Spatie\Ignition\Config\IgnitionConfig; -use Spatie\ErrorSolutions\Contracts\SolutionProviderRepository; use Spatie\Ignition\Ignition; use Spatie\LaravelIgnition\ContextProviders\LaravelContextProviderDetector; use Spatie\LaravelIgnition\Solutions\SolutionTransformers\LaravelSolutionTransformer; From e30042a9321c8d057f13610f86361f20897eaa63 Mon Sep 17 00:00:00 2001 From: Ruben Van Assche Date: Wed, 12 Jun 2024 12:22:20 +0200 Subject: [PATCH 3/4] Fix PHPStan --- phpstan-baseline.neon | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6761da23..0c7abf55 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -45,46 +45,6 @@ parameters: count: 1 path: src/Exceptions/InvalidConfig.php - - - message: "#^Class Livewire\\\\LivewireComponentsFinder not found\\.$#" - count: 1 - path: src/Solutions/LivewireDiscoverSolution.php - - - - message: "#^Parameter \\#1 \\$invalidController of method Spatie\\\\LaravelIgnition\\\\Solutions\\\\SolutionProviders\\\\InvalidRouteActionSolutionProvider\\:\\:findRelatedController\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php - - - - message: "#^Unable to resolve the template type TKey in call to function collect$#" - count: 1 - path: src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php - - - - message: "#^Unable to resolve the template type TValue in call to function collect$#" - count: 1 - path: src/Solutions/SolutionProviders/InvalidRouteActionSolutionProvider.php - - - - message: "#^Method Spatie\\\\LaravelIgnition\\\\Solutions\\\\SolutionProviders\\\\UnknownValidationSolutionProvider\\:\\:getAvailableMethods\\(\\) return type with generic class Illuminate\\\\Support\\\\Collection does not specify its types\\: TKey, TValue$#" - count: 1 - path: src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php - - - - message: "#^Parameter \\#1 \\$callback of method Illuminate\\\\Support\\\\Collection\\\\:\\:filter\\(\\) expects \\(callable\\(ReflectionMethod, int\\)\\: bool\\)\\|null, Closure\\(ReflectionMethod\\)\\: \\(0\\|1\\|false\\) given\\.$#" - count: 1 - path: src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php - - - - message: "#^Unable to resolve the template type TMakeKey in call to method static method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:make\\(\\)$#" - count: 1 - path: src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php - - - - message: "#^Unable to resolve the template type TMakeValue in call to method static method Illuminate\\\\Support\\\\Collection\\<\\(int\\|string\\),mixed\\>\\:\\:make\\(\\)$#" - count: 1 - path: src/Solutions/SolutionProviders/UnknownValidationSolutionProvider.php - - message: "#^Argument of an invalid type array\\|DateTimeImmutable\\|int\\|string\\|null supplied for foreach, only iterables are supported\\.$#" count: 1 From c0cd559dd48bf1a2dd8d914fe54c6202359d08ef Mon Sep 17 00:00:00 2001 From: Ruben Van Assche Date: Wed, 12 Jun 2024 16:57:13 +0200 Subject: [PATCH 4/4] Update dependencies --- composer.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/composer.json b/composer.json index a4de8d49..58635813 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,7 @@ "ext-json": "*", "ext-mbstring": "*", "illuminate/support": "^10.0|^11.0", - "spatie/error-solutions": "dev-main", - "spatie/flare-client-php" : "dev-solutions-refactor", - "spatie/ignition": "dev-solutions-refactor", + "spatie/ignition": "^1.15", "symfony/console": "^6.2.3|^7.0", "symfony/var-dumper": "^6.2.3|^7.0" },