CalendarService::getWeekConfig()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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