除了我们已经讨论过的各种字段,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模型belongsToManyRole模型。
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模型belongsToManyRole模型。在我们的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'),内联创建限制
内联关系创建仅支持创建一层深的关系。这意味着您不能在现有的内联创建模态中触发另一个内联创建模态。相反,您必须选择一个已存在的资源。