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

Exceeded maximum time error when overriding the newQuery on Laravel 4.0

因此,我试图针对同一主题的其他问题实施此 ...但它一直给我超时错误。有什么线索吗?

这是我的产品型号。它继承自 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。不过,如果我将完全相同的代码放入控制器中,效果会很好!我也试着把它放在一个范围内,也奏效了。这真是磨磨我的齿轮!

我不明白你的更新代码是如何工作的。 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();
}

Elloquent 有一个名为 newQuery 的函数。控制器没有。当您在模型中实现此功能时,您将覆盖 Elloquent 中的功能。如果您随后调用需要对您的模型进行新查询的 Elloquent 方法,它们才能 return,例如 ->allowed_products()->get()。然后你递归地调用你自己的 newQuery() 方法。由于用户权限没有改变,这导致无限递归。唯一的结果可能是超时,因为它会继续尝试确定过滤后的产品列表,这会导致调用 newQuery() 方法,该方法会在 return 查询之前尝试确定过滤后的产品列表,等等上。

当您将该方法放入控制器时,它不会重写 Elloquent newQuery 方法,因此在尝试获取 allowed_product 列表时没有无限递归。

根据 ID 是否在用户的 allowed_products() 列表中使用 ->whereExists() 将过滤器应用于产品查询并构建与 allowed_products() 除了现在添加条件,即您正在过滤的查询中的 id 等于允许的产品查询中的产品 id。这样过滤是在数据库而不是 PHP 中完成的,并且所有操作都在同一个查询中完成,因此没有递归。