搜索
首页后端开发php教程Laravel框架-EloquentORM进阶部分的详细介绍

关联关系

One To One
假设User模型关联了Phone模型,要定义这样一个关联,需要在User模型中定义一个phone方法,该方法返回一个hasOne方法定义的关联

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * Get the phone record associated with the user.
     */
    public function phone()
    {
        return $this->hasOne(&#39;App\Phone&#39;);
    }
}

hasOne方法的第一个参数为要关联的模型,定义好之后,可以使用下列语法查询到关联属性了

$phone = User::find(1)->phone;

Eloquent会假定关联的外键是基于模型名称的,因此Phone模型会自动使用user_id字段作为外键,可以使用第二个参数和第三个参数覆盖

return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;);return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;, &#39;local_key&#39;);

定义反向关系

定义上述的模型之后,就可以使用User模型获取Phone模型了,当然也可以通过Phone模型获取所属的User了,这就用到了belongsTo方法了

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model{
    /**
     * Get the user that owns the phone.
     */
    public function user()
    {
        return $this->belongsTo(&#39;App\User&#39;);        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;);
        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;, &#39;other_key&#39;);

    }
}

One To Many

假设有一个帖子,它有很多关联的评论信息,这种情况下应该使用一对多的关联,使用hasMany方法

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model{
    /**
     * Get the comments for the blog post.
     */
    public function comments()
    {
        return $this->hasMany(&#39;App\Comment&#39;);
    }
}

查询操作

$comments = App\Post::find(1)->comments;
foreach ($comments as $comment) {    //}

$comments = App\Post::find(1)->comments()->where(&#39;title&#39;, &#39;foo&#39;)->first();

定义反向关联

反向关联也是使用belongsTo方法,参考One To One部分。

$comment = App\Comment::find(1);
echo $comment->post->title;

Many To Many

多对多关联因为多了一个中间表,实现起来比hasOne和hasMany复杂一些。

考虑这样一个场景,用户可以属于多个角色,一个角色也可以属于多个用户。这就引入了三个表: users, roles, role_user。其中role_user表为关联表,包含两个字段user_id和role_id。

多对多关联需要使用belongsToMany方法

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * The roles that belong to the user.
     */
    public function roles()
    {
        // 指定关联表
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;);
        // 指定关联表,关联字段
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;, &#39;user_id&#39;, &#39;role_id&#39;);

        return $this->belongsToMany(&#39;App\Role&#39;);
    }
}

上述定义了一个用户属于多个角色,一旦该关系确立,就可以查询了

user = App\User::find(1);
foreach ($user->roles as $role) {    //}$roles = App\User::find(1)->roles()->orderBy(&#39;name&#39;)->get();

反向关联关系

反向关系与正向关系实现一样

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model{
    /**
     * The users that belong to the role.
     */
    public function users()
    {
        return $this->belongsToMany(&#39;App\User&#39;);
    }
}

检索中间表的列值

对多对多关系来说,引入了一个中间表,因此需要有方法能够查询到中间表的列值,比如关系确立的时间等,使用pivot属性查询中间表

$user = App\User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

上述代码访问了中间表的created_at字段。

注意的是,默认情况下之后模型的键可以通过pivot对象进行访问,如果中间表包含了额外的属性,在指定关联关系的时候,需要使用withPivot方法明确的指定列名

return $this->belongsToMany(&#39;App\Role&#39;)->withPivot(&#39;column1&#39;, &#39;column2&#39;);

Has Many Through

这种关系比较强大,假设这样一个场景:Country模型下包含了多个User模型,而每个User模型又包含了多个Post模型,也就是说一个国家有很多用户,而这些用户都有很多帖子,我们希望查询某个国家的所有帖子,怎么实现呢,这就用到了Has Many Through关系

countries    id - integer
    name - stringusers    id - integer
    country_id - integer
    name - stringposts    id - integer
    user_id - integer
    title - string

可以看到,posts表中并不直接包含country_id,但是它通过users表与countries表建立了关系

使用Has Many Through关系

namespace App;

use Illuminate\Database\Eloquent\Model;class Country extends Model{    /**
     * Get all of the posts for the country.
     */
    public function posts()
    {        // return $this->hasManyThrough(&#39;App\Post&#39;, &#39;App\User&#39;, &#39;country_id&#39;, &#39;user_id&#39;);

        return $this->hasManyThrough(&#39;App\Post&#39;, &#39;App\User&#39;);
    }
}

方法hasManyThrough的第一个参数是我们希望访问的模型名称,第二个参数是中间模型名称。

HasManyThrough hasManyThrough( 
    string $related, 
    string $through, 
    string|null $firstKey = null, 
    string|null $secondKey = null, 
    string|null $localKey = null)

Polymorphic Relations (多态关联)

多态关联使得同一个模型使用一个关联就可以属于多个不同的模型,假设这样一个场景,我们有一个帖子表和一个评论表,用户既可以对帖子执行喜欢操作,也可以对评论执行喜欢操作,这样的情况下该怎么处理呢?

表结构如下

posts    id - integer
    title - string
    body - textcomments    id - integer
    post_id - integer
    body - textlikes    id - integer
    likeable_id - integer
    likeable_type - string

可以看到,我们使用likes表中的likeable_type字段判断该记录喜欢的是帖子还是评论,表结构有了,接下来就该定义模型了

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Like extends Model{    /**
     * Get all of the owning likeable models.
     */
    public function likeable()
    {        return $this->morphTo();
    }
}class Post extends Model{    /**
     * Get all of the product&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}class Comment extends Model{    /**
     * Get all of the comment&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}

默认情况下,likeable_type的类型是关联的模型的完整名称,比如这里就是App\Post和App\Comment。

通常情况下我们可能会使用自定义的值标识关联的表名,因此,这就需要自定义这个值了,我们需要在项目的服务提供者对象的boot方法中注册关联关系,比如AppServiceProvider的boot方法中

use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([    &#39;posts&#39; => App\Post::class,
    &#39;likes&#39; => App\Like::class,]);

检索多态关系

访问一个帖子所有的喜欢

$post = App\Post::find(1);  
foreach ($post->likes as $like) {    //}

访问一个喜欢的帖子或者评论

$like = App\Like::find(1);   
$likeable = $like->likeable;

上面的例子中,返回的likeable会根据该记录的类型返回帖子或者评论。

多对多的多态关联

多对多的关联使用方法morphToMany和morphedByMany,这里就不多废话了

关联关系查询

在Eloquent中,所有的关系都是使用函数定义的,可以在不执行关联查询的情况下获取关联的实例。假设我们有一个博客系统,User模型关联了很多Post模型:

/**
 * Get all of the posts for the user.
 */public function posts()
{   return $this->hasMany(&#39;App\Post&#39;);
}

你可以像下面这样查询关联并且添加额外的约束

$user = App\User::find(1);$user->posts()->where(&#39;active&#39;, 1)->get();

如果不需要对关联的属性添加约束,可以直接作为模型的属性访问,例如上面的例子,我们可以使用下面的方式访问User的Post

$user = App\User::find(1);foreach ($user->posts as $post) {    //}

动态的属性都是延迟加载的,它们只有在被访问的时候才会去查询数据库,与之对应的是预加载,预加载可以使用关联查询出所有数据,减少执行sql的数量。

查询关系存在性

使用has方法可以基于关系的存在性返回结果

// 检索至少有一个评论的所有帖子...$posts = App\Post::has(&#39;comments&#39;)->get();
// Retrieve all posts that have three or more comments...$posts = Post::has(&#39;comments&#39;, &#39;>=&#39;, 3)->get();
// Retrieve all posts that have at least one comment with votes...$posts = Post::has(&#39;comments.votes&#39;)->get();

如果需要更加强大的功能,可以使用whereHas和orWhereHas方法,把where条件放到has语句中。

// 检索所有至少存在一个匹配foo%的评论的帖子$posts = Post::whereHas(&#39;comments&#39;, function ($query) {    
$query->where(&#39;content&#39;, &#39;like&#39;, &#39;foo%&#39;);
})->get();

预加载

在访问Eloquent模型的时候,默认情况下所有的关联关系都是延迟加载的,在使用的时候才会开始加载,这就造成了需要执行大量的sql的问题,使用预加载功能可以使用关联查询出所有结果

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Book extends Model{
    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo(&#39;App\Author&#39;);
    }
}

接下来我们检索所有的书和他们的作者

$books = App\Book::all();
foreach ($books as $book) {    
echo $book->author->name;
}

上面的查询将会执行一个查询查询出所有的书,然后在遍历的时候再执行N个查询查询出作者信息,显然这样做是非常低效的,幸好我们还有预加载功能,可以将这N+1个查询减少到2个查询,在查询的时候,可以使用with方法指定哪个关系需要预加载。

$books = App\Book::with(&#39;author&#39;)->get();
foreach ($books as $book) {
    echo $book->author->name;
}

对于该操作,会执行下列两个sql

select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)

预加载多个关系

$books = App\Book::with(&#39;author&#39;, &#39;publisher&#39;)->get();

嵌套的预加载

$books = App\Book::with(&#39;author.contacts&#39;)->get();

带约束的预加载

$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->where(&#39;title&#39;, &#39;like&#39;, &#39;%first%&#39;);
}])->get();$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->orderBy(&#39;created_at&#39;, &#39;desc&#39;);
}])->get();

延迟预加载#

有时候,在上级模型已经检索出来之后,可能会需要预加载关联数据,可以使用load方法

$books = App\Book::all();if ($someCondition) {    $books->load(&#39;author&#39;, &#39;publisher&#39;);
}$books->load([&#39;author&#39; => function ($query) {
    $query->orderBy(&#39;published_date&#39;, &#39;asc&#39;);
}]);

关联模型插入

save方法

保存单个关联模型

$comment = new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]);
$post = App\Post::find(1);$post->comments()->save($comment);

保存多个关联模型

$post = App\Post::find(1); 
$post->comments()->saveMany([    
new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]),    
new App\Comment([&#39;message&#39; => &#39;Another comment.&#39;]),
]);

save方法和多对多关联

多对多关联可以为save的第二个参数指定关联表中的属性

App\User::find(1)->roles()->save($role, [&#39;expires&#39; => $expires]);

上述代码会更新中间表的expires字段。

create方法

使用create方法与save方法的不同在于它是使用数组的形式创建关联模型的

$post = App\Post::find(1);$comment = $post->comments()->create([
    &#39;message&#39; => &#39;A new comment.&#39;,]);

更新 “Belongs To” 关系

更新belongsTo关系的时候,可以使用associate方法,该方法会设置子模型的外键

$account = App\Account::find(10);
$user->account()->associate($account);
$user->save();

要移除belongsTo关系的话,使用dissociate方法

$user->account()->dissociate();$user->save();

Many to Many 关系

中间表查询条件#

当查询时需要对使用中间表作为查询条件时,可以使用wherePivotwherePivotInorWherePivotorWherePivotIn添加查询条件。

$enterprise->with([&#39;favorites&#39; => function($query) {    
$query->wherePivot(&#39;enterprise_id&#39;, &#39;=&#39;, 12)->select(&#39;id&#39;);
}]);

Attaching / Detaching#

$user = App\User::find(1);
// 为用户添加角色
$user->roles()->attach($roleId);
// 为用户添加角色,更新中间表的expires字段
$user->roles()->attach($roleId, [&#39;expires&#39; => $expires]);
// 移除用户的单个角色
$user->roles()->detach($roleId);
// 移除用户的所有角色
$user->roles()->detach();

attach和detach方法支持数组参数,同时添加和移除多个

$user = App\User::find(1);
$user->roles()->detach([1, 2, 3]);
$user->roles()->attach([1 => [&#39;expires&#39; => $expires], 2, 3]);

更新中间表(关联表)字段

使用updateExistingPivot方法更新中间表

$user = App\User::find(1);$user->roles()->updateExistingPivot($roleId, $attributes);

同步中间表(同步关联关系)#

使用sync方法,可以指定两个模型之间只存在指定的关联关系

$user->roles()->sync([1, 2, 3]);
$user->roles()->sync([1 => [&#39;expires&#39; => true], 2, 3]);

上述两个方法都会让用户只存在1,2,3三个角色,如果用户之前存在其他角色,则会被删除。

更新父模型的时间戳#

假设场景如下,我们为一个帖子增加了一个新的评论,我们希望这个时候帖子的更新时间会相应的改变,这种行为在Eloquent中是非常容易实现的。

在子模型中使用$touches属性实现该功能

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Comment extends Model{    /**
     * All of the relationships to be touched.
     *
     * @var array
     */
    protected $touches = [&#39;post&#39;];    /**
     * Get the post that the comment belongs to.
     */
    public function post()
    {        return $this->belongsTo(&#39;App\Post&#39;);
    }
}

现在,更新评论的时候,帖子的updated_at字段也会被更新

$comment = App\Comment::find(1);$comment->text = &#39;Edit to this comment!&#39;;$comment->save();

以上是Laravel框架-EloquentORM进阶部分的详细介绍的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP:服务器端脚本语言的简介PHP:服务器端脚本语言的简介Apr 16, 2025 am 12:18 AM

PHP是一种服务器端脚本语言,用于动态网页开发和服务器端应用程序。1.PHP是一种解释型语言,无需编译,适合快速开发。2.PHP代码嵌入HTML中,易于网页开发。3.PHP处理服务器端逻辑,生成HTML输出,支持用户交互和数据处理。4.PHP可与数据库交互,处理表单提交,执行服务器端任务。

PHP和网络:探索其长期影响PHP和网络:探索其长期影响Apr 16, 2025 am 12:17 AM

PHP在过去几十年中塑造了网络,并将继续在Web开发中扮演重要角色。1)PHP起源于1994年,因其易用性和与MySQL的无缝集成成为开发者首选。2)其核心功能包括生成动态内容和与数据库的集成,使得网站能够实时更新和个性化展示。3)PHP的广泛应用和生态系统推动了其长期影响,但也面临版本更新和安全性挑战。4)近年来的性能改进,如PHP7的发布,使其能与现代语言竞争。5)未来,PHP需应对容器化、微服务等新挑战,但其灵活性和活跃社区使其具备适应能力。

为什么要使用PHP?解释的优点和好处为什么要使用PHP?解释的优点和好处Apr 16, 2025 am 12:16 AM

PHP的核心优势包括易于学习、强大的web开发支持、丰富的库和框架、高性能和可扩展性、跨平台兼容性以及成本效益高。1)易于学习和使用,适合初学者;2)与web服务器集成好,支持多种数据库;3)拥有如Laravel等强大框架;4)通过优化可实现高性能;5)支持多种操作系统;6)开源,降低开发成本。

揭穿神话:PHP真的是一种死语吗?揭穿神话:PHP真的是一种死语吗?Apr 16, 2025 am 12:15 AM

PHP没有死。1)PHP社区积极解决性能和安全问题,PHP7.x提升了性能。2)PHP适合现代Web开发,广泛用于大型网站。3)PHP易学且服务器表现出色,但类型系统不如静态语言严格。4)PHP在内容管理和电商领域仍重要,生态系统不断进化。5)通过OPcache和APC等优化性能,使用OOP和设计模式提升代码质量。

PHP与Python辩论:哪个更好?PHP与Python辩论:哪个更好?Apr 16, 2025 am 12:03 AM

PHP和Python各有优劣,选择取决于项目需求。1)PHP适合Web开发,易学,社区资源丰富,但语法不够现代,性能和安全性需注意。2)Python适用于数据科学和机器学习,语法简洁,易学,但执行速度和内存管理有瓶颈。

PHP的目的:构建动态网站PHP的目的:构建动态网站Apr 15, 2025 am 12:18 AM

PHP用于构建动态网站,其核心功能包括:1.生成动态内容,通过与数据库对接实时生成网页;2.处理用户交互和表单提交,验证输入并响应操作;3.管理会话和用户认证,提供个性化体验;4.优化性能和遵循最佳实践,提升网站效率和安全性。

PHP:处理数据库和服务器端逻辑PHP:处理数据库和服务器端逻辑Apr 15, 2025 am 12:15 AM

PHP在数据库操作和服务器端逻辑处理中使用MySQLi和PDO扩展进行数据库交互,并通过会话管理等功能处理服务器端逻辑。1)使用MySQLi或PDO连接数据库,执行SQL查询。2)通过会话管理等功能处理HTTP请求和用户状态。3)使用事务确保数据库操作的原子性。4)防止SQL注入,使用异常处理和关闭连接来调试。5)通过索引和缓存优化性能,编写可读性高的代码并进行错误处理。

您如何防止PHP中的SQL注入? (准备的陈述,PDO)您如何防止PHP中的SQL注入? (准备的陈述,PDO)Apr 15, 2025 am 12:15 AM

在PHP中使用预处理语句和PDO可以有效防范SQL注入攻击。1)使用PDO连接数据库并设置错误模式。2)通过prepare方法创建预处理语句,使用占位符和execute方法传递数据。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.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器