Completed
Push — master ( e308fa...6a1272 )
by Tim
24s
created

TimeTableService::getCompleteDate()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 20
rs 8.9777
c 0
b 0
f 0
cc 6
nc 5
nop 2
1
<?php
2
3
/**
4
 * Time table builder service.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Calendarize\Service;
9
10
use Exception;
11
use HDNET\Calendarize\Domain\Model\Configuration;
12
use HDNET\Calendarize\Domain\Model\ConfigurationInterface;
13
use HDNET\Calendarize\Domain\Repository\ConfigurationRepository;
14
use HDNET\Calendarize\Service\TimeTable\AbstractTimeTable;
15
use HDNET\Calendarize\Utility\DateTimeUtility;
16
use HDNET\Calendarize\Utility\HelperUtility;
17
use TYPO3\CMS\Core\Messaging\FlashMessage;
18
19
/**
20
 * Time table builder service.
21
 */
22
class TimeTableService extends AbstractService
23
{
24
    /**
25
     * Build the timetable for the given configuration matrix (sorted).
26
     *
27
     * @param array $ids
28
     *
29
     * @return array
30
     */
31
    public function getTimeTablesByConfigurationIds(array $ids)
32
    {
33
        $timeTable = [];
34
        if (!$ids) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ids of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
35
            return $timeTable;
36
        }
37
38
        $configRepository = HelperUtility::create(ConfigurationRepository::class);
39
        foreach ($ids as $configurationUid) {
40
            $configuration = $configRepository->findByUid($configurationUid);
41
            if (!($configuration instanceof Configuration)) {
42
                continue;
43
            }
44
45
            try {
46
                $handler = $this->buildConfigurationHandler($configuration);
47
            } catch (\Exception $exception) {
48
                HelperUtility::createFlashMessage(
49
                    $exception->getMessage(),
50
                    'Index invalid',
51
                    FlashMessage::ERROR
52
                );
53
                continue;
54
            }
55
56
            if (ConfigurationInterface::HANDLING_INCLUDE === $configuration->getHandling()) {
57
                $handler->handleConfiguration($timeTable, $configuration);
58
            } elseif (ConfigurationInterface::HANDLING_EXCLUDE === $configuration->getHandling()) {
59
                $timesToExclude = [];
60
                $handler->handleConfiguration($timesToExclude, $configuration);
61
                $timeTable = $this->checkAndRemoveTimes($timeTable, $timesToExclude);
62
            } elseif (ConfigurationInterface::HANDLING_OVERRIDE === $configuration->getHandling()) {
63
                // first remove overridden times
64
                $timesToOverride = [];
65
                $handler->handleConfiguration($timesToOverride, $configuration);
66
                $timeTable = $this->checkAndRemoveTimes($timeTable, $timesToOverride);
67
                // then add new times
68
                $handler->handleConfiguration($timeTable, $configuration);
69
            } elseif (ConfigurationInterface::HANDLING_CUTOUT === $configuration->getHandling()) {
70
                $timesToSelectBy = [];
71
                $handler->handleConfiguration($timesToSelectBy, $configuration);
72
                $timeTable = $this->selectTimesBy($timeTable, $timesToSelectBy);
73
            }
74
        }
75
76
        return $timeTable;
77
    }
78
79
    /**
80
     * Selects events by given times.
81
     *
82
     * @param array $base
83
     * @param array $selectBy
84
     *
85
     * @return array
86
     */
87
    public function selectTimesBy($base, $selectBy)
