你可以在laravel中创建一个调用各种其他范围的范围吗?

geo*_*310 4 php laravel laravel-5.1

我在Laravel中有一个模型,它定义了各种范围.我想在很多地方使用它们而不是将它们链接在一起我宁愿只能调用一个调用所有其他范围的范围,如下所示:

function scopeValid($query, $user_id) {
    $query = $this->scopeDateValid($query);
    $query = $this->scopeMaxUsesValid($query);
    $query = $this->scopeCustomerMaxUsesValid($query, $user_id);
    return $query;
}
Run Code Online (Sandbox Code Playgroud)

这似乎不起作用,有没有办法实现这一目标?

cee*_*yoz 16

文档中所示,您将要对范围的魔术函数进行范围界定$query,$this而不是调用内部实现:

public function scopeTesting($query) {
    return $query->testingTwo();
}

public function scopeTestingTwo($query) {
    return $query->where('testing', true);
}
Run Code Online (Sandbox Code Playgroud)

作为演示,您可以在此处看到调用testing()范围应用范围中的逻辑testingTwo():

>>> App\User::testing()->toSql();
=> "select * from "users" where "testing" = ?"
>>> 
Run Code Online (Sandbox Code Playgroud)

所以,对于你的代码,这应该做的伎俩:

function scopeValid($query, $user_id) {
    $query = $query->dateValid();
    $query = $query->maxUsesValid();
    $query = $query->customerMaxUsesValid($user_id);

    return $query;

    // or just return $query->dateValid()
    //                      ->maxUsesValid()
    //                      ->customerMaxUsesValid($user_id);
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是最好的答案. (3认同)

ber*_*nie 6

原始答案

查询范围是静态调用的.

$users = Model::dateValid()->get()
Run Code Online (Sandbox Code Playgroud)

$this进行静态调用时没有.尝试更换$this->scopeDateValidself::scopeDateValid

修改后的答案

您的代码可能还有其他问题,因为$this实际上Model是调用范围时的实例.您应该能够直接使用$query参数调用类范围方法(就像您所做的那样),或者使用ceejayoz提出的另一个范围方法解析链.

就个人而言,当您知道要在类上调用范围方法时,我认为在完成整个查询范围解析过程中没有太大的优势,但无论哪种方式都有效.

分析

让我们遍历调用堆栈以执行查询范围:

#0 [internal function]: App\User->scopeValid(Object(Illuminate\Database\Eloquent\Builder))
#1 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(829): call_user_func_array(Array, Array)
#2 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(940): Illuminate\Database\Eloquent\Builder->callScope('scopeOff', Array)
#3 [internal function]: Illuminate\Database\Eloquent\Builder->__call('valid', Array)
#4 [internal function]: Illuminate\Database\Eloquent\Builder->valid()
#5 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3482): call_user_func_array(Array, Array)
#6 [internal function]: Illuminate\Database\Eloquent\Model->__call('valid', Array)
#7 [internal function]: App\User->valid()
#8 /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3496): call_user_func_array(Array, Array)
#9 /app/Http/Controllers/UserController.php(22): Illuminate\Database\Eloquent\Model::__callStatic('valid', Array)
#10 /app/Http/Controllers/UserController.php(22): App\User::valid()
Run Code Online (Sandbox Code Playgroud)

#10 User::scopeValid()电话

#8 __callStatic()处理程序Model

方法重载PHP文档:

public static mixed __callStatic(string $ name,array $ arguments)

在静态上下文中调用不可访问的方法时会触发__callStatic().

的注释的代码Model.php__callStatic()方法(行3492-3497):

public static function __callStatic($method, $parameters)
{
    // Uses PHP's late static binding to create a new instance of the
    // model class (User in this case)
    $instance = new static;

    // Call the $method (valid()) on $instance (empty User) with $parameters
    return call_user_func_array([$instance, $method], $parameters);
}
Run Code Online (Sandbox Code Playgroud)

#7 User->valid()(不存在)

#5 __call处理程序Model

再次,从关于方法重载PHP文档:

public mixed __call(string $ name,array $ arguments)

在对象上下文中调用不可访问的方法时会触发__call().

注释Model.php__call()方法代码(第3474-3483行):

public function __call($method, $parameters)
{
    // increment() and decrement() methods are called on the Model
    // instance apparently. I don't know what they do.
    if (in_array($method, ['increment', 'decrement'])) {
        return call_user_func_array([$this, $method], $parameters);
    }

    // Create a new \Illuminate\Database\Eloquent\Builder query builder
    // initialized with this model (User)
    $query = $this->newQuery();

    // Call the $method (valid()) on $query with $parameters
    return call_user_func_array([$query, $method], $parameters);
}
Run Code Online (Sandbox Code Playgroud)

#2 __call处理程序的查询Builder

的注释的代码Builder.php__call()方法(线933-946):

public function __call($method, $parameters)
{
    if (isset($this->macros[$method])) {
        // Handle query builder macros (I don't know about them)
        array_unshift($parameters, $this);

        return call_user_func_array($this->macros[$method], $parameters);
    } elseif (method_exists($this->model, $scope = 'scope'.ucfirst($method))) {
        // Now we're getting somewhere! Builds the 'scopeValid' string from
        // the original 'valid()' method call. If that method exists on the
        // model, use it as a scope.
        return $this->callScope($scope, $parameters);
    }

    // Other stuff for fallback
    $result = call_user_func_array([$this->query, $method], $parameters);

    return in_array($method, $this->passthru) ? $result : $this;
}
Run Code Online (Sandbox Code Playgroud)

#1 callScope()查询方法Builder

的注释的代码Builder.php__call()方法(线825-830):

protected function callScope($scope, $parameters)
{
    // Add $this (the query) as the first parameter
    array_unshift($parameters, $this);

    // Call the query $scope method (scopeValid) in the context of an
    // empty User model instance with the $parameters.
    return call_user_func_array([$this->model, $scope], $parameters) ?: $this;
}
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这个答案是正确的。文档 [显示了`public function scopePopular(`](http://laravel.com/docs/5.1/eloquent#query-scopes),而不是`public static function`。我认为你混淆了外观(看起来是静态的,但不是) 与静态。根据链接的文档,您应该使用 `$query` 而不是 `$this` 来处理传递给作用域函数的查询构建器。请参阅我的回答 @bernie。 (2认同)