關聯關係
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('App\Phone'); } }
hasOne方法的第一個參數為要關聯的模型,定義好之後,可以使用下列語法查詢到關聯屬性了
$phone = User::find(1)->phone;
Eloquent會假定關聯的外鍵是基於模型名稱的,因此Phone模型會自動使用user_id欄位作為外鍵,可以使用第二個參數和第三個參數覆寫
return $this->hasOne('App\Phone', 'foreign_key');return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
定義反向關係
定義上述的模型之後,就可以使用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('App\User'); // return $this->belongsTo('App\User', 'foreign_key'); // return $this->belongsTo('App\User', 'foreign_key', 'other_key'); } }
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('App\Comment'); } }
查詢操作
$comments = App\Post::find(1)->comments; foreach ($comments as $comment) { //} $comments = App\Post::find(1)->comments()->where('title', 'foo')->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('App\Role', 'role_user'); // 指定关联表,关联字段 // return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); return $this->belongsToMany('App\Role'); } }
上述定義了一個使用者屬於多個角色,一旦該關係確立,就可以查詢了
user = App\User::find(1); foreach ($user->roles as $role) { //}$roles = App\User::find(1)->roles()->orderBy('name')->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('App\User'); } }
檢索中間表的列值
對多對多關係來說,引入了一個中間表,因此需要有方法能夠查詢到中間表的列值,例如關係確立的時間等,使用pivot屬性查詢中間表
$user = App\User::find(1); foreach ($user->roles as $role) { echo $role->pivot->created_at; }
上述程式碼存取了中間表的created_at欄位。
注意的是,預設情況下之後模型的鍵可以透過pivot物件進行訪問,如果中間表包含了額外的屬性,在指定關聯關係的時候,需要使用withPivot方法明確的指定列名
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
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('App\Post', 'App\User', 'country_id', 'user_id'); return $this->hasManyThrough('App\Post', 'App\User'); } }
方法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's likes. */ public function likes() { return $this->morphMany('App\Like', 'likeable'); } }class Comment extends Model{ /** * Get all of the comment's likes. */ public function likes() { return $this->morphMany('App\Like', 'likeable'); } }
預設情況下,likeable_type的類型是關聯的模型的完整名稱,例如這裡就是App\Post和App\Comment。
通常我們可能會使用自訂的值來識別關聯的表名,因此,這就需要自訂這個值了,我們需要在專案的服務提供者物件的boot方法中註冊關聯關係,例如AppServiceProvider
的boot方法中
use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([ 'posts' => App\Post::class, 'likes' => 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('App\Post'); }
你可以像下面這樣查詢關聯並且添加額外的約束
$user = App\User::find(1);$user->posts()->where('active', 1)->get();
如果不需要對關聯的屬性添加約束,可以直接作為模型的屬性訪問,例如上面的例子,我們可以使用下面的方式訪問User的Post
$user = App\User::find(1);foreach ($user->posts as $post) { //}
动态的属性都是延迟加载的,它们只有在被访问的时候才会去查询数据库,与之对应的是预加载,预加载可以使用关联查询出所有数据,减少执行sql的数量。
查询关系存在性
使用has方法可以基于关系的存在性返回结果
// 检索至少有一个评论的所有帖子...$posts = App\Post::has('comments')->get(); // Retrieve all posts that have three or more comments...$posts = Post::has('comments', '>=', 3)->get(); // Retrieve all posts that have at least one comment with votes...$posts = Post::has('comments.votes')->get();
如果需要更加强大的功能,可以使用whereHas和orWhereHas方法,把where条件放到has语句中。
// 检索所有至少存在一个匹配foo%的评论的帖子$posts = Post::whereHas('comments', function ($query) { $query->where('content', 'like', 'foo%'); })->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('App\Author'); } }
接下来我们检索所有的书和他们的作者
$books = App\Book::all(); foreach ($books as $book) { echo $book->author->name; }
上面的查询将会执行一个查询查询出所有的书,然后在遍历的时候再执行N个查询查询出作者信息,显然这样做是非常低效的,幸好我们还有预加载功能,可以将这N+1个查询减少到2个查询,在查询的时候,可以使用with方法指定哪个关系需要预加载。
$books = App\Book::with('author')->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('author', 'publisher')->get();
嵌套的预加载
$books = App\Book::with('author.contacts')->get();
带约束的预加载
$users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get();$users = App\User::with(['posts' => function ($query) { $query->orderBy('created_at', 'desc'); }])->get();
延迟预加载#
有时候,在上级模型已经检索出来之后,可能会需要预加载关联数据,可以使用load方法
$books = App\Book::all();if ($someCondition) { $books->load('author', 'publisher'); }$books->load(['author' => function ($query) { $query->orderBy('published_date', 'asc'); }]);
关联模型插入
save方法
保存单个关联模型
$comment = new App\Comment(['message' => 'A new comment.']); $post = App\Post::find(1);$post->comments()->save($comment);
保存多个关联模型
$post = App\Post::find(1); $post->comments()->saveMany([ new App\Comment(['message' => 'A new comment.']), new App\Comment(['message' => 'Another comment.']), ]);
save方法和多对多关联
多对多关联可以为save的第二个参数指定关联表中的属性
App\User::find(1)->roles()->save($role, ['expires' => $expires]);
上述代码会更新中间表的expires字段。
create方法
使用create方法与save方法的不同在于它是使用数组的形式创建关联模型的
$post = App\Post::find(1);$comment = $post->comments()->create([ 'message' => 'A new comment.',]);
更新 “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 关系
中间表查询条件#
当查询时需要对使用中间表作为查询条件时,可以使用wherePivot
, wherePivotIn
,orWherePivot
,orWherePivotIn
添加查询条件。
$enterprise->with(['favorites' => function($query) { $query->wherePivot('enterprise_id', '=', 12)->select('id'); }]);
Attaching / Detaching#
$user = App\User::find(1); // 为用户添加角色 $user->roles()->attach($roleId); // 为用户添加角色,更新中间表的expires字段 $user->roles()->attach($roleId, ['expires' => $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 => ['expires' => $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 => ['expires' => 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 = ['post']; /** * Get the post that the comment belongs to. */ public function post() { return $this->belongsTo('App\Post'); } }
现在,更新评论的时候,帖子的updated_at字段也会被更新
$comment = App\Comment::find(1);$comment->text = 'Edit to this comment!';$comment->save();
以上是Laravel框架-EloquentORM進階部分的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

PHP是一種服務器端腳本語言,用於動態網頁開發和服務器端應用程序。 1.PHP是一種解釋型語言,無需編譯,適合快速開發。 2.PHP代碼嵌入HTML中,易於網頁開發。 3.PHP處理服務器端邏輯,生成HTML輸出,支持用戶交互和數據處理。 4.PHP可與數據庫交互,處理表單提交,執行服務器端任務。

PHP在過去幾十年中塑造了網絡,並將繼續在Web開發中扮演重要角色。 1)PHP起源於1994年,因其易用性和與MySQL的無縫集成成為開發者首選。 2)其核心功能包括生成動態內容和與數據庫的集成,使得網站能夠實時更新和個性化展示。 3)PHP的廣泛應用和生態系統推動了其長期影響,但也面臨版本更新和安全性挑戰。 4)近年來的性能改進,如PHP7的發布,使其能與現代語言競爭。 5)未來,PHP需應對容器化、微服務等新挑戰,但其靈活性和活躍社區使其具備適應能力。

