AbstractField.php
1 year ago
CronExpression.php
8 months ago
DayOfMonthField.php
1 year ago
DayOfWeekField.php
1 year ago
FieldFactory.php
1 year ago
FieldFactoryInterface.php
1 year ago
FieldInterface.php
1 year ago
HoursField.php
1 year ago
MinutesField.php
1 year ago
MonthField.php
1 year ago
index.php
1 year ago
DayOfWeekField.php
125 lines
| 1 | <?php |
| 2 | declare(strict_types=1); |
| 3 | namespace Cron; |
| 4 | if (!defined('ABSPATH')) exit; |
| 5 | use DateTimeInterface; |
| 6 | use InvalidArgumentException; |
| 7 | class DayOfWeekField extends AbstractField |
| 8 | { |
| 9 | protected $rangeStart = 0; |
| 10 | protected $rangeEnd = 7; |
| 11 | protected $nthRange; |
| 12 | protected $literals = [1 => 'MON', 2 => 'TUE', 3 => 'WED', 4 => 'THU', 5 => 'FRI', 6 => 'SAT', 7 => 'SUN']; |
| 13 | public function __construct() |
| 14 | { |
| 15 | $this->nthRange = range(1, 5); |
| 16 | parent::__construct(); |
| 17 | } |
| 18 | public function isSatisfiedBy(DateTimeInterface $date, $value, bool $invert): bool |
| 19 | { |
| 20 | if ('?' === $value) { |
| 21 | return true; |
| 22 | } |
| 23 | // Convert text day of the week values to integers |
| 24 | $value = $this->convertLiterals($value); |
| 25 | $currentYear = (int) $date->format('Y'); |
| 26 | $currentMonth = (int) $date->format('m'); |
| 27 | $lastDayOfMonth = (int) $date->format('t'); |
| 28 | // Find out if this is the last specific weekday of the month |
| 29 | if ($lPosition = strpos($value, 'L')) { |
| 30 | $weekday = $this->convertLiterals(substr($value, 0, $lPosition)); |
| 31 | $weekday %= 7; |
| 32 | $daysInMonth = (int) $date->format('t'); |
| 33 | $remainingDaysInMonth = $daysInMonth - (int) $date->format('d'); |
| 34 | return (($weekday === (int) $date->format('w')) && ($remainingDaysInMonth < 7)); |
| 35 | } |
| 36 | // Handle # hash tokens |
| 37 | if (strpos($value, '#')) { |
| 38 | [$weekday, $nth] = explode('#', $value); |
| 39 | if (!is_numeric($nth)) { |
| 40 | throw new InvalidArgumentException("Hashed weekdays must be numeric, {$nth} given"); |
| 41 | } else { |
| 42 | $nth = (int) $nth; |
| 43 | } |
| 44 | // 0 and 7 are both Sunday, however 7 matches date('N') format ISO-8601 |
| 45 | if ('0' === $weekday) { |
| 46 | $weekday = 7; |
| 47 | } |
| 48 | $weekday = (int) $this->convertLiterals((string) $weekday); |
| 49 | // Validate the hash fields |
| 50 | if ($weekday < 0 || $weekday > 7) { |
| 51 | throw new InvalidArgumentException("Weekday must be a value between 0 and 7. {$weekday} given"); |
| 52 | } |
| 53 | if (!\in_array($nth, $this->nthRange, true)) { |
| 54 | throw new InvalidArgumentException("There are never more than 5 or less than 1 of a given weekday in a month, {$nth} given"); |
| 55 | } |
| 56 | // The current weekday must match the targeted weekday to proceed |
| 57 | if ((int) $date->format('N') !== $weekday) { |
| 58 | return false; |
| 59 | } |
| 60 | $tdate = clone $date; |
| 61 | $tdate = $tdate->setDate($currentYear, $currentMonth, 1); |
| 62 | $dayCount = 0; |
| 63 | $currentDay = 1; |
| 64 | while ($currentDay < $lastDayOfMonth + 1) { |
| 65 | if ((int) $tdate->format('N') === $weekday) { |
| 66 | if (++$dayCount >= $nth) { |
| 67 | break; |
| 68 | } |
| 69 | } |
| 70 | $tdate = $tdate->setDate($currentYear, $currentMonth, ++$currentDay); |
| 71 | } |
| 72 | return (int) $date->format('j') === $currentDay; |
| 73 | } |
| 74 | // Handle day of the week values |
| 75 | if (false !== strpos($value, '-')) { |
| 76 | $parts = explode('-', $value); |
| 77 | if ('7' === $parts[0]) { |
| 78 | $parts[0] = 0; |
| 79 | } elseif ('0' === $parts[1]) { |
| 80 | $parts[1] = 7; |
| 81 | } |
| 82 | $value = implode('-', $parts); |
| 83 | } |
| 84 | // Test to see which Sunday to use -- 0 == 7 == Sunday |
| 85 | $format = \in_array(7, array_map(function ($value) { |
| 86 | return (int) $value; |
| 87 | }, str_split($value)), true) ? 'N' : 'w'; |
| 88 | $fieldValue = (int) $date->format($format); |
| 89 | return $this->isSatisfied($fieldValue, $value); |
| 90 | } |
| 91 | public function increment(DateTimeInterface &$date, $invert = false, $parts = null): FieldInterface |
| 92 | { |
| 93 | if (! $invert) { |
| 94 | $date = $date->add(new \DateInterval('P1D')); |
| 95 | $date = $date->setTime(0, 0); |
| 96 | } else { |
| 97 | $date = $date->sub(new \DateInterval('P1D')); |
| 98 | $date = $date->setTime(23, 59); |
| 99 | } |
| 100 | return $this; |
| 101 | } |
| 102 | public function validate(string $value): bool |
| 103 | { |
| 104 | $basicChecks = parent::validate($value); |
| 105 | if (!$basicChecks) { |
| 106 | if ('?' === $value) { |
| 107 | return true; |
| 108 | } |
| 109 | // Handle the # value |
| 110 | if (false !== strpos($value, '#')) { |
| 111 | $chunks = explode('#', $value); |
| 112 | $chunks[0] = $this->convertLiterals($chunks[0]); |
| 113 | if (parent::validate($chunks[0]) && is_numeric($chunks[1]) && \in_array((int) $chunks[1], $this->nthRange, true)) { |
| 114 | return true; |
| 115 | } |
| 116 | } |
| 117 | if (preg_match('/^(.*)L$/', $value, $matches)) { |
| 118 | return $this->validate($matches[1]); |
| 119 | } |
| 120 | return false; |
| 121 | } |
| 122 | return $basicChecks; |
| 123 | } |
| 124 | } |
| 125 |