From 1581c97b88849796dc27242a381a2d4a07e071dc Mon Sep 17 00:00:00 2001 From: Dan <79267265+dansysanalyst@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:30:37 +0200 Subject: [PATCH] Create PowerGrid Components in different directories following Livewire Class Namespace (#1501) * Create components following a custom Livewire namespace * Add Auto-Discover Models config key * List sub-classes of Model in path --- resources/config/livewire-powergrid.php | 15 ++++++++++ src/Actions/AskModelName.php | 2 +- src/Actions/ListModels.php | 29 +++++++++++++------ src/Actions/ParseFqnClassInCode.php | 20 +++++++++++++ src/functions.php | 4 +-- tests/Feature/Actions/ListModelsTest.php | 28 +++++++++++------- .../Actions/ParseFqnClassInCodeTest.php | 25 ++++++++++++++++ tests/Feature/Support/PowerGridMakerTest.php | 20 +++++++++++++ 8 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 src/Actions/ParseFqnClassInCode.php create mode 100644 tests/Feature/Actions/ParseFqnClassInCodeTest.php diff --git a/resources/config/livewire-powergrid.php b/resources/config/livewire-powergrid.php index 31a0e110..1113fc79 100644 --- a/resources/config/livewire-powergrid.php +++ b/resources/config/livewire-powergrid.php @@ -124,4 +124,19 @@ 'csv' => \PowerComponents\LivewirePowerGrid\Components\Exports\OpenSpout\v3\ExportToCsv::class, ], ], + + /* + |-------------------------------------------------------------------------- + | Auto-Discover Models + |-------------------------------------------------------------------------- + | + | PowerGrid will search for Models in the directories listed below. + | These Models be listed as options when you run the + | "artisan powergrid:create" command. + | + */ + + 'auto_discover_models_paths' => [ + app_path('Models'), + ], ]; diff --git a/src/Actions/AskModelName.php b/src/Actions/AskModelName.php index d2b285c7..f14bd77d 100644 --- a/src/Actions/AskModelName.php +++ b/src/Actions/AskModelName.php @@ -18,7 +18,7 @@ public static function handle(): array { while (self::$model === '') { self::setModel(suggest( - label: 'Select a Model or enter its Name/FQN class.', + label: 'Select a Model or enter its Fully qualified name.', options: ListModels::handle(), required: true, )); diff --git a/src/Actions/ListModels.php b/src/Actions/ListModels.php index 3ca1c8b9..7655a3a4 100644 --- a/src/Actions/ListModels.php +++ b/src/Actions/ListModels.php @@ -9,22 +9,33 @@ final class ListModels { /** - * List files in Models folder + * List files in Models * */ public static function handle(): array { - $modelsFolder = app_path('Models'); + $directories = config('livewire-powergrid.auto_discover_models_paths', [app_path('Models')]); - return collect(File::allFiles($modelsFolder)) + /** @var Array $directories */ + return collect($directories) + ->filter(fn (string $directory) => File::exists($directory)) + ->map(fn (string $directory) => File::allFiles($directory)) + ->flatten() ->reject(fn (SplFileInfo $file): bool => $file->getExtension() != 'php') - ->map(function (SplFileInfo $file): array { - return [ - 'file' => $file->getFilenameWithoutExtension(), - 'path' => 'App\\Models\\' . $file->getFilenameWithoutExtension(), - ]; + + // Get FQN Class from source code + /** @phpstan-ignore-next-line */ + ->map(function (SplFileInfo $file): string { + $sourceCode = strval(file_get_contents($file->getPathname())); + + return rescue(fn () => ParseFqnClassInCode::handle($sourceCode), ''); }) - ->flatten() + //Remove all unqualified PHP files code + ->filter() + + // Remove classes that do not extend an Eloquent Model + /** @phpstan-ignore-next-line */ + ->reject(fn (string $fqnClass) => rescue(fn () => (new \ReflectionClass($fqnClass))->isSubclassOf(\Illuminate\Database\Eloquent\Model::class), false) === false) ->toArray(); } } diff --git a/src/Actions/ParseFqnClassInCode.php b/src/Actions/ParseFqnClassInCode.php new file mode 100644 index 00000000..99194490 --- /dev/null +++ b/src/Actions/ParseFqnClassInCode.php @@ -0,0 +1,20 @@ +ltrim('App//') + ->replace('App', 'app') ->append(DIRECTORY_SEPARATOR . $filename) ->replace('\\', '/') ->replace('//', '/') diff --git a/tests/Feature/Actions/ListModelsTest.php b/tests/Feature/Actions/ListModelsTest.php index cef2ef0a..e0b5c3e2 100644 --- a/tests/Feature/Actions/ListModelsTest.php +++ b/tests/Feature/Actions/ListModelsTest.php @@ -1,20 +1,28 @@ -artisan('make:model Demo'); -}); +it('list all Eloquent Models in a directory', function () { + app()->config->set('livewire-powergrid.auto_discover_models_paths', [ + 'tests/Concerns/Models', + ]); -test('list models', function () { expect(ListModels::handle())->toBe( [ - 'Demo', - 'App\Models\Demo', + 'PowerComponents\LivewirePowerGrid\Tests\Concerns\Models\Category', + 'PowerComponents\LivewirePowerGrid\Tests\Concerns\Models\Chef', + 'PowerComponents\LivewirePowerGrid\Tests\Concerns\Models\Dish', + 'PowerComponents\LivewirePowerGrid\Tests\Concerns\Models\Restaurant', ] ); }); + +it('will not list non-Eloquent Models', function () { + app()->config->set('livewire-powergrid.auto_discover_models_paths', [ + 'tests/Concerns/Enums', //There are no models in this directory. + + ]); + + expect(ListModels::handle())->toBe([]); +}); diff --git a/tests/Feature/Actions/ParseFqnClassInCodeTest.php b/tests/Feature/Actions/ParseFqnClassInCodeTest.php new file mode 100644 index 00000000..88eb4f13 --- /dev/null +++ b/tests/Feature/Actions/ParseFqnClassInCodeTest.php @@ -0,0 +1,25 @@ +toBe('App\Models\DemoModel'); +}); + +it('throws an exception when namespace cannot be found', function () { + ParseFqnClassInCode::handle('foobar'); +})->throws('could not find a FQN Class is source-code'); diff --git a/tests/Feature/Support/PowerGridMakerTest.php b/tests/Feature/Support/PowerGridMakerTest.php index a615c300..bb58d182 100644 --- a/tests/Feature/Support/PowerGridMakerTest.php +++ b/tests/Feature/Support/PowerGridMakerTest.php @@ -141,3 +141,23 @@ ]], ], ); + +test('Livewire class namespace is App\Livewire') + ->expect(fn () => config('livewire.class_namespace'))->toBe('App\Livewire'); + +it('can create component in a custom Livewire namespace', function () { + app()->config->set('livewire.class_namespace', 'Domains'); + + $component = PowerGridComponentMaker::make('System/Office/Users/Admin/Active/ListTable'); + + expect($component) + ->name->toBe('ListTable') + ->namespace->toBe('Domains\System\Office\Users\Admin\Active') + ->folder->toBe('System\Office\Users\Admin\Active') + ->fqn->toBe('Domains\System\Office\Users\Admin\Active\ListTable') + ->htmlTag->toBe(''); + + expect($component->createdPath())->toBe("Domains/System/Office/Users/Admin/Active/ListTable.php"); + + expect($component->savePath($component->filename))->toEndWith(str_replace('/', DIRECTORY_SEPARATOR, 'Domains/System/Office/Users/Admin/Active/ListTable.php')); +});