Skip to content

Commit

Permalink
added RelationshipReturnTypeExtension
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Jul 28, 2018
1 parent 72be78a commit 896cc93
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 0 deletions.
4 changes: 4 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ services:
class: Nextras\OrmPhpStan\Types\CollectionReturnTypeExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
-
class: Nextras\OrmPhpStan\Types\RelationshipReturnTypeExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension
-
class: Nextras\OrmPhpStan\Types\RepositoryReturnTypeExtension
tags:
Expand Down
52 changes: 52 additions & 0 deletions src/Types/RelationshipReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php declare(strict_types = 1);

namespace Nextras\OrmPhpStan\Types;

use Nextras\Orm\Collection\ICollection;
use Nextras\Orm\Relationships\HasMany;
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\IntersectionType;
use PHPStan\Type\IterableType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;


class RelationshipReturnTypeExtension implements DynamicMethodReturnTypeExtension
{
public function getClass(): string
{
return HasMany::class;
}


public function isMethodSupported(MethodReflection $methodReflection): bool
{
return $methodReflection->getName() === 'get';
}


public function getTypeFromMethodCall(
MethodReflection $methodReflection,
MethodCall $methodCall,
Scope $scope
): Type
{
$varType = $scope->getType($methodCall->var);

if ($varType instanceof IntersectionType) {
foreach ($varType->getTypes() as $type) {
if ($type instanceof IterableType) {
$collectionType = new ObjectType(ICollection::class);
return TypeCombinator::intersect($type, $collectionType);
}
}
}

return ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();
}
}
1 change: 1 addition & 0 deletions tests/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
/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/RelationshipTypesTest.php:10:Parameter #1 $book of method NextrasTests\OrmPhpStan\Types\RelationshipTypesTest::takeBook() expects NextrasTests\OrmPhpStan\Types\Book, NextrasTests\OrmPhpStan\Types\Book|null given.
/testbox/Types/RepositoryTypesTest.php:9:Parameter #1 $author of method NextrasTests\OrmPhpStan\Types\RepositoryTypesTest::takeAuthor() expects NextrasTests\OrmPhpStan\Types\Author, NextrasTests\OrmPhpStan\Types\Author|null given.
/testbox/Types/RepositoryTypesTest.php:10:Parameter #1 $author of method NextrasTests\OrmPhpStan\Types\RepositoryTypesTest::takeAuthor() expects NextrasTests\OrmPhpStan\Types\Author, NextrasTests\OrmPhpStan\Types\Author|null given.
29 changes: 29 additions & 0 deletions tests/testbox/Types/RelationshipTypesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types = 1);

namespace NextrasTests\OrmPhpStan\Types;


class RelationshipTypesTest
{
public function testError(Author $author)
{
$this->takeBook($author->books->get()->fetch());
}


public function testOk(Author $author)
{
$this->takeBookNullable($author->books->get()->fetch());
$this->takeBookNullable($author->books->get()->findBy([])->fetch());
}


private function takeBook(Book $book)
{
}


private function takeBookNullable(?Book $book)
{
}
}
4 changes: 4 additions & 0 deletions tests/testbox/Types/fixtures/Author.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

namespace NextrasTests\OrmPhpStan\Types;

use Nextras\Orm\Relationships\OneHasMany;


/**
* @property Book[]|OneHasMany $books {1:m Book::$author}
*/
class Author extends \Nextras\Orm\Entity\Entity
{
Expand Down
9 changes: 9 additions & 0 deletions tests/testbox/Types/fixtures/Book.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php declare(strict_types = 1);

namespace NextrasTests\OrmPhpStan\Types;

/**
*/
class Book extends \Nextras\Orm\Entity\Entity
{
}

0 comments on commit 896cc93

Please sign in to comment.