ldc-boutique-cnc-sable/app/Services/IcsGeneratorService.php
2026-10-27 09:58:12 +01:00

55 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services;
use App\Dto\IcsContentDto;
class IcsGeneratorService
{
public function __construct(
private readonly string $appName
) {
if (empty($this->appName)) {
throw new \InvalidArgumentException('App name must be provided for ICS generation.');
}
}
public function generate(IcsContentDto $event): string
{
$dateFormat = 'Ymd\THis\Z';
$lines = [
'BEGIN:VCALENDAR',
'VERSION:2.0',
'PRODID:-//' . $this->appName . '//NONSGML v1.0//EN',
'BEGIN:VEVENT',
'UID:' . $event->uid,
'DTSTAMP:' . now()->setTimezone('UTC')->format($dateFormat),
'DTSTART:' . $event->startsAt->setTimezone('UTC')->format($dateFormat),
'DTEND:' . $event->endsAt->setTimezone('UTC')->format($dateFormat),
'SUMMARY:' . $this->escape($event->summary),
'DESCRIPTION:' . $this->escape($event->description),
];
if ($event->url) {
$lines[] = 'URL:' . $this->escape($event->url);
}
$lines[] = 'END:VEVENT';
$lines[] = 'END:VCALENDAR';
// NOTE: ICS files must have CRLF line endings
return implode("\r\n", $lines) . "\r\n";
}
private function escape(string $text): string
{
$text = str_replace('\\', '\\\\', $text);
$text = str_replace(';', '\;', $text);
$text = str_replace(',', '\,', $text);
$text = str_replace("\n", '\n', $text);
return $text;
}
}