Passed
Push — main ( 9ae846...8c9e9f )
by Torben
04:50 queued 01:55
created

CalendarService::getWeekConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 1
dl 0
loc 17
rs 9.8666
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 RuntimeException;
17
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
0 ignored issues
show
Bug introduced by
The type TYPO3\CMS\Extbase\Persistence\QueryResultInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
class CalendarService
20
{
21
    /**
22
     * Returns an array with weeks/days for the calendar view
23
     *
24
     * @param int $month
25
     * @param int $year
26
     * @param int $today
27
     * @param int $firstDayOfWeek
28
     * @param array|QueryResultInterface $events
29
     * @return array
30
     */
31
    public function getCalendarArray(int $month, int $year, int $today, int $firstDayOfWeek = 0, $events = null): array
32
    {
33
        $weeks = [];
34
        $dateRange = $this->getCalendarDateRange($month, $year, $firstDayOfWeek);
35
        $currentDay = $dateRange['firstDayOfCalendar'];
36
        while ($currentDay <= $dateRange['lastDayOfCalendar']) {
37
            $week = [];
38
            $weekNumber = (int)date('W', $currentDay);
39
            for ($d = 0; $d < 7; $d++) {
40
                $day = [];
41
                $day['timestamp'] = $currentDay;
42
                $day['day'] = (int)date('j', $currentDay);
43
                $day['month'] = (int)date('n', $currentDay);
44
                $day['weekNumber'] = $weekNumber;
45
                $day['isCurrentMonth'] = $day['month'] === $month;
46
                $day['isCurrentDay'] = date('Ymd', $today) === date('Ymd', $day['timestamp']);
47
                if ($events) {
48
                    $searchDay = new DateTime();
49
                    $searchDay->setTimestamp($currentDay);
50
                    $day['events'] = $this->getEventsForDay($events, $searchDay);
51
                }
52
                $currentDay = strtotime('+1 day', $currentDay);
53
                $week[] = $day;
54
            }
55
            $weeks[$weekNumber] = $week;
56
        }
57
58
        return $weeks;
59
    }
60
61
    /**
62
     * Returns an array with meta information about the calendar date range for the month of the given year
63
     * respecting the firstDayOfWeek setting
64
     */
65
    public function getCalendarDateRange(int $month, int $year, int $firstDayOfWeek = 0): array
66
    {
67
        $firstDayOfMonth = mktime(0, 0, 0, $month, 1, $year);
68
        $lastDayOfMonth = mktime(0, 0, 0, $month + 1, 0, $year);
69
70
        if (!$firstDayOfMonth || !$lastDayOfMonth) {
71
            throw new RuntimeException('First- or last day of month could not be calculated. for calendar data range', 1671470629);
72
        }
73
74
        $dayOfWeekOfFirstDay = (int)date('w', $firstDayOfMonth);
75
        $firstDayOfCalendarOffset = 1 - $dayOfWeekOfFirstDay + $firstDayOfWeek;
76
        if ($firstDayOfCalendarOffset > 1) {
77
            $firstDayOfCalendarOffset -= 7;
78
        }
79
        $firstDayOfCalendar = mktime(0, 0, 0, $month, 0 + $firstDayOfCalendarOffset, $year);
80
81
        $dayOfWeekOfLastDay = (int)date('w', $lastDayOfMonth);
82
        $lastDayOfCalendarOffset = 6 - $dayOfWeekOfLastDay + $firstDayOfWeek;
83
        if ($dayOfWeekOfLastDay === 0 && $firstDayOfWeek === 1) {
84
            $lastDayOfCalendarOffset = 0;
85
        }
86
        $lastDayOfCalendar = strtotime('+' . $lastDayOfCalendarOffset . ' days', $lastDayOfMonth);
87
88
        return [
89
            'firstDayOfMonth' => $firstDayOfMonth,
90
            'lastDayOfMonth' => $lastDayOfMonth,
91
            'firstDayOfCalendar' => $firstDayOfCalendar,
92
            'lastDayOfCalendar' => $lastDayOfCalendar,
93
        ];
94
    }
95
96
    /**
97
     * Returns an array of events for the given day
98
     *
99
     * @param array|QueryResultInterface $events
100
     * @param DateTime $currentDay
101
     * @return array
102
     */
103
    protected function getEventsForDay($events, DateTime $currentDay): array
104
    {
105
        $foundEvents = [];
106
        $day = date('Y-m-d', $currentDay->getTimestamp());
107
108
        /** @var Event $event */
109
        foreach ($events as $event) {
110
            $eventBeginDate = $event->getStartdate()->format('Y-m-d');
111
            if (!is_a($event->getEnddate(), DateTime::class)) {
112
                if ($eventBeginDate === $day) {
113
                    $foundEvents[] = $event;
114
                }
115
            } else {
116
                // Create the compare date by cloning the event startdate to prevent timezone/DST issue
117
                $dayParts = explode('-', $day);
118
                $currentDayCompare = clone $event->getStartdate();
119
                $currentDayCompare->setDate((int)$dayParts[0], (int)$dayParts[1], (int)$dayParts[2]);
120
                $currentDayCompare->setTime(0, 0);
121
122
                $eventEndDate = clone $event->getEnddate();
123
                $eventEndDate->setTime(23, 59, 59);
124
                $eventBeginDate = clone $event->getStartdate();
125
                $eventBeginDate->setTime(0, 0);
126
                $currentDay->setTime(0, 0);
127
128
                if ($eventBeginDate <= $currentDayCompare && $eventEndDate >= $currentDayCompare) {
129
                    $foundEvents[] = $event;
130
                }
131
            }
132
        }
133
134
        return $foundEvents;
135
    }
136
137
    /**
138
     * Returns a date configuration for the given modifier
139
     */
140
    public function getDateConfig(int $month, int $year, string $modifier = ''): array
141
    {
142
        $date = DateTime::createFromFormat('d.m.Y', sprintf('1.%s.%s', $month, $year));
143
        if (!($date instanceof DateTime)) {
0 ignored issues
show
introduced by
$date is always a sub-type of DateTime.
Loading history...
144
            throw new RuntimeException('Unable to create date configuration', 1671471836);
145
        }
146
147
        $date->setTime(0, 0);
148
        if (!empty($modifier)) {
149
            $date->modify($modifier);
150
        }
151
152
        return [
153
            'date' => $date,
154
            'month' => (int)$date->format('n'),
155
            'year' => (int)$date->format('Y'),
156
        ];
157
    }
158
159
    /**
160
     * Returns an array holding week number any year for the current, previous and next week
161
     */
162
    public function getWeekConfig(DateTime $firstDayOfCurrentWeek): array
163
    {
164
        $firstDayPreviousWeek = (clone $firstDayOfCurrentWeek)->modify('-1 week');
165
        $firstDayNextWeek = (clone $firstDayOfCurrentWeek)->modify('+1 week');
166
167
        return [
168
            'previous' => [
169
                'weeknumber' => (int)$firstDayPreviousWeek->format('W'),
170
                'year' => (int)$firstDayPreviousWeek->format('Y'),
171
            ],
172
            'current' => [
173
                'weeknumber' => (int)$firstDayOfCurrentWeek->format('W'),
174
                'year' => (int)$firstDayOfCurrentWeek->format('Y'),
175
            ],
176
            'next' => [
177
                'weeknumber' => (int)$firstDayNextWeek->format('W'),
178
                'year' => (int)$firstDayNextWeek->format('Y'),
179
            ],
180
        ];
181
    }
182
}
183