From 46b70e17742e204e493dc8dcef1033871a8de802 Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Sat, 8 Nov 2025 21:52:40 +0000 Subject: [PATCH 1/2] feat(#473): add public getter methods to `Range` value objects --- .../Doctrine/DBAL/Types/ValueObject/Range.php | 35 ++++++++++++ .../Types/ValueObject/BaseRangeTestCase.php | 55 +++++++++++++++++++ .../DBAL/Types/ValueObject/DateRangeTest.php | 2 + .../Types/ValueObject/NumericRangeTest.php | 2 + 4 files changed, 94 insertions(+) diff --git a/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php b/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php index a9159b55..67274955 100644 --- a/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php +++ b/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php @@ -23,6 +23,10 @@ abstract class Range implements \Stringable protected const EMPTY_RANGE_STRING = 'empty'; + /** + * @param R|null $lower + * @param R|null $upper + */ public function __construct( protected readonly mixed $lower, protected readonly mixed $upper, @@ -140,4 +144,35 @@ public static function infinite(): static { return new static(null, null, false, false); } + + /** + * @return R|null + */ + public function getLower(): int|float|\DateTimeInterface|null + { + return $this->lower; + } + + /** + * @return R|null + */ + public function getUpper(): int|float|\DateTimeInterface|null + { + return $this->upper; + } + + public function isLowerBracketInclusive(): bool + { + return $this->isLowerBracketInclusive; + } + + public function isUpperBracketInclusive(): bool + { + return $this->isUpperBracketInclusive; + } + + public function isExplicitlyEmpty(): bool + { + return $this->isExplicitlyEmpty; + } } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php index b4354e47..f5c546d9 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/BaseRangeTestCase.php @@ -110,6 +110,61 @@ public function can_handle_comparison_via_is_empty(): void } } + #[Test] + public function can_get_lower_bound(): void + { + $range = $this->createSimpleRange(); + $lower = $range->getLower(); + + $this->assertNotNull($lower, 'Simple range should have a lower bound'); + } + + #[Test] + public function can_get_upper_bound(): void + { + $range = $this->createSimpleRange(); + $upper = $range->getUpper(); + + $this->assertNotNull($upper, 'Simple range should have an upper bound'); + } + + #[Test] + public function can_get_null_bounds_for_infinite_range(): void + { + $range = $this->createInfiniteRange(); + + $this->assertNull($range->getLower(), 'Infinite range should have null lower bound'); + $this->assertNull($range->getUpper(), 'Infinite range should have null upper bound'); + } + + #[Test] + public function can_get_bracket_inclusivity(): void + { + $range = $this->createSimpleRange(); + + $this->assertTrue($range->isLowerBracketInclusive(), 'Simple range should have inclusive lower bracket'); + $this->assertFalse($range->isUpperBracketInclusive(), 'Simple range should have exclusive upper bracket'); + } + + #[Test] + public function can_get_inclusive_bracket_state(): void + { + $range = $this->createInclusiveRange(); + + $this->assertTrue($range->isLowerBracketInclusive(), 'Inclusive range should have inclusive lower bracket'); + $this->assertTrue($range->isUpperBracketInclusive(), 'Inclusive range should have inclusive upper bracket'); + } + + #[Test] + public function can_get_explicitly_empty_state(): void + { + $emptyRange = $this->createEmptyRange(); + $normalRange = $this->createSimpleRange(); + + $this->assertTrue($emptyRange->isExplicitlyEmpty(), 'Empty range should be explicitly empty'); + $this->assertFalse($normalRange->isExplicitlyEmpty(), 'Normal range should not be explicitly empty'); + } + /** * Create a simple range for basic testing. * diff --git a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php index 88e242be..e965ded8 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php @@ -234,6 +234,7 @@ public function throws_exception_for_invalid_lower_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Lower bound must be DateTimeInterface'); + /** @phpstan-ignore-next-line Intentionally testing invalid input */ new DateRange('invalid', new \DateTimeImmutable('2023-12-31')); } @@ -243,6 +244,7 @@ public function throws_exception_for_invalid_upper_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Upper bound must be DateTimeInterface'); + /** @phpstan-ignore-next-line Intentionally testing invalid input */ new DateRange(new \DateTimeImmutable('2023-01-01'), 'invalid'); } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php index 280277d7..f6caaf01 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php @@ -116,6 +116,7 @@ public function throws_exception_for_invalid_lower_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Lower bound must be numeric'); + /** @phpstan-ignore-next-line Intentionally testing invalid input */ new NumericRange('invalid', 10); } @@ -125,6 +126,7 @@ public function throws_exception_for_invalid_upper_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Upper bound must be numeric'); + /** @phpstan-ignore-next-line Intentionally testing invalid input */ new NumericRange(1, 'invalid'); } From 45f21a4b862adff54fbdbea910d531ab389c1e1a Mon Sep 17 00:00:00 2001 From: Martin Georgiev Date: Sat, 8 Nov 2025 21:59:34 +0000 Subject: [PATCH 2/2] cs fixer --- .../Doctrine/DBAL/Types/ValueObject/Range.php | 10 ++-------- .../Doctrine/DBAL/Types/ValueObject/DateRangeTest.php | 4 ++-- .../DBAL/Types/ValueObject/NumericRangeTest.php | 4 ++-- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php b/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php index 67274955..28f2dce5 100644 --- a/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php +++ b/src/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/Range.php @@ -145,18 +145,12 @@ public static function infinite(): static return new static(null, null, false, false); } - /** - * @return R|null - */ - public function getLower(): int|float|\DateTimeInterface|null + public function getLower(): \DateTimeInterface|float|int|null { return $this->lower; } - /** - * @return R|null - */ - public function getUpper(): int|float|\DateTimeInterface|null + public function getUpper(): \DateTimeInterface|float|int|null { return $this->upper; } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php index e965ded8..93bdcf25 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/DateRangeTest.php @@ -234,7 +234,7 @@ public function throws_exception_for_invalid_lower_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Lower bound must be DateTimeInterface'); - /** @phpstan-ignore-next-line Intentionally testing invalid input */ + /* @phpstan-ignore-next-line Intentionally testing invalid input */ new DateRange('invalid', new \DateTimeImmutable('2023-12-31')); } @@ -244,7 +244,7 @@ public function throws_exception_for_invalid_upper_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Upper bound must be DateTimeInterface'); - /** @phpstan-ignore-next-line Intentionally testing invalid input */ + /* @phpstan-ignore-next-line Intentionally testing invalid input */ new DateRange(new \DateTimeImmutable('2023-01-01'), 'invalid'); } diff --git a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php index f6caaf01..c69d9ab8 100644 --- a/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php +++ b/tests/Unit/MartinGeorgiev/Doctrine/DBAL/Types/ValueObject/NumericRangeTest.php @@ -116,7 +116,7 @@ public function throws_exception_for_invalid_lower_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Lower bound must be numeric'); - /** @phpstan-ignore-next-line Intentionally testing invalid input */ + /* @phpstan-ignore-next-line Intentionally testing invalid input */ new NumericRange('invalid', 10); } @@ -126,7 +126,7 @@ public function throws_exception_for_invalid_upper_bound(): void $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Upper bound must be numeric'); - /** @phpstan-ignore-next-line Intentionally testing invalid input */ + /* @phpstan-ignore-next-line Intentionally testing invalid input */ new NumericRange(1, 'invalid'); }