Completed
Push — master ( 5705c5...a00397 )
by Markus
157:13 queued 130:50
created

Event::getExDates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
/*
4
 * This file is part of the eluceo/iCal package.
5
 *
6
 * (c) Markus Poerschke <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Eluceo\iCal\Component;
13
14
use Eluceo\iCal\Component;
15
use Eluceo\iCal\Property;
16
use Eluceo\iCal\Property\DateTimeProperty;
17
use Eluceo\iCal\Property\DateTimesProperty;
18
use Eluceo\iCal\Property\Event\Attendees;
19
use Eluceo\iCal\Property\Event\Geo;
20
use Eluceo\iCal\Property\Event\Organizer;
21
use Eluceo\iCal\Property\Event\RecurrenceId;
22
use Eluceo\iCal\Property\Event\RecurrenceRule;
23
use Eluceo\iCal\Property\RawStringValue;
24
use Eluceo\iCal\PropertyBag;
25
26
/**
27
 * Implementation of the EVENT component.
28
 */
29
class Event extends Component
30
{
31
    const TIME_TRANSPARENCY_OPAQUE = 'OPAQUE';
32
    const TIME_TRANSPARENCY_TRANSPARENT = 'TRANSPARENT';
33
34
    const STATUS_TENTATIVE = 'TENTATIVE';
35
    const STATUS_CONFIRMED = 'CONFIRMED';
36
    const STATUS_CANCELLED = 'CANCELLED';
37
38
    /**
39
     * @var string
40
     */
41
    protected $uniqueId;
42
43
    /**
44
     * The property indicates the date/time that the instance of
45
     * the iCalendar object was created.
46
     *
47
     * The value MUST be specified in the UTC time format.
48
     *
49
     * @var \DateTime
50
     */
51
    protected $dtStamp;
52
53
    /**
54
     * @var \DateTime
55
     */
56
    protected $dtStart;
57
58
    /**
59
     * Preferentially chosen over the duration if both are set.
60
     *
61
     * @var \DateTime
62
     */
63
    protected $dtEnd;
64
65
    /**
66
     * @var \DateInterval
67
     */
68
    protected $duration;
69
70
    /**
71
     * @var bool
72
     */
73
    protected $noTime = false;
74
75
    /**
76
     * @var string
77
     */
78
    protected $url;
79
80
    /**
81
     * @var string
82
     */
83
    protected $location;
84
85
    /**
86
     * @var string
87
     */
88
    protected $locationTitle;
89
90
    /**
91
     * @var Geo
92
     */
93
    protected $locationGeo;
94
95
    /**
96
     * @var string
97
     */
98
    protected $summary;
99
100
    /**
101
     * @var Organizer
102
     */
103
    protected $organizer;
104
105
    /**
106
     * @see https://tools.ietf.org/html/rfc5545#section-3.8.2.7
107
     *
108
     * @var string
109
     */
110
    protected $transparency = self::TIME_TRANSPARENCY_OPAQUE;
111
112
    /**
113
     * If set to true the timezone will be added to the event.
114
     *
115
     * @var bool
116
     */
117
    protected $useTimezone = false;
118
119
    /**
120
     * If set will we used as the timezone identifier.
121
     *
122
     * @var string
123
     */
124
    protected $timezoneString = '';
125
126
    /**
127
     * @var int
128
     */
129
    protected $sequence = 0;
130
131
    /**
132
     * @var Attendees
133
     */
134
    protected $attendees;
135
136
    /**
137
     * @var string
138
     */
139
    protected $description;
140
141
    /**
142
     * @var string
143
     */
144
    protected $descriptionHTML;
145
146
    /**
147
     * @var string
148
     */
149
    protected $status;
150
151
    /**
152
     * @var RecurrenceRule
153
     */
154
    protected $recurrenceRule;
155
156
    /**
157
     * @var array
158
     */
159
    protected $recurrenceRules = [];
160
161
    /**
162
     * This property specifies the date and time that the calendar
163
     * information was created.
164
     *
165
     * The value MUST be specified in the UTC time format.
166
     *
167
     * @var \DateTime
168
     */
169
    protected $created;
170
171
    /**
172
     * The property specifies the date and time that the information
173
     * associated with the calendar component was last revised.
174
     *
175
     * The value MUST be specified in the UTC time format.
176
     *
177
     * @var \DateTime
178
     */
179
    protected $modified;
180
181
    /**
182
     * Indicates if the UTC time should be used or not.
183
     *
184
     * @var bool
185
     */
186
    protected $useUtc = true;
187
188
    /**
189
     * @var bool
190
     */
191
    protected $cancelled;
192
193
    /**
194
     * This property is used to specify categories or subtypes
195
     * of the calendar component.  The categories are useful in searching
196
     * for a calendar component of a particular type and category.
197
     *
198
     * @see https://tools.ietf.org/html/rfc5545#section-3.8.1.2
199
     *
200
     * @var array
201
     */
202
    protected $categories;
203
204
    /**
205
     * https://tools.ietf.org/html/rfc5545#section-3.8.1.3.
206
     *
207
     * @var bool
208
     */
209
    protected $isPrivate = false;
210
211
    /**
212
     * Dates to be excluded from a series of events.
213
     *
214
     * @var \DateTimeInterface[]
215 4
     */
216
    protected $exDates = [];
217 4
218 2
    /**
219 2
     * @var RecurrenceId
220
     */
221 4
    protected $recurrenceId;
222 4
223
    public function __construct(string $uniqueId = null)
224
    {
225
        if (null == $uniqueId) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $uniqueId of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
226
            $uniqueId = uniqid();
227 4
        }
228
229 4
        $this->uniqueId = $uniqueId;
230
        $this->attendees = new Attendees();
231
    }
