Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
46 / 48
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReminderPolicyValue
95.83% covered (success)
95.83%
46 / 48
60.00% covered (warning)
60.00%
3 / 5
18
0.00% covered (danger)
0.00%
0 / 1
 defaults
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 normalize
96.43% covered (success)
96.43%
27 / 28
0.00% covered (danger)
0.00%
0 / 1
9
 encode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 toNonNegativeInt
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 normalizeSendTimer
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
4.03
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Policy\Provider\Reminder;
10
11final class ReminderPolicyValue {
12    /** @return array{days_before: int, days_between: int, max: int, send_timer: string} */
13    public static function defaults(): array {
14        return [
15            'days_before' => 0,
16            'days_between' => 0,
17            'max' => 0,
18            'send_timer' => '10:00',
19        ];
20    }
21
22    /** @return array{days_before: int, days_between: int, max: int, send_timer: string} */
23    public static function normalize(mixed $rawValue): array {
24        $defaults = self::defaults();
25
26        if (is_string($rawValue)) {
27            $trimmed = trim($rawValue);
28            if ($trimmed !== '') {
29                $decoded = json_decode($trimmed, true);
30                if (is_array($decoded)) {
31                    $rawValue = $decoded;
32                }
33            }
34        }
35
36        if (!is_array($rawValue)) {
37            return $defaults;
38        }
39
40        $daysBefore = self::toNonNegativeInt($rawValue['days_before'] ?? $defaults['days_before']);
41        $daysBetween = self::toNonNegativeInt($rawValue['days_between'] ?? $defaults['days_between']);
42        $max = self::toNonNegativeInt($rawValue['max'] ?? $defaults['max']);
43        $sendTimer = self::normalizeSendTimer($rawValue['send_timer'] ?? $defaults['send_timer']);
44
45        if ($daysBefore <= 0 || $daysBetween <= 0 || $max <= 0) {
46            return [
47                'days_before' => 0,
48                'days_between' => 0,
49                'max' => 0,
50                'send_timer' => '',
51            ];
52        }
53
54        if ($sendTimer === '') {
55            $sendTimer = $defaults['send_timer'];
56        }
57
58        return [
59            'days_before' => $daysBefore,
60            'days_between' => $daysBetween,
61            'max' => $max,
62            'send_timer' => $sendTimer,
63        ];
64    }
65
66    /** @param array<string, mixed> $value */
67    public static function encode(array $value): string {
68        return (string)json_encode(self::normalize($value), JSON_UNESCAPED_SLASHES);
69    }
70
71    private static function toNonNegativeInt(mixed $rawValue): int {
72        if (is_int($rawValue)) {
73            return max(0, $rawValue);
74        }
75
76        if (is_numeric($rawValue)) {
77            return max(0, (int)$rawValue);
78        }
79
80        return 0;
81    }
82
83    private static function normalizeSendTimer(mixed $rawValue): string {
84        if (!is_scalar($rawValue)) {
85            return '10:00';
86        }
87
88        $value = trim((string)$rawValue);
89        if ($value === '') {
90            return '';
91        }
92
93        if (!preg_match('/^(?:[01]\d|2[0-3]):[0-5]\d$/', $value)) {
94            return '10:00';
95        }
96
97        return $value;
98    }
99}