Laravel雄辩查询的高级

时间:2019-09-09 14:51:28

标签: php laravel eloquent

我目前只能使用一个where Laravel查询。问题是,我想根据给定表中的最新记录来过滤一些数据。目前,我的查询如下:

$clients = $clients->whereDoesntHave('bill')->orWhereHas('bill', function ($query) use ($activeSchoolYear){
     $query
         ->where('created_at', '<', Carbon::parse($activeSchoolYear->start));
 })

$activeSchoolYear->start是今天的日期。

如果我的帐单表中有多个记录,则会出现问题。举个例子,如果我有两条记录的日期分开:

ID | Name  | created_at          |
1  | test  | 2019-09-09 15:31:25|
2  | test2 | 2018-09-10 16:42:44|

查询仍然返回两个日期,即使其中之一为假。我认为该查询会查找数据库中的所有记录,并且仍然返回给定的用户,因为其中一个日期是正确的。我的问题是,是否可以仅将数据库中的最新行作为目标。否则这不能用雄辩的方式完成。任何帮助表示赞赏。

编辑:

正如@Caddy所建议的,我使用了查询范围,但对其做了一些修改:

public function scopeNoActiveBill($query){
  return $query
            ->groupBy('created_at')->take(1)
            ->where('created_at', '<=', Carbon::create(2019, 9, 1));
}

我试图只取账单表的最后一行。然后,在控制器内部,这是我的查询:

$clients = $clients->whereDoesntHave('bill')
     ->orWhereHas('bill', function ($query) use ($activeSchoolYear){
            $query->noActiveBill();
      })
      ->whereHas('contracts', function ($query) use ($request) {
            $query
                  ->where('contract_type', '<', 2)
                  ->where('signed', 1)
                  ->where('school_year_id', $request['school_year']);
       });

因此,我希望两个客户都没有任何账单,或者希望客户都具有符合给定条件的账单。如果客户只有一个帐单,查询工作正常,但问题是客户有多个帐单。如果这些账单中的任何一个符合给定范围,它将返回账单。我只想查看最新记录,如果该记录符合范围标准,则退还账单。

编辑2:

由于@Caddy DZ的努力,我设法获得了预期的结果。我只是更改条件以监视未在给定日期创建账单的客户。查询范围:

public function scopeNoActiveBill($query){
     return $query->where('created_at', '>=', Carbon::create(2019, 9, 1));
}

控制器:

$clients = $clients->whereDoesntHave('bill')
    ->orWhereDoesntHave('bill', function ($query) use ($activeSchoolYear){
        $query->noActiveBill();
    });

2 个答案:

答案 0 :(得分:1)

您正在寻找的是像这样的关系查询范围

$clients = App\Client::with(['bills' => function ($query) {
   $query->today();
}])->get();

像这样向您的today()模型添加Bill范围
Bill.php

public function scopeToday($query)
{
    // Change today by $activeSchoolYear if necessary
    return $query->whereDate('created_at', '<', today());
}

假设hasMany中的Client关系

public function bills()
{
    return $this->hasMany(Bill::class);
}

像这样播种数据
DatabaseSeeder.php

// Will be returned because whereDoesntHave('bills')
$clientWithoutBills = Client::create([]);
$client = Client::create([]);
$client->bills()->createMany([
    [
        'name' => 'test',
        'created_at' => Carbon\Carbon::yesterday()
    ],
    [
        // Will not be returned because created today (not < today)
        'name' => 'test1'
    ],
    [
        // Will not be returned because created tomorrow
        'name' => 'test2',
        'created_at' => Carbon\Carbon::tomorrow()
    ]
]);

Results

[
    {
        "id": 1,
        "created_at": "2019-09-09 16:20:24",
        "updated_at": "2019-09-09 16:20:24",
        "bills": []
    },
    {
        "id": 2,
        "created_at": "2019-09-09 16:20:24",
        "updated_at": "2019-09-09 16:20:24",
        "bills": [
            {
                "id": 1,
                "name": "test",
                "client_id": 2,
                "created_at": "2019-09-08 00:00:00",
                "updated_at": "2019-09-09 16:20:24"
            }
        ]
    }
]

希望这会有所帮助

答案 1 :(得分:0)

您可以使用Eloquent whereDate()。

->whereDate('created_at', '<', Carbon::parse($activeSchoolYear->start));