grandcreation / nova-nested-many
Laravel Nova - Nested Many
Requires
- php: ^7.4|^8.0
- laravel/nova: ^4.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.16
This package is auto-updated.
Last update: 2024-09-04 04:52:14 UTC
README
要求
php: ^7.4 | ^8
laravel/nova: ^4
安装
composer require lupennat/nova-nested-many
用法
在资源上全局注册 trait HasNestedResource
。
namespace App\Nova; use Laravel\Nova\Resource as NovaResource; use Lupennat\NestedMany\HasNestedResource; abstract class Resource extends NovaResource { use HasNestedResource; }
像 HasMany
一样使用 HasManyNested
字段。
namespace App\Nova; use Laravel\Nova\Fields\ID; use Illuminate\Http\Request; use Laravel\Nova\Fields\Text; use Laravel\Nova\Fields\Gravatar; use Laravel\Nova\Fields\Password; // Add use statement here. use Lupennat\NestedMany\Fields\HasManyNested; class User extends Resource { public function fields(Request $request) { return [ ID::make()->sortable(), Gravatar::make(), Text::make('Name') ->sortable() ->rules('required', 'max:255'), Text::make('Email') ->sortable() ->rules('required', 'email', 'max:254') ->creationRules('unique:users,email') ->updateRules('unique:users,email,{{resourceId}}'), Password::make('Password') ->onlyOnForms() ->creationRules('required', 'string', 'min:6') ->updateRules('nullable', 'string', 'min:6'), // Add HasManyNested here. HasManyNested::make('Posts'), ]; } }
HasManyNested
默认在详情页、更新页和创建页上可见。在索引页上不可用。
实现 Nestable
合同并使用 trait HasNested
为每个将用于 HasNestedMany
的相关模型。
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Lupennat\NestedMany\Models\Contracts\Nestable; use Lupennat\NestedMany\Models\HasNested; class Post extends Model implements Nestable { use HasNested; }
HasNestedMany 字段
依赖项
HasNestedMany
字段支持 Nova dependsOn
。
HasNestedMany::make('Posts', Post::class) ->dependsOn('name', function(HasNestedMany $field, NovaRequest $novaRequest, FormData $formData) { if ($formData->name === 'xxx') { $field->show(); } else { $field->hide(); } })
传播
HasNestedMany
字段可以将父字段值传播到相关资源。
HasNestedMany::make('Posts', Post::class)->propagate(['name'])
在相关资源中,可以通过在请求上调用 getNestedPropagated
方法检索传播的字段。
namespace App\Nova; use Laravel\Nova\Fields\ID; use Laravel\Nova\Fields\BelongsTo; use Laravel\Nova\Fields\Select; use Laravel\Nova\Fields\Text; use Laravel\Nova\Http\Requests\NovaRequest; class Post extends Resource { public function fields(NovaRequest $request) { return array_filter([ ID::make(), BelongsTo::make(__('User'), 'user', User::class), Select::section(__('Section'), 'section') ->options(['sport' => 'Sport', 'news' => 'News']) ->rules('required'), Text::title(__('Title'), 'title') ->rules('required'), $request->getNestedPropagated('name') === 'xxx' ? Text::make(__('Extra Field'), 'extra')->hide() : null ]); } }
默认子项
您可以使用 defaultChildren
方法在子项为空时生成默认的相关资源集合。
defaultChildren 仅在创建页上工作。
HasNestedMany::make('Posts', Post::class) ->defaultChildren([ ['title' => 'first post', 'section' => 'sport'], ['title' => 'second post', 'section' => 'news'], ])
如果您想覆盖现有的子项,可以使用
HasNestedMany::make('Posts', Post::class) ->defaultChildren([ ['title' => 'first post', 'section' => 'sport'], ['title' => 'second post', 'section' => 'news'], ], true)
附加选项
钩子
您可以在 HasNestedMany
填充数据库前后指定回调。
namespace App\Nova; use Illuminate\Http\Request; use Lupennat\NestedMany\Fields\HasManyNested; use Laravel\Nova\Http\Requests\NovaRequest; class User extends Resource { public function fields(Request $request) { return [ HasNestedMany::make('Posts', Post::class) ->beforeFill(function(\App\Models\User $user, NovaRequest $request) { // do stuff }) ->afterFill(function(\App\Models\User $user, NovaRequest $request) { // do stuff }) ]; } }
可嵌套资源
资源 trait HasNestedResource
提供了与嵌套相关的新的功能。
可嵌套标题
面板和选项卡视图都使用 nestedTitle
方法检索资源的标题。
如果找不到方法,将回退到原始的 nova 资源标题
namespace App\Nova; class User extends Resource { public function nestedTitle() { return $this->resource->name; } }
可嵌套授权
Nested Many 将使用 Laravel Nova 资源授权进行创建/更新/删除。您可以在 3 个新方法中为 Nested Many 定义不同的策略
namespace App\Nova; class User extends Resource { public static function authorizedToCreateNested(Request $request) { return true; } public function authorizedToUpdateNested(Request $request) { return false; } public function authorizedToDeleteNested(Request $request) { return $this->authorizedToDelete($request); } }
可嵌套操作
您可以通过定义嵌套操作通过服务器操作相关内容。
Nested
操作可以通过$keepOpened
属性或keepOpened()
方法在操作执行后保持模态打开。
可嵌套基本操作
默认情况下,NestedMany 有 3 个基本操作 NestedBasicAddAction
、NestedBasicDeleteAction
、NestedBasicRestoreAction
,并且您可以通过资源上的 3 个方法自定义它们。
namespace App\Nova; use Lupennat\NestedMany\Actions\Basics\NestedBasicAddAction; use Lupennat\NestedMany\Actions\Basics\NestedBasicDeleteAction; use Lupennat\NestedMany\Actions\Basics\NestedBasicRestoreAction; use Laravel\Nova\Http\Requests\NovaRequest; class Post extends Resource { /** * Get the nested create action on the entity. */ public function nestedAddAction(NovaRequest $request): NestedBasicAddAction { return new \App\Nova\NestedActions\MyCustomAddActionExtendsBasicAddAction(); } /** * Get the nested delete action on the entity. */ public function nestedDeleteAction(NovaRequest $request): NestedBasicDeleteAction { return parent::nestedDeleteAction($request)->withConfirmation(); } /** * Get the nested delete action on the entity. */ public function nestedRestoreAction(NovaRequest $request): NestedBasicRestoreAction { return parent::nestedRestoreAction($request)->withConfirmation(); } }
可嵌套软删除操作
NestedDeleteAction 自动支持 softDelete
逻辑(不是真正的 eloquent softDelete),要启用软删除/恢复逻辑,您需要在相关模型上设置 protected $nestedHasSoftDelete = true
。
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Lupennat\NestedMany\Models\Contracts\Nestable; use Lupennat\NestedMany\Models\HasNested; class Post extends Model implements Nestable { use HasNested; protected $nestedHasSoftDelete = true; }
可嵌套自定义操作
您可以使用 nested-many:action Artisan 命令生成嵌套操作。默认情况下,所有操作都放在 app/Nova/NestedActions 目录中
php artisan nested-many:action DuplicatePost
您可以通过传递 --destructive 选项生成破坏性操作
php artisan nested-many:action DeleteAllPosts --destructive
Nested Actions 与 Nova Actions 有很多相似之处,主要区别是 handle
方法应始终返回一个 NestedObject
集合。
您可以使用 $this->getNewNested()
方法生成新的 NestedObject
。
要了解如何定义 Nova 操作,让我们看看一个示例。在这个例子中,我们将定义一个复制帖子的操作
<?php namespace App\Nova\NestedActions; use Illuminate\Support\Collection; use Laravel\Nova\Fields\ActionFields; use Laravel\Nova\Http\Requests\NovaRequest; use Lupennat\NestedMany\Models\Nested; use Lupennat\NestedMany\Actions\NestedAction; class DuplicatePost extends NestedAction { /** * Handle any post-validation processing. * * @param \Illuminate\Contracts\Validation\Validator $validator * @param \Illuminate\Support\Collection<int,\Lupennat\NestedMany\Models\Nested> $resources * * @return void */ protected function afterValidation(NovaRequest $request, Collection $resources, $validator) { // do validation stuff } /** * Perform the action on the given models. * * @param \Laravel\Nova\Fields\ActionFields $actionFields * @param \Illuminate\Support\Collection<int,\Lupennat\NestedMany\Models\Nested> $children * @param string|null $selectedUid * * @return \Illuminate\Support\Collection<int,\Lupennat\NestedMany\Models\Nested> */ public function handle(ActionFields $fields, Collection $children, $selectedUid): Collection { $selectedNested = $children->where(Nested::UIDFIELD, $selectedUid)->first(); $children->push(tap($this->getNewNested(), function ($newResource) use ($selectedNested, $fields) { foreach ($selectedNested->getAttributes() as $key => $value) { if($key !== $selectedNested->getKeyName()) { $newResource->{$key} = $value; } } $newResource->active(); })); return $children; } /** * Get the fields available on the action. * * @param \Laravel\Nova\Http\Requests\NovaRequest $request * @return array */ public function fields(NovaRequest $request) { return []; } }
您可以通过在资源中调用 nestedActions
方法注册自定义 NestedActions
。
namespace App\Nova; use Lupennat\NestedMany\Actions\Basics\NestedBasicAddAction; class Post extends Resource { /** * Get the actions available on the entity. * * @return array<\Lupennat\NestedMany\Actions\NestedAction> */ public function nestedActions(NovaRequest $request): array { return [ \App\Nova\NestedActions\DuplicatePost::create() ]; } }
嵌套对象
使用 NestedActions
时,所有 Eloquent
模型默认都包装在扩展 Laravel Fluent
类的 Nested
类中。
所有模型属性都复制到 Nested
属性上,这样您可以直接修改 Nested
对象的属性值。
它提供了便捷的方法来操作对象,而无需对数据库执行查询。
当调用toModel时,如果注册了Mutators,嵌套类将对当前对象应用更改到原始Eloquent模型。
对嵌套对象执行的每个更改,在用户点击父表单页面上的创建/更新按钮之前,都不会存储在数据库中。
鸣谢
NestedForm字段基于原始的Nova嵌套表单。