mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Make table class command
This commit is contained in:
@@ -23,14 +23,14 @@ trait CanAskForComponentLocation
|
||||
|
||||
if (blank($locations)) {
|
||||
return [
|
||||
"App\\{$pathNamespace}",
|
||||
"App\\Filament\\{$pathNamespace}",
|
||||
app_path($path),
|
||||
'',
|
||||
];
|
||||
}
|
||||
|
||||
$options = [
|
||||
null => "App\\{$pathNamespace}",
|
||||
null => "App\\Filament\\{$pathNamespace}",
|
||||
...array_map(
|
||||
fn (string $namespace): string => "{$namespace}\\{$pathNamespace}",
|
||||
array_combine(
|
||||
@@ -47,7 +47,7 @@ trait CanAskForComponentLocation
|
||||
|
||||
if (blank($namespace)) {
|
||||
return [
|
||||
"App\\{$pathNamespace}",
|
||||
"App\\Filament\\{$pathNamespace}",
|
||||
app_path($path),
|
||||
'',
|
||||
];
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ use Nette\PhpGenerator\Literal;
|
||||
use Nette\PhpGenerator\Method;
|
||||
use Nette\PhpGenerator\TraitUse;
|
||||
|
||||
class LivewireTableClassGenerator extends ClassGenerator
|
||||
class LivewireTableComponentClassGenerator extends ClassGenerator
|
||||
{
|
||||
use CanGenerateTables;
|
||||
use CanReadModelSchemas;
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\Commands\FileGenerators;
|
||||
|
||||
use Filament\Support\Commands\Concerns\CanReadModelSchemas;
|
||||
use Filament\Support\Commands\FileGenerators\ClassGenerator;
|
||||
use Filament\Tables\Commands\FileGenerators\Concerns\CanGenerateTables;
|
||||
use Filament\Tables\Table;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Nette\PhpGenerator\ClassType;
|
||||
use Nette\PhpGenerator\Method;
|
||||
|
||||
class TableClassGenerator extends ClassGenerator
|
||||
{
|
||||
use CanGenerateTables;
|
||||
use CanReadModelSchemas;
|
||||
|
||||
/**
|
||||
* @param class-string<Model> $modelFqn
|
||||
*/
|
||||
final public function __construct(
|
||||
protected string $fqn,
|
||||
protected string $modelFqn,
|
||||
protected bool $isGenerated,
|
||||
) {}
|
||||
|
||||
public function getNamespace(): string
|
||||
{
|
||||
return $this->extractNamespace($this->getFqn());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getImports(): array
|
||||
{
|
||||
return [
|
||||
Table::class,
|
||||
...($this->hasPartialImports() ? ['Filament\Tables'] : []),
|
||||
Builder::class,
|
||||
$this->getModelFqn(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getBasename(): string
|
||||
{
|
||||
return class_basename($this->getFqn());
|
||||
}
|
||||
|
||||
protected function addMethodsToClass(ClassType $class): void
|
||||
{
|
||||
$this->addConfigureMethodToClass($class);
|
||||
}
|
||||
|
||||
protected function addConfigureMethodToClass(ClassType $class): void
|
||||
{
|
||||
$method = $class->addMethod('configure')
|
||||
->setPublic()
|
||||
->setStatic()
|
||||
->setReturnType(Table::class)
|
||||
->setBody($this->generateTableMethodBody($this->getModelFqn()));
|
||||
$method->addParameter('table')
|
||||
->setType(Table::class);
|
||||
|
||||
$this->configureConfigureMethod($method);
|
||||
}
|
||||
|
||||
protected function configureConfigureMethod(Method $method): void {}
|
||||
|
||||
public function getFqn(): string
|
||||
{
|
||||
return $this->fqn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?class-string<Model>
|
||||
*/
|
||||
public function getModelFqn(): ?string
|
||||
{
|
||||
return $this->modelFqn;
|
||||
}
|
||||
|
||||
public function isGenerated(): bool
|
||||
{
|
||||
return $this->isGenerated;
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ class MakeColumnCommand extends Command
|
||||
$path,
|
||||
$viewNamespace,
|
||||
] = $this->askForComponentLocation(
|
||||
path: 'Filament/Tables/Columns',
|
||||
path: 'Tables/Columns',
|
||||
question: 'Where would you like to create the column?',
|
||||
);
|
||||
|
||||
@@ -154,8 +154,8 @@ class MakeColumnCommand extends Command
|
||||
$this->viewPath,
|
||||
] = $this->askForViewLocation(
|
||||
str($this->fqn)
|
||||
->afterLast('\\Filament\\Tables\\Columns\\')
|
||||
->prepend('Filament\\Tables\\Columns\\')
|
||||
->afterLast('\\Tables\\Columns\\')
|
||||
->prepend('Tables\\Columns\\')
|
||||
->replace('\\', '/')
|
||||
->explode('/')
|
||||
->map(Str::kebab(...))
|
||||
|
||||
@@ -6,7 +6,7 @@ use Filament\Support\Commands\Concerns\CanAskForLivewireComponentLocation;
|
||||
use Filament\Support\Commands\Concerns\CanAskForViewLocation;
|
||||
use Filament\Support\Commands\Concerns\CanManipulateFiles;
|
||||
use Filament\Support\Commands\Exceptions\InvalidCommandOutput;
|
||||
use Filament\Tables\Commands\FileGenerators\LivewireTableClassGenerator;
|
||||
use Filament\Tables\Commands\FileGenerators\LivewireTableComponentClassGenerator;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -19,6 +19,7 @@ use function Laravel\Prompts\suggest;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand(name: 'make:filament-livewire-table', aliases: [
|
||||
'filament:livewire-table',
|
||||
'make:livewire-table',
|
||||
])]
|
||||
class MakeLivewireTableCommand extends Command
|
||||
@@ -35,6 +36,7 @@ class MakeLivewireTableCommand extends Command
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $aliases = [
|
||||
'filament:livewire-table',
|
||||
'make:livewire-table',
|
||||
];
|
||||
|
||||
@@ -172,10 +174,6 @@ class MakeLivewireTableCommand extends Command
|
||||
->studly()
|
||||
->replace('/', '\\');
|
||||
|
||||
if (blank($this->modelFqnEnd)) {
|
||||
$this->modelFqnEnd = 'Resource';
|
||||
}
|
||||
|
||||
$this->modelFqn = "{$modelNamespace}\\{$this->modelFqnEnd}";
|
||||
}
|
||||
|
||||
@@ -223,7 +221,7 @@ class MakeLivewireTableCommand extends Command
|
||||
throw new InvalidCommandOutput;
|
||||
}
|
||||
|
||||
$this->writeFile($this->path, app(LivewireTableClassGenerator::class, [
|
||||
$this->writeFile($this->path, app(LivewireTableComponentClassGenerator::class, [
|
||||
'fqn' => $this->fqn,
|
||||
'modelFqn' => $this->modelFqn,
|
||||
'isGenerated' => $this->isGenerated,
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Tables\Commands;
|
||||
|
||||
use Filament\Support\Commands\Concerns\CanAskForComponentLocation;
|
||||
use Filament\Support\Commands\Concerns\CanManipulateFiles;
|
||||
use Filament\Support\Commands\Exceptions\InvalidCommandOutput;
|
||||
use Filament\Tables\Commands\FileGenerators\TableClassGenerator;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use function Laravel\Prompts\confirm;
|
||||
use function Laravel\Prompts\suggest;
|
||||
use function Laravel\Prompts\text;
|
||||
|
||||
#[AsCommand(name: 'make:filament-table', aliases: [
|
||||
'filament:table',
|
||||
])]
|
||||
class MakeTableCommand extends Command
|
||||
{
|
||||
use CanAskForComponentLocation;
|
||||
use CanManipulateFiles;
|
||||
|
||||
protected $description = 'Create a new Filament table class';
|
||||
|
||||
protected $name = 'make:filament-table';
|
||||
|
||||
/**
|
||||
* @var class-string
|
||||
*/
|
||||
protected string $fqn;
|
||||
|
||||
protected string $fqnEnd;
|
||||
|
||||
protected string $path;
|
||||
|
||||
/**
|
||||
* @var class-string<Model>
|
||||
*/
|
||||
protected string $modelFqn;
|
||||
|
||||
protected string $modelFqnEnd;
|
||||
|
||||
protected bool $isGenerated;
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $aliases = [
|
||||
'filament:table',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array<InputArgument>
|
||||
*/
|
||||
protected function getArguments(): array
|
||||
{
|
||||
return [
|
||||
new InputArgument(
|
||||
name: 'name',
|
||||
mode: InputArgument::OPTIONAL,
|
||||
description: 'The name of the table class to generate, optionally prefixed with directories',
|
||||
),
|
||||
new InputArgument(
|
||||
name: 'model',
|
||||
mode: InputArgument::OPTIONAL,
|
||||
description: 'The name of the model to generate the table for, optionally prefixed with directories',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<InputOption>
|
||||
*/
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [
|
||||
new InputOption(
|
||||
name: 'generate',
|
||||
shortcut: 'G',
|
||||
mode: InputOption::VALUE_NONE,
|
||||
description: 'Generate the table columns based on the attributes of a model',
|
||||
),
|
||||
new InputOption(
|
||||
name: 'model-namespace',
|
||||
shortcut: null,
|
||||
mode: InputOption::VALUE_REQUIRED,
|
||||
description: 'The namespace of the model class, [App\\Models] by default',
|
||||
),
|
||||
new InputOption(
|
||||
name: 'force',
|
||||
shortcut: 'F',
|
||||
mode: InputOption::VALUE_NONE,
|
||||
description: 'Overwrite the contents of the files if they already exist',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
try {
|
||||
$this->configureFqnEnd();
|
||||
$this->configureModel();
|
||||
$this->configureIsGenerated();
|
||||
|
||||
$this->configureLocation();
|
||||
|
||||
$this->createTable();
|
||||
} catch (InvalidCommandOutput) {
|
||||
return static::INVALID;
|
||||
}
|
||||
|
||||
$this->components->info("Table [{$this->fqn}] created successfully.");
|
||||
|
||||
return static::SUCCESS;
|
||||
}
|
||||
|
||||
protected function configureFqnEnd(): void
|
||||
{
|
||||
$this->fqnEnd = (string) str($this->argument('name') ?? text(
|
||||
label: 'What is the Table name?',
|
||||
placeholder: 'BlogPostsTable',
|
||||
required: true,
|
||||
))
|
||||
->trim('/')
|
||||
->trim('\\')
|
||||
->trim(' ')
|
||||
->studly()
|
||||
->replace('/', '\\');
|
||||
}
|
||||
|
||||
protected function configureModel(): void
|
||||
{
|
||||
$modelNamespace = $this->option('model-namespace') ?? 'App\\Models';
|
||||
|
||||
$modelFqns = collect(get_declared_classes())
|
||||
->filter(fn (string $class): bool => is_subclass_of($class, Model::class) &&
|
||||
str($class)->startsWith("{$modelNamespace}\\"))
|
||||
->map(fn (string $class): string => str($class)->after("{$modelNamespace}\\"))
|
||||
->all();
|
||||
|
||||
$this->modelFqnEnd = (string) str($this->argument('model') ?? suggest(
|
||||
label: 'What is the model name?',
|
||||
options: function (string $search) use ($modelFqns): array {
|
||||
$search = str($search)->trim()->replace(['\\', '/'], '');
|
||||
|
||||
if (blank($search)) {
|
||||
return $modelFqns;
|
||||
}
|
||||
|
||||
return array_filter(
|
||||
$modelFqns,
|
||||
fn (string $class): bool => str($class)->replace(['\\', '/'], '')->contains($search, ignoreCase: true),
|
||||
);
|
||||
},
|
||||
placeholder: 'BlogPost',
|
||||
))
|
||||
->trim('/')
|
||||
->trim('\\')
|
||||
->trim(' ')
|
||||
->studly()
|
||||
->replace('/', '\\');
|
||||
|
||||
$this->modelFqn = "{$modelNamespace}\\{$this->modelFqnEnd}";
|
||||
}
|
||||
|
||||
protected function configureIsGenerated(): void
|
||||
{
|
||||
$this->isGenerated = $this->option('generate') || confirm(
|
||||
label: 'Would you like to generate the table columns based on the attributes of the model?',
|
||||
default: false,
|
||||
);
|
||||
}
|
||||
|
||||
protected function configureLocation(): void
|
||||
{
|
||||
[
|
||||
$namespace,
|
||||
$path,
|
||||
] = $this->askForComponentLocation(
|
||||
path: 'Tables',
|
||||
question: 'Where would you like to create the table?',
|
||||
);
|
||||
|
||||
$this->fqn = "{$namespace}\\{$this->fqnEnd}";
|
||||
$this->path = (string) str("{$path}\\{$this->fqnEnd}.php")
|
||||
->replace('\\', '/')
|
||||
->replace('//', '/');
|
||||
}
|
||||
|
||||
protected function createTable(): void
|
||||
{
|
||||
if (! $this->option('force') && $this->checkForCollision($this->path)) {
|
||||
throw new InvalidCommandOutput;
|
||||
}
|
||||
|
||||
$this->writeFile($this->path, app(TableClassGenerator::class, [
|
||||
'fqn' => $this->fqn,
|
||||
'modelFqn' => $this->modelFqn,
|
||||
'isGenerated' => $this->isGenerated,
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ class TablesServiceProvider extends PackageServiceProvider
|
||||
->hasCommands([
|
||||
Commands\MakeColumnCommand::class,
|
||||
Commands\MakeLivewireTableCommand::class,
|
||||
Commands\MakeTableCommand::class,
|
||||
])
|
||||
->hasTranslations()
|
||||
->hasViews();
|
||||
|
||||
Reference in New Issue
Block a user