From ba3b21f3ada3157b881045f9b62b192e303f81b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20W=C3=B3js?= Date: Mon, 23 Oct 2023 12:06:19 +0200 Subject: [PATCH] IBX-6827: Ranges generators --- .../Field/AbstractFieldRangeAggregation.php | 16 +++ .../Content/Query/Aggregation/Range.php | 5 + .../Ranges/DateTimeStepRangesGenerator.php | 125 ++++++++++++++++++ .../Ranges/FloatStepRangesGenerator.php | 111 ++++++++++++++++ .../Ranges/IntegerStepRangesGenerator.php | 107 +++++++++++++++ .../Ranges/RangesGeneratorInterface.php | 12 ++ 6 files changed, 376 insertions(+) create mode 100644 src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php create mode 100644 src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php create mode 100644 src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php create mode 100644 src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/AbstractFieldRangeAggregation.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/AbstractFieldRangeAggregation.php index e63e888c96..41ce7ece7e 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Field/AbstractFieldRangeAggregation.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Field/AbstractFieldRangeAggregation.php @@ -10,6 +10,8 @@ use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\AbstractRangeAggregation; use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\FieldAggregation; +use Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Ranges\RangesGeneratorInterface; +use Traversable; abstract class AbstractFieldRangeAggregation extends AbstractRangeAggregation implements FieldAggregation { @@ -26,6 +28,20 @@ public function __construct( $this->contentTypeIdentifier = $contentTypeIdentifier; $this->fieldDefinitionIdentifier = $fieldDefinitionIdentifier; } + + public static function fromGenerator( + string $name, + string $contentTypeIdentifier, + string $fieldDefinitionIdentifier, + RangesGeneratorInterface $generator + ): self { + $ranges = $generator->generate(); + if ($ranges instanceof Traversable) { + $ranges = iterator_to_array($ranges); + } + + return new static($name, $contentTypeIdentifier, $fieldDefinitionIdentifier, $ranges); + } } class_alias(AbstractFieldRangeAggregation::class, 'eZ\Publish\API\Repository\Values\Content\Query\Aggregation\Field\AbstractFieldRangeAggregation'); diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php index 5179df322b..328f4ee116 100644 --- a/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Range.php @@ -78,6 +78,11 @@ public function __toString(): string ); } + public function equalsTo(Range $value): bool + { + return $this->from === $value->from && $this->to === $value->to; + } + private function getRangeValueAsString($value): string { if ($value === null) { diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php new file mode 100644 index 0000000000..7b3e7d0589 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/DateTimeStepRangesGenerator.php @@ -0,0 +1,125 @@ +start = $start; + $this->end = $end; + $this->step = new DateInterval('P1D'); + } + + public function getStart(): DateTimeInterface + { + return $this->start; + } + + public function setStart(DateTimeInterface $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): DateTimeInterface + { + return $this->end; + } + + public function setEnd(DateTimeInterface $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): DateInterval + { + return $this->step; + } + + public function setStep(DateInterval $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): void + { + $this->isLeftOpen = $isLeftOpen; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] + */ + public function generate(): array + { + $ranges = []; + + if ($this->isLeftOpen) { + $ranges[] = Range::ofDateTime(Range::INF, $this->start); + } + + /** @var \DateTimeImmutable $current */ + $current = $this->start; + if ($current instanceof DateTime) { + $current = DateTimeImmutable::createFromMutable($current); + } + + while ($current <= $this->end) { + $next = $current->add($this->step); + $ranges[] = Range::ofDateTime($current, $next); + $current = $next; + } + + if ($this->isRightOpen) { + $ranges[] = Range::ofDateTime($this->end, Range::INF); + } + + return $ranges; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php new file mode 100644 index 0000000000..24a8e72c66 --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/FloatStepRangesGenerator.php @@ -0,0 +1,111 @@ +start = $start; + $this->end = $end; + } + + public function getStart(): float + { + return $this->start; + } + + public function setStart(float $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): float + { + return $this->end; + } + + public function setEnd(float $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): float + { + return $this->step; + } + + public function setStep(float $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): void + { + $this->isLeftOpen = $isLeftOpen; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] + */ + public function generate(): array + { + $ranges = []; + + if ($this->isLeftOpen) { + $ranges[] = Range::ofFloat(Range::INF, $this->start); + } + + $values = range($this->start, $this->end, $this->step); + for ($i = 1; $i < count($values); ++$i) { + $ranges[] = Range::ofFloat($values[$i - 1], $values[$i]); + } + + if ($this->isRightOpen) { + $ranges[] = Range::ofFloat($this->end, Range::INF); + } + + return $ranges; + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php new file mode 100644 index 0000000000..8322bf033f --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/IntegerStepRangesGenerator.php @@ -0,0 +1,107 @@ +start = $start; + $this->end = $end; + } + + public function getStart(): int + { + return $this->start; + } + + public function setStart(int $start): self + { + $this->start = $start; + + return $this; + } + + public function getEnd(): int + { + return $this->end; + } + + public function setEnd(int $end): self + { + $this->end = $end; + + return $this; + } + + public function getStep(): int + { + return $this->step; + } + + public function setStep(int $step): self + { + $this->step = $step; + + return $this; + } + + public function isLeftOpen(): bool + { + return $this->isLeftOpen; + } + + public function setLeftOpen(bool $isLeftOpen): void + { + $this->isLeftOpen = $isLeftOpen; + } + + public function isRightOpen(): bool + { + return $this->isRightOpen; + } + + public function setRightOpen(bool $isRightOpen): self + { + $this->isRightOpen = $isRightOpen; + + return $this; + } + + /** + * @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation\Range[] + */ + public function generate(): \Generator + { + if ($this->isLeftOpen) { + yield Range::ofInt(Range::INF, $this->start); + } + + $values = range($this->start, $this->end, $this->step); + for ($i = 1; $i < count($values); ++$i) { + yield Range::ofInt($values[$i - 1], $values[$i]); + } + + if ($this->isRightOpen) { + yield Range::ofInt($this->end, Range::INF); + } + } +} diff --git a/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php new file mode 100644 index 0000000000..4bc05f7c0c --- /dev/null +++ b/src/contracts/Repository/Values/Content/Query/Aggregation/Ranges/RangesGeneratorInterface.php @@ -0,0 +1,12 @@ +