113 lines
4.6 KiB
PHP
113 lines
4.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
final class RuleValidator
|
|
{
|
|
/** @var array<string,int> */
|
|
private const REPLY_FREQUENCIES = [
|
|
'30' => 30,
|
|
'60' => 60,
|
|
'120' => 120,
|
|
'360' => 360,
|
|
'720' => 720,
|
|
'1440' => 1440,
|
|
'2880' => 2880,
|
|
'10080' => 10080,
|
|
];
|
|
|
|
/** @param array<string,mixed> $input @return array<string,mixed> */
|
|
public static function validate(array $input, Settings $settings): array
|
|
{
|
|
$subjectPrefix = trim((string)($input['subject_prefix'] ?? $input['subject'] ?? ''));
|
|
if (str_contains($subjectPrefix, "\r") || str_contains($subjectPrefix, "\n")) {
|
|
throw new InvalidArgumentException('Przedrostek tematu nie może zawierać nowych linii.');
|
|
}
|
|
if (strlen($subjectPrefix) > $settings->maxSubjectBytes()) {
|
|
throw new InvalidArgumentException('Przedrostek tematu jest za długi.');
|
|
}
|
|
|
|
$body = str_replace(["\r\n", "\r", "\0"], ["\n", "\n", ''], (string)($input['body'] ?? ''));
|
|
$body = trim($body);
|
|
if ($body === '') {
|
|
throw new InvalidArgumentException('Treść wiadomości jest wymagana.');
|
|
}
|
|
if (strlen($body) > $settings->maxBodyBytes()) {
|
|
throw new InvalidArgumentException('Treść wiadomości jest za długa.');
|
|
}
|
|
|
|
$mode = $settings->scheduleMode();
|
|
$tz = new DateTimeZone($settings->timezone());
|
|
[$startTs, $startValue] = self::parseScheduleValue((string)($input['start_value'] ?? ''), $mode, $tz, true);
|
|
[$endTs, $endValue] = self::parseScheduleValue((string)($input['end_value'] ?? ''), $mode, $tz, false);
|
|
if (substr($startValue, 0, 10) < (new DateTimeImmutable('today', $tz))->format('Y-m-d')) {
|
|
throw new InvalidArgumentException('Data rozpoczęcia nie może być wcześniejsza niż aktualna data.');
|
|
}
|
|
if ($endTs <= $startTs) {
|
|
throw new InvalidArgumentException('Data zakończenia musi być późniejsza niż data rozpoczęcia.');
|
|
}
|
|
[$replyEveryMessage, $repeatMinutes] = self::parseReplyFrequency((string)($input['reply_frequency'] ?? '1440'));
|
|
|
|
return [
|
|
'subject_prefix' => $subjectPrefix,
|
|
'body' => $body,
|
|
'schedule_mode' => $mode,
|
|
'timezone' => $settings->timezone(),
|
|
'start_value' => $startValue,
|
|
'end_value' => $endValue,
|
|
'start_ts' => $startTs,
|
|
'end_ts' => $endTs,
|
|
'enabled' => self::truthy($input['enabled'] ?? false),
|
|
'reply_every_message' => $replyEveryMessage,
|
|
'repeat_minutes' => $repeatMinutes,
|
|
'dynamic_scope' => $settings->dynamicMailboxScope(),
|
|
];
|
|
}
|
|
|
|
/** @return array{0:bool,1:int} */
|
|
private static function parseReplyFrequency(string $value): array
|
|
{
|
|
$value = trim(strtolower($value));
|
|
if ($value === 'every') {
|
|
return [true, 0];
|
|
}
|
|
if (isset(self::REPLY_FREQUENCIES[$value])) {
|
|
return [false, self::REPLY_FREQUENCIES[$value]];
|
|
}
|
|
throw new InvalidArgumentException('Częstość odpowiedzi jest nieprawidłowa.');
|
|
}
|
|
|
|
/** @return array{0:int,1:string} */
|
|
private static function parseScheduleValue(string $value, string $mode, DateTimeZone $tz, bool $start): array
|
|
{
|
|
$value = trim($value);
|
|
if ($mode === 'exact_hour') {
|
|
if (!preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}$/', $value)) {
|
|
throw new InvalidArgumentException('Nieprawidłowa data lub godzina.');
|
|
}
|
|
$dt = DateTimeImmutable::createFromFormat('!Y-m-d\TH:i', $value, $tz);
|
|
if (!$dt) {
|
|
throw new InvalidArgumentException('Nieprawidłowa data lub godzina.');
|
|
}
|
|
return [$dt->getTimestamp(), $value];
|
|
}
|
|
|
|
if (!preg_match('/^([0-9]{4}-[0-9]{2}-[0-9]{2})\|(morning|afternoon|evening)$/', $value, $m)) {
|
|
throw new InvalidArgumentException('Nieprawidłowa data lub pora dnia.');
|
|
}
|
|
$hour = ['morning' => 8, 'afternoon' => 13, 'evening' => 18][$m[2]];
|
|
if (!$start && $m[2] === 'evening') {
|
|
$hour = 23;
|
|
}
|
|
$dt = DateTimeImmutable::createFromFormat('!Y-m-d H:i', $m[1] . ' ' . sprintf('%02d:00', $hour), $tz);
|
|
if (!$dt) {
|
|
throw new InvalidArgumentException('Nieprawidłowa data lub pora dnia.');
|
|
}
|
|
return [$dt->getTimestamp(), $value];
|
|
}
|
|
|
|
private static function truthy(mixed $value): bool
|
|
{
|
|
return in_array(strtolower((string)$value), ['1', 'true', 'yes', 'on'], true);
|
|
}
|
|
}
|