logo

关系

除了我们已经讨论过的各种字段,Nova 还完全支持 Laravel 的所有关系。将关系字段添加到 Nova 资源后,您将开始体验 Nova 仪表板的强大功能,因为资源详细信息页面将允许您快速查看和搜索资源的相关模型

Detail page Relationship

HasOne

HasOne 字段对应于 hasOne Eloquent 关系。例如,假设一个 User 模型 hasOne Address 模型。我们可以像这样将关系添加到我们的 User Nova 资源中

php
use Laravel\Nova\Fields\HasOne;

HasOne::make('Address'),

与其他类型的字段一样,关系字段会自动将字段的可显示名称“转换为驼峰式”以确定底层关系方法/属性。但是,您可以通过将关系方法的名称作为第二个参数传递给字段的 make 方法来显式指定关系方法的名称

php
HasOne::make('Dirección', 'address'),

HasOneOfMany

HasOne 关系字段可以使用 ofMany 方法转换为“has one of many” Eloquent 关系。例如,假设一个 User 模型 hasMany Post 模型。我们可以像这样将“has one of many”关系添加到我们的 User Nova 资源中

php
use App\Nova\Post;
use Laravel\Nova\Fields\HasOne;

HasOne::ofMany('Latest Post', 'latestPost', Post::class),

HasMany

HasMany 字段对应于 hasMany Eloquent 关系。例如,假设一个 User 模型 hasMany Post 模型。我们可以像这样将关系添加到我们的 User Nova 资源中

php
use Laravel\Nova\Fields\HasMany;

HasMany::make('Posts'),

将字段添加到资源后,它将显示在资源的详细信息页面上。

复数资源名称

在定义 HasMany 关系时,请确保使用关系的复数形式,以便 Nova 可以推断出正确的单数资源名称

php
HasMany::make('Posts'),

HasOneThrough

HasOneThrough 字段对应于 hasOneThrough Eloquent 关系。例如,假设一个 Mechanic 模型有一个 Car,每个 Car 可能有一个 Owner。虽然 MechanicOwner 没有直接连接,但 Mechanic 可以通过 Car 本身访问 Owner。您可以通过将其添加到 Nova 资源中来显示此关系

php
use Laravel\Nova\Fields\HasOneThrough;

HasOneThrough::make('Owner'),

HasManyThrough

HasManyThrough 字段对应于 hasManyThrough Eloquent 关系。例如,Country 模型可能通过中间 User 模型拥有许多 Post 模型。在此示例中,您可以轻松地收集给定国家/地区的博客文章。要在 Nova 中显示此关系,您可以将其添加到您的 Nova 资源中

php
use Laravel\Nova\Fields\HasManyThrough;

HasManyThrough::make('Posts'),

BelongsTo

BelongsTo 字段对应于 belongsTo Eloquent 关系。例如,假设 Post 模型 belongsTo User 模型。我们可以将关系添加到我们的 Post Nova 资源中,如下所示

php
use Laravel\Nova\Fields\BelongsTo;

BelongsTo::make('User'),

自定义资源类

您可以通过提供 make 方法的第二个和第三个参数来自定义关系字段使用的资源类,这两个参数定义了关系的名称和底层的 Nova 资源类

php
BelongsTo::make('Author', 'author', 'App\Nova\User'),

查看 BelongsTo 关系

当您在查看索引或详细信息视图时将鼠标悬停在 BelongsTo 链接上时,Nova 将显示一张小卡片,允许您“查看”链接的关系

Relationship Peeking

阻止查看 BelongsTo 关系

关系查看默认情况下是启用的;但是,您可以使用 BelongsTo 字段上的 noPeeking 帮助程序来阻止用户查看关系

php
BelongsTo::make('Author')->noPeeking()

您还可以使用 peekable 方法来确定是否允许用户查看关系

php
use Laravel\Nova\Http\Requests\NovaRequest;

BelongsTo::make('Author')->peekable(function (NovaRequest $request) {
    return $request->isResourceDetailRequest();
})

可空关系

如果您希望您的 BelongsTo 关系是 nullable,您只需将 nullable 方法链接到字段的定义中即可

php
use Laravel\Nova\Fields\BelongsTo;

