Publication initiale de RelaisSMS : documentation et sources nettoyees
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Calendar;
|
||||
|
||||
use Carbon\CarbonInterface;
|
||||
use DateTimeZone;
|
||||
use RuntimeException;
|
||||
use Sabre\VObject\Component\VCalendar;
|
||||
use Sabre\VObject\Component\VEvent;
|
||||
use Sabre\VObject\Reader;
|
||||
|
||||
class CalendarOccurrenceExpander
|
||||
{
|
||||
public function expand(string $ical, CarbonInterface $from, CarbonInterface $to): string
|
||||
{
|
||||
if (! preg_match('/^(RRULE|RDATE|RECURRENCE-ID)[;:]/mi', $ical)) {
|
||||
return $ical;
|
||||
}
|
||||
|
||||
$calendar = Reader::read($ical);
|
||||
if (! $calendar instanceof VCalendar) {
|
||||
throw new RuntimeException('La source agenda ne contient pas un calendrier iCalendar.');
|
||||
}
|
||||
|
||||
$additionalDates = clone $calendar;
|
||||
$additionalUids = [];
|
||||
|
||||
foreach ($calendar->select('VEVENT') as $event) {
|
||||
// A cancelled detached occurrence may contain only UID and RECURRENCE-ID.
|
||||
// It must still suppress the original occurrence during expansion.
|
||||
if (! isset($event->DTSTART) && isset($event->{'RECURRENCE-ID'})) {
|
||||
$start = clone $event->{'RECURRENCE-ID'};
|
||||
$start->name = 'DTSTART';
|
||||
$event->add($start);
|
||||
}
|
||||
|
||||
// VObject chooses RDATE instead of RRULE when both are present.
|
||||
// Expand their union separately, then deduplicate by occurrence identity.
|
||||
if (isset($event->RRULE, $event->RDATE)) {
|
||||
$additionalUids[] = (string) $event->UID;
|
||||
unset($event->RDATE);
|
||||
}
|
||||
}
|
||||
|
||||
$timezone = new DateTimeZone((string) config('app.timezone', 'UTC'));
|
||||
$expanded = $calendar->expand($from, $to, $timezone);
|
||||
|
||||
if ($additionalUids !== []) {
|
||||
foreach ($additionalDates->select('VEVENT') as $event) {
|
||||
if (! in_array((string) $event->UID, $additionalUids, true)) {
|
||||
$additionalDates->remove($event);
|
||||
} else {
|
||||
unset($event->RRULE);
|
||||
if (! isset($event->DTSTART) && isset($event->{'RECURRENCE-ID'})) {
|
||||
$start = clone $event->{'RECURRENCE-ID'};
|
||||
$start->name = 'DTSTART';
|
||||
$event->add($start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$seen = [];
|
||||
foreach ($expanded->select('VEVENT') as $event) {
|
||||
$seen[$this->identity($event)] = true;
|
||||
}
|
||||
foreach ($additionalDates->expand($from, $to, $timezone)->select('VEVENT') as $event) {
|
||||
$key = $this->identity($event);
|
||||
if (! isset($seen[$key])) {
|
||||
$expanded->add(clone $event);
|
||||
$seen[$key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $expanded->serialize();
|
||||
}
|
||||
|
||||
private function identity(VEvent $event): string
|
||||
{
|
||||
return (string) $event->UID.'|'.(string) $event->{'RECURRENCE-ID'};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user