Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Recurrence rule generation #560

Open
wants to merge 6 commits into
base: 2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions examples/example4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

/*
* This file is part of the eluceo/iCal package.
*
* (c) 2023 Markus Poerschke <markus@poerschke.nrw>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Example;

use DateTimeImmutable;
use Eluceo\iCal\Domain\Entity\Calendar;
use Eluceo\iCal\Domain\Entity\Event;
use Eluceo\iCal\Domain\Entity\RecurrenceRule;
use Eluceo\iCal\Domain\Enum\RecurrenceFrequency;
use Eluceo\iCal\Domain\Enum\RecurrenceWeekDay;
use Eluceo\iCal\Domain\ValueObject\DateTime;
use Eluceo\iCal\Domain\ValueObject\Recurrence\By;
use Eluceo\iCal\Domain\ValueObject\Recurrence\By\Day;
use Eluceo\iCal\Domain\ValueObject\Recurrence\By\SetPosition;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Count;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Exclusion;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Frequency;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Until;
use Eluceo\iCal\Domain\ValueObject\TimeSpan;
use Eluceo\iCal\Presentation\Factory\CalendarFactory;

require_once __DIR__ . '/../vendor/autoload.php';

// 1. Create the recurrence rule.
$rrule = new RecurrenceRule();
$rrule
->setFrequency(new Frequency(RecurrenceFrequency::monthly()))
->setCount(new Count(3))
->setBy(new By([
new Day([
RecurrenceWeekDay::tuesday(),
RecurrenceWeekDay::wednesday(),
RecurrenceWeekDay::thursday()
]),
new SetPosition([3])
]))
->setExclusions(new Exclusion([
new DateTime(new DateTimeImmutable('now'),true),
new DateTime(new DateTimeImmutable('2023-10-23T10:00:00'),true),
]))
->setUntil(new Until(new DateTime(new DateTimeImmutable('2023-12-31T10:00:00'),true)));

// 2. Create Event domain entity.
$event = new Event();
$event
->setSummary('Stand-up meeting')
->setOccurrence(
new TimeSpan(
new DateTime(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2023-10-15 10:00:00'), true),
new DateTime(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2023-10-15 10:30:00'), true)
)
)
->setRecurrenceRule($rrule)
;

// 3. Create Calendar domain entity.
$calendar = new Calendar([$event]);

// 4. Transform domain entity into an iCalendar component
$componentFactory = new CalendarFactory();
$calendarComponent = $componentFactory->createCalendar($calendar);

// 5. Set HTTP headers.
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');

// 6. Output.
echo $calendarComponent;
27 changes: 27 additions & 0 deletions src/Domain/Entity/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Event
private ?Organizer $organizer = null;
private ?Timestamp $lastModified = null;
private ?EventStatus $status = null;
private ?RecurrenceRule $rrule = null;

/**
* @var array<Attendee>
Expand Down Expand Up @@ -347,4 +348,30 @@ public function unsetStatus(): self

return $this;
}

public function getRecurrenceRule(): RecurrenceRule
{
assert($this->rrule !== null);

return $this->rrule;
}

public function hasRecurrenceRule(): bool
{
return $this->rrule !== null;
}

public function setRecurrenceRule(RecurrenceRule $rrule): self
{
$this->rrule = $rrule;

return $this;
}

public function unsetRecurrenceRule(): self
{
$this->rrule = null;

return $this;
}
}
217 changes: 217 additions & 0 deletions src/Domain/Entity/RecurrenceRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
<?php

/*
* This file is part of the eluceo/iCal package.
*
* (c) 2023 Markus Poerschke <markus@poerschke.nrw>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Eluceo\iCal\Domain\Entity;

use Eluceo\iCal\Domain\ValueObject\DateTime;
use Eluceo\iCal\Domain\ValueObject\Recurrence\By;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Count;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Exclusion;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Frequency;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Interval;
use Eluceo\iCal\Domain\ValueObject\Recurrence\Until;
use Eluceo\iCal\Domain\ValueObject\Recurrence\WeekStart;
use Eluceo\iCal\Presentation\Component\Property\Value\DateTimeValue;

class RecurrenceRule
{
private ?Until $until = null;
private ?Frequency $frequency = null;
private ?Count $count = null;
private ?Interval $interval = null;
private ?WeekStart $weekStart = null;
private ?By $by = null;
private ?Exclusion $exclusions = null;

public function getUntil(): ?Until
{
return $this->until;
}

public function hasUntil(): bool
{
return $this->until !== null;
}

public function setUntil(?Until $until): self
{
$this->until = $until;
return $this;
}

public function unsetUntil(): self
{
$this->until = null;
return $this;
}

public function getFrequency(): ?Frequency
{
return $this->frequency;
}

public function hasFrequency(): bool
{
return $this->frequency !== null;
}

public function setFrequency(?Frequency $frequency): self
{
$this->frequency = $frequency;
return $this;
}

public function unsetFrequency(): self
{
$this->frequency = null;
return $this;
}

public function getCount(): ?Count
{
return $this->count;
}

public function hasCount(): bool
{
return $this->count !== null;
}

public function setCount(?Count $count): self
{
$this->count = $count;
return $this;
}

public function unsetCount(): self
{
$this->count = null;
return $this;
}

public function getInterval(): ?Interval
{
return $this->interval;
}

public function hasInterval(): bool
{
return $this->interval !== null;
}

public function setInterval(?Interval $interval): self
{
$this->interval = $interval;
return $this;
}

public function unsetInterval(): self
{
$this->interval = null;
return $this;
}

public function getWeekStart(): ?WeekStart
{
return $this->weekStart;
}

public function hasWeekStart(): bool
{
return $this->weekStart !== null;
}

public function setWeekStart(?WeekStart $weekStart): self
{
$this->weekStart = $weekStart;
return $this;
}

public function unsetWeekStart(): self
{
$this->weekStart = null;
return $this;
}

public function getBy(): ?By
{
return $this->by;
}

public function hasBy(): bool
{
return !empty($this->by);
}

public function setBy(By $by): self
{
$this->by = $by;
return $this;
}

public function unsetBy(): self
{
$this->by = null;
return $this;
}

public function getExclusions(): ?Exclusion
{
return $this->exclusions;
}

public function hasExclusions(): bool
{
return !empty($this->exclusions);
}

public function setExclusions(Exclusion $exclusions): self
{
$this->exclusions = $exclusions;
return $this;
}

public function unsetExclusions(): self
{
$this->exclusions = null;
return $this;
}

public function __toString(): string
{
if (
!$this->hasUntil()
&& !$this->hasFrequency()
&& !$this->hasCount()
&& !$this->hasInterval()
&& !$this->hasInterval()
&& !$this->hasWeekStart()
&& !$this->hasBy()
) {
return '';
}

$parts = [
$this->getUntil(),
$this->getFrequency(),
$this->getCount(),
$this->getInterval(),
$this->getWeekStart(),
$this->getBy()
];

return implode(';', array_map('strval',
array_filter($parts, static function ($part) {
return !empty($part);
})
));
}
}
37 changes: 37 additions & 0 deletions src/Domain/Enum/RecurrenceEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the eluceo/iCal package.
*
* (c) 2023 Markus Poerschke <markus@poerschke.nrw>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Eluceo\iCal\Domain\Enum;

use InvalidArgumentException;
use ReflectionClass;

abstract class RecurrenceEnum
{
protected string $value;

public function __construct(string $value)
{
$constants = (new ReflectionClass(static::class))->getConstants();
if (!in_array($value, $constants, true)) {
$allowedValues = implode(', ', $constants);
throw new InvalidArgumentException(
"Value must be one of: {$allowedValues}"
);
}
$this->value = $value;
}

public function __toString(): string
{
return strtoupper($this->value);
}
}
Loading
Loading