Completed
Pull Request — master (#370)
by
unknown
01:59
created

IcsReaderService::buildWithICalDissect()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 33
rs 8.7697
c 0
b 0
f 0
cc 6
nc 6
nop 1
1
<?php
2
3
/**
4
 * ICS Service.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Calendarize\Service;
9
10
use HDNET\Calendarize\Utility\DateTimeUtility;
11
use JMBTechnologyLimited\ICalDissect\ICalEvent;
12
use JMBTechnologyLimited\ICalDissect\ICalParser;
13
use Sabre\VObject\Reader;
14
use TYPO3\CMS\Core\Utility\GeneralUtility;
15
16
/**
17
 * ICS Service.
18
 */
19
class IcsReaderService extends AbstractService
20
{
21
    /**
22
     * Generate the times of the given URL.
23
     *
24
     * @param string $url
25
     *
26
     * @return array
27
     */
28
    public function getTimes(string $url): array
29
    {
30
        $fileName = $this->getCachedUrlFile($url);
31
        //if (class_exists(Reader::class)) {
32
        //    return $this->buildWithVObject($fileName);
33
        //}
34
        return $this->buildWithICalDissect($fileName);
35
    }
36
37
    /**
38
     * Build with iCal dissect.
39
     *
40
     * @param string $filename
41
     *
42
     * @return array
43
     */
44
    protected function buildWithICalDissect(string $filename): array
45
    {
46
        $backend = new ICalParser();
47
        if (!$backend->parseFromFile($filename)) {
48
            return [];
49
        }
50
        $events = $backend->getEvents();
51
        $times = [];
52
        foreach ($events as $event) {
53
            /** @var $event ICalEvent */
54
            if (!($event->getStart() instanceof \DateTime)) {
55
                continue;
56
            }
57
            if (!($event->getEnd() instanceof \DateTime)) {
58
                continue;
59
            }
60
            $startTime = DateTimeUtility::getDaySecondsOfDateTime($event->getStart());
61
            $endTime = DateTimeUtility::getDaySecondsOfDateTime($event->getEnd());
62
            if (86399 === $endTime) {
63
                $endTime = 0;
64
            }
65
66
            $times[] = [
67
                'start_date' => $event->getStart(),
68
                'end_date' => $this->getEventsFixedEndDate($event),
69
                'start_time' => $startTime,
70
                'end_time' => $endTime,
71
                'all_day' => 0 === $endTime,
72
            ];
73
        }
74
75
        return $times;
76
    }
77
78
    /**
79
     * Build with Vobject.
80
     *
81
     * @param string $filename
82
     *
83
     * @return array
84
     *
85
     * @todo implement
86
     */
87
    protected function buildWithVObject(string $filename): array
88
    {
89
        $vcalendar = Reader::read(
90
            GeneralUtility::getUrl($filename)
91
        );
92
        $times = [];
93
        foreach ($vcalendar->VEVENT as $event) {
94
            /** @var \Sabre\VObject\Component\VEvent $event */
95
            $start = $event->DTSTAMP;
96
            if (!($start instanceof \Sabre\VObject\Property\ICalendar\DateTime)) {
97
                continue;
98
            }
99
100
            $end = $event->DTEND;
101
            if (!($end instanceof \Sabre\VObject\Property\ICalendar\DateTime)) {
102
                continue;
103
            }
104
105
            $times[] = [
106
                'start_date' => $start->getDateTime(),
107
                'end_date' => $end->getDateTime(), // $this->getEventsFixedEndDate($event),
108
                'start_time' => 0, // @todo add time
109
                'end_time' => 0, // @todo add time
110
                'all_day' => true,
111
            ];
112
        }
113
114
        return $times;
115
    }
116
117
    /**
118
     * Fixes a parser related bug where the DTEND is EXCLUSIVE.
119
     * The parser uses it inclusive so every event is one day
120
     * longer than it should be.
121
     *
122
     * @param ICalEvent $event
123
     *
124
     * @return \DateTime
125
     */
126
    protected function getEventsFixedEndDate(ICalEvent $event)
127
    {
128
        if (!$event->getEnd() instanceof \DateTimeInterface) {
129
            return $event->getStart();
130
        }
131
132
        $end = clone $event->getEnd();
133
        $end->sub(new \DateInterval('P1D'));
134
        if ($end->format('Ymd') === $event->getStart()->format('Ymd')) {
135
            return $end;
136
        }
137
138
        return $event->getEnd();
139
    }
140
141
    /**
142
     * Get cached URL file.
143
     *
144
     * @param string $url
145
     *
146
     * @return string
147
     */
148
    protected function getCachedUrlFile(string $url): string
149
    {
150
        $tempFileName = $this->getCheckedCacheFolder() . \md5($url);
151
        if (!\is_file($tempFileName) || \filemtime($tempFileName) < (\time() - DateTimeUtility::SECONDS_HOUR)) {
152
            $icsFile = GeneralUtility::getUrl($url);
153
            GeneralUtility::writeFile($tempFileName, $icsFile);
154
        }
155
156
        return $tempFileName;
157
    }
158
159
    /**
160
     * Return the cache folder and check if the folder exists.
161
     *
162
     * @return string
163
     */
164
    protected function getCheckedCacheFolder(): string
165
    {
166
        $cacheFolder = GeneralUtility::getFileAbsFileName('typo3temp/var/transient/calendarize/');
167
        if (!\is_dir($cacheFolder)) {
168
            GeneralUtility::mkdir_deep($cacheFolder);
169
        }
170
171
        return $cacheFolder;
172
    }
173
}
174