我有4个表格,其结构和流程如下:
User
Accounts
Contacts
Orders
关系如下:
$用户>的hasMany( '账户') - >的hasMany( '联系人') - >的hasMany( '订货');
/** 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个表。
如何创建关系,以便单个用户可以在不使用方法链接每个模型的情况下访问其订单,例如:
User::find(8)->orders;
答案 0 :(得分:5)
首先很难确定查询构建器如何将事物切片在一起。我知道我想用原始SQL语句格式化查询,但是我想在给定其他已定义关系的情况下将Eloquent用于此特定任务。
我能够通过重载属性并手动创建关系来解决这个问题。但是,实际查询和hasMany也需要手动构建。让我们来看看我是如何实现这一目标的。请记住,目标是通过2个多人关系从用户那里获得Orders
。
首先,重载属性。
public function getOrdersAttribute()
{
if( ! array_key_exists('orders', $this->relations)) $this->orders();
return $this->getRelation('orders');
}
上述函数中的想法是捕获何时调用延迟加载的->orders
。例如$user->orders
。这会检查orders
方法是否位于现有relations
的{{1}}数组中。如果不是,那么它会调用我们的 next 函数来填充关系,最后返回我们刚创建的关系。
这就是实际查询Orders的函数:
User model
在上面,我们告诉Orders表加入它的联系人(这是在这种情况下给定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 Illuminate\Database\Eloquent\Relations\HasMany(User::query(), $this, 'accounts.owner_id', 'id');
$hasMany->matchMany(array($this), $orders, 'orders');
return $this;
}
所有权的既定路线)。然后,通过联系人,我们加入了帐户,然后通过我们的belongsTo()
列与现有owner_id
相匹配,从我们的用户那里获得的帐户,因此我们不需要做任何事情进一步
接下来,我们需要通过从$user->id
构建器实例化hasMany
的实例来手动创建我们的关系。
鉴于Eloquent Relationship
方法实际上扩展了HasMany
抽象类,我们可以通过将参数直接传递给HasOneOrMany
来达到HasOneOrMany
抽象类,如下所示:< / p>
HasMany
$hasMany = new Illuminate\Database\Eloquent\Relations\HasMany(User::query(), $this, 'accounts.owner_id', 'id');
期望以下内容为其构造函数:
HasOneOrMany
因此,对于我们的构建器查询,我们已经传递了我们希望与之建立关系的模型实例,第二个参数是我们Model的一个实例($ this),第三个参数是外键我们的Current-&gt;第二个模型的约束,最后一个参数是我们当前模型与Current-&gt;第二个模型上的外键约束匹配的列。
一旦我们从上面的Builder $query,
Model $parent,
$foreignKey,
$localKey
声明中创建了Relation
的实例,我们就需要将关系结果与其众多父母进行匹配。我们使用HasMany
方法执行此操作,该方法接受3个参数:
matchMany()
所以在这种情况下,模型数组将是我们当前雄辩模型(用户)的数组实例,它可以包装在一个数组中以实现我们的效果。
第二个参数将是我们的array $models,
Collection $results,
$relation
函数中的初始$orders
查询的结果。
最后,第三个参数将是我们希望用来获取这种关系实例的关系orders()
;对我们来说是string
。
现在您可以更正使用Eloquent或Lazy Loading来获取我们用户的订单。
order
希望这对面临类似问题的其他人有帮助。
答案 1 :(得分:3)
您可以通过用户与function findNumber(arr, number){
var result = false;
arr.forEach(function(item, index){
if(item === number) result = true;
});
return result;
join
Orders
在同样的情况下,它对我有用,欢迎所有反馈
答案 2 :(得分:2)
我创建了一个HasManyThrough
级的无限关系:Repository on GitHub
安装后,您可以像这样使用它:
class User extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function orders() {
return $this->hasManyDeep(Order::class, [Account::class, Contact::class]);
}
}