Completed
Push — master ( 8e73fb...990815 )
by Tim
03:02
created

BackendTypo3::getCalendarObjects()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 44
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 44
rs 8.439
c 0
b 0
f 0
cc 6
eloc 35
nc 5
nop 1
1
<?php
2
/**
3
 * Backend for events
4
 *
5
 * @author  Tim Lochmüller
6
 */
7
namespace HDNET\Calendarize\Service\CalDav;
8
9
use HDNET\Calendarize\Utility\HelperUtility;
10
use Sabre\CalDAV\Backend\AbstractBackend;
11
use Sabre\CalDAV\Plugin;
12
use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
13
use Sabre\DAV\PropPatch;
14
use TYPO3\CMS\Backend\Utility\BackendUtility;
15
use TYPO3\CMS\Core\DataHandling\DataHandler;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
18
/**
19
 * Backend for events
20
 */
21
class BackendTypo3 extends AbstractBackend
22
{
23
24
    /**
25
     * The table name that will be used for calendars
26
     *
27
     * @var string
28
     */
29
    protected $calendarTableName;
30
31
    /**
32
     * The table name that will be used for calendar objects
33
     *
34
     * @var string
35
     */
36
    protected $calendarObjectTableName;
37
38
    /**
39
     * List of CalDAV properties, and how they map to database fieldnames
40
     *
41
     * Add your own properties by simply adding on to this array
42
     *
43
     * @var array
44
     */
45
    public $propertyMap = [
46
        '{DAV:}displayname'                                   => 'title',
47
        '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'tx_caldav_data',
48
        '{urn:ietf:params:xml:ns:caldav}calendar-timezone'    => 'timezone',
49
        '{http://apple.com/ns/ical/}calendar-order'           => 'calendarorder',
50
        '{http://apple.com/ns/ical/}calendar-color'           => 'calendarcolor'
51
    ];
52
53
    /**
54
     * Creates the backend
55
     *
56
     * @param string $calendarTableName
57
     * @param string $calendarObjectTableName
58
     */
59
    public function __construct($calendarTableName = 'calendars', $calendarObjectTableName = 'calendarobjects')
60
    {
61
        $this->calendarTableName = $calendarTableName;
62
        $this->calendarObjectTableName = $calendarObjectTableName;
63
    }
64
65
    /**
66
     * Returns a list of calendars for a principal.
67
     *
68
     * Every project is an array with the following keys:
69
     * * id, a unique id that will be used by other functions to modify the
70
     * calendar. This can be the same as the uri or a database key.
71
     * * uri, which the basename of the uri with which the calendar is
72
     * accessed.
73
     * * principalUri. The owner of the calendar. Almost always the same as
74
     * principalUri passed to this method.
75
     *
76
     * Furthermore it can contain webdav properties in clark notation. A very
77
     * common one is '{DAV:}displayname'.
78
     *
79
     * @param string $principalUri
80
     *
81
     * @return array
82
     */
83
    public function getCalendarsForUser($principalUri)
84
    {
85
        $principalUriParts = explode('/', $principalUri);
86
        $databaseConnection = HelperUtility::getDatabaseConnection();
87
        // $databaseConnection->
88
        die('getCalendarsForUser');
89
        $stmt = $this->pdo->prepare('SELECT uid, tx_cal_calendar FROM fe_users WHERE username = ? AND deleted=0');
90
        $stmt->execute([
91
            array_pop($principalUriParts)
92
        ]);
93
94
        $calendars = [];
95
96
        while ($user = $stmt->fetch(\PDO::FETCH_ASSOC)) {
97
            $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_calendar WHERE uid in (' . $user ['tx_cal_calendar'] . ')');
98
            $stmt->execute();
99
100
            while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
101
                $components = explode(',', 'VEVENT,VTODO');
102
103
                $calendar = [
104
                    'id'                                                          => $row ['uid'],
105
                    'uri'                                                         => $row ['title'],
106
                    'principaluri'                                                => $principalUri,
107
                    '{' . Plugin::NS_CALENDARSERVER . '}getctag'                  => $row ['tstamp'] ? $row ['tstamp'] : '0',
108
                    '{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
109
                    '{DAV:}displayname'                                           => $row ['title'],
110
                    '{urn:ietf:params:xml:ns:caldav}calendar-description'         => '',
111
                    '{urn:ietf:params:xml:ns:caldav}calendar-timezone'            => null,
112
                    '{http://apple.com/ns/ical/}calendar-order'                   => 0,
113
                    '{http://apple.com/ns/ical/}calendar-color'                   => null
114
                ];
115
116
                $calendars [] = $calendar;
117
            }
118
        }
119
120
        return $calendars;
121
    }
