Timer   A
last analyzed

Complexity

Total Complexity 38

Size/Duplication

Total Lines 288
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 38
lcom 1
cbo 1
dl 0
loc 288
rs 9.36
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
B isTimerActive() 0 28 7
A isHoliday() 0 4 1
A getHoliday() 0 4 1
A flush() 0 5 1
B checkDate() 0 26 7
B checkHoliday() 0 55 8
A checkIntervals() 0 22 5
A checkDays() 0 10 2
A checkTime() 0 29 3
A convertDate() 0 10 2
1
<?php
2
/*
3
 * This file is part of the php-utilities package.
4
 *
5
 * (c) Marc Aschmann <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace Asm\Timer;
11
12
use Asm\Config\ConfigTimer;
13
14
/**
15
 * Timer Class
16
 *
17
 * @package Asm\Timer
18
 * @author Marc Aschmann <[email protected]>
19
 */
20
final class Timer
21
{
22
    /**
23
     * @var \Asm\Data\Data
24
     */
25
    private $config;
26
27
    /**
28
     * Current timer's config.
29
     *
30
     * @var mixed
31
     */
32
    private $currentConf;
33
34
    /**
35
     * If a holiday is in place - here it is.
36
     *
37
     * @var null|\DateTime
38
     */
39
    private $holiday;
40
41
    /**
42
     * Constructor with dependency injection.
43
     *
44
     * @param ConfigTimer $config
45
     */
46
    public function __construct(ConfigTimer $config)
47
    {
48
        $this->config = $config;
49
    }
50
51
    /**
52
     * Check if timer is active.
53
     *
54
     * @param  string $type
55
     * @return bool
56
     */
57
    public function isTimerActive(string $type) : bool
58
    {
59
        $return = false;
60
        $this->currentConf = $this->config->get('timers', $type);
61
62
        // pre-check holidays
63
        if (true === isset($this->currentConf['holiday'])) {
64
            // check if general holidays are to be used
65
            if (isset($this->currentConf['holiday']['use_general'])
66
                && true === (bool)$this->currentConf['holiday']['use_general']
67
            ) {
68
                if (false === $this->isHoliday()) {
69
                    $return = $this->checkDate();
70
                }
71
            } elseif (0 < count($this->config->get('holidays'))) {
72
                if (false === $this->checkIntervals($this->config->get('holidays'))) {
73
                    // we're not in a holiday
74
                    $return = $this->checkDate();
75
                }
76
            }
77
        } else {
78
            $return = $this->checkDate();
79
        }
80
81
        $this->flush();
82
83
        return $return;
84
    }
85
86
    /**
87
     * Calculate difference between holiday DateTime objects and current or given time.
88
     *
89
     * @param  string|null $date
90
     * @return bool
91
     */
92
    public function isHoliday($date = null) : bool
93
    {
94
        return $this->checkHoliday($date);
95
    }
96
97
    /**
98
     * Returns holiday object, if set.
99
     *
100
     * @return \DateTime|null
101
     */
102
    public function getHoliday()
103
    {
104
        return $this->holiday;
105
    }
106
107
    /**
108
     * Clear current configuration.
109
     */
110
    public function flush()
111
    {
112
        $this->currentConf = [];
113
        $this->holiday = null;
114
    }
115
116
    /**
117
     * Date checks on config.
118
     *
119
     * @return bool
120
     */
121
    private function checkDate() : bool
122
    {
123
        $return = false;
124
125
        // reverse switch to call checks
126
        switch (true) {
127
            case array_key_exists('interval', $this->currentConf):
128
                $return = $this->checkIntervals();
129
                break;
130
            case (array_key_exists('time', $this->currentConf) && array_key_exists('day', $this->currentConf)):
131
                // first check if we're on configured day
132
                if (true === $this->checkDays()) {
133
                    // then see if we're in the timeframe
134
                    $return = $this->checkTime();
135
                }
136
                break;
137
            case array_key_exists('day', $this->currentConf):
138
                $return = $this->checkDays();
139
                break;
140
            case array_key_exists('time', $this->currentConf):
141
                $return = $this->checkTime();
142
                break;
143
        }
144
145
        return $return;
146
    }
147
148
    /**
149
     * Check for holidays.
150
     *
151
     * @param  string|null $date
152
     * @return bool
153
     */
154
    private function checkHoliday($date = null) : bool
155
    {
156
        $mixReturn = false;
157
158
        $today = $this->convertDate($date);
159
160
        foreach ($this->config->get('general_holidays') as $holiday) {
161
            // clone for start/enddate
162
            $holidayEnd = clone $holiday;
163
            $holidayStart = clone $holiday;
164
            $startTime = ['00', '00', '00'];
165
            $endTime = ['23', '59', '59'];
166
167
            if (true === isset($this->currentConf['holiday']['interval'])) {
168
                $startTime = explode(':', $this->currentConf['holiday']['interval'][0]);
169
                $endTime = explode(':', $this->currentConf['holiday']['interval'][1]);
170
            }
171
172
            // check if there's a modifier for holiday range and if it's before or after the actual holiday
173
            if (isset($this->currentConf['holiday']['additional'])) {
174
                // create interval object for difference to add/subtract
175
                $intervalDiff = new \DateInterval('P' . $this->currentConf['holiday']['additional'][1] . 'D');
176
                switch ($this->currentConf['holiday']['additional'][0]) {
177
                    // @codeCoverageIgnoreStart
178
                    case 'add':
179
                        // if days are added, date will be enddate
180
                        $holidayEnd->{$this->currentConf['holiday']['additional'][0]}($intervalDiff);
181
                        break;
182
                    case 'sub':
183
                        // if days are subtracted, date will be startdate
184
                        $holidayStart->{$this->currentConf['holiday']['additional'][0]}($intervalDiff);
185
                        break;
186
                    // @codeCoverageIgnoreEnd
187
                }
188
            }
189
190
            // calculate difference between today and timed startdate
191
            $intervalStart = $today->diff(
192
                $holidayStart->setTime($startTime[0], $startTime[1], $startTime[2])
193
            );
194
            // calculate difference between today and timed enddate
195
            $intervalEnd = $today->diff(
196
                $holidayEnd->setTime($endTime[0], $endTime[1], $endTime[2])
197
            );
198
199
            // check if current date has passed start but not endtime
200
            if ((1 == $intervalStart->invert) && (0 == $intervalEnd->invert)) {
201
                $this->holiday = $holiday;
202
                $mixReturn = true;
203
                break;
204
            }
205
        }
206
207
        return $mixReturn;
208
    }
209
210
    /**
211
     * Check if current date is in interval.
212
     *
213
     * @param  array $intervals
214
     * @return bool
215
     */
216
    private function checkIntervals(array $intervals = []) : bool
217
    {
218
        $today = new \DateTime();
219
        $return = false;
220
221
        if (empty($intervals)) {
222
            $intervals = $this->currentConf['interval'];
223
        }
224
225
        foreach ($intervals as $interval) {
226
            $intervalStart = $today->diff($interval[0]);
227
            $intervalEnd = $today->diff($interval[1]);
228
229
            // check if current date has passed start but not endtime
230
            if ((1 == $intervalStart->invert) && (0 == $intervalEnd->invert)) {
231
                $return = true;
232
                break;
233
            }
234
        }
235
236
        return $return;
237
    }
238
239
    /**
240
     * Check if today is in days array.
241
     *
242
     * @return bool
243
     */
244
    private function checkDays() : bool
245
    {
246
        $return = false;
247
248
        if (in_array(strtolower(date('l')), $this->currentConf['day'])) {
249
            $return = true;
250
        }
251
252
        return $return;
253
    }
254
255
    /**
256
     * Do time comparison.
257
     *
258
     * @param array $intervals
259
     * @return bool
260
     */
261
    private function checkTime($intervals = []) : bool
262
    {
263
        $return = [];
264
        if (empty($intervals)) {
265
            $intervals = $this->currentConf['time'];
266
        }
267
268
        foreach ($intervals as $intKey => $intervalParts) {
269
            // build objects for comparison
270
            $startTime = new \DateTime();
271
            $startTimeParts = explode(':', $intervalParts[0]);
272
273
            $return[$intKey][0] = $startTime->setTime(
274
                $startTimeParts[0],
275
                $startTimeParts[1],
276
                $startTimeParts[2]
277
            );
278
279
            $endTime = new \DateTime();
280
            $endTimeParts = explode(':', $intervalParts[1]);
281
            $return[$intKey][1] = $endTime->setTime(
282
                $endTimeParts[0],
283
                $endTimeParts[1],
284
                $endTimeParts[2]
285
            );
286
        }
287
288
        return $this->checkIntervals($return);
289
    }
290
291
    /**
292
     * Check date string or object and convert if necessary.
293
     *
294
     * @param string|null $date
295
     * @return \DateTime
296
     */
297
    private function convertDate($date) : \DateTime
298
    {
299
        if (empty($date)) {
300
            $today = new \DateTime();
301
        } else {
302
            $today = new \DateTime($date);
303
        }
304
305
        return $today;
306
    }
307
}
308