232
233
    /**
234
     * {@inheritdoc}
235 4
     */
236
    public function getType()
237 4
    {
238
        return 'VEVENT';
239
    }
240 4
241
    /**
242 4
     * {@inheritdoc}
243 4
     */
244 4
    public function buildPropertyBag()
245
    {
246 4
        $propertyBag = new PropertyBag();
247
248
        // mandatory information
249
        $propertyBag->set('UID', $this->uniqueId);
250
251 4
        $propertyBag->add(new DateTimeProperty('DTSTART', $this->dtStart, $this->noTime, $this->useTimezone, $this->useUtc, $this->timezoneString));
252 2
        $propertyBag->set('SEQUENCE', $this->sequence);
253
        $propertyBag->set('TRANSP', $this->transparency);
254
255 2
        if ($this->status) {
256 4
            $propertyBag->set('STATUS', $this->status);
257
        }
258
259
        // An event can have a 'dtend' or 'duration', but not both.
260
        if ($this->dtEnd !== null) {
261 4
            if ($this->noTime === true) {
262
                $this->dtEnd->add(new \DateInterval('P1D'));
263
            }
264
            $propertyBag->add(new DateTimeProperty('DTEND', $this->dtEnd, $this->noTime, $this->useTimezone, $this->useUtc, $this->timezoneString));
265 4
        } elseif ($this->duration !== null) {
266
            $propertyBag->set('DURATION', $this->duration->format('P%dDT%hH%iM%sS'));
267
        }
268
269
        // optional information
270
        if (null != $this->url) {
271
            $propertyBag->set('URL', $this->url);
272
        }
273
274
        if (null != $this->location) {
275
            $propertyBag->set('LOCATION', $this->location);
276
277
            if (null != $this->locationGeo) {
278
                $propertyBag->add(
279
                    new Property(
280
                        'X-APPLE-STRUCTURED-LOCATION',
281
                        new RawStringValue('geo:' . $this->locationGeo->getGeoLocationAsString(',')),
282
                        [
283
                            'VALUE' => 'URI',
284
                            'X-ADDRESS' => $this->location,
285 4
                            'X-APPLE-RADIUS' => 49,
286
                            'X-TITLE' => $this->locationTitle,
287
                        ]
288
                    )
289 4
                );
290
            }
291
        }
292
293 4
        if (null != $this->locationGeo) {
294
            $propertyBag->add($this->locationGeo);
295 4
        }
296 2
297 2
        if (null != $this->summary) {
298
            $propertyBag->set('SUMMARY', $this->summary);
299 4
        }
300
301
        if (null != $this->attendees) {
302
            $propertyBag->add($this->attendees);
303
        }
304
305
        $propertyBag->set('CLASS', $this->isPrivate ? 'PRIVATE' : 'PUBLIC');
306
307
        if (null != $this->description) {
308
            $propertyBag->set('DESCRIPTION', $this->description);
309
        }
310
311 4
        if (null != $this->descriptionHTML) {
312
            $propertyBag->add(
313
                new Property(
314
                    'X-ALT-DESC',
315 4
                    $this->descriptionHTML,
316
                    [
317 4
                        'FMTTYPE' => 'text/html',
318
                    ]
319 4
                )
320
            );
321
        }
322
323
        if (null != $this->recurrenceRule) {
324 4
            $propertyBag->set('RRULE', $this->recurrenceRule);
325
        }
326
327
        foreach ($this->recurrenceRules as $recurrenceRule) {
328 4
            $propertyBag->set('RRULE', $recurrenceRule);
329
        }
330
331
        if (null != $this->recurrenceId) {
332 4
            $this->recurrenceId->applyTimeSettings($this->noTime, $this->useTimezone, $this->useUtc, $this->timezoneString);
333 2
            $propertyBag->add($this->recurrenceId);
334 2
        }
335
336 4
        if (!empty($this->exDates)) {
337
            $propertyBag->add(new DateTimesProperty('EXDATE', $this->exDates, $this->noTime, $this->useTimezone, $this->useUtc, $this->timezoneString));
338
        }
339
340 4
        if ($this->cancelled) {
341
            $propertyBag->set('STATUS', 'CANCELLED');
342
        }
343
344 4
        if (null != $this->organizer) {
345 4
            $propertyBag->add($this->organizer);
346 4
        }
347
348 4
        if ($this->noTime) {
349
            $propertyBag->set('X-MICROSOFT-CDO-ALLDAYEVENT', 'TRUE');
350
        }
351
352 4
        if (null != $this->categories) {
353
            $propertyBag->set('CATEGORIES', $this->categories);
354
        }
355
356 4
        $propertyBag->add(
357
            new DateTimeProperty('DTSTAMP', $this->dtStamp ?: new \DateTimeImmutable(), false, false, true)
358
        );
359
360
        if ($this->created) {
361
            $propertyBag->add(new DateTimeProperty('CREATED', $this->created, false, false, true));
362
        }
363
364 2
        if ($this->modified) {
365
            $propertyBag->add(new DateTimeProperty('LAST-MODIFIED', $this->modified, false, false, true));
366 2
        }
367
368 2
        return $propertyBag;
369
    }