122
123
    /**
124
     * Creates a new calendar for a principal.
125
     *
126
     * If the creation was a success, an id must be returned that can be used to reference
127
     * this calendar in other methods, such as updateCalendar
128
     *
129
     * @param string $principalUri
130
     * @param string $calendarUri
131
     * @param array  $properties
132
     *
133
     * @return mixed
134
     * @throws Sabre_DAV_Exception
135
     */
136
    public function createCalendar($principalUri, $calendarUri, array $properties)
137
    {
138
        $fieldNames = [
139
            'principaluri',
140
            'uri',
141
            'ctag'
142
        ];
143
        $values = [
144
            ':principaluri' => $principalUri,
145
            ':uri'          => $calendarUri,
146
            ':ctag'         => 1
147
        ];
148
149
        // Default value
150
        $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
151
        $fieldNames [] = 'components';
152
        if (!isset($properties [$sccs])) {
153
            $values [':components'] = 'VEVENT,VTODO';
154
        } else {
155
            if (!($properties [$sccs] instanceof Sabre_CalDAV_Property_SupportedCalendarComponentSet)) {
156
                throw new Sabre_DAV_Exception('The ' . $sccs . ' property must be of type: Sabre_CalDAV_Property_SupportedCalendarComponentSet');
157
            }
158
            $values [':components'] = implode(',', $properties [$sccs]->getValue());
159
        }
160
161
        foreach ($this->propertyMap as $xmlName => $dbName) {
162
            if (isset($properties [$xmlName])) {
163
                $myValue = $properties [$xmlName];
164
                $values [':' . $dbName] = $properties [$xmlName];
165
                $fieldNames [] = $dbName;
166
            }
167
        }
168
169
        $stmt = $this->pdo->prepare('INSERT INTO tx_cal_calendar (' . implode(', ', $fieldNames) . ') VALUES (' . implode(
170
            ', ',
171
            array_keys($values)
172
        ) . ')');
173
        $stmt->execute($values);
174
175
        return $this->pdo->lastInsertId();
176
    }
177
178
    /**
179
     * Updates a calendars properties
180
     *
181
     * The properties array uses the propertyName in clark-notation as key,
182
     * and the array value for the property value. In the case a property
183
     * should be deleted, the property value will be null.
184
     *
185
     * This method must be atomic. If one property cannot be changed, the
186
     * entire operation must fail.
187
     *
188
     * If the operation was successful, true can be returned.
189
     * If the operation failed, false can be returned.
190
     *
191
     * Deletion of a non-existant property is always succesful.
192
     *
193
     * Lastly, it is optional to return detailed information about any
194
     * failures. In this case an array should be returned with the following
195
     * structure:
196
     *
197
     * array(
198
     * 403 => array(
199
     * '{DAV:}displayname' => null,
200
     * ),
201
     * 424 => array(
202
     * '{DAV:}owner' => null,
203
     * )
204
     * )
205
     *
206
     * In this example it was forbidden to update {DAV:}displayname.
207
     * (403 Forbidden), which in turn also caused {DAV:}owner to fail
208
     * (424 Failed Dependency) because the request needs to be atomic.
209
     *
210
     * @param string               $calendarId
211
     * @param PropPatch $properties
212
     *
213
     * @return bool|array
214
     */
