Skip to content

Commit dfd625f

Browse files
authored
Merge pull request #6 from adhocore/develop
Refactor
2 parents 3ee70f0 + 3b1b9f2 commit dfd625f

File tree

5 files changed

+200
-151
lines changed

5 files changed

+200
-151
lines changed

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ php:
1111
install:
1212
- composer install --prefer-dist
1313

14+
before_script:
15+
- for P in src tests; do find $P -type f -name '*.php' -exec php -l {} \;; done
16+
1417
script:
1518
- vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml
1619

src/Expression.php

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,36 @@ class Expression
5858
*/
5959
public static function isDue($expr, $time = null)
6060
{
61-
list($expr, $time) = static::process($expr, $time);
61+
static $instance;
6262

63+
if (!$instance) {
64+
$instance = new static;
65+
}
66+
67+
return $instance->isCronDue($expr, $time);
68+
}
69+
70+
/**
71+
* Instance call.
72+
*
73+
* Parse cron expression to decide if it can be run on given time (or default now).
74+
*
75+
* @param string $expr The cron expression.
76+
* @param int $time The timestamp to validate the cron expr against. Defaults to now.
77+
*
78+
* @return bool
79+
*/
80+
public function isCronDue($expr, $time = null)
81+
{
82+
list($expr, $time) = $this->process($expr, $time);
83+
84+
$checker = new SegmentChecker;
6385
foreach ($expr as $pos => $segment) {
6486
if ($segment === '*' || $segment === '?') {
6587
continue;
6688
}
6789

68-
if (!SegmentChecker::isDue($segment, $pos, $time)) {
90+
if (!$checker->isDue($segment, $pos, $time)) {
6991
return false;
7092
}
7193
}
@@ -81,53 +103,38 @@ public static function isDue($expr, $time = null)
81103
*
82104
* @return array
83105
*/
84-
protected static function process($expr, $time)
106+
protected function process($expr, $time)
85107
{
86108
if (isset(static::$expressions[$expr])) {
87109
$expr = static::$expressions[$expr];
88110
}
89111

90-
$expr = str_ireplace(array_keys(static::$literals), array_values(static::$literals), $expr);
91-
$expr = explode(' ', $expr);
112+
$expr = \str_ireplace(\array_keys(static::$literals), \array_values(static::$literals), $expr);
113+
$expr = \explode(' ', $expr);
92114

93-
if (count($expr) < 5 || count($expr) > 6) {
115+
if (\count($expr) < 5 || \count($expr) > 6) {
94116
throw new \UnexpectedValueException(
95117
'Cron $expr should have 5 or 6 segments delimited by space'
96118
);
97119
}
98120

99121
$time = static::normalizeTime($time);
100122

101-
$time = array_map('intval', explode(' ', date('i G j n w Y t d m N', $time)));
123+
$time = \array_map('intval', \explode(' ', \date('i G j n w Y t d m N', $time)));
102124

103125
return [$expr, $time];
104126
}
105127

106-
protected static function normalizeTime($time)
128+
protected function normalizeTime($time)
107129
{
108130
if (empty($time)) {
109-
$time = time();
110-
} elseif (is_string($time)) {
111-
$time = strtotime($time);
131+
$time = \time();
132+
} elseif (\is_string($time)) {
133+
$time = \strtotime($time);
112134
} elseif ($time instanceof \DateTime) {
113135
$time = $time->getTimestamp();
114136
}
115137

116138
return $time;
117139
}
118-
119-
/**
120-
* Instance call.
121-
*
122-
* Parse cron expression to decide if it can be run on given time (or default now).
123-
*
124-
* @param string $expr The cron expression.
125-
* @param int $time The timestamp to validate the cron expr against. Defaults to now.
126-
*
127-
* @return bool
128-
*/
129-
public function isCronDue($expr, $time = null)
130-
{
131-
return static::isDue($expr, $time);
132-
}
133140
}

src/SegmentChecker.php

Lines changed: 35 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,38 @@
33
namespace Ahc\Cron;
44

55
/**
6-
* Cron Expression Parser.
6+
* Cron Expression segment checker.
77
*
88
* This class checks if a cron segment satisfies given time.
99
*
1010
* @author Jitendra Adhikari <[email protected]>
1111
*/
1212
class SegmentChecker
1313
{
14-
public static function isDue($segment, $pos, $time)
14+
/** @var Validator */
15+
protected $validator;
16+
17+
public function __construct()
18+
{
19+
$this->validator = new validator;
20+
}
21+
22+
/**
23+
* Checks if a cron segment satisfies given time.
24+
*
25+
* @param string $segment
26+
* @param int $pos
27+
* @param int $time
28+
*
29+
* @return bool
30+
*/
31+
public function isDue($segment, $pos, $time)
1532
{
1633
$isDue = true;
17-
$offsets = explode(',', trim($segment));
34+
$offsets = \explode(',', \trim($segment));
1835

1936
foreach ($offsets as $offset) {
20-
if (null === $isDue = static::isOffsetDue($offset, $pos, $time)) {
37+
if (null === $isDue = $this->isOffsetDue($offset, $pos, $time)) {
2138
throw new \UnexpectedValueException(
2239
sprintf('Invalid offset value %s for segment #%d', $offset, $pos)
2340
);
@@ -40,142 +57,37 @@ public static function isDue($segment, $pos, $time)
4057
*
4158
* @return bool|null
4259
*/
43-
protected static function isOffsetDue($offset, $pos, $time)
60+
protected function isOffsetDue($offset, $pos, $time)
4461
{
45-
if (strpos($offset, '/') !== false) {
46-
return static::inStep($time[$pos], $offset);
62+
if (\strpos($offset, '/') !== false) {
63+
return $this->validator->inStep($time[$pos], $offset);
4764
}
4865

49-
if (strpos($offset, '-') !== false) {
50-
return static::inRange($time[$pos], $offset);
66+
if (\strpos($offset, '-') !== false) {
67+
return $this->validator->inRange($time[$pos], $offset);
5168
}
5269

53-
if (is_numeric($offset)) {
70+
if (\is_numeric($offset)) {
5471
return $time[$pos] == $offset;
5572
}
5673

57-
return static::inModifier($offset, $pos, $time);
74+
return $this->checkModifier($offset, $pos, $time);
5875
}
5976

60-
protected static function inModifier($offset, $pos, $time)
77+
protected function checkModifier($offset, $pos, $time)
6178
{
62-
$isModifier = strpbrk($offset, 'LCW#');
79+
$isModifier = \strpbrk($offset, 'LCW#');
6380

6481
if ($pos === 2 && $isModifier) {
65-
return static::checkMonthDay($offset, $time);
82+
return $this->validator->isValidMonthDay($offset, $time);
6683
}
6784

6885
if ($pos === 4 && $isModifier) {
69-
return static::checkWeekDay($offset, $time);
70-
}
71-
}
72-
73-
protected static function inRange($value, $offset)
74-
{
75-
$parts = explode('-', $offset);
76-
77-
return $parts[0] <= $value && $value <= $parts[1];
78-
}
79-
80-
protected static function inStep($value, $offset)
81-
{
82-
if (strpos($offset, '*/') !== false || strpos($offset, '0/') !== false) {
83-
$parts = explode('/', $offset, 2);
84-
85-
return $value % $parts[1] === 0;
86-
}
87-
88-
$parts = explode('/', $offset, 2);
89-
$subparts = explode('-', $parts[0], 2) + [1 => $value];
90-
91-
return ($subparts[0] <= $value && $value <= $subparts[1] && $parts[1])
92-
? in_array($value, range($subparts[0], $subparts[1], $parts[1]))
93-
: false;
94-
}
95-
96-
/**
97-
* Check if modifiers [L C W #] are satisfied.
98-
*
99-
* @internal
100-
*
101-
* @param string $value
102-
* @param int $time
103-
*
104-
* @return bool|null
105-
*/
106-
protected static function checkMonthDay($value, $time)
107-
{
108-
$month = $time[8] < 10 ? '0' . $time[8] : $time[8];
109-
110-
if ($value == 'L') {
111-
return $time[2] == $time[6];
86+
return $this->validator->isValidWeekDay($offset, $time);
11287
}
11388

114-
if ($pos = strpos($value, 'W')) {
115-
$value = substr($value, 0, $pos);
116-
117-
return static::isClosestWeekDay($value, $month, $time);
118-
}
119-
}
120-
121-
protected static function isClosestWeekDay($value, $month, $time)
122-
{
123-
foreach ([0, -1, 1, -2, 2] as $i) {
124-
$incr = $value + $i;
125-
if ($incr > 0 && $incr <= $time[6]) {
126-
if ($incr < 10) {
127-
$incr = '0' . $incr;
128-
}
129-
130-
$parts = explode(' ', date('N m j', strtotime("$time[5]-$month-$incr")));
131-
if ($parts[0] < 6 && $parts[1] == $month) {
132-
return $time[2] == $parts[2];
133-
}
134-
}
135-
}
136-
}
137-
138-
/**
139-
* Check if modifiers [L C W #] are satisfied.
140-
*
141-
* @internal
142-
*
143-
* @param string $value
144-
* @param int $time
145-
*
146-
* @return bool|null
147-
*/
148-
protected static function checkWeekDay($value, $time)
149-
{
150-
$month = $time[8] < 10 ? '0' . $time[8] : $time[8];
151-
152-
if (strpos($value, 'L')) {
153-
return static::lastWeekDay($value, $month, $time);
154-
}
155-
156-
if (strpos($value, '#')) {
157-
$value = explode('#', str_replace('0#', '7#', $value));
158-
159-
if ($value[0] < 0 || $value[0] > 7 || $value[1] < 1 || $value[1] > 5 || $time[9] != $value[0]) {
160-
return false;
161-
}
162-
163-
return intval($time[7] / 7) == $value[1] - 1;
164-
}
165-
}
166-
167-
protected static function lastWeekDay($value, $month, $time)
168-
{
169-
$value = explode('L', str_replace('7L', '0L', $value));
170-
$decr = $time[6];
171-
172-
for ($i = 0; $i < 7; $i++) {
173-
$decr -= $i;
174-
if (date('w', strtotime("$time[5]-$month-$decr")) == $value[0]) {
175-
return $time[2] == $decr;
176-
}
177-
}
178-
179-
return false;
89+
// @codeCoverageIgnoreStart
90+
return !$isModifier;
91+
// @codeCoverageIgnoreEnd
18092
}
18193
}

0 commit comments

Comments
 (0)