問題描述
我有 4 個表,其結構和流程如下:
I have 4 tables with a structure and flow like this:
User
Accounts
Contacts
Orders
關系如下:
$user->hasMany('accounts')->hasMany('contacts')->hasMany('orders');
$user->hasMany('accounts')->hasMany('contacts')->hasMany('orders');
/** User Model **/
class User extend Eloquent {
public function accounts(){
return $this->hasMany('Accounts');
}
public function contacts(){
return $this->hasManyThrough('Contact', 'Account', 'owner_id');
}
//how do I get this?
public function orders(){
}
}
/** Account Model */
class Account extends Eloquent {
public function $user(){
return $this->belongsTo('User');
}
public function contacts(){
return $this->hasMany('Contact');
}
}
/** Contact Model **/
class Contact extends Eloquent {
public function account(){
return $this->belongsTo('Account');
}
public function orders(){
return $this->hasMany('Order');
}
}
/** Order Model **/
class Order extends Eloquent {
public function contact(){
return $this->belongsTo('contact');
}
}
經典的 hasManyThrough
是不可能的,因為我們有 4 個表.
A classic hasManyThrough
is not possible because we have 4 tables.
如何創建關系以便單個用戶可以訪問它的訂單,而無需鏈接每個模型的方法,例如:
How can I create a relationship so that a single user can have it's orders accessed without method chaining each model, such as:
User::find(8)->orders;
推薦答案
一開始很難確定查詢構建器是如何將事物切分在一起的.我知道我想如何使用原始 SQL 語句格式化查詢,但我想使用 Eloquent 來完成這個特定任務,因為其他定義的關系.
It was quite difficult at first to identify exactly how the query builder slices things together. I knew how I wanted to format the query with a raw SQL statement, but I wanted to use Eloquent for this particular task given the other defined relationships.
我能夠通過重載屬性并手動創建關系來解決這個問題.但是,實際的查詢和 hasMany 也需要手動構建.讓我們來看看我是如何做到這一點的.請記住,我們的目標是通過 2 個 has-Many 關系從用戶那里獲得 Orders
.
I was able to resolve this by overloading the attribute and manually creating the relation. However, the actual query and hasMany needs to be built manually as well. Let's take a look at how I achieved this. Remember, the goal is to get Orders
off of the user through 2 has-Many relationships.
一是屬性的重載.
public function getOrdersAttribute()
{
if( ! array_key_exists('orders', $this->relations)) $this->orders();
return $this->getRelation('orders');
}
上面函數中的想法是捕獲延遲加載的->orders
何時被調用.例如$user->orders
.這將檢查 orders
方法是否在現有 User 模型
的 relations
數組中.如果不是,那么它會調用我們的 next 函數來填充關系,最后返回我們剛剛創建的關系.
The idea in the above function is to capture when a lazy loaded ->orders
is called. such as $user->orders
. This checks to see if the orders
method is in the relations
array for the existing User model
. If it's not, then it calls our next function in order to populate the relatioship, and finally returns the relationship we've just created.
這是實際查詢訂單的函數的樣子:
This is what the function that actually queries the Orders looks like:
public function orders()
{
$orders = Order::join('contacts', 'orders.contact_id', '=', 'contacts.id')
->join('accounts', 'contacts.account_id', '=', 'accounts.id')
->where('accounts.owner_id', $this->getkey())
->get();
$hasMany = new IlluminateDatabaseEloquentRelationsHasMany(User::query(), $this, 'accounts.owner_id', 'id');
$hasMany->matchMany(array($this), $orders, 'orders');
return $this;
}
在上面,我們告訴 Orders 表加入它的聯系人(在這種情況下,這是給定 belongsTo()
所有權的既定路由).然后從聯系人中,我們加入帳戶,然后從帳戶中我們可以通過將我們的 owner_id
列與我們現有的 $user->id
進行匹配來從我們的用戶那里獲得,所以我們不需要再做任何事情了.
In the above, we tell the Orders table to join it's contacts (which is the established route given the ownership of belongsTo()
in this scenario). Then from the contacts, we join the accounts, then from the accounts we can get there from our user by matching our owner_id
column against our existing $user->id
, so we don't need to do anything further.
接下來,我們需要通過從 Eloquent Relationship
構建器實例化 hasMany
的實例來手動創建我們的關系.
Next, we need to manually create our relationship by instantiating an instance of hasMany
from the Eloquent Relationship
builder.
鑒于 HasMany
方法實際上擴展了 HasOneOrMany
抽象類,我們可以通過將我們的參數直接傳遞給 HasOneOrMany
抽象類來訪問 HasOneOrMany
code>HasMany,如下所示:
Given that the HasMany
method actually extends the HasOneOrMany
abstract class, we can reach the HasOneOrMany
abstract class by passing our arguments directly to HasMany
, like below:
$hasMany = new IlluminateDatabaseEloquentRelationsHasMany(User::query(), $this, 'accounts.owner_id', 'id');
HasOneOrMany
期望它的構造函數如下:
The HasOneOrMany
expects the following to it's constructor:
Builder $query,
Model $parent,
$foreignKey,
$localKey
因此,對于我們的構建器查詢,我們傳遞了一個我們希望與之建立關系的模型實例,第二個參數是我們模型的實例($this),第三個參數是來自我們的 Current->2nd 模型,最后一個參數是我們當前模型中與 Current->2nd 模型上的外鍵約束相匹配的列.
So for our builder query, we've passed an instance of our model that we wish to establish the relationship with, the 2nd argument being an instance of our Model ($this), the 3rd argument being the foreign key constraint from our Current->2nd model, and finally the last argument being the column to match from our current model against the foreign key constraint on our Current->2nd model.
一旦我們從上面的 HasMany
聲明中創建了 Relation
的實例,我們就需要將關系的結果與它們的許多父項進行匹配.我們使用接受 3 個參數的 matchMany()
方法來做到這一點:
Once we've created our instance of Relation
from our HasMany
declaration above, we then need to match the results of the relationship to their many parents. We do this with the matchMany()
method which accepts 3 arguments:
array $models,
Collection $results,
$relation
因此在這種情況下,模型數組將是我們當前 eloquent 模型(用戶)的數組實例,可以將其包裝在數組中以實現我們的效果.
So in this case, the array of models would be an array instance of our current eloquent model (user) which can be wrapped in an array to achieve our effect.
第二個參數將是我們在 orders()
函數中初始 $orders
查詢的結果.
The 2nd argument would be the result of our intitial $orders
query in our orders()
function.
最后,第三個參數將是我們希望用來獲取此關系實例的關系 string
;這對我們來說是order
.
Finally, the 3rd argument will be the relation string
that we wish to use to fetch our instance of this relationship; which for us is order
.
現在您可以正確使用 Eloquent 或 Lazy Loading 來為我們的用戶獲取訂單.
Now you can correct use either Eloquent or Lazy Loading to fetch our orders for our user.
User::find(8)->orders();
$user->orders;
希望這對面臨類似問題的其他人有所幫助.
Hopefully this is helpful for someone else facing a similar issue.
這篇關于如何在 4 個表中使用 Laravel 的 hasManyThrough的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!