搜索
首页后端开发php教程重新引入雄辩的多态关系

Re-Introducing Eloquent's Polymorphic Relationships

核心要点

  • Laravel的多态关联允许一个模型在一个关联上属于多个其他模型。这简化了数据库结构,使代码更易维护,并允许更动态和灵活的数据关系。
  • 在Laravel中设置多态关联涉及在Eloquent模型中定义关联。morphTo方法用于接收多态关联的模型,而morphManymorphOne方法用于与其他模型关联的模型。
  • Laravel的MorphMap方法可用于指示Eloquent对每个模型使用自定义名称,而不是类名。这在模型命名空间更改或命名空间过长的情况下很有帮助。
  • Laravel支持多对多多态关系,允许一个模型在多对多的基础上属于多个模型。这在复杂的应用程序中特别有用。

本文由Younes Rafie同行评审。感谢所有SitePoint的同行评审者,使SitePoint的内容尽善尽美!


Re-Introducing Eloquent's Polymorphic Relationships

您可能已经使用了模型或数据库表之间不同类型的关系,例如Laravel中常见的:一对一、一对多、多对多以及has-many-through。但还有一种不太常见的类型:多态关联。那么什么是多态关联呢?

多态关联是指一个模型在一个关联上可以属于多个其他模型。

为了阐明这一点,让我们创建一个虚构的场景,其中我们有Topic和Post模型。用户可以在主题和帖子中留下评论。使用多态关系,我们可以对这两种情况使用单个comments表。令人惊讶,对吧?这似乎有点不切实际,因为理想情况下,我们必须创建post_comments表和topic_comments表来区分评论。使用多态关系,我们不需要两个表。让我们通过一个实际示例来了解多态关系。

我们将构建的内容

我们将创建一个演示音乐应用程序,其中包含歌曲和专辑。在这个应用程序中,我们可以对歌曲和专辑进行点赞。使用多态关系,我们将对这两种情况使用单个upvotes表。首先,让我们检查构建此关系所需的表结构:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

让我们讨论一下upvoteable_idupvoteable_type列,对于那些以前没有使用过多态关系的人来说,这些列可能看起来有点陌生。upvoteable_id列将包含专辑或歌曲的ID值,而upvoteable_type列将包含拥有模型的类名。upvoteable_type列是ORM在访问upvoteable关系时确定要返回哪个“类型”拥有模型的方式。

生成模型以及迁移

我假设您已经拥有一个正在运行的Laravel应用程序。如果没有,这个高级快速入门课程可能会有所帮助。让我们首先创建三个模型和迁移,然后编辑迁移以满足我们的需求。

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

请注意,在创建模型时传递-m标志也会生成与这些模型关联的迁移。让我们调整这些迁移中的up方法以获得所需的表结构:

{some_timestamp}_create_albums_table.php

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

{some_timestamp}_create_songs_table.php

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}

{some_timestamp}_create_upvotes_table.php

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}

现在,我们可以运行artisan migrate命令来创建这三个表:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}

现在让我们配置我们的模型以注意专辑、歌曲和点赞之间的多态关系:

app/Upvote.php

<code>php artisan migrate</code>

app/Album.php

[...]
class Upvote extends Model
{
    /**
     * 获取所有拥有模型。
     */
    public function upvoteable()
    {
        return $this->morphTo();
    }
}

app/Song.php

class Album extends Model
{
    protected $fillable = ['name'];