BelongsTo::make('User')->nullable(),

标题属性

当在资源创建/更新页面上显示BelongsTo字段时,下拉选择菜单或搜索菜单将显示资源的“标题”。例如,User资源可以使用name属性作为其标题。然后,当资源在BelongsTo选择菜单中显示时,将显示该属性。

Belongs To Title

要自定义资源的“标题”属性,可以在资源类上定义title属性。

php
public static $title = 'name';

或者,可以覆盖资源的title方法。

php
/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

禁用按标题排序

默认情况下,关联资源在选择下拉列表中列出时将按其标题排序。使用dontReorderAssociatables方法,可以禁用此行为,以便根据关联查询指定的排序对资源进行排序。

php
BelongsTo::make('User')->dontReorderAssociatables(),

过滤已删除的项目

默认情况下,BelongsTo字段允许用户选择软删除的模型;但是,可以使用withoutTrashed方法禁用此功能。

php
BelongsTo::make('User')->withoutTrashed(),

BelongsToMany

BelongsToMany字段对应于belongsToMany Eloquent 关系。例如,假设User模型belongsToManyRole模型。

php
public function roles()
{
    return $this->belongsToMany(Role::class);
}

我们可以像这样将关系添加到我们的User Nova 资源中。

php
use Laravel\Nova\Fields\BelongsToMany;

BelongsToMany::make('Roles'),

可以通过向make方法提供第二个和第三个参数来自定义关系字段使用的资源类。

php
BelongsToMany::make('Pseudonyms', 'pseudonyms', 'App\Nova\Author'),

将字段添加到资源后,它将显示在资源的详细信息页面上。

枢纽字段

如果您的belongsToMany关系与存储在多对多关系的中间表上的其他“枢纽”字段交互,您也可以将这些字段附加到您的BelongsToMany Nova 关系。一旦这些字段附加到关系字段,并且关系已在两个相关模型/资源上定义,它们将显示在相关资源索引上。

例如,假设我们的User模型belongsToManyRole模型。在我们的role_user中间表上,假设我们有一个notes字段,其中包含一些关于关系的简单文本注释。我们可以使用fields方法将此枢纽字段附加到BelongsToMany字段。

php
BelongsToMany::make('Roles')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

当然,我们也可能在关系的反向关系中定义此字段。因此,如果我们在User资源上定义BelongsToMany字段,我们将在Role资源上定义其反向关系。

php
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方法。

php
BelongsToMany::make('Users')->fields(new RoleUserFields),

在这个例子中,RoleUserFields 类将是一个简单的可调用类,它返回枢纽字段的数组。

php
<?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 关系字段的字段列表中定义计算字段。

php
BelongsToMany::make('Users')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),

            Boolean::make('Has Notes', function ($pivot) {
                return ! empty($pivot->notes);
            }),
        ];
    }),

枢纽操作

通常,Nova 操作 在资源上运行。但是,你也可以将操作附加到 belongsToMany 字段,以便它们可以在枢纽/中间表记录上运行。要实现这一点,你可以在字段定义上链接 actions 方法。

php
BelongsToMany::make('Roles')
    ->actions(function () {
        return [
            new Actions\MarkAsActive,
        ];
    }),

将操作附加到字段后,你将能够从父资源详细信息页面上的关系索引中选择操作并执行它。

操作

要了解有关 Nova 操作的更多信息,请查看完整的 操作文档

标题属性

当在资源创建/更新页面上显示 BelongsToMany 字段时,下拉选择菜单或搜索菜单将显示资源的“标题”。例如,Role 资源可以使用 name 属性作为其标题。然后,当资源在 BelongsToMany 选择菜单中显示时,将显示该属性。

Belongs To Many Title

要自定义资源的“标题”属性,可以在资源类上定义title属性。

php
public static $title = 'name';

或者,可以覆盖资源的title方法。

php
/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

禁用按标题排序

默认情况下,关联资源在选择下拉列表中列出时将按其标题排序。使用 dontReorderAttachables 方法,你可以禁用此行为,以便根据 关联查询 指定的排序对资源进行排序。

php
BelongsToMany::make('Roles')->dontReorderAttachables(),

允许重复关系

