Skip to content

Commit f9b3387

Browse files
committed
✨ DateTimeCollection
✅ **Tested!** upon `\DateTime` ✨ Features ========== * Define `containsDateTimeValue()` function for all `DateTimeInterfaceCollection` - Verify upon "date time + timezone" rather than object hash - Same for nullable `\DateTimeInterface`
1 parent bedf5b5 commit f9b3387

14 files changed

+485
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\ObjectCollection\DateTime;
6+
7+
trait ContainsDateTimeNullableValueTrait
8+
{
9+
public function containsDateTimeValue(\DateTime $dateTime): bool
10+
{
11+
foreach ($this->toArray() as $value) {
12+
if (
13+
$value === null
14+
|| ($dateTime->getTimestamp() + $dateTime->getOffset())
15+
!== ($value->getTimestamp() + $value->getOffset())
16+
) {
17+
continue;
18+
}
19+
20+
return true;
21+
}
22+
23+
return false;
24+
}
25+
26+
/** @return array<?\DateTimeInterface> */
27+
abstract protected function toArray(): array;
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\ObjectCollection\DateTime;
6+
7+
trait ContainsDateTimeStrictValueTrait
8+
{
9+
public function containsDateTimeValue(\DateTimeInterface $dateTime): bool
10+
{
11+
foreach ($this->toArray() as $value) {
12+
if (
13+
($dateTime->getTimestamp() + $dateTime->getOffset())
14+
!== ($value->getTimestamp() + $value->getOffset())
15+
) {
16+
continue;
17+
}
18+
19+
return true;
20+
}
21+
22+
return false;
23+
}
24+
25+
/** @return array<\DateTimeInterface> */
26+
abstract protected function toArray(): array;
27+
}

src/ObjectCollection/DateTimeCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeStrictValueTrait;
8+
79
/** @extends AbstractObjectCollection<\DateTime> */
810
class DateTimeCollection extends AbstractObjectCollection
911
{
12+
use ContainsDateTimeStrictValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTime::class;

src/ObjectCollection/DateTimeImmutableCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeStrictValueTrait;
8+
79
/** @extends AbstractObjectCollection<\DateTimeImmutable> */
810
class DateTimeImmutableCollection extends AbstractObjectCollection
911
{
12+
use ContainsDateTimeStrictValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTimeImmutable::class;

src/ObjectCollection/DateTimeImmutableNullableCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeNullableValueTrait;
8+
79
/** @extends AbstractObjectNullableCollection<\DateTimeImmutable|null> */
810
class DateTimeImmutableNullableCollection extends AbstractObjectNullableCollection
911
{
12+
use ContainsDateTimeNullableValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTimeImmutable::class;

src/ObjectCollection/DateTimeInterfaceCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeStrictValueTrait;
8+
79
/** @extends AbstractObjectCollection<\DateTimeInterface> */
810
class DateTimeInterfaceCollection extends AbstractObjectCollection
911
{
12+
use ContainsDateTimeStrictValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTimeInterface::class;

src/ObjectCollection/DateTimeInterfaceNullableCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeNullableValueTrait;
8+
79
/** @extends AbstractObjectNullableCollection<\DateTimeInterface|null> */
810
class DateTimeInterfaceNullableCollection extends AbstractObjectNullableCollection
911
{
12+
use ContainsDateTimeNullableValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTimeInterface::class;

src/ObjectCollection/DateTimeNullableCollection.php

+4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44

55
namespace Steevanb\PhpCollection\ObjectCollection;
66

7+
use Steevanb\PhpCollection\ObjectCollection\DateTime\ContainsDateTimeNullableValueTrait;
8+
79
/** @extends AbstractObjectNullableCollection<\DateTime|null> */
810
class DateTimeNullableCollection extends AbstractObjectNullableCollection
911
{
12+
use ContainsDateTimeNullableValueTrait;
13+
1014
public static function getValueFqcn(): string
1115
{
1216
return \DateTime::class;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\ObjectCollection\DateTimeCollection;
9+
10+
/**
11+
* @covers \Steevanb\PhpCollection\ObjectCollection\DateTimeCollection::containsDateTimeValue
12+
* @internal
13+
*/
14+
final class ContainsDateTimeValueTest extends TestCase
15+
{
16+
public function testContainsDateTimeValue(): void
17+
{
18+
$dateTimeA = new \DateTime();
19+
$dateTimeCopy = $dateTimeA;
20+
// Asserting different timestamps
21+
$dateTimeB = (new \DateTime())->add(new \DateInterval('PT1S'));
22+
$dateTimeClone = clone $dateTimeA;
23+
$dateTimeSameTime = (new \DateTime())->setTimestamp($dateTimeA->getTimestamp());
24+
25+
$dateTimeCollection = new DateTimeCollection([$dateTimeA]);
26+
27+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeA));
28+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeCopy));
29+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
30+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeClone));
31+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeSameTime));
32+
}
33+
34+
public function testContainsDateTimeValueWithTimezone(): void
35+
{
36+
$dateTime = new \DateTime('2024-07-14 12:00:00');
37+
$dateTimeB = clone $dateTime;
38+
$dateTimeC = clone $dateTime;
39+
$dateTimeD = clone $dateTime;
40+
41+
// Setting timezones
42+
$dateTime->setTimezone(new \DateTimeZone('+0800'));
43+
$dateTimeB->setTimezone(new \DateTimeZone('+0600'));
44+
$dateTimeC->setTimezone(new \DateTimeZone('-0600'));
45+
$dateTimeD->setTimezone($dateTime->getTimezone());
46+
47+
$dateTimeCollection = new DateTimeCollection([$dateTime]);
48+
49+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeB));
50+
static::assertFalse($dateTimeCollection->containsDateTimeValue($dateTimeC));
51+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTimeD));
52+
}
53+
54+
public function testContainsDateTimeValueAfterClone(): void
55+
{
56+
$dateTime = new \DateTime();
57+
58+
$dateTimeCollection = (new DateTimeCollection([$dateTime]));
59+
$dateTimeCollectionClone = clone ($dateTimeCollection);
60+
61+
static::assertTrue($dateTimeCollection->containsDateTimeValue($dateTime));
62+
static::assertTrue($dateTimeCollectionClone->containsDateTimeValue($dateTime));
63+
}
64+
65+
public function testContainsDateTimeValueAfterMerge(): void
66+
{
67+
$dateTime = new \DateTime();
68+
69+
static::assertTrue(
70+
(new DateTimeCollection([$dateTime]))
71+
->merge(new DateTimeCollection([new \DateTime()]))
72+
->containsDateTimeValue($dateTime)
73+
);
74+
}
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\ObjectCollection\DateTimeCollection;
9+
10+
/**
11+
* @covers \Steevanb\PhpCollection\ObjectCollection\DateTimeCollection::contains
12+
* @internal
13+
*/
14+
final class ContainsTest extends TestCase
15+
{
16+
public function testContains(): void
17+
{
18+
$dateTimeA = new \DateTime();
19+
$dateTimeCopy = $dateTimeA;
20+
$dateTimeB = new \DateTime();
21+
$dateTimeClone = clone $dateTimeA;
22+
$dateTimeSameTime = (new \DateTime())->setTimestamp($dateTimeA->getTimestamp());
23+
24+
$dateTimeCollection = new DateTimeCollection([$dateTimeA]);
25+
26+
static::assertTrue($dateTimeCollection->contains($dateTimeA));
27+
static::assertTrue($dateTimeCollection->contains($dateTimeCopy));
28+
static::assertFalse($dateTimeCollection->contains($dateTimeB));
29+
static::assertFalse($dateTimeCollection->contains($dateTimeClone));
30+
static::assertFalse($dateTimeCollection->contains($dateTimeSameTime));
31+
}
32+
33+
public function testContainsAfterClone(): void
34+
{
35+
$dateTime = new \DateTime();
36+
37+
$dateTimeCollection = (new DateTimeCollection([$dateTime]));
38+
$dateTimeCollectionClone = clone ($dateTimeCollection);
39+
40+
static::assertTrue($dateTimeCollection->contains($dateTime));
41+
static::assertTrue($dateTimeCollectionClone->contains($dateTime));
42+
}
43+
44+
public function testContainsAfterMerge(): void
45+
{
46+
$dateTime = new \DateTime();
47+
48+
static::assertTrue(
49+
(new DateTimeCollection([$dateTime]))
50+
->merge(new DateTimeCollection([new \DateTime()]))
51+
->contains($dateTime)
52+
);
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Steevanb\PhpCollection\Tests\Unit\ObjectCollection\DateTimeCollection;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Steevanb\PhpCollection\{
9+
Exception\InvalidTypeException,
10+
ObjectCollection\DateTimeCollection
11+
};
12+
13+
/**
14+
* @covers \Steevanb\PhpCollection\ObjectCollection\DateTimeCollection
15+
* @internal
16+
*/
17+
final class TypeTest extends TestCase
18+
{
19+
public function testAllowDateTime(): void
20+
{
21+
$dateTime = new \DateTime();
22+
$dateTimeCollection = new DateTimeCollection([$dateTime]);
23+
24+
static::assertCount(expectedCount: 1, haystack: $dateTimeCollection);
25+
static::assertSame(expected: $dateTime, actual: $dateTimeCollection->get(0));
26+
}
27+
28+
/** @dataProvider provideInvalidType */
29+
public function testInvalidType(mixed $value): void
30+
{
31+
$this->expectException(InvalidTypeException::class);
32+
/** @phpstan-ignore-next-line Parameter #1 $values ... constructor expects ... array<int, mixed> given. */
33+
new DateTimeCollection([$value]);
34+
}
35+
36+
/** @return iterable<string, mixed> */
37+
public static function provideInvalidType(): iterable
38+
{
39+
yield 'it_throws_invalid_type_exception_on_null_value' => [
40+
'value' => null,
41+
];
42+
yield 'it_throws_invalid_type_exception_on_true_value' => [
43+
'value' => true,
44+
];
45+
yield 'it_throws_invalid_type_exception_on_false_value' => [
46+
'value' => false,
47+
];
48+
yield 'it_throws_invalid_type_exception_on_string_value' => [
49+
'value' => '--value--',
50+
];
51+
yield 'it_throws_invalid_type_exception_on_integer_value' => [
52+
'value' => 42,
53+
];
54+
yield 'it_throws_invalid_type_exception_on_float_value' => [
55+
'value' => 3.14,
56+
];
57+
yield 'it_throws_invalid_type_exception_on_empty_array_value' => [
58+
'value' => [],
59+
];
60+
yield 'it_throws_invalid_type_exception_on_DateTime_array_value' => [
61+
'value' => [new \DateTime()],
62+
];
63+
yield 'it_throws_invalid_type_exception_on_object_value' => [
64+
'value' => new class() {
65+
},
66+
];
67+
yield 'it_throws_invalid_type_exception_on_DateTimeCollection_value' => [
68+
'value' => new DateTimeCollection(),
69+
];
70+
}
71+
}

0 commit comments

Comments
 (0)