    public function songs()
    {
        return $this->hasMany(Song::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}

Album和Song模型中的upvotes方法定义了这些模型和Upvote模型之间的多态一对多关系,并将帮助我们获取该特定模型实例的所有点赞。

定义了关系后,我们现在可以试用该应用程序,以便更好地了解多态关系的工作原理。我们不会为此应用程序创建任何视图,我们只会从控制台试用我们的应用程序。

如果您考虑控制器以及我们应该放置点赞方法的位置,我建议创建一个AlbumUpvoteController和一个SongUpvoteController。通过这种方式,我们在处理多态关系时,可以将事情严格地与我们正在操作的对象联系起来。在我们的例子中,我们可以对专辑和歌曲进行点赞。点赞不属于专辑,也不属于歌曲。此外,它不是一般的点赞,这与我们在大多数一对多关系中拥有UpvotesController的方式相反。希望这说得通。

让我们启动控制台:

class Song extends Model
{
    protected $fillable = ['title', 'album_id'];

    public function album()
    {
        return $this->belongsTo(Album::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}

检索关系

现在我们已经准备好了一些数据,我们可以通过我们的模型访问我们的关系。以下是upvotes表中数据的屏幕截图:

Re-Introducing Eloquent's Polymorphic Relationships

要访问专辑的所有点赞,我们可以使用upvotes动态属性:

<code>php artisan tinker
>>> $album = App\Album::create(['name' => 'More Life']);
>>> $song = App\Song::create(['title' => 'Free smoke', 'album_id' => 1]);
>>> $upvote1 = new App\Upvote;
>>> $upvote2 = new App\Upvote;
>>> $upvote3 = new App\Upvote;
>>> $album->upvotes()->save($upvote1);
>>> $song->upvotes()->save($upvote2);
>>> $album->upvotes()->save($upvote3);</code>

也可以通过访问执行对morphTo的调用的方法的名称,从多态模型检索多态关系的所有者。在我们的例子中,那是Upvote模型上的upvoteable方法。因此,我们将访问该方法作为动态属性:

$album = App\Album::find(1);
$upvotes = $album->upvotes;
$upvotescount = $album->upvotes->count();

Upvote模型上的upvoteable关系将返回一个Album实例,因为此点赞由Album实例的实例拥有。

由于可以获取歌曲或专辑的点赞数量,因此我们可以根据视图上的点赞对歌曲或专辑进行排序。这就是音乐排行榜的工作方式。

对于歌曲,我们将像这样获取点赞:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

自定义多态类型

默认情况下,Laravel将使用完全限定的类名来存储相关模型的类型。例如,在上面的示例中,Upvote可能属于Album或Song,默认的upvoteable_type分别为App\AlbumApp\Song

但是,这有一个很大的缺陷。如果Album模型的命名空间发生更改怎么办?我们将不得不进行某种迁移以重命名upvotes表中的所有出现。这有点棘手!如果命名空间很长(例如App\Models\Data\Topics\Something\SomethingElse)会发生什么?这意味着我们必须在列上设置一个很长的最大长度。这就是MorphMap方法可以帮助我们的地方。

“morphMap”方法将指示Eloquent对每个模型使用自定义名称,而不是类名:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

我们可以在AppServiceProvider的boot函数中注册morphMap,或者创建一个单独的服务提供者。为了使新的更改生效,我们必须运行composer dump-autoload命令。因此,现在我们可以添加这个新的点赞记录:

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}

它的行为方式与之前的示例完全相同。

结论

即使您可能从未遇到过需要使用多态关系的情况,但那一天最终可能会到来。使用Laravel的好处是,处理这种情况非常容易,无需进行任何模型关联技巧即可使事情正常工作。Laravel甚至支持多对多多态关系。您可以在此处阅读更多相关信息。

我希望您现在已经了解了多态关系以及可能需要这些类型关系的情况。另一个关于多态关系的稍微高级一点的例子在这里。如果您觉得这有帮助,请与您的朋友分享,不要忘记点击点赞按钮。请随时在下面的评论部分留下您的想法!

关于Eloquent的多态关系的常见问题解答

使用Laravel中的多态关系有哪些好处?

Laravel中的多态关系提供了一种灵活且有效的方式来处理不同模型之间的相关数据。它们允许一个模型在一个关联上属于多个其他类型的模型。这意味着您可以拥有所有相关数据的单个唯一标识符列表,而不管它们的类型如何。这可以极大地简化您的数据库结构并使您的代码更易于维护。它还允许更动态和灵活的数据关系,这在复杂的应用程序中特别有用。

如何在Laravel中设置多态关系?

在Laravel中设置多态关系涉及在Eloquent模型中定义关系。首先,您需要在将接收多态关系的模型上定义关系。这是使用morphTo方法完成的。然后,在将与其他模型关联的模型上,根据关系是一对多还是一对一,使用morphManymorphOne方法。

你能提供一个Laravel中多态关系的例子吗?

当然,让我们考虑一个博客平台,其中帖子和用户都可以有评论。在这种情况下,Comment模型将与Post和User模型具有多态关系。以下是如何定义此关系:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

如何使用多态关系检索相关记录?

您可以像使用任何其他Eloquent关系一样检索多态关系中的相关记录。例如,如果您想检索帖子的所有评论,您可以这样做:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

如何使用多态关系保存相关记录?

保存多态关系中的相关记录也类似于其他Eloquent关系。您可以使用associate方法关联模型,然后保存模型。这是一个例子:

public function up()
{
    Schema::create('albums', function (Blueprint $table) {
       $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}

多态关系的一些常见用例是什么?

在模型可以属于多个其他类型模型的情况下,多态关系特别有用。一些常见的用例包括可以属于帖子和用户的评论、可以应用于多种类型内容的标签以及可以附加到各种类型的实体的图像或文件。

使用多态关系有哪些限制或缺点?

虽然多态关系提供了很大的灵活性,但它们也可能比标准的Eloquent关系更复杂,更难以设置和管理。它们也不支持标准关系的所有功能,例如渴望加载约束。

如何删除多态关系中的相关记录?

您可以使用关系上的delete方法删除多态关系中的相关记录。例如,要删除帖子的所有评论,您可以这样做:

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}

我可以将多态关系与多对多关系一起使用吗?

是的,Laravel通过morphToManymorphedByMany方法支持多对多多态关系。这允许一个模型在多对多的基础上属于多个模型。

如何在数据库迁移中处理多态关系?

在数据库迁移中,您通常会向将接收多态关系的表中添加两列:一列用于相关模型ID,另一列用于相关模型类型。Laravel提供了一个方便的morphs方法来添加这些列:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}

这会向表中添加commentable_idcommentable_type列。

以上是重新引入雄辩的多态关系的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP的当前状态:查看网络开发趋势PHP的当前状态:查看网络开发趋势Apr 13, 2025 am 12:20 AM

PHP在现代Web开发中仍然重要,尤其在内容管理和电子商务平台。1)PHP拥有丰富的生态系统和强大框架支持,如Laravel和Symfony。2)性能优化可通过OPcache和Nginx实现。3)PHP8.0引入JIT编译器,提升性能。4)云原生应用通过Docker和Kubernetes部署,提高灵活性和可扩展性。