默认情况下,Laravel Nova 确保“属于多方”关系是唯一的。但是,如果需要,你可以指示 Nova 允许重复关系条目。

要开始,你应该确保你的枢纽记录的 id 列是可用的,方法是在你的 Eloquent 模型上定义关系时使用 withPivot 方法。在这个例子中,让我们假设一个 User 可以购买一个或多个 Book

php
public function books()
{
    return $this->belongsToMany(Book::class)
                ->using(BookPurchase::class)
                ->withPivot('id', 'notes')
                ->withTimestamps();
}

接下来,我们可以使用 allowDuplicateRelations 方法定义允许重复关系的 Nova 关系。

php
BelongsToMany::make('Books')
    ->fields(function () {
        return [
            Text::make('Notes'),
        ];
    })->allowDuplicateRelations(),

MorphOne

MorphOne 字段对应 morphOne Eloquent 关系。例如,假设一个 PostImage 模型之间存在一对一的多态关系。我们可以像这样将关系添加到我们的 Post Nova 资源中

php
use Laravel\Nova\Fields\MorphOne;

MorphOne::make('Image'),

MorphOneOfMany

MorphOne 关系字段可以使用 ofMany 方法转换为 "morph one of many" Eloquent 关系。例如,假设一个 PostComment 模型之间存在一对多的多态关系。我们可以像这样将关系添加到我们的 Post Nova 资源中

php
use App\Nova\Comment;
use Laravel\Nova\Fields\MorphOne;

MorphOne::ofMany('Latest Comment', 'latestComment', Comment::class),

MorphMany

MorphMany 字段对应 morphMany Eloquent 关系。例如,假设一个 PostComment 模型之间存在一对多的多态关系。我们可以像这样将关系添加到我们的 Post Nova 资源中

php
use Laravel\Nova\Fields\MorphMany;

MorphMany::make('Comments'),

MorphTo

MorphTo 字段对应 morphTo Eloquent 关系。例如,假设一个 Comment 模型与 PostVideo 模型之间都存在多态关系。我们可以像这样将关系添加到我们的 Comment Nova 资源中

php
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 字段的类型选择菜单

Morph To Type

MorphTo 标题属性

当在资源创建/更新页面上显示 MorphTo 字段时,将自动显示可用资源的 标题属性

可空 MorphTo 关系

如果您希望 MorphTo 关系为 nullable,请将 nullable 方法链接到字段的定义中

php
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 将显示一张小卡片,允许您“查看”链接的关系

Relationship Peeking

阻止查看 MorphTo 关系

关系查看默认情况下是启用的;但是,您可以使用 MorphTo 字段上的 noPeeking 帮助程序阻止用户查看关系

php
MorphTo::make('Author')->noPeeking()

您还可以使用 peekable 方法来确定是否允许用户查看关系

php
use Laravel\Nova\Http\Requests\NovaRequest;

MorphTo::make('Author')->peekable(function (NovaRequest $request) {
    return $request->isResourceDetailRequest();
})

MorphTo 关系中设置默认值

在设置 MorphTo 字段的默认值时,除了使用 default 方法设置字段的初始值外,还需要指定要使用的资源的类名。您可以通过 defaultResource 方法来实现这一点。

php
use App\Nova\Post;

MorphTo::make('Commentable')
    ->default(1)
    ->defaultResource(Post::class)

MorphToMany

MorphToMany 字段对应于 morphToMany Eloquent 关系。例如,假设一个 PostTag 模型具有多对多多态关系。我们可以像这样将关系添加到我们的 Post Nova 资源中

php
use Laravel\Nova\Fields\MorphToMany;

MorphToMany::make('Tags'),

枢纽字段

如果您的 morphToMany 关系与存储在多对多关系中间表上的其他“枢纽”字段交互,您也可以将这些字段附加到您的 MorphToMany Nova 关系。将这些字段附加到关系字段后,它们将显示在相关资源索引中。

例如,在我们的 taggables 中间表上,假设我们有一个 notes 字段,其中包含一些关于关系的简单文本注释。我们可以使用 fields 方法将此枢纽字段附加到 MorphToMany 字段

php
MorphToMany::make('Tags')
    ->fields(function ($request, $relatedModel) {
        return [
            Text::make('Notes'),
        ];
    }),

