1<?php
2
3namespace Cron;
4
5/**
6 * Abstract CRON expression field
7 */
8abstract class AbstractField implements FieldInterface
9{
10    /**
11     * Check to see if a field is satisfied by a value
12     *
13     * @param string $dateValue Date value to check
14     * @param string $value     Value to test
15     *
16     * @return bool
17     */
18    public function isSatisfied($dateValue, $value)
19    {
20        if ($this->isIncrementsOfRanges($value)) {
21            return $this->isInIncrementsOfRanges($dateValue, $value);
22        } elseif ($this->isRange($value)) {
23            return $this->isInRange($dateValue, $value);
24        }
25
26        return $value == '*' || $dateValue == $value;
27    }
28
29    /**
30     * Check if a value is a range
31     *
32     * @param string $value Value to test
33     *
34     * @return bool
35     */
36    public function isRange($value)
37    {
38        return strpos($value, '-') !== false;
39    }
40
41    /**
42     * Check if a value is an increments of ranges
43     *
44     * @param string $value Value to test
45     *
46     * @return bool
47     */
48    public function isIncrementsOfRanges($value)
49    {
50        return strpos($value, '/') !== false;
51    }
52
53    /**
54     * Test if a value is within a range
55     *
56     * @param string $dateValue Set date value
57     * @param string $value     Value to test
58     *
59     * @return bool
60     */
61    public function isInRange($dateValue, $value)
62    {
63        $parts = array_map('trim', explode('-', $value, 2));
64
65        return $dateValue >= $parts[0] && $dateValue <= $parts[1];
66    }
67
68    /**
69     * Test if a value is within an increments of ranges (offset[-to]/step size)
70     *
71     * @param string $dateValue Set date value
72     * @param string $value     Value to test
73     *
74     * @return bool
75     */
76    public function isInIncrementsOfRanges($dateValue, $value)
77    {
78        $parts = array_map('trim', explode('/', $value, 2));
79        $stepSize = isset($parts[1]) ? (int) $parts[1] : 0;
80
81        if ($stepSize === 0) {
82            return false;
83        }
84
85        if (($parts[0] == '*' || $parts[0] === '0')) {
86            return (int) $dateValue % $stepSize == 0;
87        }
88
89        $range = explode('-', $parts[0], 2);
90        $offset = $range[0];
91        $to = isset($range[1]) ? $range[1] : $dateValue;
92        // Ensure that the date value is within the range
93        if ($dateValue < $offset || $dateValue > $to) {
94            return false;
95        }
96
97        if ($dateValue > $offset && 0 === $stepSize) {
98          return false;
99        }
100
101        for ($i = $offset; $i <= $to; $i+= $stepSize) {
102            if ($i == $dateValue) {
103                return true;
104            }
105        }
106
107        return false;
108    }
109
110    /**
111     * Returns a range of values for the given cron expression
112     *
113     * @param string $expression The expression to evaluate
114     * @param int $max           Maximum offset for range
115     *
116     * @return array
117     */
118    public function getRangeForExpression($expression, $max)
119    {
120        $values = array();
121
122        if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) {
123            if (!$this->isIncrementsOfRanges($expression)) {
124                list ($offset, $to) = explode('-', $expression);
125                $stepSize = 1;
126            }
127            else {
128                $range = array_map('trim', explode('/', $expression, 2));
129                $stepSize = isset($range[1]) ? $range[1] : 0;
130                $range = $range[0];
131                $range = explode('-', $range, 2);
132                $offset = $range[0];
133                $to = isset($range[1]) ? $range[1] : $max;
134            }
135            $offset = $offset == '*' ? 0 : $offset;
136            for ($i = $offset; $i <= $to; $i += $stepSize) {
137                $values[] = $i;
138            }
139            sort($values);
140        }
141        else {
142            $values = array($expression);
143        }
144
145        return $values;
146    }
147
148}
149