You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii 2如何实现新增任务时间不与已有时间区间重叠的校验

Yii2 任务时间区间重叠校验实现方案

你写的SQL正确性说明

你提供的SQL可以覆盖「新任务的开始/结束时间落在已有任务区间内」的场景,但遗漏了新任务时间区间完全包含已有任务区间的极端重叠场景,比如已有任务是10/11/2021 1:20 PM - 3:20 PM,新任务选了10/11/2021 1:00 PM - 4:00 PM,此时你的SQL查询不到重叠,但实际属于需要拦截的重叠场景。

更简洁且覆盖所有重叠场景的判断逻辑是:新任务开始时间 < 已有任务结束时间 AND 新任务结束时间 > 已有任务开始时间,该逻辑覆盖所有时间重叠情况:

  • 新任务开始/结束时间落在已有区间内
  • 新任务完全包含已有任务区间
  • 新任务完全被已有任务区间包含
  • 新任务和已有任务起止点重合

Yii2 集成方案

原来的unique校验器仅支持完全相等的值校验,不适用区间判断,你需要替换为自定义校验器,步骤如下:

步骤1:删除无用规则

删除原有rules数组中start_date、end_date对应的两个unique校验规则。

步骤2:新增自定义校验规则

在rules数组中新增一条自定义校验规则:

public function rules()
{
    return [
        // 保留你原来的其他规则,新增下面这条
        ['start_date', 'validateTimeOverlap'],
        // ... 其他原有规则
    ];
}

步骤3:实现校验方法

在Task模型类中新增校验方法:

/**
 * 校验任务时间是否和已有任务重叠
 */
public function validateTimeOverlap($attribute, $params)
{
    // 存在其他基础错误时不跑重叠校验
    if ($this->hasErrors()) {
        return;
    }
    $newStart = $this->start_date;
    $newEnd = $this->end_date;

    // 查询所有重叠的任务
    $overlapQuery = Task::find()
        ->where(['<', 'start_date', $newEnd])
        ->andWhere(['>', 'end_date', $newStart]);

    // 更新场景下排除当前任务本身,避免自己和自己判定重叠
    if (!$this->isNewRecord) {
        $overlapQuery->andWhere(['!=', 'id', $this->id]);
    }

    // 存在重叠任务时抛出错误
    if ($overlapQuery->exists()) {
        $this->addError($attribute, '该时间段已被占用,请选择其他时间');
    }
}

说明

你的原有规则中已经通过filter将start_date、end_date转为时间戳整数,上述数值比较逻辑完全适用,所有重叠场景都会被正常拦截。

内容的提问来源于stack exchange,提问作者Angel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 22:39:00