From c8186ff3aa3b9337c256e19a579c52f2148896f1 Mon Sep 17 00:00:00 2001 From: Eric Lippmann Date: Fri, 17 Feb 2023 15:38:48 +0100 Subject: [PATCH] WIP --- src/RRule.php | 52 +++++--------- tests/Lib/BaseTestFrequency.php | 1 + tests/RRuleTest.php | 120 ++++---------------------------- 3 files changed, 32 insertions(+), 141 deletions(-) diff --git a/src/RRule.php b/src/RRule.php index 2597c1a..3d38d02 100644 --- a/src/RRule.php +++ b/src/RRule.php @@ -161,6 +161,8 @@ public function isExpired(DateTimeInterface $dateTime): bool /** * Set the start time of this frequency * + * The given datetime will be cloned and microseconds removed since iCalendar datetimes only work to the second. + * * @param DateTimeInterface $start * * @return $this @@ -172,7 +174,7 @@ public function startAt(DateTimeInterface $start): self // the transformer operates only up to seconds level. See also the upstream issue #155 $startDate->setTime($start->format('H'), $start->format('i'), $start->format('s')); - $this->rrule->setStartDate($startDate); + $this->rrule->setStartDate($startDate, true); return $this; } @@ -185,12 +187,17 @@ public function getStart(): ?DateTimeInterface /** * Set the end time of this frequency * + * The given datetime will be cloned and microseconds removed since iCalendar datetimes only work to the second. + * * @param DateTimeInterface $end * * @return $this */ public function endAt(DateTimeInterface $end): self { + $end = clone $end; + $end->setTime($end->format('H'), $end->format('i'), $end->format('s')); + $this->rrule->setEndDate($end); return $this; @@ -257,47 +264,20 @@ public function getNextRecurrences( public static function fromJson(string $json): Frequency { - $data = json_decode($json, true); - if (! isset($data['FREQ'])) { - throw new InvalidRRule('Missing required attribute "FREQ"'); - } - - if (! isset($data['INTERVAL'])) { - $self = static::fromFrequency($data['FREQ']); - if (isset($data['DTSTART'])) { - $self->startAt(new DateTime($data['DTSTART'])); - } - - if (isset($data['DTEND'])) { - $self->endAt(new DateTime($data['DTEND'])); - } - - return $self; - } + $data = json_decode($json); + $self = new static($data->rrule); + $self->frequency = $data->frequency; - return new static($data); + return $self; } #[\ReturnTypeWillChange] public function jsonSerialize() { - $data = $this->rrule->parseString($this->rrule->getString()); - if ($this->getFrequency() === static::QUARTERLY) { - $data['FREQ'] = static::QUARTERLY; - unset($data['INTERVAL']); - } - - $start = $this->getStart(); - if ($start) { - $data['DTSTART'] = $start->format(static::SERIALIZED_DATETIME_FORMAT); - } - - $end = $this->getEnd(); - if ($end) { - $data['DTEND'] = $end->format(static::SERIALIZED_DATETIME_FORMAT); - } - - return json_encode($data); + return [ + 'rrule' => $this->rrule->getString(), + 'frequency' => $this->frequency + ]; } /** diff --git a/tests/Lib/BaseTestFrequency.php b/tests/Lib/BaseTestFrequency.php index 57ccfb5..f9e6c0a 100644 --- a/tests/Lib/BaseTestFrequency.php +++ b/tests/Lib/BaseTestFrequency.php @@ -33,6 +33,7 @@ public static function fromJson(string $json): Frequency throw new LogicException('Not implemented'); } + #[\ReturnTypeWillChange] public function jsonSerialize() { throw new LogicException('Not implemented'); diff --git a/tests/RRuleTest.php b/tests/RRuleTest.php index 1b54d91..f4c7991 100644 --- a/tests/RRuleTest.php +++ b/tests/RRuleTest.php @@ -69,6 +69,7 @@ public function testGetNextDueWithoutEndTime() public function testGetNextDueWithEndTime() { $end = new DateTime('+5 minutes'); + $end->setTime($end->format('H'), $end->format('i'), $end->format('s')); $rrule = RRule::fromFrequency(RRule::MINUTELY) ->startAt(new DateTime()) ->endAt($end); @@ -132,118 +133,27 @@ public function testQuarterlyFrequency() $this->assertEquals($start->modify('+3 months'), $recurrences->current()); } - public function testJsonSerializeMinutelyFrequency() + public function testJSON() { - $rule = RRule::fromFrequency(RRule::MINUTELY); - $this->assertSame('{"FREQ":"MINUTELY"}', $rule->jsonSerialize()); - - $start = new DateTime('2023-02-15T15:11:00'); - $rule->startAt($start); - - $this->assertSame( - sprintf('{"FREQ":"MINUTELY","DTSTART":"%s"}', $start->format(Frequency::SERIALIZED_DATETIME_FORMAT)), - $rule->jsonSerialize() - ); - - $end = new DateTime(); - $rule->endAt($end); - - $this->assertSame( - sprintf( - '{"FREQ":"MINUTELY","DTEND":"%s","DTSTART":"%s"}', - $end->format(Frequency::SERIALIZED_DATETIME_FORMAT), - $start->format(Frequency::SERIALIZED_DATETIME_FORMAT) - ), - $rule->jsonSerialize() - ); - } + $rrule = RRule::fromFrequency(RRule::QUARTERLY) + ->startAt(new DateTime('tomorrow')) + ->endAt(new DateTime('next week')); - public function testJsonSerializeQuarterly() - { - $rule = RRule::fromFrequency(RRule::QUARTERLY); - $this->assertSame('{"FREQ":"QUARTERLY"}', $rule->jsonSerialize()); - - $start = new DateTime('2023-02-15T15:11:00'); - $rule->startAt($start); - - $this->assertSame( - sprintf('{"FREQ":"QUARTERLY","DTSTART":"%s"}', $start->format(Frequency::SERIALIZED_DATETIME_FORMAT)), - $rule->jsonSerialize() - ); - - $end = new DateTime(); - $rule->endAt($end); - - $this->assertSame( - sprintf( - '{"FREQ":"QUARTERLY","DTEND":"%s","DTSTART":"%s"}', - $end->format(Frequency::SERIALIZED_DATETIME_FORMAT), - $start->format(Frequency::SERIALIZED_DATETIME_FORMAT) - ), - $rule->jsonSerialize() - ); - } + $this->assertEquals($rrule, RRule::fromJson(json_encode($rrule))); - public function testFromJsonWithInvalidData() - { - $this->expectException(InvalidRRule::class); + $rrule = RRule::fromFrequency(RRule::QUARTERLY) + ->endAt(new DateTime('next week')); - RRule::fromJson('{}'); - } + $this->assertEquals($rrule, RRule::fromJson(json_encode($rrule))); - public function testFromJsonMinutelyFrequency() - { - $this->assertEquals(RRule::fromFrequency(RRule::MINUTELY), RRule::fromJson('{"FREQ":"MINUTELY"}')); + $rrule = RRule::fromFrequency(RRule::QUARTERLY); - $start = new DateTime(); - $rule = RRule::fromFrequency(RRule::MINUTELY)->startAt($start); - $this->assertEquals( - $rule, - RRule::fromJson( - sprintf('{"FREQ":"MINUTELY","DTSTART":"%s"}', $start->format(Frequency::SERIALIZED_DATETIME_FORMAT)) - ) - ); - - $end = new DateTime(); - $rule->endAt($end); - - $this->assertEquals( - $rule, - RRule::fromJson( - sprintf( - '{"FREQ":"MINUTELY","DTEND":"%s","DTSTART":"%s"}', - $end->format(Frequency::SERIALIZED_DATETIME_FORMAT), - $start->format(Frequency::SERIALIZED_DATETIME_FORMAT) - ) - ) - ); - } + $this->assertEquals($rrule, RRule::fromJson(json_encode($rrule))); - public function testFromJsonQuarterlyFrequency() - { - $this->assertEquals(RRule::fromFrequency(RRule::QUARTERLY), RRule::fromJson('{"FREQ":"QUARTERLY"}')); + $rrule = (new RRule('FREQ=MINUTELY')) + ->startAt(new DateTime('tomorrow')) + ->endAt(new DateTime('next week')); - $start = new DateTime(); - $rule = RRule::fromFrequency(RRule::QUARTERLY)->startAt($start); - $this->assertEquals( - $rule, - RRule::fromJson( - sprintf('{"FREQ":"QUARTERLY","DTSTART":"%s"}', $start->format(Frequency::SERIALIZED_DATETIME_FORMAT)) - ) - ); - - $end = new DateTime(); - $rule->endAt($end); - - $this->assertEquals( - $rule, - RRule::fromJson( - sprintf( - '{"FREQ":"QUARTERLY","DTEND":"%s","DTSTART":"%s"}', - $end->format(Frequency::SERIALIZED_DATETIME_FORMAT), - $start->format(Frequency::SERIALIZED_DATETIME_FORMAT) - ) - ) - ); + $this->assertEquals($rrule, RRule::fromJson(json_encode($rrule))); } }