Passed
Pull Request — master (#2)
by Kevin
02:04
created

BetweenTimeExtension::__toString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
rs 10
ccs 4
cts 4
cp 1
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Zenstruck\ScheduleBundle\Schedule\Extension;
4
5
use Zenstruck\ScheduleBundle\Event\BeforeTaskEvent;
6
use Zenstruck\ScheduleBundle\Schedule\Exception\SkipTask;
7
8
/**
9
 * @author Kevin Bond <[email protected]>
10
 */
11
final class BetweenTimeExtension extends SelfHandlingExtension
12
{
13
    private $startTime;
14
    private $endTime;
15
    private $within;
16
    private $inclusive;
17
18 13
    private function __construct(string $startTime, string $endTime, bool $within, bool $inclusive)
19
    {
20 13
        $this->startTime = self::normalizeTime($startTime);
21 13
        $this->endTime = self::normalizeTime($endTime);
22 13
        $this->within = $within;
23 13
        $this->inclusive = $inclusive;
24 13
    }
25
26 1
    public function __toString(): string
27
    {
28 1
        if ($this->within) {
29 1
            return "Only run between {$this->startTime} and {$this->endTime}";
30
        }
31
32 1
        return "Only run if not between {$this->startTime} and {$this->endTime}";
33
    }
34
35 12
    public function filterTask(BeforeTaskEvent $event): void
36
    {
37 12
        $isBetween = $this->isBetween($event->getTask()->getTimezone());
38
39 12
        if ($this->within && !$isBetween) {
40 3
            throw new SkipTask("Only runs between {$this->startTime} and {$this->endTime}");
41
        }
42
43 9
        if (!$this->within && $isBetween) {
44 3
            throw new SkipTask("Only runs if not between {$this->startTime} and {$this->endTime}");
45
        }
46 6
    }
47
48 7
    public static function whenWithin(string $startTime, string $endTime, bool $inclusive = true): self
49
    {
50 7
        return new self($startTime, $endTime, true, $inclusive);
51
    }
52
53 7
    public static function unlessWithin(string $startTime, string $endTime, bool $inclusive = true): self
54
    {
55 7
        return new self($startTime, $endTime, false, $inclusive);
56
    }
57
58 12
    private function isBetween(?\DateTimeZone $timezone): bool
59
    {
60
        [$now, $startTime, $endTime] = [
61 12
            new \DateTime(\date('Y-m-d H:i:00'), $timezone),
62 12
            self::parseTime($this->startTime, $timezone),
63 12
            self::parseTime($this->endTime, $timezone),
64
        ];
65
66 12
        if ($endTime < $startTime) {
67
            // account for overnight
68 4
            $endTime = $endTime->add(new \DateInterval('P1D'));
69
        }
70
71 12
        if ($this->inclusive) {
72 8
            return $now >= $startTime && $now <= $endTime;
73
        }
74
75 4
        return $now > $startTime && $now < $endTime;
76
    }
77
78 13
    private static function normalizeTime(string $time): string
79
    {
80 13
        return false === \mb_strpos($time, ':') ? "{$time}:00" : $time;
81
    }
82
83 12
    private static function parseTime(string $time, ?\DateTimeZone $timezone): \DateTime
84
    {
85 12
        [$hour, $minute] = \explode(':', $time, 2);
86
87 12
        return (new \DateTime('today', $timezone))
88 12
            ->add(new \DateInterval("PT{$hour}H{$minute}M"))
89
        ;
90
    }
91
}
92