Laravel Nova 模型关联

2023-02-16 17:08 更新

除了我们之前讨论过的那些字段,Nova 还支持 Laravel 模型的关联关系。只要给资源添加一个关联关系,你就能体会到 Nova 的强大之处,因为你可以在资源详情页快速的查看并搜索该资源的关联模型:


一对一

这个 HasOne 对应一个 hasOne Eloquent 关系。例如,让我们假设一个 User 模型 hasOne Address 模型。我们可以将这种关系添加到我们的  User Nova 资源中,如下所示:

use Laravel\Nova\Fields\HasOne;

HasOne::make('Address')

就像其他类型的字段一样,关系字段将自动地 “snake case” 字段的显示名称,来确定底层关系的方法或属性。然而,你可以将它作为第二个参数传递给这个字段的 make 方法,来明确地指定关系方法的名称。如下所示:

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

一对多

HasMany 字段对应 Eloquent 中的 hasMany 关系。假设一个 User 模型 hasMany Post 模型,那么我们可以给 Nova 的 User 资源添加如下关系:

use Laravel\Nova\Fields\HasMany;

HasMany::make('Posts')

一对多(逆向)

BelongsTo 字段对应 Eloquent 中的 belongsTo 关系。假设一个 Post 模型 belongsTo 一个 User 模型,那么我们可以给 Nova 的 Post 资源添加如下关系:

use Laravel\Nova\Fields\BelongsTo;

BelongsTo::make('User')

标题属性

当创建或编辑包含 BelongsTo 字段的资源时,下拉框或搜索框里会显示该资源的「标题」。假如 User 资源的标题是 name 属性,那么 BelongsTo 选择菜单里显示的就是他的  name


如果要自定义资源的「titile」,可以在资源类里定义一个 title 属性:

public static $title = 'name';

此外,你也可以覆盖资源的 title 方法:

/**
 * 获取资源显示的值。
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

多对多

BelongsToMany 字段对应于模型的 belongsToMany 关联。例如,我们假定有一个 User 模型 belongsToMany Role 模型。我们就可以像这样将它添加到 User Nova 资源中:

use Laravel\Nova\Fields\BelongsToMany;

BelongsToMany::make('Roles')

主字段

如果你的 belongsToMany 关联中间表还存着其他的关联字段,你也可以将它附到 BelongsToMany Nova 关联字段上。一旦这些字段被附到该关联,那他们将会在关联资源列表中展示.

例如,我们假定我们的 User 模型 belongsToMany Role 模型。在 role_user 中间表,让我们想象一下 notes 字段包含一些关联关系中简单的文本 我们可以使用 fields 方法把这个字段附加到  BelongsToMany 字段上:

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

当然,这也可以在定义相反关联时使用。所以,如果我们在 User 资源中定义了一个 BelongsToMany 字段,我们也可以在 Role 资源中定义反向关联:

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

在两处分别定义这样的关联可能会让我们的代码重复,Nova 允许你通过传入一个可调用的对象给 fields 方法:

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

上面的例子中,RoleUserFields 类可以只有一个 __invoke 方法,并返回一个包含附加字段的数组:

<?php

namespace App\Nova;

use Laravel\Nova\Fields\Text;

class RoleUserFields
{
    /**
     *  获取关联模型的附加字段
     *
     * @return array
     */
    public function __invoke()
    {
        return [
            Text::make('Notes'),
        ];
    }
}

主操作

通常,Nova actions 是基于资源操作的。 然而,你也可以把 actions 绑定到 belongsToMany 字段 然后他们就可以在 pivot / 中间表记录上操作了。为了实现它,你可以在字段定义时使用 actions 链式方法:

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

一旦 action 被绑定到这个字段,你就可以从父级资源屏幕上的关系索引中选择这个 action 并且执行它。

标题属性

当 BelongsToMany 字段出现在资源创建和更新操作时,一个下拉选择菜单或搜索框会显示当前资源的 “title” 。例如: Role 资源可以使用 name 属性作为其标题。然后,当资源显示在 BelongsToMany 选择菜单时,这个属性也会显示。


为了自定义这个资源的 “title” ,你可以在类内定义一个 title 成员属性:

public static $title = 'name';

另外,你可以复写资源的 title 方法:

/**
 * 获取资源需要被显示的值
 * @return string
 */
public function title()
{
    return $this->name;
}

远层一对多

MorphMany 字段响应 morphMany Eloquent 关联。例如:我们假设

Post 与 Comment 模型存在一对多的多态关联。我们可以为 Post Nova 资源添加关联,如下:

use Laravel\Nova\Fields\MorphMany;

MorphMany::make('Comments')

多态关联

MorphTo 字段对应于 morphTo Eloquent 关系。 例如,让我们假设一个 Comment 模型与 Post 和 Video 模型都有多态关系。 我们可以将这种关系添加到我们的 Comment Nova 资源中,如下所示:

use Laravel\Nova\Post;
use Laravel\Nova\Video;
use Laravel\Nova\Fields\MorphTo;

MorphTo::make('Commentable')->types([
    Post::class,
    Video::class,
])

正如上面的示例中所看到的,types 方法用于指示 MorphTo 字段可以与哪些类型的资源相关联。 Nova 将使用此信息在创建和更新显示 MorphTo 字段的类型选择菜单:


多态标题属性

当在资源创建 / 更新显示 MorphTo 字段时,将自动显示可用资源的 [标题属性](#title-attributes)。

多对多的多态关联

MorphToMany 字段对应于 morphToMany Eloquent 关系。例如,让我们假设一个 Post 模型与 Tag 模型有多对多多态关系。 我们可以将这种关系添加到我们的 Post Nova 资源中,如下所示:

use Laravel\Nova\Fields\MorphToMany;

MorphToMany::make('Tags')

中间表字段

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

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

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

当然,我们很可能也会在关系的反方向定义这个字段。 所以,如果我们在 Post 资源上定义 MorphToMany 字段,我们将在 Tag 资源中定义它的反向关联:

MorphToMany::make('Posts')
    ->fields(function () {
        return [
            Text::make('Notes'),
        ];
    });

由于在关系的两端定义字段会导致一些代码重复,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.
     *
     * @return array
     */
    public function __invoke()
    {
        return [
            Text::make('Notes'),
        ];
    }
}

标题属性

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


您可以在资源类上定义一个 title 属性,自定义资源的 title 属性值:

public static $title = 'name';

或者你可以重写资源的 title 方法:

/**
 * 获取资源类显示的标题。
 *
 * @return string
 */
public function title()
{
    return $this->name;
}

关联搜索

在我们使用 BelongsTo、BelongsToMany、MorphTo、MorphToMany 来建立两个模型的关联关系时,Nova 会默认显示一个简单的下拉选择栏。但是,当我们两个关联模型有很多数据,这样在创建模型时就成一场灾难。例如,你创建用户的年龄,它有着 1、2、3、4 …… 到 200 岁的下拉菜单选项。

您可以将这两个模型的关系标记为 searchable,此时不会显示下拉菜单选项,而是显示为一个可输入的、漂亮的搜索栏。


要将关系模型中的下拉菜单变为 “搜索栏”,请在关联模型的位置,添加方法 searchable()

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


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号