370
371
    /**
372
     * @param $dtEnd
373
     *
374
     * @return $this
375
     */
376 2
    public function setDtEnd($dtEnd)
377
    {
378 2
        $this->dtEnd = $dtEnd;
379
380 2
        return $this;
381
    }
382
383
    public function getDtEnd()
384
    {
385
        return $this->dtEnd;
386
    }
387
388
    public function setDtStart($dtStart)
389
    {
390
        $this->dtStart = $dtStart;
391
392
        return $this;
393
    }
394
395
    public function getDtStart()
396
    {
397
        return $this->dtStart;
398
    }
399
400
    /**
401
     * @param $dtStamp
402
     *
403
     * @return $this
404
     */
405
    public function setDtStamp($dtStamp)
406
    {
407
        $this->dtStamp = $dtStamp;
408
409
        return $this;
410
    }
411
412
    /**
413
     * @param $duration
414
     *
415
     * @return $this
416
     */
417
    public function setDuration($duration)
418
    {
419
        $this->duration = $duration;
420
421
        return $this;
422
    }
423
424
    /**
425
     * @param string     $location
426
     * @param string     $title
427
     * @param Geo|string $geo
428
     *
429
     * @return $this
430
     */
431
    public function setLocation($location, $title = '', $geo = null)
432
    {
433
        if (is_scalar($geo)) {
434
            $geo = Geo::fromString($geo);
0 ignored issues
show
Deprecated Code introduced by
The method Eluceo\iCal\Property\Event\Geo::fromString() has been deprecated with message: This method is used to allow backwards compatibility for Event::setLocation

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
435
        } elseif (!is_null($geo) && !$geo instanceof Geo) {
436
            $className = get_class($geo);
437
            throw new \InvalidArgumentException(
438
                "The parameter 'geo' must be a string or an instance of " . Geo::class
439
                . " but an instance of {$className} was given."
440
            );
441
        }
442
443
        $this->location = $location;
444
        $this->locationTitle = $title;
445
        $this->locationGeo = $geo;
446
447
        return $this;
448
    }
449
450
    /**
451
     * @param Geo $geoProperty
452
     *
453
     * @return $this
454
     */
455
    public function setGeoLocation(Geo $geoProperty)
456
    {
457
        $this->locationGeo = $geoProperty;
458
459
        return $this;
460
    }
461
462
    /**
463
     * @param $noTime
464
     *
465 2
     * @return $this
466
     */
467 2
    public function setNoTime($noTime)
468
    {
469 2
        $this->noTime = $noTime;
470
471
        return $this;
472
    }
473
474
    /**
475
     * @param int $sequence
476
     *
477
     * @return $this
478
     */
