diff --git a/README.md b/README.md index c370c59..3a8489c 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,15 @@ $event = NowCal::create(['start' => 'October 5, 2019 6:03PM'])) The following properties can be get/set on the NowCal instance. Users can take advantage of the set property helpers in the class, i.e.: `$nowcal->location('Event Location');` as they provide a nice syntax to string multiple calls together and support callbacks if necessary. -| Property | Description | -| -------- | ------------------------------------------------------------------------------------------------------ | -| start | A string parseable by DateTime | -| end | A string parseable by DateTime, as per RFC 5545, only an end value or duration value may be used | -| duration | A string parseable by DateInterval, as per RFC 5545, only an end value or duration value may be used | -| summary | A short description of the event | -| location | The location where the event is taking place | +| Property | Description | +| -------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| uid | A globally unique ID. NOTE: passing the same ICS file into a calendar app with the same UI allows you to update the existing invite | +| start | A string parseable by DateTime | +| timezone | A string parseable by DateTimeZone | +| end | A string parseable by DateTime, as per RFC 5545, only an end value or duration value may be used | +| duration | A string parseable by DateInterval, as per RFC 5545, only an end value or duration value may be used | +| summary | A short description of the event | +| location | The location where the event is taking place | ### Methods diff --git a/src/NowCal/NowCal.php b/src/NowCal/NowCal.php index 22dae3e..88baa23 100644 --- a/src/NowCal/NowCal.php +++ b/src/NowCal/NowCal.php @@ -2,9 +2,11 @@ namespace NowCal; +use Closure; use DateInterval; use DateTime; use DateTimeZone; +use Exception; class NowCal { @@ -37,6 +39,7 @@ class NowCal * @see https://tools.ietf.org/html/rfc5545#section-3.8 */ public const ALLOWED = [ + 'uid', 'end', 'start', 'summary', @@ -102,6 +105,14 @@ class NowCal */ protected string $version = '2.0'; + /** + * The globally unique identifier for the calendar component. If not + * provided one will be generated automatically. + * + * @see https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.4.7 + */ + public ?string $uid = null; + /** * This property specifies when the calendar component begins. * @@ -203,10 +214,17 @@ public static function file(array $props = []): string return self::create($props)->file; } + public function uid(string|Closure $uid): self + { + $this->set('uid', $uid); + + return $this; + } + /** * Set the event's start date. */ - public function start(string|\Closure|\DateTime $datetime): self + public function start(string|Closure|DateTime $datetime): self { $this->set('start', $datetime); @@ -216,7 +234,7 @@ public function start(string|\Closure|\DateTime $datetime): self /** * Set the event's end date. */ - public function end(string|\Closure|\DateTime $datetime): self + public function end(string|Closure|DateTime $datetime): self { if (!$this->has('duration')) { $this->set('end', $datetime); @@ -228,7 +246,7 @@ public function end(string|\Closure|\DateTime $datetime): self /** * Set the event's summary. */ - public function summary(string|\Closure $summary): self + public function summary(string|Closure $summary): self { $this->set('summary', $summary); @@ -238,7 +256,7 @@ public function summary(string|\Closure $summary): self /** * Set the event's location. */ - public function location(string|\Closure $location): self + public function location(string|Closure $location): self { $this->set('location', $location); @@ -248,7 +266,7 @@ public function location(string|\Closure $location): self /** * Set the event's duration using a DateInterval. */ - public function duration(string|\Closure $duration): self + public function duration(string|Closure $duration): self { if (!$this->has('end')) { $this->set('duration', $duration); @@ -260,7 +278,7 @@ public function duration(string|\Closure $duration): self /** * Set the event's duration using a DateInterval. */ - public function timezone(string|\Closure $timezone): self + public function timezone(string|DateTimeZone|Closure $timezone): self { $this->set('timezone', $timezone); @@ -430,14 +448,13 @@ protected function createTimezone(): void } if (!$hasDaylightSavings && $transition['isdst']) { + $daylight = $transition; $hasDaylightSavings = true; - } - if ($transition['isdst']) { - $daylight = $transition; - } else { - $standard = $transition; + continue; } + + $standard = $transition; } $this->output[] = 'BEGIN:STANDARD'; @@ -493,7 +510,7 @@ protected function getParameter(string $key): string } if ($this->required($key)) { - throw new \Exception('Key "' . $key . '" is not set but is required'); + throw new Exception('Key "' . $key . '" is not set but is required'); } } @@ -563,6 +580,10 @@ protected function getEventParametersAttribute(): array */ protected function getUidAttribute(): string { + if ($this->uid) { + return $this->uid; + } + // Generate 16 bytes (128 bits) of random data or use the data passed into the function. $data = $data ?? random_bytes(16); assert(strlen($data) == 16); @@ -645,7 +666,7 @@ protected function convertStringToPascalCase(string $string): string /** * Parses and creates a datetime. */ - protected function createDateTime(string|DateTime|\Closure $datetime = 'now'): string + protected function createDateTime(string|DateTime|Closure $datetime = 'now'): string { return (new DateTime($datetime ?? 'now')) ->format(static::DATETIME_FORMAT); diff --git a/tests/NowCal/NowCalTest.php b/tests/NowCal/NowCalTest.php index 15db16d..0b9adb7 100644 --- a/tests/NowCal/NowCalTest.php +++ b/tests/NowCal/NowCalTest.php @@ -134,4 +134,11 @@ public function test_places_that_do_not_witness_dst_dont_get_daylight_hours() echo $this->nowcal->plain; } + + public function test_it_can_customize_the_uid() + { + $this->nowcal->uid($uid = 'abcd-1234'); + + $this->assertEquals($uid, $this->nowcal->uid); + } }