当然,我们也可能在关系的反向关系中定义此字段。因此,如果我们在 Post 资源上定义 MorphToMany 字段,我们将在 Tag 资源上定义它的反向关系

php
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方法。

php
MorphToMany::make('Users')->fields(new TaggableFields),

在此示例中,TaggableFields 类将是一个简单的可调用类,它返回枢纽字段的数组

php
<?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 选择菜单中时,将显示该属性

Morph To Many Title

要自定义资源的“标题”属性,可以在资源类上定义title属性。

php
public static $title = 'name';

或者,可以覆盖资源的title方法。

php
/**
 * Get the value that should be displayed to represent the resource.
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

可折叠关系

默认情况下,BelongsToManyHasManyMorphToMany 关系字段显示在资源详细信息页面上。但是,如果资源具有许多性能密集型关系,这会导致页面变慢,这很快就会变得很麻烦。

出于这个原因,Nova 允许您将关系标记为 collapsable。当关系可折叠时,用户可以折叠给定资源的一些关系,Nova 将记住他们在后续页面加载时的首选项。折叠的关系不会从数据库中检索,直到关系在 Nova 的用户界面中展开

php
MorphToMany::make('Tags')->collapsable(),

您也可以通过 collapsedByDefault 方法指示关系默认情况下始终处于折叠状态。

php
MorphToMany::make('Tags')->collapsedByDefault(),

可搜索关系

默认情况下,当 BelongsToMorphToBelongsToManyMorphToMany 关系字段显示在资源创建/更新页面上时,将显示一个简单的下拉选择菜单。但是,如果资源模型具有许多记录,这很快就会变得很麻烦。例如,想象一个下拉选择菜单,其中填充了超过 10,000 个用户!

您可以将关系标记为 searchable,而不是显示下拉选择菜单。当关系被标记为 searchable 时,将显示一个漂亮的搜索输入控件。

Belongs To Search

要将关系标记为 searchable,请将 searchable 方法链接到字段的定义中。如果您想有条件地确定字段是否应该可搜索,可以将闭包传递给 searchable 方法。

php
BelongsTo::make('User')->searchable(),

BelongsTo::make('User')->searchable(function ($request) {
    return true;
}),

您还可以指示关系字段显示 资源的副标题,方法是在定义字段时调用 withSubtitles 方法。

php
BelongsTo::make('User')->searchable()->withSubtitles(),

相关查询过滤

如果您想自定义相关查询,可以通过调用 relatableQueryUsing 方法来实现。

php
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 方法也会很有用。

php
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 属性来限制搜索字段时返回的结果数量。

php
/**
 * The number of results to display when searching for relatable resources without Scout.
 *
 * @var int|null
 */
public static $relatableSearchResults = 200;

创建内联关系

为了方便起见,当 BelongsToMorphTo 关系字段显示在资源创建或更新页面上时,您可以通过模态窗口内联创建相关资源,而无需离开创建/更新页面。

Creating Inline Relations

要启用此功能,请在定义关系字段时调用 showCreateRelationButton 方法。

php
BelongsTo::make('User')->showCreateRelationButton(),

您也可以将闭包传递给showCreateRelationButton方法,以有条件地确定是否应启用内联资源创建。

php
BelongsTo::make('User')->showCreateRelationButton(function ($request) {
    //
}),

您也可以从“附加”和“更新附加”页面创建相关的多对多关系。要启用此功能,请在定义BelongsToManyMorphToMany关系时调用showCreateRelationButton

php
BelongsToMany::make('Roles')->showCreateRelationButton(),

要隐藏内联创建按钮,请在定义关系字段时调用hideCreateRelationButton方法。

php
BelongsTo::make('User')->hideCreateRelationButton(),

内联关系创建过程将尊重您定义的任何授权策略

内联创建模态大小

您可以使用modalSize方法调整模态的大小。

php
// Can be "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl".
BelongsTo::make('User')->showCreateRelationButton()->modalSize('7xl'),

内联创建限制

内联关系创建仅支持创建一层深的关系。这意味着您不能在现有的内联创建模态中触发另一个内联创建模态。相反,您必须选择一个已存在的资源。