215
    public function updateCalendar($calendarId, PropPatch $properties)
216
    {
217
        $newValues = [];
218
        $result = [
219
            200 => [], // Ok
220
            403 => [], // Forbidden
221
            424 => []  // Failed Dependency
222
        ];
223
224
        $hasError = false;
225
226
        foreach ($properties as $propertyName => $propertyValue) {
227
            // We don't know about this property.
228
            if (!isset($this->propertyMap [$propertyName])) {
229
                $hasError = true;
230
                $result [403] [$propertyName] = null;
231
                unset($properties [$propertyName]);
232
                continue;
233
            }
234
235
            $fieldName = $this->propertyMap [$propertyName];
236
            $newValues [$fieldName] = $propertyValue;
237
        }
238
239
        // If there were any errors we need to fail the request
240
        if ($hasError) {
241
            // Properties has the remaining properties
242
            foreach ($properties as $propertyName => $propertyValue) {
243
                $result [424] [$propertyName] = null;
244
            }
245
246
            // Removing unused statuscodes for cleanliness
247
            foreach ($result as $status => $properties) {
248
                if (is_array($properties) && count($properties) === 0) {
249
                    unset($result [$status]);
250
                }
251
            }
252
            return $result;
253
        }
254
255
        // Success
256
257
        // Now we're generating the sql query.
258
        $valuesSql = [];
259
        foreach ($newValues as $fieldName => $value) {
260
            $valuesSql [] = $fieldName . ' = ?';
261
        }
262
        $now = new \DateTime();
263
        $valuesSql [] = $now->getTimestamp();
264
265
        $stmt = $this->pdo->prepare('UPDATE tx_cal_calendar SET ' . implode(', ', $valuesSql) . ' WHERE id = ?');
266
        $newValues ['id'] = $calendarId;
267
        $stmt->execute(array_values($newValues));
268
269
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_calendar WHERE uid = ?');
270
        $stmt->execute([
271
            $calendarId
272
        ]);
273
        $calendarRow = $stmt->fetch();
274
        $this->clearCache($calendarRow ['pid']);
275
276
        return true;
277
    }
278
279
    /**
280
     * Delete a calendar and all it's objects
281
     *
282
     * @param string $calendarId
283
     *
284
     * @return void
285
     */
286
    public function deleteCalendar($calendarId)
287
    {
288
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_calendar WHERE uid = ?');
289
        $stmt->execute([
290
            $calendarId
291
        ]);
292
        $calendarRow = $stmt->fetch();
293
294
        $stmt = $this->pdo->prepare('DELETE FROM tx_cal_event WHERE calendar_id = ?');
295
        $stmt->execute([
296
            $calendarId
297
        ]);
298
299
        $stmt = $this->pdo->prepare('DELETE FROM tx_cal_calendar WHERE uid = ?');
300
        $stmt->execute([
301
            $calendarId
302
        ]);
303
        $this->clearCache($calendarRow ['pid']);
304
    }
305
306
    /**
307
     * Returns all calendar objects within a calendar object.
308
     *
309
     * Every item contains an array with the following keys:
310
     * * id - unique identifier which will be used for subsequent updates
311
     * * calendardata - The iCalendar-compatible calnedar data
312
     * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
313
     * * lastmodified - a timestamp of the last modification time
314
     *
315
     * @param string $calendarId
316
     *
317
     * @return array
318
     */
319
    public function getCalendarObjects($calendarId)