PHP的核心優勢包括易於學習、強大的web開發支持、豐富的庫和框架、高性能和可擴展性、跨平台兼容性以及成本效益高。 1)易於學習和使用,適合初學者;2)與web服務器集成好,支持多種數據庫;3)擁有如Laravel等強大框架;4)通過優化可實現高性能;5)支持多種操作系統;6)開源,降低開發成本。

PHP沒有死。 1)PHP社區積極解決性能和安全問題,PHP7.x提升了性能。 2)PHP適合現代Web開發,廣泛用於大型網站。 3)PHP易學且服務器表現出色,但類型系統不如靜態語言嚴格。 4)PHP在內容管理和電商領域仍重要,生態系統不斷進化。 5)通過OPcache和APC等優化性能,使用OOP和設計模式提升代碼質量。

PHP和Python各有優劣,選擇取決於項目需求。 1)PHP適合Web開發,易學,社區資源豐富,但語法不夠現代,性能和安全性需注意。 2)Python適用於數據科學和機器學習,語法簡潔,易學,但執行速度和內存管理有瓶頸。

PHP用於構建動態網站,其核心功能包括:1.生成動態內容,通過與數據庫對接實時生成網頁;2.處理用戶交互和表單提交,驗證輸入並響應操作;3.管理會話和用戶認證,提供個性化體驗;4.優化性能和遵循最佳實踐,提升網站效率和安全性。

PHP在數據庫操作和服務器端邏輯處理中使用MySQLi和PDO擴展進行數據庫交互,並通過會話管理等功能處理服務器端邏輯。 1)使用MySQLi或PDO連接數據庫,執行SQL查詢。 2)通過會話管理等功能處理HTTP請求和用戶狀態。 3)使用事務確保數據庫操作的原子性。 4)防止SQL注入,使用異常處理和關閉連接來調試。 5)通過索引和緩存優化性能,編寫可讀性高的代碼並進行錯誤處理。

在PHP中使用預處理語句和PDO可以有效防範SQL注入攻擊。 1)使用PDO連接數據庫並設置錯誤模式。 2)通過prepare方法創建預處理語句,使用佔位符和execute方法傳遞數據。 3)處理查詢結果並確保代碼的安全性和性能。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載
最受歡迎的的開源編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版
好用的JavaScript開發工具