Passed
Push — 6.x ( 11a975...1dc47f )
by Torben
09:01 queued 39s
created

CalendarService::getEventsForDay()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 20
nc 5
nop 2
dl 0
loc 32
rs 8.9777
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Extension "sf_event_mgt" for TYPO3 CMS.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.txt file that was distributed with this source code.
10
 */
11
12
namespace DERHANSEN\SfEventMgt\Service;
13
14
use DateTime;
15
use DERHANSEN\SfEventMgt\Domain\Model\Event;
16
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
17
18
/**
19
 * CalendarService
20
 */
21
class CalendarService
22
{
23
    /**
24
     * Returns an array with weeks/days for the calendar view
25
     *
26
     * @param int $month
27
     * @param int $year
28
     * @param int $today
29
     * @param int $firstDayOfWeek
30
     * @param array|QueryResultInterface $events
31
     * @return array
32
     */
33
    public function getCalendarArray(int $month, int $year, int $today, int $firstDayOfWeek = 0, $events = null): array
34
    {
35
        $weeks = [];
36
        $dateRange = $this->getCalendarDateRange($month, $year, $firstDayOfWeek);
37
        $currentDay = $dateRange['firstDayOfCalendar'];
38
        while ($currentDay <= $dateRange['lastDayOfCalendar']) {
39
            $week = [];
40
            $weekNumber = (int)date('W', $currentDay);
41
            for ($d = 0; $d < 7; $d++) {
42
                $day = [];
43
                $day['timestamp'] = $currentDay;
44
                $day['day'] = (int)date('j', $currentDay);
45
                $day['month'] = (int)date('n', $currentDay);
46
                $day['weekNumber'] = $weekNumber;
47
                $day['isCurrentMonth'] = $day['month'] === $month;
48
                $day['isCurrentDay'] = date('Ymd', $today) === date('Ymd', $day['timestamp']);
49
                if ($events) {
50
                    $searchDay = new \DateTime();
51
                    $searchDay->setTimestamp($currentDay);
52
                    $day['events'] = $this->getEventsForDay($events, $searchDay);
53
                }
54
                $currentDay = strtotime('+1 day', $currentDay);
55
                $week[] = $day;
56
            }
57
            $weeks[$weekNumber] = $week;
58
        }
59
60
        return $weeks;
61
    }
62
63
    /**
64
     * Returns an array with meta information about the calendar date range for the month of the given year
65
     * respecting the firstDayOfWeek setting
66
     */
67
    public function getCalendarDateRange(int $month, int $year, int $firstDayOfWeek = 0): array
68
    {
69
        $firstDayOfMonth = mktime(0, 0, 0, $month, 1, $year);
70
        $dayOfWeekOfFirstDay = (int)date('w', $firstDayOfMonth);
71
        $firstDayOfCalendarOffset = 1 - $dayOfWeekOfFirstDay + $firstDayOfWeek;
72
        if ($firstDayOfCalendarOffset > 1) {
73
            $firstDayOfCalendarOffset -= 7;
74
        }
75
        $firstDayOfCalendar = mktime(0, 0, 0, $month, 0 + $firstDayOfCalendarOffset, $year);
76
77
        $lastDayOfMonth = mktime(0, 0, 0, $month + 1, 0, $year);
78
        $dayOfWeekOfLastDay = (int)date('w', $lastDayOfMonth);
79
        $lastDayOfCalendarOffset = 6 - $dayOfWeekOfLastDay + $firstDayOfWeek;
80
        if ($dayOfWeekOfLastDay === 0 && $firstDayOfWeek === 1) {
81
            $lastDayOfCalendarOffset = 0;
82
        }
83
        $lastDayOfCalendar = strtotime('+' . $lastDayOfCalendarOffset . ' days', $lastDayOfMonth);
84
85
        return [
86
            'firstDayOfMonth' => $firstDayOfMonth,
87
            'lastDayOfMonth' => $lastDayOfMonth,
88
            'firstDayOfCalendar' => $firstDayOfCalendar,
89
            'lastDayOfCalendar' => $lastDayOfCalendar,
90
        ];
91
    }
92
93
    /**
94
     * Returns an array of events for the given day
95
     *
96
     * @param array|QueryResultInterface $events
97
     * @param DateTime $currentDay
98
     * @return array
99
     */
100
    protected function getEventsForDay($events, DateTime $currentDay): array
101
    {
102
        $foundEvents = [];
103
        $day = date('Y-m-d', $currentDay->getTimestamp());
104
105
        /** @var Event $event */
106
        foreach ($events as $event) {
107
            $eventBeginDate = $event->getStartdate()->format('Y-m-d');
108
            if (!is_a($event->getEnddate(), DateTime::class)) {
109
                if ($eventBeginDate === $day) {
110
                    $foundEvents[] = $event;
111
                }
112
            } else {
113
                // Create the compare date by cloning the event startdate to prevent timezone/DST issue
114
                $dayParts = explode('-', $day);
115
                $currentDayCompare = clone $event->getStartdate();
116
                $currentDayCompare->setDate((int)$dayParts[0], (int)$dayParts[1], (int)$dayParts[2]);
117
                $currentDayCompare->setTime(0, 0);
118
119
                $eventEndDate = clone $event->getEnddate();
120
                $eventEndDate->setTime(23, 59, 59);
121
                $eventBeginDate = clone $event->getStartdate();
122
                $eventBeginDate->setTime(0, 0);
123
                $currentDay->setTime(0, 0);
124
125
                if ($eventBeginDate <= $currentDayCompare && $eventEndDate >= $currentDayCompare) {
126
                    $foundEvents[] = $event;
127
                }
128
            }
129
        }
130
131
        return $foundEvents;
132
    }
133
134
    /**
135
     * Returns a date configuration for the given modifier
136
     */
137
    public function getDateConfig(int $month, int $year, string $modifier = ''): array
138
    {
139
        $date = \DateTime::createFromFormat('d.m.Y', sprintf('1.%s.%s', $month, $year));
140
        $date->setTime(0, 0, 0);
141
        if (!empty($modifier)) {
142
            $date->modify($modifier);
143
        }
144
145
        return [
146
            'date' => $date,
147
            'month' => (int)$date->format('n'),
148
            'year' => (int)$date->format('Y'),
149
        ];
150
    }
151
152
    /**
153
     * Returns an array holding weeknumber any year for the current, previous and next week
154
     */
155
    public function getWeekConfig(DateTime $firstDayOfCurrentWeek): array
156
    {
157
        $firstDayPreviousWeek = (clone $firstDayOfCurrentWeek)->modify('-1 week');
158
        $firstDayNextWeek = (clone $firstDayOfCurrentWeek)->modify('+1 week');
159
160
        return [
161
            'previous' => [
162
                'weeknumber' => (int)$firstDayPreviousWeek->format('W'),
163
                'year' => (int)$firstDayPreviousWeek->format('Y'),
164
            ],
165
            'current' => [
166
                'weeknumber' => (int)$firstDayOfCurrentWeek->format('W'),
167
                'year' => (int)$firstDayOfCurrentWeek->format('Y'),
168
            ],
169
            'next' => [
170
                'weeknumber' => (int)$firstDayNextWeek->format('W'),
171
                'year' => (int)$firstDayNextWeek->format('Y'),
172
            ],
173
        ];
174
    }
175
}
176