Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
declare(strict_types=1);
4
 
5
namespace Cron;
6
 
7
use DateTimeInterface;
8
use InvalidArgumentException;
9
 
10
/**
11
 * Day of week field.  Allows: * / , - ? L #.
12
 *
13
 * Days of the week can be represented as a number 0-7 (0|7 = Sunday)
14
 * or as a three letter string: SUN, MON, TUE, WED, THU, FRI, SAT.
15
 *
16
 * 'L' stands for "last". It allows you to specify constructs such as
17
 * "the last Friday" of a given month.
18
 *
19
 * '#' is allowed for the day-of-week field, and must be followed by a
20
 * number between one and five. It allows you to specify constructs such as
21
 * "the second Friday" of a given month.
22
 */
23
class DayOfWeekField extends AbstractField
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    protected $rangeStart = 0;
29
 
30
    /**
31
     * {@inheritdoc}
32
     */
33
    protected $rangeEnd = 7;
34
 
35
    /**
36
     * @var array Weekday range
37
     */
38
    protected $nthRange;
39
 
40
    /**
41
     * {@inheritdoc}
42
     */
43
    protected $literals = [1 => 'MON', 2 => 'TUE', 3 => 'WED', 4 => 'THU', 5 => 'FRI', 6 => 'SAT', 7 => 'SUN'];
44
 
45
    /**
46
     * Constructor
47
     */
48
    public function __construct()
49
    {
50
        $this->nthRange = range(1, 5);
51
        parent::__construct();
52
    }
53
 
54
    /**
55
     * @inheritDoc
56
     */
57
    public function isSatisfiedBy(DateTimeInterface $date, $value, bool $invert): bool
58
    {
59
        if ('?' === $value) {
60
            return true;
61
        }
62
 
63
        // Convert text day of the week values to integers
64
        $value = $this->convertLiterals($value);
65
 
66
        $currentYear = (int) $date->format('Y');
67
        $currentMonth = (int) $date->format('m');
68
        $lastDayOfMonth = (int) $date->format('t');
69
 
70
        // Find out if this is the last specific weekday of the month
71
        if ($lPosition = strpos($value, 'L')) {
72
            $weekday = $this->convertLiterals(substr($value, 0, $lPosition));
73
            $weekday %= 7;
74
 
75
            $daysInMonth = (int) $date->format('t');
76
            $remainingDaysInMonth = $daysInMonth - (int) $date->format('d');
77
            return (($weekday === (int) $date->format('w')) && ($remainingDaysInMonth < 7));
78
        }
79
 
80
        // Handle # hash tokens
81
        if (strpos($value, '#')) {
82
            [$weekday, $nth] = explode('#', $value);
83
 
84
            if (!is_numeric($nth)) {
85
                throw new InvalidArgumentException("Hashed weekdays must be numeric, {$nth} given");
86
            } else {
87
                $nth = (int) $nth;
88
            }
89
 
90
            // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601
91
            if ('0' === $weekday) {
92
                $weekday = 7;
93
            }
94
 
95
            $weekday = (int) $this->convertLiterals((string) $weekday);
96
 
97
            // Validate the hash fields
98
            if ($weekday < 0 || $weekday > 7) {
99
                throw new InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given");
100
            }
101
 
102
            if (!\in_array($nth, $this->nthRange, true)) {
103
                throw new InvalidArgumentException("There are never more than 5 or less than 1 of a given weekday in a month, {$nth} given");
104
            }
105
 
106
            // The current weekday must match the targeted weekday to proceed
107
            if ((int) $date->format('N') !== $weekday) {
108
                return false;
109
            }
110
 
111
            $tdate = clone $date;
112
            $tdate = $tdate->setDate($currentYear, $currentMonth, 1);
113
            $dayCount = 0;
114
            $currentDay = 1;
115
            while ($currentDay < $lastDayOfMonth + 1) {
116
                if ((int) $tdate->format('N') === $weekday) {
117
                    if (++$dayCount >= $nth) {
118
                        break;
119
                    }
120
                }
121
                $tdate = $tdate->setDate($currentYear, $currentMonth, ++$currentDay);
122
            }
123
 
124
            return (int) $date->format('j') === $currentDay;
125
        }
126
 
127
        // Handle day of the week values
128
        if (false !== strpos($value, '-')) {
129
            $parts = explode('-', $value);
130
            if ('7' === $parts[0]) {
131
                $parts[0] = 0;
132
            } elseif ('0' === $parts[1]) {
133
                $parts[1] = 7;
134
            }
135
            $value = implode('-', $parts);
136
        }
137
 
138
        // Test to see which Sunday to use -- 0 == 7 == Sunday
139
        $format = \in_array(7, array_map(function ($value) {
140
            return (int) $value;
141
        }, str_split($value)), true) ? 'N' : 'w';
142
        $fieldValue = (int) $date->format($format);
143
 
144
        return $this->isSatisfied($fieldValue, $value);
145
    }
146
 
147
    /**
148
     * @inheritDoc
149
     */
150
    public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface
151
    {
152
        if (! $invert) {
153
            $date = $date->add(new \DateInterval('P1D'));
154
            $date = $date->setTime(0, 0);
155
        } else {
156
            $date = $date->sub(new \DateInterval('P1D'));
157
            $date = $date->setTime(23, 59);
158
        }
159
 
160
        return $this;
161
    }
162
 
163
    /**
164
     * {@inheritdoc}
165
     */
166
    public function validate(string $value): bool
167
    {
168
        $basicChecks = parent::validate($value);
169
 
170
        if (!$basicChecks) {
171
            if ('?' === $value) {
172
                return true;
173
            }
174
 
175
            // Handle the # value
176
            if (false !== strpos($value, '#')) {
177
                $chunks = explode('#', $value);
178
                $chunks[0] = $this->convertLiterals($chunks[0]);
179
 
180
                if (parent::validate($chunks[0]) && is_numeric($chunks[1]) && \in_array((int) $chunks[1], $this->nthRange, true)) {
181
                    return true;
182
                }
183
            }
184
 
185
            if (preg_match('/^(.*)L$/', $value, $matches)) {
186
                return $this->validate($matches[1]);
187
            }
188
 
189
            return false;
190
        }
191
 
192
        return $basicChecks;
193
    }
194
}