所以,我试图在同一主题的另一个问题上实现这个answer ...并且它一直给我提供超出的时间错误。有线索吗?
这是我的产品型号。它继承自Eloquent
。
public function newQuery($excludeDeleted = true)
{
$user_permission = Auth::user()->permissions;
if( $user_permission->master )
return parent::newQuery();
else if( $user_permission->web_service )
{
$allowed_ids = array();
foreach( $user_permission->allowed_products()->get() as $allowed)
$allowed_ids[] = $allowed->id;
return parent::newQuery()->whereIn('id', $allowed_ids);
}
return parent::newQuery();
}
如果用户是master
,则无需在请求中查询范围。但是,如果不是,那么我需要按记录用户的权限进行过滤。
更新:
我在控制器中尝试了以下代码,它可以正常工作:
$user_permission = Auth::user()->permissions;
echo "<PRE>"; print_r($user_permission->allowed_products()->get()); exit;
更新2:
伙计们,我刚刚发现问题出在这个代码的和平之中:
$allowed = Auth::user()->permissions()->first()->allowed_products()->get()->list('id');
它以某种方式给我一个Maximum execution time of 30 seconds exceeded
。如果我将完全相同的代码放在控制器中,就像魅力一样!我也尝试将它放在一个范围内,也有效。这真的磨了我的齿轮!
答案 0 :(得分:2)
Elloquent有一个名为newQuery的函数。控制器没有。在模型中实现此功能时,您将覆盖Elloquent中的该功能。然后,如果您在返回之前调用需要针对模型的新查询的Elloquent方法,例如->allowed_products()->get()
。然后递归调用自己的newQuery()方法。由于用户权限未更改,因此会导致无限递归。唯一的结果可能是超时,因为它会继续尝试确定过滤的产品列表,这会导致您的newQuery()方法被调用,它会在返回查询之前尝试确定过滤的产品列表,依此类推。
当您将方法放入Controller时,它不会覆盖Elloquent newQuery方法,因此在尝试获取allowed_product列表时没有无限递归。
根据id是否在用户的allowed_products()列表中使用->whereExists()
将过滤器应用于产品查询会更高效,并建立与allowed_products()相同的查询,除非现在添加条件您过滤的查询中的ID等于允许的产品查询中的产品ID。这样,过滤在数据库而不是PHP中完成,所有过程都在同一个查询中完成,因此没有递归。
答案 1 :(得分:1)
我看不到您的更新代码是如何工作的。 Illuminate\Database\Eloquent\Collection
没有任何魔术方法来调用关系函数,你应该尝试一个未定义的方法错误。
你可以试试像
这样的东西public function newQuery($excludeDeleted = true)
{
// Returns `Illuminate\Database\Eloquent\Collection`
$user_permission = Auth::user()->permissions;
if ($user_permission->master)
{
return parent::newQuery();
}
else if ($user_permission->web_service)
{
// If here you was to call $user_permission->allowed_products()->get() not much is going to happen, besides probably getting an undefined method error.
$allowed_ids = Auth::user()->permissions()->allowed_products()->get()->lists('id');
return parent::newQuery()->whereIn('id', $allowed_ids);
}
return parent::newQuery();
}
更新:根据下面的评论,我认为问题是由于newQuery()
被多次调用,因为在控制器中调用一次代码工作正常。当这应用于每个查询时,不需要一遍又一遍地收集所有ID(假设每次调用它们都不会改变)。如下所示的内容将允许您存储这些内容,并且每个请求只处理一次,而不是每次运行查询。
private $allowed_ids_cache = null;
public function newQuery($excludeDeleted = true)
{
$user_permission = Auth::user()->permissions;
if ($user_permission->master)
{
return parent::newQuery();
}
else if ($user_permission->web_service)
{
if ($this->allowed_ids_cache === null)
{
$this->allowed_ids_cache = Auth::user()->permissions()->allowed_products()->get()->lists('id');
}
return parent::newQuery()->whereIn('id', $this->allowed_ids_cache);
}
return parent::newQuery();
}