diff --git a/src/OpeningHours.php b/src/OpeningHours.php index 7078dd1..45aab1e 100644 --- a/src/OpeningHours.php +++ b/src/OpeningHours.php @@ -144,29 +144,32 @@ public static function createFromStructuredData( /** * @param array $data hours definition array or sub-array + * @param bool $ignoreData should ignore data * @param array $excludedKeys keys to ignore from parsing * @return array */ - public static function mergeOverlappingRanges(array $data, array $excludedKeys = ['data', 'dateTimeClass', 'filters', 'overflow']): array + public static function mergeOverlappingRanges(array $data, bool $ignoreData = true, array $excludedKeys = ['data', 'dateTimeClass', 'filters', 'overflow']): array { $result = []; $ranges = []; - foreach (static::filterHours($data, $excludedKeys) as $key => $value) { + foreach (static::filterHours($data, $excludedKeys) as $key => [$value, $data]) { + $dataString = $ignoreData ? '' : json_encode($data); + $value = is_array($value) - ? static::mergeOverlappingRanges($value, ['data']) - : (is_string($value) ? TimeRange::fromString($value) : $value); + ? static::mergeOverlappingRanges($value, $ignoreData) + : (is_string($value) ? TimeRange::fromString($value, $data) : $value); if ($value instanceof TimeRange) { $newRanges = []; - foreach ($ranges as $range) { + foreach (($ranges[$dataString] ?? []) as $range) { if ($value->format() === $range->format()) { continue 2; } if ($value->overlaps($range) || $range->overlaps($value)) { - $value = TimeRange::fromList([$value, $range]); + $value = TimeRange::fromList([$value, $range], $data); continue; } @@ -175,7 +178,7 @@ public static function mergeOverlappingRanges(array $data, array $excludedKeys = } $newRanges[] = $value; - $ranges = $newRanges; + $ranges[$dataString] = $newRanges; continue; } @@ -184,7 +187,9 @@ public static function mergeOverlappingRanges(array $data, array $excludedKeys = } foreach ($ranges as $range) { - $result[] = $range; + foreach ((array) $range as $rangeItem) { + $result[] = $rangeItem; + } } return $result; @@ -205,11 +210,12 @@ public static function mergeOverlappingRanges(array $data, array $excludedKeys = * } $data * @param string|DateTimeZone|null $timezone * @param string|DateTimeZone|null $outputTimezone + * @param bool $ignoreData * @return static */ - public static function createAndMergeOverlappingRanges(array $data, $timezone = null, $outputTimezone = null): self + public static function createAndMergeOverlappingRanges(array $data, $timezone = null, $outputTimezone = null, bool $ignoreData = true): self { - return static::create(static::mergeOverlappingRanges($data), $timezone, $outputTimezone); + return static::create(static::mergeOverlappingRanges($data, $ignoreData), $timezone, $outputTimezone); } /** @@ -1034,13 +1040,13 @@ private static function filterHours(array $data, array $excludedKeys): Generator if (is_int($key) && is_array($value) && isset($value['hours'])) { foreach ((array) $value['hours'] as $subKey => $hour) { - yield "$key.$subKey" => $hour; + yield "$key.$subKey" => [$hour, $value['data'] ?? null]; } continue; } - yield $key => $value; + yield $key => [$value, null]; } } diff --git a/src/OpeningHoursForDay.php b/src/OpeningHoursForDay.php index 10e28f6..1ebb751 100644 --- a/src/OpeningHoursForDay.php +++ b/src/OpeningHoursForDay.php @@ -38,7 +38,7 @@ public static function fromStrings(array $strings, mixed $data = null): static uasort($strings, static fn ($a, $b) => strcmp(static::getHoursFromRange($a), static::getHoursFromRange($b))); return new static( - Arr::map($strings, static fn ($string) => TimeRange::fromDefinition($string)), + Arr::map($strings, static fn ($string) => $string instanceof TimeRange ? $string : TimeRange::fromDefinition($string)), $data, ); } diff --git a/src/TimeRange.php b/src/TimeRange.php index 2730aeb..32e72c4 100644 --- a/src/TimeRange.php +++ b/src/TimeRange.php @@ -63,7 +63,7 @@ public static function fromDefinition($value): self return is_array($value) ? static::fromArray($value) : static::fromString($value); } - public static function fromList(array $ranges): self + public static function fromList(array $ranges, $data = null): self { if (count($ranges) === 0) { throw InvalidTimeRangeList::create(); @@ -88,7 +88,7 @@ public static function fromList(array $ranges): self } } - return new self($start, $end); + return new self($start, $end, $data); } public static function fromMidnight(Time $end, $data = null): self diff --git a/tests/OpeningHoursFillTest.php b/tests/OpeningHoursFillTest.php index 2d994e1..9158c5e 100644 --- a/tests/OpeningHoursFillTest.php +++ b/tests/OpeningHoursFillTest.php @@ -359,6 +359,31 @@ public function it_should_merge_ranges_including_explicit_24_00() ], $dump); } + #[Test] + public function it_should_merge_ranges_and_keep_data() + { + $hours = OpeningHours::createAndMergeOverlappingRanges([ + 'monday' => [ + ['hours' => '08:00-12:00', 'data' => ['testdata' => true]], + ['hours' => '12:00-24:00', 'data' => ['testdata' => true]], + ['hours' => '05:00-08:00', 'data' => ['testdata' => false]], + ], + ], null, null, false); + $dump = []; + $data = null; + /** @var TimeRange $range */ + foreach ($hours->forDay('monday') as $range) { + $data = $range->data; + $dump[] = $range->format(); + } + + $this->assertSame([ + '05:00-08:00', + '08:00-24:00', + ], $dump); + $this->assertSame(['testdata' => true], $data); + } + #[Test] public function it_should_reorder_ranges() {