How to use Laravel#39;s hasManyThrough across 4 tables(如何在 4 个表中使用 Laravel 的 hasManyThrough)
问题描述
我有 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 4 个表中使用 Laravel 的 hasManyThrough
基础教程推荐
- 如何在 XAMPP 上启用 mysqli? 2021-01-01
- Doctrine 2 - 在多对多关系中记录更改 2022-01-01
- 在 yii2 中迁移时出现异常“找不到驱动程序" 2022-01-01
- 找不到类“AppHttpControllersDB",我也无法使用新模型 2022-01-01
- phpmyadmin 错误“#1062 - 密钥 1 的重复条目‘1’" 2022-01-01
- 使用 PDO 转义列名 2021-01-01
- HTTP 与 FTP 上传 2021-01-01
- 如何在 Symfony 和 Doctrine 中实现多对多和一对多? 2022-01-01
- PHP 守护进程/worker 环境 2022-01-01
- 在 CakePHP 2.0 中使用 Html Helper 时未定义的变量 2021-01-01