Skip to content

Commit

Permalink
Merge pull request #185 from spatie/ICS_presentationOptions
Browse files Browse the repository at this point in the history
ICS: support different presentation (file, HTML)
  • Loading branch information
alies-dev committed Jan 26, 2024
2 parents 7bfd76e + 28d5971 commit 824c1b6
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 18 deletions.
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -67,8 +67,10 @@ echo $link->webOutlook();
// Generate a link to create an event on outlook.office.com calendar
echo $link->webOffice();

// Generate a data uri for an ics file (for iCal & Outlook)
// Generate a data URI for an ics file (for iCal & Outlook)
echo $link->ics();
echo $link->ics(['URL' => 'https://my-page.com', 'UID' => 'custom-id']); //
echo $link->ics([], ['format' => 'file']); // e.g. to attach ics as a file to an email.

// Generate a data URI using arbitrary generator:
echo $link->formatWith(new \Your\Generator());
Expand Down
24 changes: 21 additions & 3 deletions src/Generators/Ics.php
Expand Up @@ -10,6 +10,9 @@
*/
class Ics implements Generator
{
public const FORMAT_HTML = 'html';
public const FORMAT_FILE = 'file';

/** @var string {@see https://www.php.net/manual/en/function.date.php} */
protected $dateFormat = 'Ymd';
/** @var string */
Expand All @@ -18,12 +21,17 @@ class Ics implements Generator
/** @var array<non-empty-string, non-empty-string> */
protected $options = [];

/** @var array{format?: self::FORMAT_*} */
protected $presentationOptions = [];

/**
* @param array<non-empty-string, non-empty-string> $options
* @param array<non-empty-string, non-empty-string> $options Optional ICS properties and components
* @param array{format?: self::FORMAT_*} $presentationOptions
*/
public function __construct(array $options = [])
public function __construct(array $options = [], array $presentationOptions = [])
{
$this->options = $options;
$this->presentationOptions = $presentationOptions;
}

/** {@inheritDoc} */
Expand Down Expand Up @@ -64,14 +72,24 @@ public function generate(Link $link): string
$url[] = 'END:VEVENT';
$url[] = 'END:VCALENDAR';

return $this->buildLink($url);
$format = $this->presentationOptions['format'] ?? self::FORMAT_HTML;

return match ($format) {
'file' => $this->buildFile($url),
default => $this->buildLink($url),
};
}

protected function buildLink(array $propertiesAndComponents): string
{
return 'data:text/calendar;charset=utf8;base64,'.base64_encode(implode("\r\n", $propertiesAndComponents));
}

protected function buildFile(array $propertiesAndComponents): string
{
return implode("\r\n", $propertiesAndComponents);
}

/** @see https://tools.ietf.org/html/rfc5545.html#section-3.3.11 */
protected function escapeString(string $field): string
{
Expand Down
7 changes: 4 additions & 3 deletions src/Link.php
Expand Up @@ -128,12 +128,13 @@ public function google(): string
}

/**
* @param array<non-empty-string, non-empty-string> $options
* @param array<non-empty-string, non-empty-string> $options ICS specific properties and components
* @param array{format?: \Spatie\CalendarLinks\Generators\Ics::FORMAT_*} $presentationOptions
* @return string
*/
public function ics(array $options = []): string
public function ics(array $options = [], array $presentationOptions = []): string
{
return $this->formatWith(new Ics($options));
return $this->formatWith(new Ics($options, $presentationOptions));
}

public function yahoo(): string
Expand Down
26 changes: 15 additions & 11 deletions tests/Generators/IcsGeneratorTest.php
Expand Up @@ -14,15 +14,11 @@ class IcsGeneratorTest extends TestCase
* @param array $options @see \Spatie\CalendarLinks\Generators\Ics::__construct
* @return \Spatie\CalendarLinks\Generator
*/
protected function generator(array $options = []): Generator
protected function generator(array $options = [], array $presentationOptions = []): Generator
{
// extend base class just to make output more readable and simplify reviewing of the snapshot diff
return new class($options) extends Ics {
protected function buildLink(array $propertiesAndComponents): string
{
return implode("\r\n", $propertiesAndComponents);
}
};
$presentationOptions['format'] ??= Ics::FORMAT_FILE;

return new Ics($options, $presentationOptions);
}

protected function linkMethodName(): string
Expand All @@ -34,23 +30,31 @@ protected function linkMethodName(): string
public function it_can_generate_an_ics_link_with_custom_uid(): void
{
$this->assertMatchesSnapshot(
$this->generator(['UID' => 'random-uid'])->generate($this->createShortEventLink())
$this->generator(['UID' => 'random-uid', ['format' => Ics::FORMAT_FILE]])->generate($this->createShortEventLink())
);
}

/** @test */
public function it_has_a_product_id(): void
{
$this->assertMatchesSnapshot(
$this->generator(['PRODID' => 'Spatie calendar-links'])->generate($this->createShortEventLink())
$this->generator(['PRODID' => 'Spatie calendar-links'], ['format' => Ics::FORMAT_FILE])->generate($this->createShortEventLink())
);
}

/** @test */
public function it_has_a_product_dtstamp(): void
{
$this->assertMatchesSnapshot(
$this->generator(['DTSTAMP' => '20180201T090000Z'])->generate($this->createShortEventLink())
$this->generator(['DTSTAMP' => '20180201T090000Z'], ['format' => Ics::FORMAT_FILE])->generate($this->createShortEventLink())
);
}

/** @test */
public function it_generates_base64_encoded_link_for_html(): void
{
$this->assertMatchesSnapshot(
$this->generator([], ['format' => Ics::FORMAT_FILE])->generate($this->createShortEventLink())
);
}

Expand Down
@@ -0,0 +1 @@
data:text/calendar;charset=utf8;base64,QkVHSU46VkNBTEVOREFSDQpWRVJTSU9OOjIuMA0KUFJPRElEOlNwYXRpZSBjYWxlbmRhci1saW5rcw0KQkVHSU46VkVWRU5UDQpVSUQ6OTRhYjc1YWRkODRhNjdjMDE5ZWFlNTc1Mzk2NTgwMzYNClNVTU1BUlk6QmlydGhkYXkNCkRUU1RBTVA6MjAxODAyMDFUMDkwMDAwWg0KRFRTVEFSVDoyMDE4MDIwMVQwOTAwMDBaDQpEVEVORDoyMDE4MDIwMVQxODAwMDBaDQpERVNDUklQVElPTjpXaXRoIGJhbGxvb25zXCwgY2xvd25zIGFuZCBzdHVmZlxuQnJpbmcgYSBkb2dcLCBicmluZyBhIGZyb2cNCkxPQ0FUSU9OOlBhcnR5IExhbmUgMUFcLCAxMzM3IEZ1bnRvd24NCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVI=

0 comments on commit 824c1b6

Please sign in to comment.