479
    public function setSequence($sequence)
480
    {
481
        $this->sequence = $sequence;
482
483
        return $this;
484
    }
485
486
    /**
487
     * @return int
488
     */
489
    public function getSequence()
490
    {
491
        return $this->sequence;
492
    }
493
494
    /**
495
     * @param Organizer $organizer
496
     *
497
     * @return $this
498
     */
499
    public function setOrganizer(Organizer $organizer)
500
    {
501
        $this->organizer = $organizer;
502
503
        return $this;
504
    }
505
506
    /**
507
     * @param $summary
508
     *
509
     * @return $this
510
     */
511
    public function setSummary($summary)
512
    {
513
        $this->summary = $summary;
514
515
        return $this;
516
    }
517
518
    /**
519
     * @param $uniqueId
520
     *
521
     * @return $this
522
     */
523
    public function setUniqueId($uniqueId)
524
    {
525
        $this->uniqueId = $uniqueId;
526
527
        return $this;
528
    }
529
530
    /**
531
     * @return string
532
     */
533
    public function getUniqueId()
534
    {
535
        return $this->uniqueId;
536
    }
537
538
    /**
539
     * @param $url
540
     *
541
     * @return $this
542
     */
543
    public function setUrl($url)
544
    {
545
        $this->url = $url;
546
547
        return $this;
548
    }
549
550
    /**
551
     * @param $useTimezone
552
     *
553
     * @return $this
554
     */
555
    public function setUseTimezone($useTimezone)
556
    {
557
        $this->useTimezone = $useTimezone;
558
559
        return $this;
560
    }
561
562
    /**
563
     * @return bool
564
     */
565
    public function getUseTimezone()
566
    {
567
        return $this->useTimezone;
568
    }
569
570
    /**
571
     * @param $timezoneString
572
     *
573
     * @return $this
574
     */
575
    public function setTimezoneString($timezoneString)
576
    {
577 2
        $this->timezoneString = $timezoneString;
578
579 2
        return $this;
580
    }
581 2
582
    /**
583
     * @return bool
584
     */
585
    public function getTimezoneString()
586
    {
587
        return $this->timezoneString;
588
    }
589
590
    /**
591
     * @param Attendees $attendees
592
     *
593
     * @return $this
594
     */
595
    public function setAttendees(Attendees $attendees)
596
    {
597
        $this->attendees = $attendees;
598
599
        return $this;
600
    }
601
602
    /**
603
     * @param string $attendee
604
     * @param array  $params
605
     *
606
     * @return $this
607
     */
608
    public function addAttendee($attendee, $params = [])
609
    {
610
        $this->attendees->add($attendee, $params);
611
612
        return $this;
613
    }
614
615
    /**
616
     * @return Attendees
617
     */
618
    public function getAttendees(): Attendees
619
    {
620
        return $this->attendees;
621
    }
622
623
    /**
624
     * @param $description
625
     *
626
     * @return $this
627
     */
628
    public function setDescription($description)
629
    {
630
        $this->description = $description;
631
632
        return $this;
633
    }
634
635
    /**
636
     * @param $descriptionHTML
637
     *
638
     * @return $this
639
     */
640
    public function setDescriptionHTML($descriptionHTML)
641
    {
642
        $this->descriptionHTML = $descriptionHTML;
643
644
        return $this;
645
    }
646
647
    /**
648
     * @param bool $useUtc
649
     *
650
     * @return $this
651
     */
652
    public function setUseUtc($useUtc = true)
653
    {
654
        $this->useUtc = $useUtc;
655
656
        return $this;
657
    }
658
659
    /**
660
     * @return string
661
     */
662
    public function getDescription()
663
    {
664
        return $this->description;
665
    }
666
667
    /**
668
     * @return string
669
     */
670
    public function getDescriptionHTML()
671
    {
672
        return $this->descriptionHTML;
673
    }
674
675
    /**
676
     * @param $status
677
     *
678
     * @return $this
679
     */
680
    public function setCancelled($status)
681
    {
682
        $this->cancelled = (bool) $status;
683
684
        return $this;
685
    }
686
687
    /**
688
     * @param $transparency
689
     *
690
     * @return $this
691
     *
692
     * @throws \InvalidArgumentException
693
     */
694 View Code Duplication
    public function setTimeTransparency($transparency)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
