Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added the missing make:filament-action command #43

Merged
merged 16 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Kickstart your project and save time with Larament! This time-saving starter kit
- All component labels are automatically translatable.
- A `composer review` command that runs PINT, PHPStan, and PEST.
- Helper file is included for custom helper functions.
- A custom `php artisan make:filament-action` command is available for creating actions.

### Design
![user-global-search](https://raw.githubusercontent.com/CodeWithDennis/larament/main/resources/images/user-global-search.jpg)
Expand Down
163 changes: 163 additions & 0 deletions app/Console/Commands/MakeFilamentActionCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

use function Laravel\Prompts\info;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\warning;

class MakeFilamentActionCommand extends Command
{
protected $signature = 'make:filament-action {name?}
{--form : Generate a form component action}
{--table : Generate a table component action}
{--table-bulk : Generate a table bulk action}
{--custom-component : Generate a custom component action}
{--infolist : Generate an infolist component action}
{--notification : Generate a notification action}
{--global-search : Generate a global search result action}';

protected $description = 'Create a new Filament action class';

/**
* @var array<string, string>
*/
protected array $actionTypes = [
'form' => 'Filament\\Forms\\Components\\Actions\\Action',
'table' => 'Filament\\Tables\\Actions\\Action',
'table-bulk' => 'Filament\\Tables\\Actions\\BulkAction',
'custom-component' => 'Filament\\Actions\\Action',
'infolist' => 'Filament\\Infolists\\Components\\Actions\\Action',
'notification' => 'Filament\\Notifications\\Actions\\Action',
'global-search' => 'Filament\\GlobalSearch\\Actions\\Action',
];

public function handle(): void
{
$name = $this->getNameArgument();
$className = $this->getClassName($name);
$type = $this->getActionType();
$actionClass = $this->actionTypes[$type];
$baseClass = $type === 'table-bulk' ? 'BulkAction' : 'Action';
$path = $this->getFilePath($className, $type);

if ($this->fileExists($path)) {
warning("$className already exists.");

return;
}

$stubContent = $this->getStubContent();
$this->generateActionFile($path, $className, $actionClass, $stubContent, $baseClass);

info("$className created successfully at:");
info($path);
}

private function getNameArgument(): string
{
return $this->argument('name') ?? text(
label: 'Enter the name of the Filament Action',
required: 'Action name is required.',
);
}

private function getClassName(string $name): string
{
return Str::endsWith(Str::lower($name), 'action')
? Str::studly($name)
: Str::studly($name).'Action';
}

private function getActionType(): string
{
$selectedTypes = array_filter([
'form' => $this->option('form'),
'table' => $this->option('table'),
'table-bulk' => $this->option('table-bulk'),
'custom-component' => $this->option('custom-component'),
'infolist' => $this->option('infolist'),
'notification' => $this->option('notification'),
'global-search' => $this->option('global-search'),
]);

if (count($selectedTypes) > 1) {
warning('Please specify only one action type.');

exit;
}

if (count($selectedTypes) === 0) {
$selectedType = select(
label: 'Please select the type of the Filament Action',
options: [
johntrickett86 marked this conversation as resolved.
Show resolved Hide resolved
'form' => 'Form',
'table' => 'Table',
'table-bulk' => 'TableBulk',
'infolist' => 'Infolist',
'notification' => 'Notification',
'global-search' => 'GlobalSearch',
'custom-component' => 'Custom',
]
);

return (string) $selectedType;
}

return (string) key($selectedTypes);
}

private function getFilePath(string $className, string $type): string
{
$subDirectory = match ($type) {
'form' => 'Forms',
'table', 'table-bulk' => 'Tables',
'infolist' => 'Infolists',
'notification' => 'Notifications',
'global-search' => 'GlobalSearch',
'custom-component' => 'Custom',
default => '',
};

return app_path("Filament/Actions/$subDirectory/$className.php");
}

private function fileExists(string $path): bool
{
return File::exists($path);
}

private function getStubContent(): string
{
$stubPath = app_path('Filament/Actions/Stubs/FilamentAction.stub');

return File::get($stubPath);
}

private function generateActionFile(string $path, string $className, string $actionClass, string $stubContent, string $baseClass): void
{
$namespace = $this->getNamespace($path);
$defaultName = Str::camel(Str::replaceLast('Action', '', $className));

$content = str_replace(
['{{ namespace }}', '{{ className }}', '{{ defaultName }}', '{{ actionClass }}', '{{ baseClass }}'],
[$namespace, $className, $defaultName, $actionClass, $baseClass],
$stubContent
);

File::ensureDirectoryExists(dirname($path));
File::put($path, $content);
}

private function getNamespace(string $path): string
{
$relativePath = Str::after($path, app_path().'/');

return 'App\\'.Str::replace('/', '\\', dirname($relativePath));
}
}
20 changes: 20 additions & 0 deletions app/Filament/Actions/GlobalSearch/TestAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\Filament\Actions\GlobalSearch;

use Filament\GlobalSearch\Actions\Action;

class TestAction extends Action
{
public static function getDefaultName(): ?string
{
return 'test';
}

protected function setUp(): void
{
parent::setUp();

// TODO: Add your setup logic here
}
}
20 changes: 20 additions & 0 deletions app/Filament/Actions/Stubs/FilamentAction.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace {{ namespace }};

use {{ actionClass }};

class {{ className }} extends {{ baseClass }}
{
public static function getDefaultName(): ?string
{
return '{{ defaultName }}';
}

protected function setUp(): void
{
parent::setUp();

// TODO: Add your setup logic here
}
}