Skip to content

Commit

Permalink
List sub-classes of Model in path
Browse files Browse the repository at this point in the history
  • Loading branch information
dansysanalyst committed Apr 9, 2024
1 parent 013b44f commit 6f70943
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/Actions/AskModelName.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
));
Expand Down
29 changes: 20 additions & 9 deletions src/Actions/ListModels.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<int,string> $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();
}
}
20 changes: 20 additions & 0 deletions src/Actions/ParseFqnClassInCode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace PowerComponents\LivewirePowerGrid\Actions;

final class ParseFqnClassInCode
{
/**
* Parse namespace from PHP source code
* Inspired by: https://gist.github.com/ludofleury/1886076
* @throws \Exception
*/
public static function handle(string $sourceCode): string
{
if (preg_match('#^namespace\s+(.+?);.*class\s+(\w+).+;$#sm', $sourceCode, $matches)) {
return $matches[1] . '\\' . $matches[2];
}

throw new \Exception('could not find a FQN Class is source-code');
}
}
28 changes: 18 additions & 10 deletions tests/Feature/Actions/ListModelsTest.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
<?php

use Illuminate\Support\Facades\File;
<?php

use PowerComponents\LivewirePowerGrid\Actions\ListModels;

beforeEach(function () {
File::cleanDirectory(base_path('app/Models'));

$this->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([]);
});
25 changes: 25 additions & 0 deletions tests/Feature/Actions/ParseFqnClassInCodeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

use PowerComponents\LivewirePowerGrid\Actions\ParseFqnClassInCode;

it('can find the namespace in a PHP file source code', function () {
$code = <<<EOD
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class DemoModel extends Model
{
use HasFactory;
}
EOD;

expect(ParseFqnClassInCode::handle($code))->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');

0 comments on commit 6f70943

Please sign in to comment.