除了我们已经讨论过的各种字段,Nova 还完全支持 Laravel 的所有关系。将关系字段添加到 Nova 资源后,您将开始体验 Nova 仪表板的强大功能,因为资源详细信息页面将允许您快速查看和搜索资源的相关模型
HasOne
字段对应于 hasOne
Eloquent 关系。例如,假设一个 User
模型 hasOne
Address
模型。我们可以像这样将关系添加到我们的 User
Nova 资源中
use Laravel\Nova\Fields\HasOne;
HasOne::make('Address'),
与其他类型的字段一样,关系字段会自动将字段的可显示名称“转换为驼峰式”以确定底层关系方法/属性。但是,您可以通过将关系方法的名称作为第二个参数传递给字段的 make
方法来显式指定关系方法的名称
HasOne::make('Dirección', 'address'),
HasOne
关系字段可以使用 ofMany
方法转换为“has one of many” Eloquent 关系。例如,假设一个 User
模型 hasMany
Post
模型。我们可以像这样将“has one of many”关系添加到我们的 User
Nova 资源中
use App\Nova\Post;
use Laravel\Nova\Fields\HasOne;
HasOne::ofMany('Latest Post', 'latestPost', Post::class),
HasMany
字段对应于 hasMany
Eloquent 关系。例如,假设一个 User
模型 hasMany
Post
模型。我们可以像这样将关系添加到我们的 User
Nova 资源中
use Laravel\Nova\Fields\HasMany;
HasMany::make('Posts'),
将字段添加到资源后,它将显示在资源的详细信息页面上。
复数资源名称
在定义 HasMany
关系时,请确保使用关系的复数形式,以便 Nova 可以推断出正确的单数资源名称
HasMany::make('Posts'),
HasOneThrough
字段对应于 hasOneThrough
Eloquent 关系。例如,假设一个 Mechanic
模型有一个 Car
,每个 Car
可能有一个 Owner
。虽然 Mechanic
和 Owner
没有直接连接,但 Mechanic
可以通过 Car
本身访问 Owner
。您可以通过将其添加到 Nova 资源中来显示此关系
use Laravel\Nova\Fields\HasOneThrough;
HasOneThrough::make('Owner'),
HasManyThrough
字段对应于 hasManyThrough
Eloquent 关系。例如,Country
模型可能通过中间 User
模型拥有许多 Post
模型。在此示例中,您可以轻松地收集给定国家/地区的博客文章。要在 Nova 中显示此关系,您可以将其添加到您的 Nova 资源中
use Laravel\Nova\Fields\HasManyThrough;
HasManyThrough::make('Posts'),
BelongsTo
字段对应于 belongsTo
Eloquent 关系。例如,假设 Post
模型 belongsTo
User
模型。我们可以将关系添加到我们的 Post
Nova 资源中,如下所示
use Laravel\Nova\Fields\BelongsTo;
BelongsTo::make('User'),
自定义资源类
您可以通过提供 make
方法的第二个和第三个参数来自定义关系字段使用的资源类,这两个参数定义了关系的名称和底层的 Nova 资源类
BelongsTo::make('Author', 'author', 'App\Nova\User'),
当您在查看索引或详细信息视图时将鼠标悬停在 BelongsTo
链接上时,Nova 将显示一张小卡片,允许您“查看”链接的关系
BelongsTo
关系 关系查看默认情况下是启用的;但是,您可以使用 BelongsTo
字段上的 noPeeking
帮助程序来阻止用户查看关系
BelongsTo::make('Author')->noPeeking()
您还可以使用 peekable
方法来确定是否允许用户查看关系
use Laravel\Nova\Http\Requests\NovaRequest;
BelongsTo::make('Author')->peekable(function (NovaRequest $request) {
return $request->isResourceDetailRequest();
})
如果您希望您的 BelongsTo
关系是 nullable
,您只需将 nullable
方法链接到字段的定义中即可
use Laravel\Nova\Fields\BelongsTo;
BelongsTo::make('User')->nullable(),
当在资源创建/更新页面上显示BelongsTo
字段时,下拉选择菜单或搜索菜单将显示资源的“标题”。例如,User
资源可以使用name
属性作为其标题。然后,当资源在BelongsTo
选择菜单中显示时,将显示该属性。
要自定义资源的“标题”属性,可以在资源类上定义title
属性。
public static $title = 'name';
或者,可以覆盖资源的title
方法。
/**
* Get the value that should be displayed to represent the resource.
*
* @return string
*/
public function title()
{
return $this->name;
}
默认情况下,关联资源在选择下拉列表中列出时将按其标题排序。使用dontReorderAssociatables
方法,可以禁用此行为,以便根据关联查询指定的排序对资源进行排序。
BelongsTo::make('User')->dontReorderAssociatables(),
默认情况下,BelongsTo
字段允许用户选择软删除的模型;但是,可以使用withoutTrashed
方法禁用此功能。
BelongsTo::make('User')->withoutTrashed(),
BelongsToMany
字段对应于belongsToMany
Eloquent 关系。例如,假设User
模型belongsToMany
Role
模型。
public function roles()
{
return $this->belongsToMany(Role::class);
}
我们可以像这样将关系添加到我们的User
Nova 资源中。
use Laravel\Nova\Fields\BelongsToMany;
BelongsToMany::make('Roles'),
可以通过向make
方法提供第二个和第三个参数来自定义关系字段使用的资源类。
BelongsToMany::make('Pseudonyms', 'pseudonyms', 'App\Nova\Author'),
将字段添加到资源后,它将显示在资源的详细信息页面上。
如果您的belongsToMany
关系与存储在多对多关系的中间表上的其他“枢纽”字段交互,您也可以将这些字段附加到您的BelongsToMany
Nova 关系。一旦这些字段附加到关系字段,并且关系已在两个相关模型/资源上定义,它们将显示在相关资源索引上。
例如,假设我们的User
模型belongsToMany
Role
模型。在我们的role_user
中间表上,假设我们有一个notes
字段,其中包含一些关于关系的简单文本注释。我们可以使用fields
方法将此枢纽字段附加到BelongsToMany
字段。
BelongsToMany::make('Roles')
->fields(function ($request, $relatedModel) {
return [
Text::make('Notes'),
];
}),
当然,我们也可能在关系的反向关系中定义此字段。因此,如果我们在User
资源上定义BelongsToMany
字段,我们将在Role
资源上定义其反向关系。
BelongsToMany::make('Users')
->fields(function ($request, $relatedModel) {
return [
Text::make('Notes'),
];
}),
必须定义枢纽字段。
不要忘记使用withPivot
方法在您的模型的关系定义中定义枢纽字段:https://laravel.net.cn/docs/eloquent-relationships#retrieving-intermediate-table-columns
由于在关系的两端定义字段会导致一些代码重复,因此 Nova 允许您将可调用对象传递给fields
方法。
BelongsToMany::make('Users')->fields(new RoleUserFields),
在这个例子中,RoleUserFields
类将是一个简单的可调用类,它返回枢纽字段的数组。
<?php
namespace App\Nova;
use Laravel\Nova\Fields\Text;
class RoleUserFields
{
/**
* Get the pivot fields for the relationship.
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Illuminate\Database\Eloquent\Model $relatedModel
* @return array
*/
public function __invoke($request, $relatedModel)
{
return [
Text::make('Notes'),
];
}
}
Laravel Nova 也允许你在 belongsToMany
关系字段的字段列表中定义计算字段。
BelongsToMany::make('Users')
->fields(function ($request, $relatedModel) {
return [
Text::make('Notes'),
Boolean::make('Has Notes', function ($pivot) {
return ! empty($pivot->notes);
}),
];
}),
通常,Nova 操作 在资源上运行。但是,你也可以将操作附加到 belongsToMany
字段,以便它们可以在枢纽/中间表记录上运行。要实现这一点,你可以在字段定义上链接 actions
方法。
BelongsToMany::make('Roles')
->actions(function () {
return [
new Actions\MarkAsActive,
];
}),
将操作附加到字段后,你将能够从父资源详细信息页面上的关系索引中选择操作并执行它。
操作
要了解有关 Nova 操作的更多信息,请查看完整的 操作文档。
当在资源创建/更新页面上显示 BelongsToMany
字段时,下拉选择菜单或搜索菜单将显示资源的“标题”。例如,Role
资源可以使用 name
属性作为其标题。然后,当资源在 BelongsToMany
选择菜单中显示时,将显示该属性。
要自定义资源的“标题”属性,可以在资源类上定义title
属性。
public static $title = 'name';
或者,可以覆盖资源的title
方法。
/**
* Get the value that should be displayed to represent the resource.
*
* @return string
*/
public function title()
{
return $this->name;
}
默认情况下,关联资源在选择下拉列表中列出时将按其标题排序。使用 dontReorderAttachables
方法,你可以禁用此行为,以便根据 关联查询 指定的排序对资源进行排序。
BelongsToMany::make('Roles')->dontReorderAttachables(),
默认情况下,Laravel Nova 确保“属于多方”关系是唯一的。但是,如果需要,你可以指示 Nova 允许重复关系条目。
要开始,你应该确保你的枢纽记录的 id
列是可用的,方法是在你的 Eloquent 模型上定义关系时使用 withPivot
方法。在这个例子中,让我们假设一个 User
可以购买一个或多个 Book
。
public function books()
{
return $this->belongsToMany(Book::class)
->using(BookPurchase::class)
->withPivot('id', 'notes')
->withTimestamps();
}
接下来,我们可以使用 allowDuplicateRelations
方法定义允许重复关系的 Nova 关系。
BelongsToMany::make('Books')
->fields(function () {
return [
Text::make('Notes'),
];
})->allowDuplicateRelations(),
MorphOne
字段对应 morphOne
Eloquent 关系。例如,假设一个 Post
与 Image
模型之间存在一对一的多态关系。我们可以像这样将关系添加到我们的 Post
Nova 资源中
use Laravel\Nova\Fields\MorphOne;
MorphOne::make('Image'),
MorphOne
关系字段可以使用 ofMany
方法转换为 "morph one of many" Eloquent 关系。例如,假设一个 Post
与 Comment
模型之间存在一对多的多态关系。我们可以像这样将关系添加到我们的 Post
Nova 资源中
use App\Nova\Comment;
use Laravel\Nova\Fields\MorphOne;
MorphOne::ofMany('Latest Comment', 'latestComment', Comment::class),
MorphMany
字段对应 morphMany
Eloquent 关系。例如,假设一个 Post
与 Comment
模型之间存在一对多的多态关系。我们可以像这样将关系添加到我们的 Post
Nova 资源中
use Laravel\Nova\Fields\MorphMany;
MorphMany::make('Comments'),
MorphTo
字段对应 morphTo
Eloquent 关系。例如,假设一个 Comment
模型与 Post
和 Video
模型之间都存在多态关系。我们可以像这样将关系添加到我们的 Comment
Nova 资源中
use App\Nova\Post;
use App\Nova\Video;
use Laravel\Nova\Fields\MorphTo;
MorphTo::make('Commentable')->types([
Post::class,
Video::class,
]),
如上例所示,types
方法用于指示 MorphTo
字段可以与哪些类型的资源相关联。Nova 将使用此信息在创建和更新页面上填充 MorphTo
字段的类型选择菜单
MorphTo 标题属性
当在资源创建/更新页面上显示 MorphTo
字段时,将自动显示可用资源的 标题属性。
MorphTo
关系 如果您希望 MorphTo
关系为 nullable
,请将 nullable
方法链接到字段的定义中
use App\Nova\Post;
use App\Nova\Video;
use Laravel\Nova\Fields\MorphTo;
MorphTo::make('Commentable')->types([
Post::class,
Video::class,
])->nullable(),
MorphTo
关系 当在查看索引或详细信息视图时将鼠标悬停在 MorphTo
链接上时,Nova 将显示一张小卡片,允许您“查看”链接的关系
MorphTo
关系 关系查看默认情况下是启用的;但是,您可以使用 MorphTo
字段上的 noPeeking
帮助程序阻止用户查看关系
MorphTo::make('Author')->noPeeking()
您还可以使用 peekable
方法来确定是否允许用户查看关系
use Laravel\Nova\Http\Requests\NovaRequest;
MorphTo::make('Author')->peekable(function (NovaRequest $request) {
return $request->isResourceDetailRequest();
})
MorphTo
关系中设置默认值 在设置 MorphTo
字段的默认值时,除了使用 default
方法设置字段的初始值外,还需要指定要使用的资源的类名。您可以通过 defaultResource
方法来实现这一点。
use App\Nova\Post;
MorphTo::make('Commentable')
->default(1)
->defaultResource(Post::class)
MorphToMany
字段对应于 morphToMany
Eloquent 关系。例如,假设一个 Post
与 Tag
模型具有多对多多态关系。我们可以像这样将关系添加到我们的 Post
Nova 资源中
use Laravel\Nova\Fields\MorphToMany;
MorphToMany::make('Tags'),
如果您的 morphToMany
关系与存储在多对多关系中间表上的其他“枢纽”字段交互,您也可以将这些字段附加到您的 MorphToMany
Nova 关系。将这些字段附加到关系字段后,它们将显示在相关资源索引中。
例如,在我们的 taggables
中间表上,假设我们有一个 notes
字段,其中包含一些关于关系的简单文本注释。我们可以使用 fields
方法将此枢纽字段附加到 MorphToMany
字段
MorphToMany::make('Tags')
->fields(function ($request, $relatedModel) {
return [
Text::make('Notes'),
];
}),
当然,我们也可能在关系的反向关系中定义此字段。因此,如果我们在 Post
资源上定义 MorphToMany
字段,我们将在 Tag
资源上定义它的反向关系
MorphToMany::make('Posts')
->fields(function ($request, $relatedModel) {
return [
Text::make('Notes'),
];
}),
必须定义枢纽字段。
不要忘记使用withPivot
方法在您的模型的关系定义中定义枢纽字段:https://laravel.net.cn/docs/eloquent-relationships#retrieving-intermediate-table-columns
由于在关系的两端定义字段会导致一些代码重复,因此 Nova 允许您将可调用对象传递给fields
方法。
MorphToMany::make('Users')->fields(new TaggableFields),
在此示例中,TaggableFields
类将是一个简单的可调用类,它返回枢纽字段的数组
<?php
namespace App\Nova;
use Laravel\Nova\Fields\Text;
class TaggableFields
{
/**
* Get the pivot fields for the relationship.
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Illuminate\Database\Eloquent\Model $relatedModel
* @return array
*/
public function __invoke($request, $relatedModel)
{
return [
Text::make('Notes'),
];
}
}
当在资源创建/更新页面上显示 MorphToMany
字段时,下拉选择菜单或搜索菜单将显示资源的“标题”。例如,Tag
资源可以使用 name
属性作为其标题。然后,当资源显示在 MorphToMany
选择菜单中时,将显示该属性
要自定义资源的“标题”属性,可以在资源类上定义title
属性。
public static $title = 'name';
或者,可以覆盖资源的title
方法。
/**
* Get the value that should be displayed to represent the resource.
*
* @return string
*/
public function title()
{
return $this->name;
}
默认情况下,BelongsToMany
、HasMany
和 MorphToMany
关系字段显示在资源详细信息页面上。但是,如果资源具有许多性能密集型关系,这会导致页面变慢,这很快就会变得很麻烦。
出于这个原因,Nova 允许您将关系标记为 collapsable
。当关系可折叠时,用户可以折叠给定资源的一些关系,Nova 将记住他们在后续页面加载时的首选项。折叠的关系不会从数据库中检索,直到关系在 Nova 的用户界面中展开
MorphToMany::make('Tags')->collapsable(),
您也可以通过 collapsedByDefault
方法指示关系默认情况下始终处于折叠状态。
MorphToMany::make('Tags')->collapsedByDefault(),
默认情况下,当 BelongsTo
、MorphTo
、BelongsToMany
和 MorphToMany
关系字段显示在资源创建/更新页面上时,将显示一个简单的下拉选择菜单。但是,如果资源模型具有许多记录,这很快就会变得很麻烦。例如,想象一个下拉选择菜单,其中填充了超过 10,000 个用户!
您可以将关系标记为 searchable
,而不是显示下拉选择菜单。当关系被标记为 searchable
时,将显示一个漂亮的搜索输入控件。
要将关系标记为 searchable
,请将 searchable
方法链接到字段的定义中。如果您想有条件地确定字段是否应该可搜索,可以将闭包传递给 searchable
方法。
BelongsTo::make('User')->searchable(),
BelongsTo::make('User')->searchable(function ($request) {
return true;
}),
您还可以指示关系字段显示 资源的副标题,方法是在定义字段时调用 withSubtitles
方法。
BelongsTo::make('User')->searchable()->withSubtitles(),
如果您想自定义相关查询,可以通过调用 relatableQueryUsing
方法来实现。
use Illuminate\Database\Eloquent\Builder;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Http\Requests\NovaRequest;
BelongsTo::make('User')
->relatableQueryUsing(function (NovaRequest $request, Builder $query) {
$query->whereIn('teams', ['editor', 'writer']);
}),
当您需要根据另一个字段的值调整查询时,relatableQueryUsing
方法也会很有用。
use Illuminate\Database\Eloquent\Builder;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\FormData;
use Laravel\Nova\Http\Requests\NovaRequest;
BelongsTo::make('User')
->dependsOn('topic', function (BelongsTo $field, NovaRequest $request, FormData $formData) {
if ($formData->topic === 'laravel-nova') {
$field->relatableQueryUsing(function (NovaRequest $request, Builder $query) {
$query->whereIn('email', ['[email protected]', '[email protected]']);
});
}
}),
您可以通过在要搜索的资源类的类上定义 relatableSearchResults
属性来限制搜索字段时返回的结果数量。
/**
* The number of results to display when searching for relatable resources without Scout.
*
* @var int|null
*/
public static $relatableSearchResults = 200;
为了方便起见,当 BelongsTo
或 MorphTo
关系字段显示在资源创建或更新页面上时,您可以通过模态窗口内联创建相关资源,而无需离开创建/更新页面。
要启用此功能,请在定义关系字段时调用 showCreateRelationButton
方法。
BelongsTo::make('User')->showCreateRelationButton(),
您也可以将闭包传递给showCreateRelationButton
方法,以有条件地确定是否应启用内联资源创建。
BelongsTo::make('User')->showCreateRelationButton(function ($request) {
//
}),
您也可以从“附加”和“更新附加”页面创建相关的多对多关系。要启用此功能,请在定义BelongsToMany
或MorphToMany
关系时调用showCreateRelationButton
。
BelongsToMany::make('Roles')->showCreateRelationButton(),
要隐藏内联创建按钮,请在定义关系字段时调用hideCreateRelationButton
方法。
BelongsTo::make('User')->hideCreateRelationButton(),
内联关系创建过程将尊重您定义的任何授权策略。
您可以使用modalSize
方法调整模态的大小。
// Can be "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl".
BelongsTo::make('User')->showCreateRelationButton()->modalSize('7xl'),
内联创建限制
内联关系创建仅支持创建一层深的关系。这意味着您不能在现有的内联创建模态中触发另一个内联创建模态。相反,您必须选择一个已存在的资源。