Skip to content

Commit

Permalink
support writing string to DateTimeImmutable properties [closes #8]
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Apr 9, 2021
1 parent 2602358 commit ad59e93
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 1 deletion.
4 changes: 4 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ services:
class: Nextras\OrmPhpStan\Reflection\EntityRelationshipPropertyReflectionExtension
tags:
- phpstan.broker.propertiesClassReflectionExtension
-
class: Nextras\OrmPhpStan\Reflection\EntityDateTimePropertyReflectionExtension
tags:
- phpstan.broker.propertiesClassReflectionExtension
-
class: Nextras\OrmPhpStan\Rules\SetValueMethodRule
tags:
Expand Down
62 changes: 62 additions & 0 deletions src/Reflection/EntityDateTimePropertyReflectionExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php declare(strict_types = 1);

namespace Nextras\OrmPhpStan\Reflection;

use Nextras\Orm\Entity\IEntity;
use Nextras\OrmPhpStan\Reflection\Annotations\AnnotationPropertyReflection;
use PHPStan\Reflection\Annotations\AnnotationsPropertiesClassReflectionExtension;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Type\ObjectType;
use PHPStan\Type\StringType;
use PHPStan\Type\TypeCombinator;


class EntityDateTimePropertyReflectionExtension implements PropertiesClassReflectionExtension
{
/** @var AnnotationsPropertiesClassReflectionExtension */
private $annotationsExtension;


public function __construct(AnnotationsPropertiesClassReflectionExtension $annotationsExtension)
{
$this->annotationsExtension = $annotationsExtension;
}


public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
{
$hasProperty = $this->annotationsExtension->hasProperty($classReflection, $propertyName);
if (!$hasProperty) {
return false;
}

$interfaces = array_map(function (ClassReflection $interface) {
return $interface->getName();
}, $classReflection->getInterfaces());
if (!in_array(IEntity::class, $interfaces, true)) {
return false;
}

$property = $this->annotationsExtension->getProperty($classReflection, $propertyName);
$propertyType = TypeCombinator::removeNull($property->getReadableType()); // remove null to be properly match subtype
$dateTimeType = new ObjectType(\DateTimeImmutable::class);
$hasDateTime = $dateTimeType->isSuperTypeOf($propertyType)->yes();

return $hasDateTime;
}


public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
{
$property = $this->annotationsExtension->getProperty($classReflection, $propertyName);
return new AnnotationPropertyReflection(
$property->getDeclaringClass(),
$property->getReadableType(),
TypeCombinator::union($property->getWritableType(), new StringType()),
$property->isReadable(),
$property->isWritable()
);
}
}
3 changes: 2 additions & 1 deletion tests/expected.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/testbox/Rules/Test.php:21:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $age (int) does not accept string.
/testbox/Rules/Test.php:22:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $description (string) does not accept int.
/testbox/Rules/Test.php:23:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $createdAt (DateTimeImmutable) does not accept DateTime.
/testbox/Rules/Test.php:23:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $createdAt (DateTimeImmutable|string) does not accept DateTime.
/testbox/Rules/Test.php:24:Entity NextrasTests\OrmPhpStan\Rules\Entity has no $foo property.
/testbox/Rules/Test.php:25:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $read is read-only.
/testbox/Rules/Test.php:26:Entity NextrasTests\OrmPhpStan\Rules\Entity: property $age (int) does not accept string.
/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.
/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.
/testbox/Types/DateTimePropertyTypesTest.php:9:Property NextrasTests\OrmPhpStan\Types\Book::$date (DateTimeImmutable|string|null) does not accept int.
/testbox/Types/RelationshipPropertyTypesTest.php:11:Parameter #1 $int of method NextrasTests\OrmPhpStan\Types\RelationshipPropertyTypesTest::takeInt() expects int, NextrasTests\OrmPhpStan\Types\Author given.
/testbox/Types/RelationshipPropertyTypesTest.php:13:Parameter #1 $int of method NextrasTests\OrmPhpStan\Types\RelationshipPropertyTypesTest::takeInt() expects int, NextrasTests\OrmPhpStan\Types\Author given.
/testbox/Types/RelationshipPropertyTypesTest.php:14:Property NextrasTests\OrmPhpStan\Types\Book::$author (int|NextrasTests\OrmPhpStan\Types\Author) does not accept NextrasTests\OrmPhpStan\Types\Book.
Expand Down
24 changes: 24 additions & 0 deletions tests/testbox/Types/DateTimePropertyTypesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types = 1);

namespace NextrasTests\OrmPhpStan\Types;

class DateTimePropertyTypesTest
{
public function testError(Book $book): void
{
$book->date = 1;
}


public function testOk(Book $book): void
{
$book->date = 'now';
$this->takeNullableDateTime($book->date);
$book->date = null;
}


private function takeNullableDateTime(?\DateTimeImmutable $data): void
{
}
}
1 change: 1 addition & 0 deletions tests/testbox/Types/fixtures/Book.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

/**
* @property Author $author {m:1 Author::$books}
* @property \DateTimeImmutable|null $date
*/
class Book extends \Nextras\Orm\Entity\Entity
{
Expand Down

0 comments on commit ad59e93

Please sign in to comment.