filament-plugin
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFilament Plugin Skill — Modular Laravel Architecture
Filament插件技能——Laravel模块化架构
Concept
概念
Each plugin lives in and is registered as a local Composer package via
a path repository in . The main project consumes it like any other Composer
package, keeping full independence and modularity.
plugins/{name}/composer.json每个插件位于目录中,并通过中的路径仓库注册为本地Composer包。主项目像使用其他Composer包一样使用它,保持完全的独立性和模块化。
plugins/{name}/composer.jsonRequired plugin structure
必需的插件结构
plugins/
└── {name}/
├── composer.json
├── src/
│ ├── {Name}ServiceProvider.php
│ ├── {Name}Plugin.php <- Filament Plugin class
│ └── Commands/
│ └── Install{Name}Command.php
├── resources/
│ ├── views/
│ └── lang/
├── config/
│ └── {name}.php
└── database/
└── migrations/plugins/
└── {name}/
├── composer.json
├── src/
│ ├── {Name}ServiceProvider.php
│ ├── {Name}Plugin.php <- Filament Plugin类
│ └── Commands/
│ └── Install{Name}Command.php
├── resources/
│ ├── views/
│ └── lang/
├── config/
│ └── {name}.php
└── database/
└── migrations/Step 1 — Create plugins/{name}/composer.json
plugins/{name}/composer.json步骤1 — 创建plugins/{name}/composer.json
plugins/{name}/composer.jsonjson
{
"name": "app/{name}",
"description": "Modular {Name} plugin for Filament",
"type": "library",
"require": {
"filament/filament": "^3.0"
},
"autoload": {
"psr-4": {
"App\\Plugins\\{Name}\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"App\\Plugins\\{Name}\\{Name}ServiceProvider"
]
}
},
"minimum-stability": "dev",
"prefer-stable": true
}json
{
"name": "app/{name}",
"description": "Modular {Name} plugin for Filament",
"type": "library",
"require": {
"filament/filament": "^3.0"
},
"autoload": {
"psr-4": {
"App\\Plugins\\{Name}\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"App\\Plugins\\{Name}\\{Name}ServiceProvider"
]
}
},
"minimum-stability": "dev",
"prefer-stable": true
}Step 2 — Register in the project root composer.json
composer.json步骤2 — 在项目根目录的composer.json
中注册
composer.jsonAdd the local path repository and require the package:
json
{
"repositories": [
{
"type": "path",
"url": "plugins/{name}",
"options": {
"symlink": true
}
}
],
"require": {
"app/{name}": "*"
}
}Then run:
bash
composer require app/{name} --no-scripts
composer dump-autoloadWARNING: If other path plugins already exist in repositories, only ADD the new entry — do NOT replace existing ones.
添加本地路径仓库并引入该包:
json
{
"repositories": [
{
"type": "path",
"url": "plugins/{name}",
"options": {
"symlink": true
}
}
],
"require": {
"app/{name}": "*"
}
}然后运行:
bash
composer require app/{name} --no-scripts
composer dump-autoload注意:如果仓库中已存在其他路径插件,只需添加新条目——不要替换现有插件。
Step 3 — ServiceProvider
步骤3 — ServiceProvider
File:
plugins/{name}/src/{Name}ServiceProvider.phpphp
<?php
namespace App\Plugins\{Name};
use Illuminate\Support\ServiceProvider;
class {Name}ServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(
__DIR__ . '/../config/{name}.php',
'{name}'
);
}
public function boot(): void
{
$this->loadViewsFrom(__DIR__ . '/../resources/views', '{name}');
$this->loadTranslationsFrom(__DIR__ . '/../resources/lang', '{name}');
// Migrations are loaded directly from the plugin so `migrate` works
// out of the box. The Install command copies them physically (Step 5).
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__ . '/../database/migrations' => database_path('migrations'),
], '{name}-migrations');
$this->publishes([
__DIR__ . '/../config/{name}.php' => config_path('{name}.php'),
], '{name}-config');
$this->publishes([
__DIR__ . '/../resources/views' => resource_path('views/vendor/{name}'),
], '{name}-views');
$this->commands([
\App\Plugins\{Name}\Commands\Install{Name}Command::class,
]);
}
}
}文件:
plugins/{name}/src/{Name}ServiceProvider.phpphp
<?php
namespace App\Plugins\{Name};
use Illuminate\Support\ServiceProvider;
class {Name}ServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->mergeConfigFrom(
__DIR__ . '/../config/{name}.php',
'{name}'
);
}
public function boot(): void
{
$this->loadViewsFrom(__DIR__ . '/../resources/views', '{name}');
$this->loadTranslationsFrom(__DIR__ . '/../resources/lang', '{name}');
// 迁移文件直接从插件加载,因此`migrate`命令可直接生效
// 安装命令会将它们物理复制到项目中(步骤5)。
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
if ($this->app->runningInConsole()) {
$this->publishes([
__DIR__ . '/../database/migrations' => database_path('migrations'),
], '{name}-migrations');
$this->publishes([
__DIR__ . '/../config/{name}.php' => config_path('{name}.php'),
], '{name}-config');
$this->publishes([
__DIR__ . '/../resources/views' => resource_path('views/vendor/{name}'),
], '{name}-views');
$this->commands([
\App\Plugins\{Name}\Commands\Install{Name}Command::class,
]);
}
}
}Step 4 — Filament Plugin Class
步骤4 — Filament插件类
File:
plugins/{name}/src/{Name}Plugin.phpphp
<?php
namespace App\Plugins\{Name};
use Filament\Contracts\Plugin;
use Filament\Panel;
class {Name}Plugin implements Plugin
{
public function getId(): string
{
return '{name}';
}
public function register(Panel $panel): void
{
// Register resources, pages, widgets, etc.
// Example:
// $panel->resources([
// \App\Plugins\{Name}\Resources\{Name}Resource::class,
// ]);
}
public function boot(Panel $panel): void
{
//
}
public static function make(): static
{
return app(static::class);
}
}Important: Remind the user to register the plugin in their Panel Provider:
php
// app/Providers/Filament/AdminPanelProvider.php
->plugins([
\App\Plugins\{Name}\{Name}Plugin::make(),
])文件:
plugins/{name}/src/{Name}Plugin.phpphp
<?php
namespace App\Plugins\{Name};
use Filament\Contracts\Plugin;
use Filament\Panel;
class {Name}Plugin implements Plugin
{
public function getId(): string
{
return '{name}';
}
public function register(Panel $panel): void
{
// 注册资源、页面、小组件等
// 示例:
// $panel->resources([
// \App\Plugins\{Name}\Resources\{Name}Resource::class,
// ]);
}
public function boot(Panel $panel): void
{
//
}
public static function make(): static
{
return app(static::class);
}
}重要提示:提醒用户在Panel Provider中注册插件:
php
// app/Providers/Filament/AdminPanelProvider.php
->plugins([
\App\Plugins\{Name}\{Name}Plugin::make(),
])Step 5 — Install Command (with migration copy)
步骤5 — 安装命令(含迁移文件复制)
File:
plugins/{name}/src/Commands/Install{Name}Command.phpphp
<?php
namespace App\Plugins\{Name}\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class Install{Name}Command extends Command
{
protected $signature = '{name}:install {--force : Overwrite existing files}';
protected $description = 'Install the {Name} plugin and publish its assets';
public function handle(): int
{
$this->info('Installing {Name} plugin...');
// 1. Publish config
$this->callSilently('vendor:publish', [
'--tag' => '{name}-config',
'--force' => $this->option('force'),
]);
$this->line(' [OK] Config published');
// 2. Copy migrations into the project
$this->publishMigrations();
// 3. Publish views (optional)
if ($this->confirm('Would you like to publish the views for customization?', false)) {
$this->callSilently('vendor:publish', [
'--tag' => '{name}-views',
'--force' => $this->option('force'),
]);
$this->line(' [OK] Views published');
}
$this->newLine();
$this->info('{Name} plugin installed successfully.');
$this->line(' -> Remember to add <comment>{Name}Plugin::make()</comment> to your Panel Provider.');
$this->line(' -> Run <comment>php artisan migrate</comment> to apply the migrations.');
return self::SUCCESS;
}
protected function publishMigrations(): void
{
$source = __DIR__ . '/../../database/migrations';
$destination = database_path('migrations');
if (! File::isDirectory($source)) {
$this->line(' [i] No migrations found in this plugin');
return;
}
$files = File::files($source);
$copied = 0;
$skipped = 0;
foreach ($files as $file) {
$target = $destination . '/' . $file->getFilename();
if (File::exists($target) && ! $this->option('force')) {
$skipped++;
continue;
}
File::copy($file->getPathname(), $target);
$copied++;
}
if ($copied > 0) {
$this->line(" [OK] {$copied} migration(s) copied to database/migrations");
}
if ($skipped > 0) {
$this->line(" [i] {$skipped} migration(s) skipped (already exist — use --force to overwrite)");
}
}
}文件:
plugins/{name}/src/Commands/Install{Name}Command.phpphp
<?php
namespace App\Plugins\{Name}\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
class Install{Name}Command extends Command
{
protected $signature = '{name}:install {--force : Overwrite existing files}';
protected $description = 'Install the {Name} plugin and publish its assets';
public function handle(): int
{
$this->info('Installing {Name} plugin...');
// 1. 发布配置文件
$this->callSilently('vendor:publish', [
'--tag' => '{name}-config',
'--force' => $this->option('force'),
]);
$this->line(' [OK] 配置文件已发布');
// 2. 将迁移文件复制到项目中
$this->publishMigrations();
// 3. 发布视图文件(可选)
if ($this->confirm('是否要发布视图文件以便自定义?', false)) {
$this->callSilently('vendor:publish', [
'--tag' => '{name}-views',
'--force' => $this->option('force'),
]);
$this->line(' [OK] 视图文件已发布');
}
$this->newLine();
$this->info('{Name}插件安装成功。');
$this->line(' -> 请记得将<comment>{Name}Plugin::make()</comment>添加到你的Panel Provider中。');
$this->line(' -> 运行<comment>php artisan migrate</comment>以执行迁移。');
return self::SUCCESS;
}
protected function publishMigrations(): void
{
$source = __DIR__ . '/../../database/migrations';
$destination = database_path('migrations');
if (! File::isDirectory($source)) {
$this->line(' [i] 此插件中未找到迁移文件');
return;
}
$files = File::files($source);
$copied = 0;
$skipped = 0;
foreach ($files as $file) {
$target = $destination . '/' . $file->getFilename();
if (File::exists($target) && ! $this->option('force')) {
$skipped++;
continue;
}
File::copy($file->getPathname(), $target);
$copied++;
}
if ($copied > 0) {
$this->line(" [OK] 已将{$copied}个迁移文件复制到database/migrations");
}
if ($skipped > 0) {
$this->line(" [i] 已跳过{$skipped}个迁移文件(已存在——使用--force参数可覆盖)");
}
}
}Step 6 — Minimal supporting files
步骤6 — 基础支持文件
plugins/{name}/config/{name}.php
plugins/{name}/config/{name}.phpplugins/{name}/config/{name}.php
plugins/{name}/config/{name}.phpphp
<?php
return [
'enabled' => true,
];php
<?php
return [
'enabled' => true,
];plugins/{name}/database/migrations/
(if applicable)
plugins/{name}/database/migrations/plugins/{name}/database/migrations/
(如有需要)
plugins/{name}/database/migrations/Name migrations with a timestamp + description:
2024_01_01_000000_create_{name}_table.php迁移文件命名格式为:时间戳 + 描述:
2024_01_01_000000_create_{name}_table.phpNaming conventions
命名规范
| Token | Example (name = "invoicing") |
|---|---|
| |
| |
| namespace | |
| package | |
| directory | |
| command | |
For compound names (e.g. "purchase order"):
- ->
{name}(kebab-case for Composer and directory)purchase-order - ->
{Name}(PascalCase for classes)PurchaseOrder - namespace ->
App\Plugins\PurchaseOrder
| 占位符 | 示例(name = "invoicing") |
|---|---|
| |
| |
| 命名空间 | |
| 包名 | |
| 目录 | |
| 命令 | |
对于复合名称(如“purchase order”):
- ->
{name}(Composer和目录使用短横线命名法)purchase-order - ->
{Name}(类使用大驼峰命名法)PurchaseOrder - 命名空间 ->
App\Plugins\PurchaseOrder
Delivery checklist
交付检查清单
After creating a plugin, always show this summary to the user:
[OK] Plugin {Name} created at plugins/{name}/
[OK] Registered in composer.json (path repository)
[OK] ServiceProvider with loadMigrationsFrom()
[OK] Install command: php artisan {name}:install
Next steps:
1. composer require app/{name}
2. php artisan {name}:install
3. Add {Name}Plugin::make() to your Panel Provider
4. php artisan migrate创建插件后,务必向用户展示以下摘要:
[OK] 插件{Name}已创建于plugins/{name}/
[OK] 已在composer.json中注册(路径仓库)
[OK] 已创建包含loadMigrationsFrom()的ServiceProvider
[OK] 已创建安装命令:php artisan {name}:install
后续步骤:
1. composer require app/{name}
2. php artisan {name}:install
3. 将{Name}Plugin::make()添加到你的Panel Provider中
4. php artisan migrateAdditional reference
额外参考
For complex plugins with Filament Resources, Pages, and Widgets, see:
references/filament-components.mdFor advanced migration handling and versioning, see:
references/migrations-advanced.md如需创建包含Filament资源、页面和小组件的复杂插件,请查看:
references/filament-components.md如需了解高级迁移处理和版本控制,请查看:
references/migrations-advanced.md