我想知道如何将参数传递给模型关系函数。为了明确,我不是在谈论查询回调。
考虑这样一个模型:
class UserRelationships extends Model
{
// other stuff
// dynamic scope:
/**
* Scope a query to only include users of a given type.
*
* @param IlluminateDatabaseEloquentBuilder $query
* @param mixed $type
* @return IlluminateDatabaseEloquentBuilder
*/
// $relationships = UserRelationships::at( Carbon::parse('2022-10-10') )->get();
public function scopeAt($query, Carbon $date)
{
return $query->where('superseded_at', '>', $date )
->where('created_at', '<=', $date );
}
}
和具有以下关系的相关模型:
class User extends Authenticatable
{
public function progenial_relation(Carbon $date=null) // returns this user record in the userRelationships table, which can be used to retrieve this users parent (directly lookup the sponsor_id)
// when eager loading, this is useful for getting all users whose parent is x, hence the name
{
return $this->hasOne(UserRelationships::class, 'user_id', 'id')
->at( @$date ?: Carbon::now() ) // local dynamic scope in userRelationships
->orderByDesc('created_at')
->limit(1);
}
public function parental_relation(Carbon $date=null) // returns records from the userRelationships table, of all the users which refer to this user as their sponsor
// when eager loading, this is useful for getting the user whose child is x, hence the name
{
return $this->hasMany(UserRelationships::class, 'sponsor_id', 'id')
->at( @$date ?: Carbon::now() ); // local dynamic scope in userRelationships
}
}
你可以看到我的关系接受一个参数(日期)。
现在,如果你想像这样直接使用这些关系,没有问题:
$date = CarbonCarbon::parse('2022-06-01');
$relations_at_date = User::find(1)->parental_relation( $date )->get();
但是,如果您需要使用急切加载方法,如has()
,whereHas()
,doesntHave()
,whereDoesntHave()
,会发生什么?你如何将一个参数传递给关系?例如,我想向我的User模型添加其他关系。
public function children(Carbon $date=null)
{
$date = @$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) {
$q->where('sponsor_id', $this->id);
}, $date); // not working
}
我尝试了这些语法,但它不起作用:
whereHas( 'relationship_name', $callback, $argument )
whereHas( 'relationship_name', $argument, $callback )
whereHas( 'relationship_name', [$argument], $callback )
whereHas( 'relationship_name', $callback, [$argument] )
这有可能吗?有其他选择吗?
为了完整起见,我将添加使用普通闭包时会发生的情况:
public function children(Carbon $date=null)
{
$date = @$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) use ($date) {
$q->at($date)->where('sponsor_id', $this->id);
});
}
这是生成的SQL。正如您所看到的,约束被应用了两次。一次通过查询回调,一次通过关系。但是因为我不能传递正确的参数给关系,它得到默认的参数。两个约束发生冲突,查询不能工作。
"select * from `users`
where exists (
select *
from `user_relationships`
where `users`.`id` = `user_relationships`.`user_id`
and `user_relationships`.`superseded_at` > ?
and `user_relationships`.`created_at` <= ?
and `sponsor_id` = ?
and `user_relationships`.`superseded_at` > ?
and `user_relationships`.`created_at` <= ?
)
and `users`.`deleted_at` is null"
我不认为它可能传递变量的关系方法当这样的急于加载
但是你可以对wherehas
应用子查询:
$date = @$date ?: Carbon::now();
return self::whereHas('progenial_relation', function($q) use ($date) {
$q
->where('sponsor_id', $this->id)
->at( @$date ?: Carbon::now() );
}, $date);
虽然我不确定你添加的->at
方法/范围是什么