Laravel 查询:获取 child 的日期范围不在日期范围数组中的模型

Laravel Query: get models where child's date ranges is not in array of date ranges

我有 Event 个模型,hasMany 个孩子有 Time 个模型。 Time 是具有 start_timeend_time 字段的日期时间范围。

如何获得所有 Events 其中 none 的孩子 Timesarray 的日期范围相交?

示例:

$events = Event::notInDateRange([
    [ 'start_date' => '2000.01.01 00:00:00', 'end_date' => '2000.01.01 12:00:00' ],
    [ 'start_date' => '2000.01.02 12:00:00', 'end_date' => '2000.01.02 16:00:00' ],
    [ 'start_date' => '2000.01.03 10:00:00', 'end_date' => '2000.01.03 12:30:00' ],
])->get();
// In this case I don't want to get Event where one of Time is 
// [ 'start_date' => '2000.01.03 12:00:00' => 'end_date' => '2000.01.03 14:00:00' ]

您可以在新范围内创建一个新的 query scope to create a notInDateRange scope in your Event model and use the whereNotBetween where clause

在您的 Event 模型 class 中,定义一个名为 scopeNotInDateRange 的新函数,它接受开始和结束日期并将其定义如下:

public function scopeNotInDateRange($query, $start_date, $end_date)
    $start = new Carbon($start_date);
    $end = new Carbon($end_date);
    return $query->whereNotBetween('start_date', [$start, $end])
                 ->whereNotBetween('end_date', [$start, $end]);

另外记得将 use Carbon\Carbon; 添加到 Event class 的顶部。我们将使用 Carbon 将字符串转换为日期。

然后您可以使用新的查询范围,例如 App\Event::notInDateRange($start, $end)。您还可以链接范围,因此在您的示例中您可以使用:

$events = Event::notInDateRange('2000-01-01 00:00:00', '2000-01-01 12:00:00')
               ->notInDateRange('2000-01-02 12:00:00', '2000-01-02 16:00:00')
               ->notInDateRange('2000-01-03 10:00:00', '2000-01-03 12:30:00')
               ->get();

请注意,我还将您在日期中使用的 . 更改为 -,以便 Carbon 能够将字符串转换为日期。

如果您还没有,还请确保您的 start_dateend_date 列已使用 Date Mutators 转换为碳日期,当您使用 Laravel.为此,请将以下代码段添加到您的 Event 模型 class:

/**
 * The attributes that should be mutated to dates.
 *
 * @var array
 */
protected $dates = [
    'start_date', 'end_date'
];