【问题标题】:Complex query constraint on queryScope in laravellaravel中queryScope的复杂查询约束
【发布时间】:2020-11-17 05:32:12
【问题描述】:

users 表有以下列:

  1. created_at(时间戳)
  2. last_order(时间戳)

当创建新用户时,last_order 为空,created_at 为当前时间戳。 当用户下订单时,最后一个订单列将更新为下订单时间的时间戳。 现在我想检索过去 7 天没有下任何订单的所有用户。我将我的用户模型定义如下:

class User extends Model
{
    /**
     * @var string The database table used by the model.
     */
    public $table = 'users';

    /**
     * @var array Validation rules
     */
    public $rules = [
    ];
    public $hasMany  = [
        'voucher' => ['ItScholarBd\Api\Models\Voucher'],
        'order' => ['ItScholarBd\Api\Models\OrderLog']
    ];

   public function scopeCustomer($query)
    {
        return $query->where('role_id', '=', 5);
    }
   public function scopeNew($query,$days)
    {
        return $query->where('created_at', '>=', Carbon::now()->subDays($days));
    }
   public function scopeIdle($query,$days)
   {

       $dayOffset = Carbon::now()->subDays($days);

      return $query->where(function($q,$dayOffset){
        $q->whereNull('last_order')
          ->where('created_at','<',$dayOffset);
       })->orWhere(function($q,$days){
        $q->whereNotNull('last_order')
        ->whereRaw("DATEDIFF(created_at,last_order)>$days");
       });

   } 

}

这里scopeNew() 工作正常,但scopeIdle() 抛出以下错误:

Type error: Too few arguments to function App\User::App\{closure}(),
  1 passed in .\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php on line 222 and exactly 2 expected

【问题讨论】:

    标签: php laravel laravel-query-builder


    【解决方案1】:

    你不能为你无法控制的函数编写参数。闭包将传递一个参数,您需要使用use 导入任何其他变量:

    
    public function scopeIdle($query, $days)
    {
        $dayOffset = Carbon::now()->subDays($days);
    
        return $query
            ->where(function ($q) use ($dayOffset) {
                $q->whereNull('last_order')
                    ->where('created_at', '<', $dayOffset);
            })
            ->orWhere(function ($q) use ($days) {
                $q->whereNotNull('last_order')
                    ->whereRaw("DATEDIFF(created_at, last_order) > ?", [$days]);
           });
    }
    

    注意whereRaw语句中参数的使用,可以避免SQL注入。如果您始终如一地缩进和间隔,您还会发现您的代码更容易处理。

    【讨论】:

    • 谢谢@milken32。当 last_order 为 null 并且 created_at 早于 $days 时,我们将获取数据。但是当 created_at 和 last_order 都早于 $days 时,则不会检索到任何数据。有什么想法吗?
    • 您没有检查它们是否都比$days 更老。您正在检查created_atlast_order 之间是否存在超过$days 天的差异。由于last_order 始终大于created_at,因此DATEDIFF() 的结果将始终为负数。
    【解决方案2】:

    尝试使用闭包:

    return $query->where(function($q) use ($dayOffset){
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-10
      • 2022-11-17
      • 2014-08-18
      • 1970-01-01
      • 2020-08-15
      • 2015-12-06
      • 2021-11-16
      相关资源
      最近更新 更多