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