GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

BusinessHours::setDays()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php
2
3
/**
4
 * This file is part of Business-hours.
5
 * Copyright (c) 2015 - 2016 original code: Florian Voutzinos <[email protected]
6
 * Copyright (c) 2015 - 2017 additions and changes: Speicher 210 GmbH
7
 * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code.
8
 */
9
10
declare(strict_types = 1);
11
12
namespace Speicher210\BusinessHours;
13
14
use Speicher210\BusinessHours\Day\DayInterface;
15
use Speicher210\BusinessHours\Day\Time\TimeBuilder;
16
use Speicher210\BusinessHours\Day\Time\TimeIntervalInterface;
17
18
/**
19
 * Default implementation of BusinessHoursInterface.
20
 */
21
class BusinessHours implements BusinessHoursInterface
22
{
23
    /**
24
     * The days.
25
     *
26
     * @var DayInterface[]
27
     */
28
    protected $days;
29
30
    /**
31
     * The time zone.
32
     *
33
     * @var \DateTimeZone
34 27
     */
35
    protected $timezone;
36 27
37 24
    /**
38 24
     * @param DayInterface[] $days
39
     * @param \DateTimeZone|null $timezone
40
     */
41
    public function __construct(array $days, \DateTimeZone $timezone = null)
42
    {
43 9
        $this->setDays($days);
44
        $this->timezone = $timezone ?: new \DateTimeZone(\date_default_timezone_get());
45 9
    }
46
47
    /**
48
     * {@inheritdoc}
49
     */
50
    public function getTimezone(): \DateTimeZone
51
    {
52
        return $this->timezone;
53 9
    }
54
55 9
    /**
56
     * Get the days.
57
     *
58
     * @return DayInterface[]
59
     */
60
    public function getDays(): array
61
    {
62
        return \array_values($this->days);
63
    }
64 27
65
    /**
66 27
     * Add a set of days.
67 3
     *
68
     * @param DayInterface[] $days The days.
69
     * @throws \InvalidArgumentException If no days are passed.
70 24
     */
71
    protected function setDays(array $days): void
72 24
    {
73 24
        if (empty($days)) {
74 24
            throw new \InvalidArgumentException('At least one day must be added.');
75 24
        }
76
77
        $this->days = [];
78
79
        foreach ($days as $day) {
80 48
            $this->addDay($day);
81
        }
82 48
    }
83 48
84
    /**
85 48
     * {@inheritdoc}
86 39
     */
87
    public function within(\DateTime $date): bool
88
    {
89 12
        $tmpDate = clone $date;
90
        $tmpDate->setTimezone($this->timezone);
91
92
        if (null !== $day = $this->getDay((int)$tmpDate->format('N'))) {
93
            return $day->isWithinOpeningHours(TimeBuilder::fromDate($tmpDate));
94
        }
95 21
96
        return false;
97 21
    }
98 21
99 21
    /**
100
     * {@inheritdoc}
101 21
     */
102 9
    public function getNextChangeDateTime(\DateTime $date): \DateTime
103
    {
104 12
        $tmpDate = clone $date;
105
        $tmpDate->setTimezone($this->timezone);
106
        $dateInterval = $this->getNextClosestInterval($tmpDate);
107
108
        if ($this->within($date)) {
109
            return ($date == $dateInterval->getStart()) ? $dateInterval->getStart() : $dateInterval->getEnd();
110
        }
111 21
112
        return $dateInterval->getStart();
113 21
    }
114 21
115 21
    /**
116
     * {@inheritdoc}
117 21
     */
118 9
    public function getPreviousChangeDateTime(\DateTime $date): \DateTime
119
    {
120 12
        $tmpDate = clone $date;
121
        $tmpDate->setTimezone($this->timezone);
122
        $dateInterval = $this->getPreviousClosestInterval($tmpDate);
123
124
        if ($this->within($date)) {
125
            return ($date == $dateInterval->getEnd()) ? $dateInterval->getEnd() : $dateInterval->getStart();
126
        }
127 3
128
        return $dateInterval->getEnd();
129
    }
130 3
131 3
    /**
132 3
     * {@inheritdoc}
133
     */
134
    public function jsonSerialize()
135
    {
136
        return [
137
            'days' => $this->days,
138
            'timezone' => $this->timezone->getName(),
139
        ];
140
    }
141 6
142
    /**
143 6
     * Get the closest business hours date interval before the given date.
144 6
     *
145 6
     * @param \DateTime $date The given date.
146
     * @return DateTimeInterval
147 6
     */
148 3
    private function getClosestDateIntervalBefore(\DateTime $date): DateTimeInterval
149
    {
150
        $tmpDate = clone $date;
151 3
        $dayOfWeek = (int)$tmpDate->format('N');
152
        $time = TimeBuilder::fromDate($tmpDate);
153 6
154
        if (null !== $day = $this->getDay($dayOfWeek)) {
155 6
            if (null !== $closestTime = $day->getClosestPreviousOpeningHoursInterval($time)) {
156
                return $this->buildDateTimeInterval($tmpDate, $closestTime);
157 6
            }
158 6
        }
159
160 6
        $tmpDate = $this->getDateBefore($tmpDate);
161
162
        $closestDay = $this->getClosestDayBefore((int)$tmpDate->format('N'));
163
164
        $closingTime = $closestDay->getClosingTime();
165
        $closestTime = $closestDay->getClosestPreviousOpeningHoursInterval($closingTime);
166
167
        return $this->buildDateTimeInterval($tmpDate, $closestTime);
168
    }
169 6
170
    /**
171 6
     * Get the closest business hours date interval after the given date.
172 6
     *
173 6
     * @param \DateTime $date The given date.
174
     * @return DateTimeInterval
175 6
     */
176 3
    private function getClosestDateIntervalAfter(\DateTime $date): DateTimeInterval
177
    {
178
        $tmpDate = clone $date;
179 3
        $dayOfWeek = (int)$tmpDate->format('N');
180
        $time = TimeBuilder::fromDate($tmpDate);
181 6
182
        if (null !== $day = $this->getDay($dayOfWeek)) {
183 6
            if (null !== $closestTime = $day->getClosestNextOpeningHoursInterval($time)) {
184
                return $this->buildDateTimeInterval($tmpDate, $closestTime);
185 6
            }
186 6
        }
187
188 6
        $tmpDate = $this->getDateAfter($tmpDate);
189
190
        $closestDay = $this->getClosestDayBefore((int)$tmpDate->format('N'));
191
192
        $openingTime = $closestDay->getOpeningTime();
193
        $closestTime = $closestDay->getClosestNextOpeningHoursInterval($openingTime);
194
195
        return $this->buildDateTimeInterval($tmpDate, $closestTime);
196
    }
197
198 42
    /**
199
     * Build a new date time interval for a date.
200 42
     *
201 42
     * @param \DateTime $date The date.
202
     * @param TimeIntervalInterface $timeInterval
203 42
     * @return DateTimeInterval
204 42
     */
205 42
    private function buildDateTimeInterval(\DateTime $date, TimeIntervalInterface $timeInterval): DateTimeInterval
206 42
    {
207 42
        $intervalStart = clone $date;
208 42
        $intervalEnd = clone $date;
209 42
210 42
        $intervalStart->setTime(
211 42
            $timeInterval->getStart()->getHours(),
212 42
            $timeInterval->getStart()->getMinutes(),
213
            $timeInterval->getStart()->getSeconds()
214 42
        );
215
        $intervalEnd->setTime(
216
            $timeInterval->getEnd()->getHours(),
217
            $timeInterval->getEnd()->getMinutes(),
218
            $timeInterval->getEnd()->getSeconds()
219
        );
220
221
        return new DateTimeInterval($intervalStart, $intervalEnd);
222
    }
223 6
224
    /**
225 6
     * Get the business hours date before the given date.
226 6
     *
227
     * @param \DateTime $date
228 6
     * @return \DateTime
229 6
     */
230 6
    private function getDateBefore(\DateTime $date): \DateTime
231 3
    {
232 3
        $tmpDate = clone $date;
233 6
        $tmpDate->modify('-1 day');
234
235
        $dayOfWeek = (int)$tmpDate->format('N');
236
        $closestDay = $this->getClosestDayBefore($dayOfWeek);
237
        if ($closestDay->getDayOfWeek() !== $dayOfWeek) {
238
            $tmpDate->modify(\sprintf('last %s', $closestDay->getDayOfWeekName()));
239
        }
240
        return $tmpDate;
241
    }
242 6
243
    /**
244 6
     * Get the business hours date after the given date.
245 6
     *
246
     * @param \DateTime $date
247 6
     * @return \DateTime
248 6
     */
249
    private function getDateAfter(\DateTime $date): \DateTime
250 6
    {
251 3
        $tmpDate = clone $date;
252 3
        $tmpDate->modify('+1 day');
253
254 6
        $dayOfWeek = (int)$tmpDate->format('N');
255
        $closestDay = $this->getClosestDayAfter($dayOfWeek);
256
257
        if ($closestDay->getDayOfWeek() !== $dayOfWeek) {
258
            $tmpDate->modify(\sprintf('next %s', $closestDay->getDayOfWeekName()));
259
        }
260
261
        return $tmpDate;
262
    }
263 21
264
    /**
265 21
     * Get the closest interval endpoint after the given date.
266 21
     *
267 21
     * @param \DateTime $date
268
     * @return DateTimeInterval
269 21
     */
270 18
    private function getPreviousClosestInterval(\DateTime $date): DateTimeInterval
271 15
    {
272
        $tmpDate = clone $date;
273 3
        $dayOfWeek = (int)$tmpDate->format('N');
274
        $time = TimeBuilder::fromDate($tmpDate);
275 6
276
        if (null !== $day = $this->getDay($dayOfWeek)) {
277
            if (null !== $closestTime = $day->getClosestPreviousOpeningHoursInterval($time)) {
278
                return $this->buildDateTimeInterval($tmpDate, $closestTime);
279
            }
280
        }
281
282
        return $this->getClosestDateIntervalBefore($date);
283
    }
284 21
285
    /**
286 21
     * Get the closest interval endpoint after the given date.
287 21
     *
288 21
     * @param \DateTime $date
289
     * @return DateTimeInterval
290 21
     */
291 18
    private function getNextClosestInterval(\DateTime $date): DateTimeInterval
292 15
    {
293
        $tmpDate = clone $date;
294 3
        $dayOfWeek = (int)$tmpDate->format('N');
295
        $time = TimeBuilder::fromDate($tmpDate);
296 6
297
        if (null !== $day = $this->getDay($dayOfWeek)) {
298
            if (null !== $closestTime = $day->getClosestNextOpeningHoursInterval($time)) {
299
                return $this->buildDateTimeInterval($tmpDate, $closestTime);
300
            }
301
        }
302
303
        return $this->getClosestDateIntervalAfter($date);
304
    }
305 12
306
    /**
307 12
     * Get the closest business hours day before a given day number (including it).
308 12
     *
309
     * @param integer $dayNumber
310
     * @return DayInterface|null
311 3
     */
312
    private function getClosestDayBefore(int $dayNumber)
313
    {
314
        if (null !== $day = $this->getDay($dayNumber)) {
315
            return $day;
316
        }
317
318
        return $this->getDayBefore($dayNumber);
319
    }
320 6
321
    /**
322 6
     * Get the closest business hours day after a given day number (including it).
323 3
     *
324
     * @param integer $dayNumber
325
     * @return DayInterface|null
326 3
     */
327
    private function getClosestDayAfter($dayNumber)
328
    {
329
        if (null !== $day = $this->getDay($dayNumber)) {
330
            return $day;
331
        }
332
333
        return $this->getDayAfter($dayNumber);
334
    }
335 3
336
    /**
337 3
     * Get the business hours day before the day number.
338
     *
339 3
     * @param integer $dayNumber
340 3
     * @return DayInterface|null
341
     */
342 3
    private function getDayBefore(int $dayNumber)
343 3
    {
344
        $tmpDayNumber = $dayNumber;
345 3
346
        for ($i = 0; $i < 6; $i++) {
347
            $tmpDayNumber = (DayInterface::WEEK_DAY_MONDAY === $tmpDayNumber) ? DayInterface::WEEK_DAY_SUNDAY : --$tmpDayNumber;
348
349
            if (null !== $day = $this->getDay($tmpDayNumber)) {
350
                return $day;
351
            }
352
        }
353
354
        return $this->getDay($dayNumber);
355
    }
356 3
357
    /**
358 3
     * Get the business hours day after the day number.
359
     *
360 3
     * @param integer $dayNumber
361 3
     * @return DayInterface|null
362
     */
363 3
    private function getDayAfter($dayNumber)
364 3
    {
365
        $tmpDayNumber = $dayNumber;
366 3
367
        for ($i = 0; $i < 6; $i++) {
368
            $tmpDayNumber = (DayInterface::WEEK_DAY_SUNDAY === $tmpDayNumber) ? DayInterface::WEEK_DAY_MONDAY : ++$tmpDayNumber;
369
370
            if (null !== $day = $this->getDay($tmpDayNumber)) {
371
                return $day;
372
            }
373
        }
374
375
        return $this->getDay($dayNumber);
376
    }
377 48
378
    /**
379 48
     * Get the day corresponding to the day of the week.
380
     *
381
     * @param integer $dayOfWeek The day of the week.
382
     * @return DayInterface|null
383
     */
384
    private function getDay($dayOfWeek): ?DayInterface
385
    {
386
        return $this->days[$dayOfWeek] ?? null;
387 24
    }
388
389 24
    /**
390 24
     * Add a day.
391
     *
392
     * @param DayInterface $day The day.
393
     */
394
    private function addDay(DayInterface $day): void
395 6
    {
396
        $this->days[$day->getDayOfWeek()] = $day;
397 6
    }
398 6
399 6
    public function __clone()
400 6
    {
401
        $days = [];
402 6
        foreach ($this->days as $key => $day) {
403 6
            $days[$key] = clone $day;
404
        }
405
406
        $this->days = $days;
407
    }
408
}
409