320
    {
321
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_event WHERE calendar_id = ? AND deleted = 0');
322
        $stmt->execute([
323
            $calendarId
324
        ]);
325
        $eventArray = $stmt->fetchAll();
326
        $preparedArray = [];
327
        foreach ($eventArray as $eventRow) {
328
            if ($eventRow ['tx_caldav_uid'] == '' && $eventRow ['icsUid'] == '') {
329
                $eventRow ['tx_caldav_uid'] = 'a1b2c3_' . $eventRow ['calendar_id'] . '_' . $eventRow ['uid'];
330
                $eventRow ['icsUid'] = $eventRow ['tx_caldav_uid'];
331
                $stmt = $this->pdo->prepare('UPDATE tx_cal_event SET tx_caldav_uid = ?, icsUid = ? WHERE uid = ?');
332
                $stmt->execute([
333
                    $eventRow ['tx_caldav_uid'],
334
                    $eventRow ['icsUid'],
335
                    $eventRow ['uid']
336
                ]);
337
            } elseif ($eventRow ['tx_caldav_uid'] == '') {
338
                $eventRow ['tx_caldav_uid'] = $eventRow ['icsUid'];
339
                $stmt = $this->pdo->prepare('UPDATE tx_cal_event SET tx_caldav_uid = ? WHERE uid = ?');
340
                $stmt->execute([
341
                    $eventRow ['tx_caldav_uid'],
342
                    $eventRow ['uid']
343
                ]);
344
            } elseif ($eventRow ['icsUid'] == '') {
345
                $eventRow ['icsUid'] = $eventRow ['tx_caldav_uid'];
346
                $stmt = $this->pdo->prepare('UPDATE tx_cal_event SET icsUid = ? WHERE uid = ?');
347
                $stmt->execute([
348
                    $eventRow ['icsUid'],
349
                    $eventRow ['uid']
350
                ]);
351
            }
352
            $preparedArray [] = [
353
                'id'           => $eventRow ['uid'],
354
                'displayname'  => $eventRow ['title'],
355
                'calendardata' => $eventRow ['tx_caldav_data'],
356
                'uri'          => $eventRow ['tx_caldav_uid'],
357
                'calendarid'   => $calendarId,
358
                'lastmodified' => $eventRow ['tstamp']
359
            ];
360
        }
361
        return $preparedArray;
362
    }
363
364
    /**
365
     * Returns information from a single calendar object, based on it's object uri.
366
     *
367
     * @param string $calendarId
368
     * @param string $objectUri
369
     *
370
     * @return array
371
     */
372
    public function getCalendarObject($calendarId, $objectUri)
373
    {
374
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_event WHERE calendar_id = ? AND tx_caldav_uid = ? AND deleted = 0');
375
        $stmt->execute([
376
            $calendarId,
377
            $objectUri
378
        ]);
379
        $eventRow = $stmt->fetch();
380
        if (empty($eventRow)) {
381
            return [];
382
        }
383
        return [
384
            'id'           => $eventRow ['uid'],
385
            'displayname'  => $eventRow ['title'],
386
            'calendardata' => $eventRow ['tx_caldav_data'],
387
            'uri'          => $eventRow ['icsUid'],
388
            'calendarid'   => $calendarId,
389
            'lastmodified' => $eventRow ['tstamp']
390
        ];
391
    }
392
393
    /**
394
     * Creates a new calendar object.
395
     *
396
     * @param string $calendarId
397
     * @param string $objectUri
398
     * @param string $calendarData
399
     *
400
     * @return void
401
     */
402
    public function createCalendarObject($calendarId, $objectUri, $calendarData)
403
    {
404
        $now = new \DateTime();
405
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_calendar WHERE uid = ?');
406
        $stmt->execute([
407
            $calendarId
408
        ]);
409
        $calendarRow = $stmt->fetch();
410
411
        $stmt = $this->pdo->prepare('INSERT INTO tx_cal_event (pid,calendar_id, tx_caldav_uid, tx_caldav_data, tstamp) VALUES (?,?,?,?,?)');
412
        $uid = $this->pdo->lastInsertId();
413
        $stmt->execute([
414
            $calendarRow ['pid'],
415
            $calendarId,
416
            $objectUri,
417
            $calendarData,
418
            $now->getTimestamp();
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ';', expecting ']'
Loading history...
419
        ]);
420
        $stmt = $this->pdo->prepare('UPDATE tx_cal_calendar SET tstamp = tstamp + 1 WHERE uid = ? AND deleted = 0');
421
        $stmt->execute([
422
            $calendarId
423
        ]);
424
        $this->updateCalEvent($calendarId, $objectUri, $calendarData);
425
        $this->clearCache($calendarRow ['pid']);
426
    }