PHP与其他语言:比较PHP与其他语言:比较Apr 13, 2025 am 12:19 AM

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

PHP与Python:核心功能PHP与Python:核心功能Apr 13, 2025 am 12:16 AM

PHP和Python各有优势,适合不同场景。1.PHP适用于web开发,提供内置web服务器和丰富函数库。2.Python适合数据科学和机器学习,语法简洁且有强大标准库。选择时应根据项目需求决定。

PHP:网络开发的关键语言PHP:网络开发的关键语言Apr 13, 2025 am 12:08 AM

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP:许多网站的基础PHP:许多网站的基础Apr 13, 2025 am 12:07 AM

PHP成为许多网站首选技术栈的原因包括其易用性、强大社区支持和广泛应用。1)易于学习和使用,适合初学者。2)拥有庞大的开发者社区,资源丰富。3)广泛应用于WordPress、Drupal等平台。4)与Web服务器紧密集成,简化开发部署。

超越炒作:评估当今PHP的角色超越炒作:评估当今PHP的角色Apr 12, 2025 am 12:17 AM

PHP在现代编程中仍然是一个强大且广泛使用的工具,尤其在web开发领域。1)PHP易用且与数据库集成无缝,是许多开发者的首选。2)它支持动态内容生成和面向对象编程,适合快速创建和维护网站。3)PHP的性能可以通过缓存和优化数据库查询来提升,其广泛的社区和丰富生态系统使其在当今技术栈中仍具重要地位。

PHP中的弱参考是什么?什么时候有用?PHP中的弱参考是什么?什么时候有用?Apr 12, 2025 am 12:13 AM

在PHP中,弱引用是通过WeakReference类实现的,不会阻止垃圾回收器回收对象。弱引用适用于缓存系统和事件监听器等场景,需注意其不能保证对象存活,且垃圾回收可能延迟。

解释PHP中的__ Invoke Magic方法。解释PHP中的__ Invoke Magic方法。Apr 12, 2025 am 12:07 AM

\_\_invoke方法允许对象像函数一样被调用。1.定义\_\_invoke方法使对象可被调用。2.使用$obj(...)语法时,PHP会执行\_\_invoke方法。3.适用于日志记录和计算器等场景,提高代码灵活性和可读性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。