Completed
Push — master ( a79d86...61314e )
by Nuno
01:56
created

Scheduler::isDateRelative()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Jupitern\Scheduler;
4
5
/*
6
 * Simple Scheduler class
7
 *
8
 * Author: Nuno Chaves
9
 * */
10
11
class Scheduler {
12
13
    private $schedules = [];
14
    private $oneTimeEvents = [];
15
    private $startTime = null;
16
    private $endTime = null;
17
18
    /**
19
     * @return static
20
     */
21
    public static function instance()
22
    {
23
        return new static();
24
    }
25
26
27
    /**
28
     * set a time frame in which events will occur
29
     *
30
     * @param string $startTime time string compatible with \Datetime object. example: '08:00'
31
     * @param string $endTime time string compatible with \Datetime object. example: '17:00'
32
     */
33
    public function setTimeFrame( $startTime = null, $endTime = null )
34
    {
35
        if ($startTime !== null && !empty($startTime)) {
36
            $this->startTime = new \DateTime($startTime);
37
        }
38
        if ($endTime !== null && !empty($endTime)) {
39
            $this->endTime = new \DateTime($endTime);
40
        }
41
42
        return $this;
43
    }
44
45
46
    /**
47
     * add a one time occurring date
48
     *
49
     * @param string $dateTimeStr date string compatible with \Datetime object
50
     */
51
    public function add( $dateTimeStr )
52
    {
53
        $this->oneTimeEvents[] = $dateTimeStr;
54
        return $this;
55
    }
56
57
    /**
58
     * add a recurring date
59
     *
60
     * @param string $dateTimeStr date string compatible with \Datetime object
61
     */
62
    public function addRecurring( $dateTimeStr )
63
    {
64
        $this->schedules[] = $dateTimeStr;
65
        return $this;
66
    }
67
68
69
    /**
70
     * get next schedule date
71
     *
72
     * @param string $fromDateStr date string compatible with \Datetime object
73
     * @return \Datetime or null
74
     */
75
    public function getNextSchedule( $fromDateStr = 'now' )
76
    {
77
        $dates = $this->getNextSchedules($fromDateStr, 1);
78
        return count($dates) ? $dates[0] : null;
79
    }
80
81
82
    /**
83
     * get a number of next schedule dates
84
     *
85
     * @param string $fromDateStr date string compatible with \Datetime object
86
     * @param int $limit number of dates to return
87
     * @return array
88
     */
89
    public function getNextSchedules( $fromDateStr = 'now', $limit = 5 )
90
    {
91
        $dates = [];
92
93
        foreach ($this->oneTimeEvents as $schedule) {
94
			$dt = new \DateTime($fromDateStr);
95
			$dt->modify($schedule);
96
			
97
            if ($this->isInTimeFrame($dt, $fromDateStr)) {
98
                $dates[] = $dt;
99
            }
100
        }
101
102
        foreach ($this->schedules as $schedule) {
103
            $d = new \DateTime($fromDateStr);
104
105
            for ($i=0, $maxRecursion = 100 * $limit; $i < $limit && $maxRecursion > 0; ++$i, --$maxRecursion) {
106
107
                if ($this->isDateRelative($schedule)) {
108
                    if ($this->startTime instanceof \DateTime && $d < $this->startTime->modify($d->format('Y-m-d'))) {
109
                        $d->modify($this->startTime->format('H:i:s'));
110
                    }
111
                    elseif ($this->endTime instanceof \DateTime && $d > $this->endTime->modify($d->format('Y-m-d'))) {
112
                        $d->modify('next day')->modify($this->startTime->format('H:i:s'));
113
                    }
114
115
                    $dates[] = clone $d;
116
                    $d->modify($schedule);
117
                }
118
                elseif ($this->isInTimeFrame($d->modify($schedule), $fromDateStr)) {
119
                    $dates[] = clone $d;
120
                }
121
                else {
122
                    --$i;
123
                }
124
            }
125
        }
126
127
        $this->orderDates($dates);
128
        return array_slice($dates, 0, $limit);
129
    }
130
131
132
    /**
133
     * @param array $dates
134
	 * @return array
135
     */
136
    private function orderDates( &$dates )
137
    {
138
        uasort($dates, function($a, $b) {
139
            return strtotime($a->format('Y-m-d H:i:s')) > strtotime($b->format('Y-m-d H:i:s')) ? 1 : -1;
140
        });
141
    }
142
143
    /**
144
     * @param \DateTime $date
145
	 * @return bool
146
     */
147
    private function isInTimeFrame(\DateTime $date, $fromDateStr = 'now')
148
    {
149
        if ($date < new \DateTime($fromDateStr)) {
150
            return false;
151
        }
152
153
        if ($this->startTime && $date < $this->startTime->modify($date->format('Y-m-d'))) {
154
            return false;
155
        }
156
        if ($this->endTime && $date > $this->endTime->modify($date->format('Y-m-d'))) {
157
            return false;
158
        }
159
160
        return true;
161
    }
162
163
	/**
164
	 * @param string $dateStr \Datetime object valid date string
165
	 * @return bool
166
	 */
167
	private function isDateRelative($dateStr)
168
	{
169
		return strpos($dateStr, '+') !== false;
170
	}
171
172
}