Laravel:在使用whereHas时传递一个参数给关系函数(而不是查询回调函数)



我想知道如何将参数传递给模型关系函数。为了明确,我不是在谈论查询回调。

考虑这样一个模型:

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方法/范围是什么

相关内容

  • 没有找到相关文章

最新更新