 实现记录一键复制)
Filament ReplicateAction 完整实战指南基于 Eloquent replicate() 实现记录一键复制【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filamentFilament 内置的ReplicateAction是一套围绕 Laravel Eloquentreplicate()方法封装的高层复制操作它通过弹窗modal展示待复制字段支持排除指定列、在填充表单前改写数据、自定义成功跳转与通知并提供完整生命周期钩子。阅读本文后你将掌握在 Filament 资源页、表格行操作与自定义 Livewire 页面中配置和深度定制复制功能的全套方法包括源码级的执行原理与测试验证。引言一行代码获得记录复制能力Filament 提供了开箱即用的复制动作其底层基于 Laravel 的 Eloquent 模型复制机制即Model::replicate()。你只需在资源页面或表格中声明该动作即可use Filament\Actions\ReplicateAction; ReplicateAction::make()从源码看ReplicateAction继承自Action见 ReplicateAction.php并在setUp()中完成了默认配置默认动作名为replicategetDefaultName()返回replicate默认标签、弹窗标题、提交按钮文案均来自翻译文件filament-actions::replicate.single.*弹窗标题会自动拼入当前记录标题默认成功通知标题来自filament-actions::replicate.single.notifications.replicated.title表格图标与分组图标默认使用Heroicon::Square2Stack可通过FilamentIcon::resolve()覆盖。动作执行时会弹出 modal将原记录的字段值填入表单用户确认后生成一条新记录。复制动作的典型挂载位置在资源页面中ReplicateAction常作为行操作使用例如在表格中为每行记录提供复制入口use Filament\Actions\ReplicateAction; public function table(Table $table): Table { return $table -recordActions([ // ... ReplicateAction::make(), ]); }也可以在资源表单页头部、自定义页面中按需挂载。仓库测试夹具 PostsTable.php 演示了它在表格行操作中的典型用法并额外通过mutateRecordDataUsing()为标题追加 (Copy)后缀、通过schema()为复制弹窗提供可编辑字段ReplicateAction::make() -mutateRecordDataUsing(function (array $data): array { $data[title] . (Copy); return $data; }) -schema([ TextInput::make(title)-required(), ]),排除复制属性excludeAttributes()默认情况下复制动作会把原记录的所有属性attributesToArray()结果带入新记录。很多场景下我们并不希望照搬全部字段——例如唯一性字段slug、密码、token、时间戳等。此时使用excludeAttributes()指定需要排除的列use Filament\Actions\ReplicateAction; ReplicateAction::make() -excludeAttributes([slug])该方法在源码中的签名支持数组、闭包与null三种形态见 ReplicateAction.phppublic function excludeAttributes(array | Closure | null $attributes): static传null可清空之前的排除配置传闭包可动态计算排除列闭包支持注入参数详见下文依赖注入。底层实现上排除逻辑发生在两个阶段见 ReplicateAction.php表单填充阶段通过Arr::except($record-attributesToArray(), $this-getExcludedAttributes() ?? [])从原记录属性中剔除排除项再填充进 modal 表单执行保存阶段$record-replicate($this-getExcludedAttributes())直接调用 Eloquent 原生复制把排除列传给 Laravel 的replicate()方法确保新记录不携带这些属性。仓库测试 ReplicateActionTest.php 对该方法做了系统验证默认返回null、支持闭包求值、传null可清空、链式调用返回$this。填充表单前改写数据mutateRecordDataUsing()复制弹窗打开时原记录数据会先被填充进表单。若希望在填充之前修改这份数据例如把新记录的user_id指向当前登录用户可使用mutateRecordDataUsing()use Filament\Actions\ReplicateAction; ReplicateAction::make() -mutateRecordDataUsing(function (array $data): array { $data[user_id] auth()-id(); return $data; })源码中的执行逻辑ReplicateAction.php为先用Arr::except()剔除排除属性再调用evaluate()求值该闭包注入data参数把返回值作为最终填充到表单的数据。需要特别注意的是该闭包在动作真正执行时也会再次被调用当弹窗表单被跳过例如! $schema blank($data)的无表单场景且配置了该闭包时执行阶段会用同一套逻辑重新计算$data保证表单模式与直通模式下行为一致见 ReplicateAction.php。这正是 ReplicateActionTest.php 中标题追加(Copy)后写入数据库能够成立的原因。复制成功后的重定向successRedirectUrl()表单提交成功后默认不会发生页面跳转。通过successRedirectUrl()可以指定成功后的自定义跳转地址use Filament\Actions\ReplicateAction; ReplicateAction::make() -successRedirectUrl(route(posts.list))该方法来自CanRedirecttrait见 CanRedirect.php签名支持字符串或闭包public function successRedirectUrl(string | Closure | null $url): static除$record原记录外闭包还可以注入多种工具作为参数详见下文依赖注入一节例如ReplicateAction::make() -successRedirectUrl(function (Model $replica) { return route(posts.edit, $replica); })其中$replica即刚创建的复制模型实例。自定义成功通知记录复制成功后Filament 会向用户派发一条成功通知。你可以通过三种方式定制它。1. 仅修改通知标题successNotificationTitle()use Filament\Actions\ReplicateAction; ReplicateAction::make() -successNotificationTitle(Category replicated)该方法来自CanNotifytraitCanNotify.php同样支持静态字符串或闭包动态计算闭包可注入$replica等工具。2. 完整定制通知对象successNotification()需要同时控制标题、正文、图标等更多细节时传入一个Notification实例use Filament\Actions\ReplicateAction; use Filament\Notifications\Notification; ReplicateAction::make() -successNotification( Notification::make() -success() -title(Category replicated) -body(The category has been replicated successfully.), )该方法签名支持Notification | Closure | nullCanNotify.php。其底层派发逻辑在sendSuccessNotification()CanNotify.php默认构造Notification::make()-success()-title(...)作为起点再交由闭包求值若闭包返回null或传入null则直接禁用通知。闭包版本可以拿到默认通知对象作为起点进行微调ReplicateAction::make() -successNotification(function (Notification $notification, Model $replica): Notification { return $notification -body(A copy of {$replica-title} has been created.); })闭包可注入的典型参数包括$notification默认通知对象可作为定制起点与$replica刚创建的复制模型。3. 完全禁用通知successNotification(null)use Filament\Actions\ReplicateAction; ReplicateAction::make() -successNotification(null)传入null时CanNotifytrait 会将内部isSuccessNotificationDisabled置为true见 CanNotify.phpsendSuccessNotification()会在入口直接返回不再派发任何通知。生命周期钩子before / beforeReplicaSaved / after你可以在复制动作生命周期的不同阶段插入业务代码。完整的钩子链如下use Filament\Actions\ReplicateAction; use Illuminate\Database\Eloquent\Model; ReplicateAction::make() -before(function () { // 在记录被复制之前运行 }) -beforeReplicaSaved(function (Model $replica): void { // 在记录复制完成、但尚未写入数据库之前运行 }) -after(function (Model $replica): void { // 在复制记录保存到数据库之后运行 })钩子的底层执行顺序结合 ReplicateAction.php 与 HasLifecycleHooks.php动作提交时的实际调用链为$this-process(...)通过CanCustomizeProcesstraitCanCustomizeProcess.php执行默认流程也可用using()整体替换默认流程$record-replicate($this-getExcludedAttributes())创建复制模型$this-replica-fill($data)填充表单数据callBeforeReplicaSaved()触发beforeReplicaSaved钩子此时记录尚未save()$this-replica-save()写入数据库流程结束后在finally中调用$this-success()标记成功见 Action.php并触发成功通知。其中before()/after()来自通用生命周期钩子 trait HasLifecycleHooks.phpbefore()执行时会派发ActionCalling事件after()执行完毕会派发ActionCalled事件钩子链上还有beforeFormFilled、afterFormFilled、beforeFormValidated、afterFormValidated等表单阶段钩子可供选用。另外注意afterReplicaSaved()是已废弃的旧方法名现在等价于after()见 ReplicateAction.php建议直接使用after()。依赖注入机制以上钩子闭包支持按参数名自动注入工具。ReplicateAction重写了resolveDefaultClosureDependencyForEvaluationByName()见 ReplicateAction.php专门注册了replica注入项replica [$this-getReplica()],getReplica()ReplicateAction.php返回当前复制出来的模型实例。因此在beforeReplicaSaved、after、successNotification*、successRedirectUrl等所有闭包中只要参数命名为$replica即可获得Illuminate\Database\Eloquent\Model类型的复制实例——这也是文档中UtilityInjection能力的具体实现。中止复制流程halt() 与 cancel()在任意生命周期钩子中你可以调用$action-halt()中断整个复制流程。典型场景是业务校验不通过时先给出警示通知再中止操作use App\Models\Post; use Filament\Actions\Action; use Filament\Actions\ReplicateAction; use Filament\Notifications\Notification; ReplicateAction::make() -before(function (ReplicateAction $action, Post $record) { if (! $record-team-subscribed()) { Notification::make() -warning() -title(You don\t have an active subscription!) -body(Choose a plan to continue.) -persistent() -actions([ Action::make(subscribe) -button() -url(route(subscribe), shouldOpenInNewTab: true), ]) -send(); $action-halt(); } })halt()与cancel()的实现位于 Action.php它们分别抛出Halt与Cancel异常来中断流程。两者区别在于halt()中止复制流程但保留当前弹窗例如让用户修正表单或完成支付后重试cancel()不仅中止流程还会关闭动作弹窗完全取消这次操作。两个方法都接受一个可选的bool $shouldRollBackDatabaseTransaction参数当复制动作运行在数据库事务中时可传入true让异常触发事务回滚。源码级实现要点补充schema 模型绑定避免编辑原记录的错觉ReplicateAction重写了getSchema()见 ReplicateAction.php默认情况下 schema 的模型会被绑定到正在复制的原记录但这会让人误以为是在编辑原记录。因此该动作会将 schema 模型显式设置为复制模型的类名$this-getModel()让表单行为更接近创建一条新记录。using()整体替换默认复制流程借助CanCustomizeProcesstrait你还可以用using()完全接管默认的复制与保存逻辑ReplicateAction::make() -using(function (array $data, Model $record, Schema $schema): void { // 自定义复制与保存逻辑 })process()CanCustomizeProcess.php会优先求值using闭包否则回落到默认流程。测试覆盖与验证仓库为ReplicateAction提供了完整的测试套件 ReplicateActionTest.php覆盖了动作可渲染、弹窗可挂载mountAction/assertActionMounted实际复制后数据库出现标题为Original Post (Copy)的新记录复制后记录总数 1且原记录保持不变$post-refresh()-title仍是原文成功通知正常派发assertNotifiedmutateRecordDataUsing()对表单数据与落库数据的改写均生效支持连续复制多条记录excludeAttributes()的默认值、闭包求值、null清空等边界行为默认名称为replicate、各链式方法返回$this、执行前getReplica()返回null。这些测试基于PostsTableLivewire 夹具PostsTable.php运行可作为你在真实项目中集成ReplicateAction时的行为参考。结语ReplicateAction把复制一条 Eloquent 记录这件高频操作包装成了声明式、可弹窗编辑、可钩子定制的完整能力excludeAttributes()控制复制范围mutateRecordDataUsing()改写填充数据successRedirectUrl()与successNotification*()管理成功后效before/beforeReplicaSaved/after三阶段钩子加上halt()/cancel()则赋予你对流程的精确控制力。结合 ReplicateAction.php 的源码与 ReplicateActionTest.php 的测试用例你可以在自己的 Filament 面板中快速落地稳健、可维护的记录复制功能。【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考