Files
chatroom/app/Rules/HolidayEventScheduleRule.php
T

99 lines
3.0 KiB
PHP
Raw Normal View History

<?php
/**
* 文件功能:节日福利年度调度校验规则
*
* 负责校验 yearly 模式下的月/日/时间、多天与多轮次组合是否合法。
*/
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Translation\PotentiallyTranslatedString;
/**
* 类功能:校验节日福利年度调度配置的组合合法性。
*/
class HolidayEventScheduleRule implements DataAwareRule, ValidationRule
{
/**
* 当前请求的全部字段。
*
* @var array<string, mixed>
*/
protected array $data = [];
/**
* 注入待校验的完整数据集。
*
* @param array<string, mixed> $data
*/
public function setData(array $data): static
{
$this->data = $data;
return $this;
}
/**
* 运行年度调度规则校验。
*
* @param Closure(string, ?string=): PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$repeatType = (string) ($this->data['repeat_type'] ?? $value ?? '');
if ($repeatType !== 'yearly') {
return;
}
$month = (int) ($this->data['schedule_month'] ?? 0);
$day = (int) ($this->data['schedule_day'] ?? 0);
$time = (string) ($this->data['schedule_time'] ?? '');
$durationDays = (int) ($this->data['duration_days'] ?? 0);
$dailyOccurrences = (int) ($this->data['daily_occurrences'] ?? 0);
$intervalMinutes = $this->data['occurrence_interval_minutes'];
if ($month < 1 || $month > 12) {
$fail('年度节日模式必须设置有效的触发月份。');
}
if ($day < 1 || $day > 31) {
$fail('年度节日模式必须设置有效的触发日期。');
}
if ($month > 0 && $day > 0 && ! checkdate($month, $day, 2024)) {
$fail('所选月份和日期不是有效的公历节日日期。');
}
if (! preg_match('/^\d{2}:\d{2}$/', $time)) {
$fail('年度节日模式必须设置首轮开始时间。');
return;
}
if ($durationDays < 1 || $durationDays > 31) {
$fail('连续发放天数必须在 1 到 31 天之间。');
}
if ($dailyOccurrences < 1 || $dailyOccurrences > 24) {
$fail('每天发送次数必须在 1 到 24 次之间。');
}
if ($dailyOccurrences > 1 && ((int) $intervalMinutes) < 1) {
$fail('同一天多轮发送时,必须设置大于 0 的间隔分钟数。');
}
[$hour, $minute] = array_map('intval', explode(':', $time));
$startMinutes = $hour * 60 + $minute;
$lastOffsetMinutes = max(0, ($dailyOccurrences - 1) * (int) ($intervalMinutes ?? 0));
if ($startMinutes + $lastOffsetMinutes >= 1440) {
$fail('同一天多轮发送的最后一轮不能跨到次日,请缩短间隔或减少次数。');
}
}
}