427
428
    /**
429
     * Updates an existing calendarobject, based on it's uri.
430
     *
431
     * @param string $calendarId
432
     * @param string $objectUri
433
     * @param string $calendarData
434
     *
435
     * @return void
436
     */
437
    public function updateCalendarObject($calendarId, $objectUri, $calendarData)
438
    {
439
        $now = new \DateTime();
440
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_event WHERE calendar_id = ?');
441
        $stmt->execute([
442
            $calendarId
443
        ]);
444
        $calendarRow = $stmt->fetch();
445
        $stmt = $this->pdo->prepare('UPDATE tx_cal_event SET tx_caldav_data = ?, tstamp = ? WHERE calendar_id = ? AND icsUid = ? AND deleted = 0');
446
        $stmt->execute([
447
            $calendarData,
448
            $now->getTimeStamp(),
449
            $calendarId,
450
            $objectUri
451
        ]);
452
        $stmt = $this->pdo->prepare('UPDATE tx_cal_calendar SET tstamp = tstamp + 1 WHERE uid = ? AND deleted = 0');
453
        $stmt->execute([
454
            $calendarId
455
        ]);
456
        $this->updateCalEvent($calendarId, $objectUri, $calendarData);
457
        $this->clearCache($calendarRow ['pid']);
458
    }
459
460
    /**
461
     * Deletes an existing calendar object.
462
     *
463
     * @param string $calendarId
464
     * @param string $objectUri
465
     *
466
     * @return void
467
     */
468
    public function deleteCalendarObject($calendarId, $objectUri)
469
    {
470
        $stmt = $this->pdo->prepare('SELECT * FROM tx_cal_event WHERE calendar_id = ?');
471
        $stmt->execute([
472
            $calendarId
473
        ]);
474
        $calendarRow = $stmt->fetch();
475
476
        $stmt = $this->pdo->prepare('DELETE FROM tx_cal_event WHERE calendar_id = ? AND icsUid = ? AND deleted = 0');
477
        $stmt->execute([
478
            $calendarId,
479
            $objectUri
480
        ]);
481
        $stmt = $this->pdo->prepare('UPDATE tx_cal_calendar SET tstamp = tstamp + 1 WHERE uid = ? AND deleted = 0');
482
        $stmt->execute([
483
            $calendarId
484
        ]);
485
        $this->clearCache($calendarRow ['pid']);
486
    }
487
488
    /**
489
     * Update cal event
490
     *
491
     * @param $calendarId
492
     * @param $objectUri
493
     * @param $calendarData
494
     */
495
    private function updateCalEvent($calendarId, $objectUri, $calendarData)
496
    {
497
        // var_dump($calendarId);
498
        // var_dump($objectUri);
499
        // var_dump($calendarData);
500
        // die();
501
    }
502
503
    /**
504
     * Clear cache
505
     *
506
     * @param int $pid
507
     */
508
    private function clearCache($pid)
509
    {
510
        $pageTSConf = BackendUtility::getPagesTSconfig($pid);
511
        $pageIDForPlugin = $pid;
512
513
        if ($pageTSConf ['TCEMAIN.'] ['clearCacheCmd']) {
514
            $pageIDForPlugin = $pageTSConf ['TCEMAIN.'] ['clearCacheCmd'];
515
        }
516
517
        $tce = GeneralUtility::makeInstance(DataHandler::class);
518
        // 		$tce->clear_cacheCmd ( $pageIDForPlugin ); // ID of the page for which to clear the cache
519
    }
520
}
521