在Laravel 4.0上覆盖newQuery时超过了最大时间错误

时间:2015-02-21 17:33:40

标签: php laravel laravel-4 eloquent

所以,我试图在同一主题的另一个问题上实现这个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。如果我将完全相同的代码放在控制器中,就像魅力一样!我也尝试将它放在一个范围内,也有效。这真的磨了我的齿轮!

2 个答案:

答案 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();
}