695
    {
696
        $transparency = strtoupper($transparency);
697
        if ($transparency === self::TIME_TRANSPARENCY_OPAQUE
698
            || $transparency === self::TIME_TRANSPARENCY_TRANSPARENT
699
        ) {
700
            $this->transparency = $transparency;
701
        } else {
702
            throw new \InvalidArgumentException('Invalid value for transparancy');
703
        }
704
705
        return $this;
706
    }
707
708
    /**
709
     * @param $status
710
     *
711
     * @return $this
712
     *
713
     * @throws \InvalidArgumentException
714
     */
715
    public function setStatus($status)
716
    {
717
        $status = strtoupper($status);
718
        if ($status == self::STATUS_CANCELLED
719
            || $status == self::STATUS_CONFIRMED
720
            || $status == self::STATUS_TENTATIVE
721
        ) {
722
            $this->status = $status;
723
        } else {
724
            throw new \InvalidArgumentException('Invalid value for status');
725
        }
726
727
        return $this;
728
    }
729
730
    /**
731
     * @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use addRecurrenceRule instead.
732
     *
733
     * @param RecurrenceRule $recurrenceRule
734
     *
735
     * @return $this
736
     */
737
    public function setRecurrenceRule(RecurrenceRule $recurrenceRule)
738
    {
739
        @trigger_error('setRecurrenceRule() is deprecated since version 0.11.0 and will be removed in 1.0. Use addRecurrenceRule instead.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
740
741
        $this->recurrenceRule = $recurrenceRule;
742
743
        return $this;
744
    }
745
746
    /**
747
     * @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use getRecurrenceRules instead.
748
     *
749
     * @return RecurrenceRule
750
     */
751
    public function getRecurrenceRule()
752
    {
753
        @trigger_error('getRecurrenceRule() is deprecated since version 0.11.0 and will be removed in 1.0. Use getRecurrenceRules instead.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
754
755
        return $this->recurrenceRule;
756
    }
757
758
    /**
759
     * @param RecurrenceRule $recurrenceRule
760
     *
761
     * @return $this
762
     */
763
    public function addRecurrenceRule(RecurrenceRule $recurrenceRule)
764
    {
765
        $this->recurrenceRules[] = $recurrenceRule;
766
767
        return $this;
768
    }
769
770
    /**
771
     * @return array
772
     */
773
    public function getRecurrenceRules()
774
    {
775
        return $this->recurrenceRules;
776
    }
777
778
    /**
779
     * @param $dtStamp
780
     *
781
     * @return $this
782
     */
783
    public function setCreated($dtStamp)
784
    {
785
        $this->created = $dtStamp;
786
787
        return $this;
788
    }
789
790
    /**
791
     * @param $dtStamp
792
     *
793
     * @return $this
794
     */
795
    public function setModified($dtStamp)
796
    {
797
        $this->modified = $dtStamp;
798
799
        return $this;
800
    }
801
802
    /**
803
     * @param $categories
804
     *
805
     * @return $this
806
     */
807
    public function setCategories($categories)
808
    {
809
        $this->categories = $categories;
810
811
        return $this;
812
    }
813
814
    /**
815
     * Sets the event privacy.
816
     *
817
     * @param bool $flag
818
     *
819
     * @return $this
820
     */
821
    public function setIsPrivate($flag)
822
    {
823
        $this->isPrivate = (bool) $flag;
824
825
        return $this;
826
    }
827
828
    /**
829
     * @param \DateTimeInterface $dateTime
830
     *
831
     * @return \Eluceo\iCal\Component\Event
832
     */
833
    public function addExDate(\DateTimeInterface $dateTime)
834
    {
835
        $this->exDates[] = $dateTime;
836
837
        return $this;
838
    }
839
840
    /**
841
     * @return \DateTimeInterface[]
842
     */
843
    public function getExDates()
844
    {
845
        return $this->exDates;
846
    }
847
848
    /**
849
     * @param \DateTimeInterface[]
850
     *
851
     * @return \Eluceo\iCal\Component\Event
852
     */
853
    public function setExDates(array $exDates)
854
    {
855
        $this->exDates = $exDates;
856
857
        return $this;
858
    }
859
860
    /**
861
     * @return \Eluceo\iCal\Property\Event\RecurrenceId
862
     */
863
    public function getRecurrenceId()
864
    {
865
        return $this->recurrenceId;
866
    }
867
868
    /**
869
     * @param RecurrenceId $recurrenceId
870
     *
871
     * @return \Eluceo\iCal\Component\Event
872
     */
873
    public function setRecurrenceId(RecurrenceId $recurrenceId)
874
    {
875
        $this->recurrenceId = $recurrenceId;
876
877
        return $this;
878
    }
879
}
880