88
    {
89
        $timeTableSelection = [];
90
91
        foreach ($base as $baseValue) {
92
            try {
93
                $eventStart = $this->getCompleteDate($baseValue, 'start');
94
                $eventEnd = $this->getCompleteDate($baseValue, 'end');
95
            } catch (Exception $ex) {
96
                continue;
97
            }
98
99
            foreach ($selectBy as $selectByValue) {
100
                try {
101
                    $selectionStart = $this->getCompleteDate($selectByValue, 'start');
102
                    $selectionEnd = $this->getCompleteDate($selectByValue, 'end');
103
                } catch (Exception $ex) {
104
                    continue;
105
                }
106
107
                $startIn = ($eventStart >= $selectionStart && $eventStart < $selectionEnd);
108
                $endIn = ($eventEnd > $selectionStart && $eventEnd <= $selectionEnd);
109
                $envelope = ($eventStart < $selectionStart && $eventEnd > $selectionEnd);
110
111
                if ($startIn && $endIn || $envelope) {
112
                    $timeTableSelection[] = $baseValue;
113
                    break;
114
                }
115
            }
116
        }
117
118
        return $timeTableSelection;
119
    }
120
121
    /**
122
     * Remove excluded events.
123
     *
124
     * @param array $base
125
     * @param $remove
126
     *
127
     * @return array
128
     */
129
    public function checkAndRemoveTimes($base, $remove)
130
    {
131
        foreach ($base as $key => $value) {
132
            try {
133
                $eventStart = $this->getCompleteDate($value, 'start');
134
                $eventEnd = $this->getCompleteDate($value, 'end');
135
            } catch (Exception $ex) {
136
                continue;
137
            }
138
139
            foreach ($remove as $removeValue) {
140
                try {
141
                    $removeStart = $this->getCompleteDate($removeValue, 'start');
142
                    $removeEnd = $this->getCompleteDate($removeValue, 'end');
143
                } catch (Exception $ex) {
144
                    continue;
145
                }
146
147
                $startIn = ($eventStart >= $removeStart && $eventStart < $removeEnd);
148
                $endIn = ($eventEnd > $removeStart && $eventEnd <= $removeEnd);
149
                $envelope = ($eventStart < $removeStart && $eventEnd > $removeEnd);
150
151
                if ($startIn || $endIn || $envelope) {
152
                    unset($base[$key]);
153
                    continue;
154
                }
155
            }
156
        }
157
158
        return $base;
159
    }
160
161
    /**
162
     * Get the complete day.
163
     *
164
     * @param array  $record
165
     * @param string $position
166
     *
167
     * @throws Exception
168
     *
169
     * @return \DateTime
170
     */
171
    protected function getCompleteDate(array $record, $position)
172
    {
173
        if (!($record[$position . '_date'] instanceof \DateTimeInterface)) {
174
            throw new Exception('no valid record', 1236781);
175
        }
176
        /** @var \DateTime $base */
177
        $base = clone $record[$position . '_date'];
178
        if (\is_int($record[$position . '_time']) && (int) $record[$position . '_time'] > 0) {
179
            // Fix handling, if the time field contains a complete timestamp
180
            $seconds = $record[$position . '_time'] % DateTimeUtility::SECONDS_DAY;
181
            $base->setTime(0, 0, 0);
182
            $base->modify('+ ' . $seconds . ' seconds');
183
        }
184
        if ($record['all_day'] && $position == 'end') {
185
            $base->setTime(0, 0, 0);
186
            $base->modify('+1 day');
187
        }
188
189
        return $base;
190
    }
191
192
    /**
193
     * Build the configuration handler.
194
     *
195
     * @param Configuration $configuration
196
     *
197
     * @throws Exception
198
     *
199
     * @return AbstractTimeTable
200
     */
201
    protected function buildConfigurationHandler(Configuration $configuration): AbstractTimeTable
202
    {
203
        $handler = 'HDNET\\Calendarize\\Service\\TimeTable\\' . \ucfirst($configuration->getType()) . 'TimeTable';
204
        if (!\class_exists($handler)) {
205
            throw new \Exception('There is no TimeTable handler for the given configuration type: ' . $configuration->getType(), 1236781);
206
        }
207
208
        return HelperUtility::create($handler);
209
    }
210
}
211