From 8929a05973a8b0527a050d11adca9fc316c2e435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Wed, 25 Feb 2026 11:22:40 +0300 Subject: [PATCH 1/4] Fix weekday constraint when chaining every* methods (#105) --- src/Event.php | 45 +++++++++++++++++++++++++++++----------- tests/Unit/EventTest.php | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/Event.php b/src/Event.php index 0f67428..935d83b 100644 --- a/src/Event.php +++ b/src/Event.php @@ -1033,62 +1033,62 @@ public function refreshLock(): void public function everyMinute(): self { - return $this->cron('* * * * *'); + return $this->cronPreservingCurrentDayOfWeek('* * * * *'); } public function everyTwoMinutes(): self { - return $this->cron('*/2 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/2 * * * *'); } public function everyThreeMinutes(): self { - return $this->cron('*/3 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/3 * * * *'); } public function everyFourMinutes(): self { - return $this->cron('*/4 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/4 * * * *'); } public function everyFiveMinutes(): self { - return $this->cron('*/5 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/5 * * * *'); } public function everyTenMinutes(): self { - return $this->cron('*/10 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/10 * * * *'); } public function everyFifteenMinutes(): self { - return $this->cron('*/15 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/15 * * * *'); } public function everyThirtyMinutes(): self { - return $this->cron('*/30 * * * *'); + return $this->cronPreservingCurrentDayOfWeek('*/30 * * * *'); } public function everyTwoHours(): self { - return $this->cron('0 */2 * * *'); + return $this->cronPreservingCurrentDayOfWeek('0 */2 * * *'); } public function everyThreeHours(): self { - return $this->cron('0 */3 * * *'); + return $this->cronPreservingCurrentDayOfWeek('0 */3 * * *'); } public function everyFourHours(): self { - return $this->cron('0 */4 * * *'); + return $this->cronPreservingCurrentDayOfWeek('0 */4 * * *'); } public function everySixHours(): self { - return $this->cron('0 */6 * * *'); + return $this->cronPreservingCurrentDayOfWeek('0 */6 * * *'); } /** @@ -1246,6 +1246,27 @@ protected function applyMask($unit) return $this->cron(\implode(' ', $cron)); } + /** + * Preserve day-of-week constraints while applying every* frequency shortcuts. + * + * @param string $expression + */ + protected function cronPreservingCurrentDayOfWeek($expression): self + { + $currentExpressionParts = \explode(' ', $this->expression); + $newExpressionParts = \explode(' ', $expression); + + if ( + isset($currentExpressionParts[4], $newExpressionParts[4]) + && '*' !== $currentExpressionParts[4] + && '*' === $newExpressionParts[4] + ) { + $newExpressionParts[4] = $currentExpressionParts[4]; + } + + return $this->cron(\implode(' ', $newExpressionParts)); + } + /** * Lock the event. */ diff --git a/tests/Unit/EventTest.php b/tests/Unit/EventTest.php index 9299a9c..177ffe7 100644 --- a/tests/Unit/EventTest.php +++ b/tests/Unit/EventTest.php @@ -434,6 +434,44 @@ public function test_every_methods(string $method, string $expectedCronExpressio self::assertSame($expectedCronExpression, $event->getExpression()); } + /** @dataProvider everyMethodProvider */ + public function test_every_methods_keep_weekday_constraint(string $method, string $expectedCronExpression): void + { + // Arrange + $event = new Event($this->id, 'php -i'); + $event->mondays(); + /** @var callable $methodCall */ + $methodCall = [$event, $method]; + $methodCallClosure = \Closure::fromCallable($methodCall); + + $expressionParts = \explode(' ', $expectedCronExpression); + $expressionParts[4] = '1'; + $expectedExpression = \implode(' ', $expressionParts); + + // Act + $methodCallClosure(); + + // Assert + self::assertSame($expectedExpression, $event->getExpression()); + } + + public function test_between_and_weekday_can_be_chained_with_every_five_minutes(): void + { + // Arrange + $event = new Event($this->id, 'php -i'); + + // Act + $event + ->mondays() + ->everyFiveMinutes() + ->between('08:00', '17:00'); + + // Assert + self::assertSame('*/5 * * * 1', $event->getExpression()); + self::assertSame('08:00', $event->getFrom()); + self::assertSame('17:00', $event->getTo()); + } + public function test_hourly_at_with_valid_minute(): void { // Arrange From b52b16c0a47637c6fe8987d4ac65749d9ed549e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Wed, 25 Feb 2026 11:28:39 +0300 Subject: [PATCH 2/4] Remove redundant between() regression test --- tests/Unit/EventTest.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/tests/Unit/EventTest.php b/tests/Unit/EventTest.php index 177ffe7..1e85750 100644 --- a/tests/Unit/EventTest.php +++ b/tests/Unit/EventTest.php @@ -455,23 +455,6 @@ public function test_every_methods_keep_weekday_constraint(string $method, strin self::assertSame($expectedExpression, $event->getExpression()); } - public function test_between_and_weekday_can_be_chained_with_every_five_minutes(): void - { - // Arrange - $event = new Event($this->id, 'php -i'); - - // Act - $event - ->mondays() - ->everyFiveMinutes() - ->between('08:00', '17:00'); - - // Assert - self::assertSame('*/5 * * * 1', $event->getExpression()); - self::assertSame('08:00', $event->getFrom()); - self::assertSame('17:00', $event->getTo()); - } - public function test_hourly_at_with_valid_minute(): void { // Arrange From 17b5ae8e0b9ec42e0f82e3719a386587e2355bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Wed, 25 Feb 2026 14:47:48 +0300 Subject: [PATCH 3/4] Harden weekday preservation helper and expand regression coverage --- src/Event.php | 19 ++++++++++++------- tests/Unit/EventTest.php | 25 ++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/Event.php b/src/Event.php index 935d83b..37afbda 100644 --- a/src/Event.php +++ b/src/Event.php @@ -1250,18 +1250,23 @@ protected function applyMask($unit) * Preserve day-of-week constraints while applying every* frequency shortcuts. * * @param string $expression + * + * @return self */ - protected function cronPreservingCurrentDayOfWeek($expression): self + protected function cronPreservingCurrentDayOfWeek(string $expression): self { - $currentExpressionParts = \explode(' ', $this->expression); - $newExpressionParts = \explode(' ', $expression); + $weekdayPosition = $this->fieldsPosition['week'] - 1; + $currentExpressionParts = \preg_split('/\s+/', $this->expression, -1, PREG_SPLIT_NO_EMPTY); + $newExpressionParts = \preg_split('/\s+/', $expression, -1, PREG_SPLIT_NO_EMPTY); + $currentExpressionParts = false === $currentExpressionParts ? [] : $currentExpressionParts; + $newExpressionParts = false === $newExpressionParts ? [] : $newExpressionParts; if ( - isset($currentExpressionParts[4], $newExpressionParts[4]) - && '*' !== $currentExpressionParts[4] - && '*' === $newExpressionParts[4] + isset($currentExpressionParts[$weekdayPosition], $newExpressionParts[$weekdayPosition]) + && '*' !== $currentExpressionParts[$weekdayPosition] + && '*' === $newExpressionParts[$weekdayPosition] ) { - $newExpressionParts[4] = $currentExpressionParts[4]; + $newExpressionParts[$weekdayPosition] = $currentExpressionParts[$weekdayPosition]; } return $this->cron(\implode(' ', $newExpressionParts)); diff --git a/tests/Unit/EventTest.php b/tests/Unit/EventTest.php index 1e85750..cd13c19 100644 --- a/tests/Unit/EventTest.php +++ b/tests/Unit/EventTest.php @@ -445,7 +445,30 @@ public function test_every_methods_keep_weekday_constraint(string $method, strin $methodCallClosure = \Closure::fromCallable($methodCall); $expressionParts = \explode(' ', $expectedCronExpression); - $expressionParts[4] = '1'; + $dayOfWeekPosition = \count($expressionParts) - 1; + $expressionParts[$dayOfWeekPosition] = '1'; + $expectedExpression = \implode(' ', $expressionParts); + + // Act + $methodCallClosure(); + + // Assert + self::assertSame($expectedExpression, $event->getExpression()); + } + + /** @dataProvider everyMethodProvider */ + public function test_every_methods_keep_comma_separated_weekday_constraint(string $method, string $expectedCronExpression): void + { + // Arrange + $event = new Event($this->id, 'php -i'); + $event->days(1, 3); + /** @var callable $methodCall */ + $methodCall = [$event, $method]; + $methodCallClosure = \Closure::fromCallable($methodCall); + + $expressionParts = \explode(' ', $expectedCronExpression); + $dayOfWeekPosition = \count($expressionParts) - 1; + $expressionParts[$dayOfWeekPosition] = '1,3'; $expectedExpression = \implode(' ', $expressionParts); // Act From fe44afd49c7f592d01c51ef9d77ef5357ea4c9be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ey=C3=BCp=20Can=20Akman?= Date: Wed, 25 Feb 2026 15:22:27 +0300 Subject: [PATCH 4/4] Drop redundant phpdoc tags for helper method --- src/Event.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Event.php b/src/Event.php index 37afbda..5452453 100644 --- a/src/Event.php +++ b/src/Event.php @@ -1248,10 +1248,6 @@ protected function applyMask($unit) /** * Preserve day-of-week constraints while applying every* frequency shortcuts. - * - * @param string $expression - * - * @return self */ protected function cronPreservingCurrentDayOfWeek(string $expression): self {