Skip to content

Commit ad59e93

Browse files
committed
support writing string to DateTimeImmutable properties [closes #8]
1 parent 2602358 commit ad59e93

File tree

5 files changed

+93
-1
lines changed

5 files changed

+93
-1
lines changed

extension.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ services:
1919
class: Nextras\OrmPhpStan\Reflection\EntityRelationshipPropertyReflectionExtension
2020
tags:
2121
- phpstan.broker.propertiesClassReflectionExtension
22+
-
23+
class: Nextras\OrmPhpStan\Reflection\EntityDateTimePropertyReflectionExtension
24+
tags:
25+
- phpstan.broker.propertiesClassReflectionExtension
2226
-
2327
class: Nextras\OrmPhpStan\Rules\SetValueMethodRule
2428
tags:
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Nextras\OrmPhpStan\Reflection;
4+
5+
use Nextras\Orm\Entity\IEntity;
6+
use Nextras\OrmPhpStan\Reflection\Annotations\AnnotationPropertyReflection;
7+
use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension;
8+
use PHPStan\Reflection\ClassReflection;
9+
use PHPStan\Reflection\PropertiesClassReflectionExtension;
10+
use PHPStan\Reflection\PropertyReflection;
11+
use PHPStan\Type\ObjectType;
12+
use PHPStan\Type\StringType;
13+
use PHPStan\Type\TypeCombinator;
14+
15+
16+
class EntityDateTimePropertyReflectionExtension implements PropertiesClassReflectionExtension
17+
{
18+
/** @var AnnotationsPropertiesClassReflectionExtension */
19+
private $annotationsExtension;
20+
21+
22+
public function __construct(AnnotationsPropertiesClassReflectionExtension $annotationsExtension)
23+
{
24+
$this->annotationsExtension = $annotationsExtension;
25+
}
26+
27+
28+
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
29+
{
30+
$hasProperty = $this->annotationsExtension->hasProperty($classReflection, $propertyName);
31+
if (!$hasProperty) {
32+
return false;
33+
}
34+
35+
$interfaces = array_map(function (ClassReflection $interface) {
36+
return $interface->getName();
37+
}, $classReflection->getInterfaces());
38+
if (!in_array(IEntity::class, $interfaces, true)) {
39+
return false;
40+
}
41+
42+
$property = $this->annotationsExtension->getProperty($classReflection, $propertyName);
43+
$propertyType = TypeCombinator::removeNull($property->getReadableType()); // remove null to be properly match subtype
44+
$dateTimeType = new ObjectType(\DateTimeImmutable::class);
45+
$hasDateTime = $dateTimeType->isSuperTypeOf($propertyType)->yes();
46+
47+
return $hasDateTime;
48+
}
49+
50+
51+
public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
52+
{
53+
$property = $this->annotationsExtension->getProperty($classReflection, $propertyName);
54+
return new AnnotationPropertyReflection(
55+
$property->getDeclaringClass(),
56+
$property->getReadableType(),
57+
TypeCombinator::union($property->getWritableType(), new StringType()),
58+
$property->isReadable(),
59+
$property->isWritable()
60+
);
61+
}
62+
}

tests/expected.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/testbox/Rules/Test.php:21:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $age (int) does not accept string.
22
/testbox/Rules/Test.php:22:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $description (string) does not accept int.
3-
/testbox/Rules/Test.php:23:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $createdAt (DateTimeImmutable) does not accept DateTime.
3+
/testbox/Rules/Test.php:23:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $createdAt (DateTimeImmutable|string) does not accept DateTime.
44
/testbox/Rules/Test.php:24:Entity NextrasTests\OrmPhpStan\Rules\Entity has no $foo property.
55
/testbox/Rules/Test.php:25:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $read is read-only.
66
/testbox/Rules/Test.php:26:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $age (int) does not accept string.
77
/testbox/Types/CollectionTypesTest.php:15:Parameter #1 $author of method NextrasTests\OrmPhpStan\Types\CollectionTypesTest::takeAuthor() expects NextrasTests\OrmPhpStan\Types\Author, NextrasTests\OrmPhpStan\Types\Author|null given.
88
/testbox/Types/CollectionTypesTest.php:16:Parameter #1 $author of method NextrasTests\OrmPhpStan\Types\CollectionTypesTest::takeAuthor() expects NextrasTests\OrmPhpStan\Types\Author, NextrasTests\OrmPhpStan\Types\Author|null given.
9+
/testbox/Types/DateTimePropertyTypesTest.php:9:Property NextrasTests\OrmPhpStan\Types\Book::$date (DateTimeImmutable|string|null) does not accept int.
910
/testbox/Types/RelationshipPropertyTypesTest.php:11:Parameter #1 $int of method NextrasTests\OrmPhpStan\Types\RelationshipPropertyTypesTest::takeInt() expects int, NextrasTests\OrmPhpStan\Types\Author given.
1011
/testbox/Types/RelationshipPropertyTypesTest.php:13:Parameter #1 $int of method NextrasTests\OrmPhpStan\Types\RelationshipPropertyTypesTest::takeInt() expects int, NextrasTests\OrmPhpStan\Types\Author given.
1112
/testbox/Types/RelationshipPropertyTypesTest.php:14:Property NextrasTests\OrmPhpStan\Types\Book::$author (int|NextrasTests\OrmPhpStan\Types\Author) does not accept NextrasTests\OrmPhpStan\Types\Book.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace NextrasTests\OrmPhpStan\Types;
4+
5+
class DateTimePropertyTypesTest
6+
{
7+
public function testError(Book $book): void
8+
{
9+
$book->date = 1;
10+
}
11+
12+
13+
public function testOk(Book $book): void
14+
{
15+
$book->date = 'now';
16+
$this->takeNullableDateTime($book->date);
17+
$book->date = null;
18+
}
19+
20+
21+
private function takeNullableDateTime(?\DateTimeImmutable $data): void
22+
{
23+
}
24+
}

tests/testbox/Types/fixtures/Book.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
/**
66
* @property Author $author {m:1 Author::$books}
7+
* @property \DateTimeImmutable|null $date
78
*/
89
class Book extends \Nextras\Orm\Entity\Entity
910
{

0 commit comments

Comments
 (0)