Completed
Pull Request — master (#77)
by Patrick
03:36
created

Event::addRecurrenceRule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
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\Event\Attendees;
18
use Eluceo\iCal\Property\Event\Organizer;
19
use Eluceo\iCal\Property\Event\RecurrenceRule;
20
use Eluceo\iCal\Property\Event\Description;
21
use Eluceo\iCal\PropertyBag;
22
use Eluceo\iCal\Property\Event\RecurrenceId;
23
use Eluceo\iCal\Property\DateTimesProperty;
24
25
/**
26
 * Implementation of the EVENT component.
27
 */
28
class Event extends Component
29
{
30
    const TIME_TRANSPARENCY_OPAQUE      = 'OPAQUE';
31
    const TIME_TRANSPARENCY_TRANSPARENT = 'TRANSPARENT';
32
33
    const STATUS_TENTATIVE = 'TENTATIVE';
34
    const STATUS_CONFIRMED = 'CONFIRMED';
35
    const STATUS_CANCELLED = 'CANCELLED';
36
37
    /**
38
     * @var string
39
     */
40
    protected $uniqueId;
41
42
    /**
43
     * The property indicates the date/time that the instance of
44
     * the iCalendar object was created.
45
     *
46
     * The value MUST be specified in the UTC time format.
47
     *
48
     * @var \DateTime
49
     */
50
    protected $dtStamp;
51
52
    /**
53
     * @var \DateTime
54
     */
55
    protected $dtStart;
56
57
    /**
58
     * Preferentially chosen over the duration if both are set.
59
     *
60
     * @var \DateTime
61
     */
62
    protected $dtEnd;
63
64
    /**
65
     * @var \DateInterval
66
     */
67
    protected $duration;
68
69
    /**
70
     * @var bool
71
     */
72
    protected $noTime = false;
73
74
    /**
75
     * @var string
76
     */
77
    protected $url;
78
79
    /**
80
     * @var string
81
     */
82
    protected $location;
83
84
    /**
85
     * @var string
86
     */
87
    protected $locationTitle;
88
89
    /**
90
     * @var string
91
     */
92
    protected $locationGeo;
93
94
    /**
95
     * @var string
96
     */
97
    protected $summary;
98
99
    /**
100
     * @var Organizer
101
     */
102
    protected $organizer;
103
104
    /**
105
     * @see http://www.ietf.org/rfc/rfc2445.txt 4.8.2.7 Time Transparency
106
     *
107
     * @var string
108
     */
109
    protected $transparency = self::TIME_TRANSPARENCY_OPAQUE;
110
111
    /**
112
     * If set to true the timezone will be added to the event.
113
     *
114
     * @var bool
115
     */
116
    protected $useTimezone = false;
117
118
    /**
119
     * @var int
120
     */
121
    protected $sequence = 0;
122
123
    /**
124
     * @var Attendees
125
     */
126
    protected $attendees;
127
128
    /**
129
     * @var string
130
     */
131
    protected $description;
132
133
    /**
134
     * @var string
135
     */
136
    protected $descriptionHTML;
137
138
    /**
139
     * @var string
140
     */
141
    protected $status;
142
143
    /**
144
     * @var RecurrenceRule
145
     */
146
    protected $recurrenceRule;
147
148
    /**
149
     * @var array
150
     */
151
    protected $recurrenceRules = array();
152
153
    /**
154
     * This property specifies the date and time that the calendar
155
     * information was created.
156
     *
157
     * The value MUST be specified in the UTC time format.
158
     *
159
     * @var \DateTime
160
     */
161
    protected $created;
162
163
    /**
164
     * The property specifies the date and time that the information
165
     * associated with the calendar component was last revised.
166
     *
167
     * The value MUST be specified in the UTC time format.
168
     *
169
     * @var \DateTime
170
     */
171
    protected $modified;
172
173
    /**
174
     * Indicates if the UTC time should be used or not.
175
     *
176
     * @var bool
177
     */
178
    protected $useUtc = true;
179
180
    /**
181
     * @var bool
182
     */
183
    protected $cancelled;
184
185
    /**
186
     * This property is used to specify categories or subtypes
187
     * of the calendar component.  The categories are useful in searching
188
     * for a calendar component of a particular type and category.
189
     *
190
     * @see https://tools.ietf.org/html/rfc5545#section-3.8.1.2
191
     *
192
     * @var array
193
     */
194
    protected $categories;
195
196
    /**
197
     * https://tools.ietf.org/html/rfc5545#section-3.8.1.3.
198
     *
199
     * @var bool
200
     */
201
    protected $isPrivate = false;
202
203
    /**
204
     * Dates to be excluded from a series of events.
205
     *
206
     * @var \DateTime[]
207
     */
208
    protected $exDates = array();
209
210
    /**
211
     * @var RecurrenceId
212
     */
213
    protected $recurrenceId;
214
215 4
    public function __construct($uniqueId = null)
216
    {
217 4
        if (null == $uniqueId) {
218 2
            $uniqueId = uniqid();
219 2
        }
220
221 4
        $this->uniqueId = $uniqueId;
222 4
    }
223
224
    /**
225
     * {@inheritdoc}
226
     */
227 4
    public function getType()
228
    {
229 4
        return 'VEVENT';
230
    }
231
232
    /**
233
     * {@inheritdoc}
234
     */
235 4
    public function buildPropertyBag()
236
    {
237 4
        $propertyBag = new PropertyBag();
238
239
        // mandatory information
240 4
        $propertyBag->set('UID', $this->uniqueId);
241
242 4
        $propertyBag->add(new DateTimeProperty('DTSTART', $this->dtStart, $this->noTime, $this->useTimezone, $this->useUtc));
243 4
        $propertyBag->set('SEQUENCE', $this->sequence);
244 4
        $propertyBag->set('TRANSP', $this->transparency);
245
246 4
        if ($this->status) {
247
            $propertyBag->set('STATUS', $this->status);
248
        }
249
250
        // An event can have a 'dtend' or 'duration', but not both.
251 4
        if (null != $this->dtEnd) {
252 2
            $propertyBag->add(new DateTimeProperty('DTEND', $this->dtEnd, $this->noTime, $this->useTimezone, $this->useUtc));
253 4
        } elseif (null != $this->duration) {
254
            $propertyBag->set('DURATION', $this->duration->format('P%dDT%hH%iM%sS'));
255
        }
256
257
        // optional information
258 4
        if (null != $this->url) {
259
            $propertyBag->set('URL', $this->url);
260
        }
261
262 4
        if (null != $this->location) {
263
            $propertyBag->set('LOCATION', $this->location);
264
265
            if (null != $this->locationGeo) {
266
                $propertyBag->add(
267
                    new Property(
268
                        'X-APPLE-STRUCTURED-LOCATION',
269
                        'geo:' . $this->locationGeo,
270
                        array(
271
                            'VALUE'          => 'URI',
272
                            'X-ADDRESS'      => $this->location,
273
                            'X-APPLE-RADIUS' => 49,
274
                            'X-TITLE'        => $this->locationTitle,
275
                        )
276
                    )
277
                );
278
                $propertyBag->set('GEO', str_replace(',', ';', $this->locationGeo));
279
            }
280
        }
281
282 4
        if (null != $this->summary) {
283
            $propertyBag->set('SUMMARY', $this->summary);
284
        }
285
286 4
        if (null != $this->attendees) {
287
            $propertyBag->add($this->attendees);
288
        }
289
290 4
        $propertyBag->set('CLASS', $this->isPrivate ? 'PRIVATE' : 'PUBLIC');
291
292 4
        if (null != $this->description) {
293 2
            $propertyBag->set('DESCRIPTION', new Description($this->description));
294 2
        }
295
296 4
        if (null != $this->descriptionHTML) {
297
            $propertyBag->add(
298
                new Property(
299
                    'X-ALT-DESC',
300
                    $this->descriptionHTML,
301
                    array(
302
                        'FMTTYPE' => 'text/html',
303
                    )
304
                )
305
            );
306
        }
307
308 4
        if (null != $this->recurrenceRule) {
309
            $propertyBag->set('RRULE', $this->recurrenceRule);
310
        }
311
312 4
        foreach ($this->recurrenceRules as $recurrenceRule) {
313
            $propertyBag->set('RRULE', $recurrenceRule);
314 4
        }
315
316 4
        if (null != $this->recurrenceId) {
317
            $this->recurrenceId->applyTimeSettings($this->noTime, $this->useTimezone, $this->useUtc);
318
            $propertyBag->add($this->recurrenceId);
319
        }
320
321 4
        if (!empty($this->exDates)) {
322
            $propertyBag->add(new DateTimesProperty('EXDATE', $this->exDates, $this->noTime, $this->useTimezone, $this->useUtc));
323
        }
324
325 4
        if ($this->cancelled) {
326
            $propertyBag->set('STATUS', 'CANCELLED');
327
        }
328
329 4
        if (null != $this->organizer) {
330 2
            $propertyBag->add($this->organizer);
331 2
        }
332
333 4
        if ($this->noTime) {
334
            $propertyBag->set('X-MICROSOFT-CDO-ALLDAYEVENT', 'TRUE');
335
        }
336
337 4
        if (null != $this->categories) {
338
            $propertyBag->set('CATEGORIES', $this->categories);
339
        }
340
341 4
        $propertyBag->add(
342 4
            new DateTimeProperty('DTSTAMP', $this->dtStamp ?: new \DateTime(), false, false, true)
343 4
        );
344
345 4
        if ($this->created) {
346
            $propertyBag->add(new DateTimeProperty('CREATED', $this->created, false, false, true));
347
        }
348
349 4
        if ($this->modified) {
350
            $propertyBag->add(new DateTimeProperty('LAST-MODIFIED', $this->modified, false, false, true));
351
        }
352
353 4
        return $propertyBag;
354
    }
355
356
    /**
357
     * @param $dtEnd
358
     *
359
     * @return $this
360
     */
361 2
    public function setDtEnd($dtEnd)
362
    {
363 2
        $this->dtEnd = $dtEnd;
364
365 2
        return $this;
366
    }
367
368
    public function getDtEnd()
369
    {
370
        return $this->dtEnd;
371
    }
372
373 2
    public function setDtStart($dtStart)
374
    {
375 2
        $this->dtStart = $dtStart;
376
377 2
        return $this;
378
    }
379
380
    /**
381
     * @param $dtStamp
382
     *
383
     * @return $this
384
     */
385
    public function setDtStamp($dtStamp)
386
    {
387
        $this->dtStamp = $dtStamp;
388
389
        return $this;
390
    }
391
392
    /**
393
     * @param $duration
394
     *
395
     * @return $this
396
     */
397
    public function setDuration($duration)
398
    {
399
        $this->duration = $duration;
400
401
        return $this;
402
    }
403
404
    /**
405
     * @param        $location
406
     * @param string $title
407
     * @param null   $geo
408
     *
409
     * @return $this
410
     */
411
    public function setLocation($location, $title = '', $geo = null)
412
    {
413
        $this->location      = $location;
414
        $this->locationTitle = $title;
415
        $this->locationGeo   = $geo;
416
417
        return $this;
418
    }
419
420
    /**
421
     * @param $noTime
422
     *
423
     * @return $this
424
     */
425
    public function setNoTime($noTime)
426
    {
427
        $this->noTime = $noTime;
428
429
        return $this;
430
    }
431
432
    /**
433
     * @param int $sequence
434
     *
435
     * @return $this
436
     */
437
    public function setSequence($sequence)
438
    {
439
        $this->sequence = $sequence;
440
441
        return $this;
442
    }
443
444
    /**
445
     * @return int
446
     */
447
    public function getSequence()
448
    {
449
        return $this->sequence;
450
    }
451
452
    /**
453
     * @param Organizer $organizer
454
     *
455
     * @return $this
456
     */
457 2
    public function setOrganizer(Organizer $organizer)
458
    {
459 2
        $this->organizer = $organizer;
460
461 2
        return $this;
462
    }
463
464
    /**
465
     * @param $summary
466
     *
467
     * @return $this
468
     */
469
    public function setSummary($summary)
470
    {
471
        $this->summary = $summary;
472
473
        return $this;
474
    }
475
476
    /**
477
     * @param $uniqueId
478
     *
479
     * @return $this
480
     */
481
    public function setUniqueId($uniqueId)
482
    {
483
        $this->uniqueId = $uniqueId;
484
485
        return $this;
486
    }
487
488
    /**
489
     * @return string
490
     */
491
    public function getUniqueId()
492
    {
493
        return $this->uniqueId;
494
    }
495
496
    /**
497
     * @param $url
498
     *
499
     * @return $this
500
     */
501
    public function setUrl($url)
502
    {
503
        $this->url = $url;
504
505
        return $this;
506
    }
507
508
    /**
509
     * @param $useTimezone
510
     *
511
     * @return $this
512
     */
513
    public function setUseTimezone($useTimezone)
514
    {
515
        $this->useTimezone = $useTimezone;
516
517
        return $this;
518
    }
519
520
    /**
521
     * @return bool
522
     */
523
    public function getUseTimezone()
524
    {
525
        return $this->useTimezone;
526
    }
527
528
    /**
529
     * @param Attendees $attendees
530
     *
531
     * @return $this
532
     */
533
    public function setAttendees(Attendees $attendees)
534
    {
535
        $this->attendees = $attendees;
536
537
        return $this;
538
    }
539
540
    /**
541
     * @param string $attendee
542
     * @param array  $params
543
     *
544
     * @return $this
545
     */
546
    public function addAttendee($attendee, $params = array())
547
    {
548
        if (!isset($this->attendees)) {
549
            $this->attendees = new Attendees();
550
        }
551
        $this->attendees->add($attendee, $params);
552
553
        return $this;
554
    }
555
556
    /**
557
     * @return Attendees
558
     */
559
    public function getAttendees()
560
    {
561
        return $this->attendees;
562
    }
563
564
    /**
565
     * @param $description
566
     *
567
     * @return $this
568
     */
569 2
    public function setDescription($description)
570
    {
571 2
        $this->description = $description;
572
573 2
        return $this;
574
    }
575
576
    /**
577
     * @param $descriptionHTML
578
     *
579
     * @return $this
580
     */
581
    public function setDescriptionHTML($descriptionHTML)
582
    {
583
        $this->descriptionHTML = $descriptionHTML;
584
585
        return $this;
586
    }
587
588
    /**
589
     * @param bool $useUtc
590
     *
591
     * @return $this
592
     */
593
    public function setUseUtc($useUtc = true)
594
    {
595
        $this->useUtc = $useUtc;
596
597
        return $this;
598
    }
599
600
    /**
601
     * @return string
602
     */
603
    public function getDescription()
604
    {
605
        return $this->description;
606
    }
607
608
    /**
609
     * @return string
610
     */
611
    public function getDescriptionHTML()
612
    {
613
        return $this->descriptionHTML;
614
    }
615
616
    /**
617
     * @param $status
618
     *
619
     * @return $this
620
     */
621
    public function setCancelled($status)
622
    {
623
        $this->cancelled = (bool) $status;
624
625
        return $this;
626
    }
627
628
    /**
629
     * @param $transparency
630
     *
631
     * @return $this
632
     *
633
     * @throws \InvalidArgumentException
634
     */
635 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...
636
    {
637
        $transparency = strtoupper($transparency);
638
        if ($transparency === self::TIME_TRANSPARENCY_OPAQUE
639
            || $transparency === self::TIME_TRANSPARENCY_TRANSPARENT
640
        ) {
641
            $this->transparency = $transparency;
642
        } else {
643
            throw new \InvalidArgumentException('Invalid value for transparancy');
644
        }
645
646
        return $this;
647
    }
648
649
    /**
650
     * @param $status
651
     *
652
     * @return $this
653
     *
654
     * @throws \InvalidArgumentException
655
     */
656
    public function setStatus($status)
657
    {
658
        $status = strtoupper($status);
659
        if ($status == self::STATUS_CANCELLED
660
            || $status == self::STATUS_CONFIRMED
661
            || $status == self::STATUS_TENTATIVE
662
        ) {
663
            $this->status = $status;
664
        } else {
665
            throw new \InvalidArgumentException('Invalid value for status');
666
        }
667
668
        return $this;
669
    }
670
671
    /**
672
     * @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use addRecurrenceRule instead.
673
     *
674
     * @param RecurrenceRule $recurrenceRule
675
     *
676
     * @return $this
677
     */
678
    public function setRecurrenceRule(RecurrenceRule $recurrenceRule)
679
    {
680
        @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...
681
682
        $this->recurrenceRule = $recurrenceRule;
683
684
        return $this;
685
    }
686
687
    /**
688
     * @deprecated Deprecated since version 0.11.0, to be removed in 1.0. Use getRecurrenceRules instead.
689
     *
690
     * @return RecurrenceRule
691
     */
692
    public function getRecurrenceRule()
693
    {
694
        @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...
695
696
        return $this->recurrenceRule;
697
    }
698
699
    /**
700
     * @param RecurrenceRule $recurrenceRule
701
     *
702
     * @return $this
703
     */
704
    public function addRecurrenceRule(RecurrenceRule $recurrenceRule)
705
    {
706
        $this->recurrenceRules[] = $recurrenceRule;
707
708
        return $this;
709
    }
710
711
    /**
712
     * @return array
713
     */
714
    public function getRecurrenceRules()
715
    {
716
        return $this->recurrenceRules;
717
    }
718
719
    /**
720
     * @param $dtStamp
721
     *
722
     * @return $this
723
     */
724
    public function setCreated($dtStamp)
725
    {
726
        $this->created = $dtStamp;
727
728
        return $this;
729
    }
730
731
    /**
732
     * @param $dtStamp
733
     *
734
     * @return $this
735
     */
736
    public function setModified($dtStamp)
737
    {
738
        $this->modified = $dtStamp;
739
740
        return $this;
741
    }
742
743
    /**
744
     * @param $categories
745
     *
746
     * @return $this
747
     */
748
    public function setCategories($categories)
749
    {
750
        $this->categories = $categories;
751
752
        return $this;
753
    }
754
755
    /**
756
     * Sets the event privacy.
757
     *
758
     * @param bool $flag
759
     *
760
     * @return $this
761
     */
762
    public function setIsPrivate($flag)
763
    {
764
        $this->isPrivate = (bool) $flag;
765
766
        return $this;
767
    }
768
769
    /**
770
     * @param \DateTime $dateTime
771
     *
772
     * @return \Eluceo\iCal\Component\Event
773
     */
774
    public function addExDate(\DateTime $dateTime)
775
    {
776
        $this->exDates[] = $dateTime;
777
778
        return $this;
779
    }
780
781
    /**
782
     * @return \DateTime[]
783
     */
784
    public function getExDates()
785
    {
786
        return $this->exDates;
787
    }
788
789
    /**
790
     * @param \DateTime[]
791
     *
792
     * @return \Eluceo\iCal\Component\Event
793
     */
794
    public function setExDates(array $exDates)
795
    {
796
        $this->exDates = $exDates;
797
798
        return $this;
799
    }
800
801
    /**
802
     * @return \Eluceo\iCal\Property\Event\RecurrenceId
803
     */
804
    public function getRecurrenceId()
805
    {
806
        return $this->recurrenceId;
807
    }
808
809
    /**
810
     * @param RecurrenceId $recurrenceId
811
     *
812
     * @return \Eluceo\iCal\Component\Event
813
     */
814
    public function setRecurrenceId(RecurrenceId $recurrenceId)
815
    {
816
        $this->recurrenceId = $recurrenceId;
817
818
        return $this;
819
    }
820
}
821