Skip to content

Commit

Permalink
fix: corrected return type of MorphToMany methods (larastan#699)
Browse files Browse the repository at this point in the history
  • Loading branch information
canvural authored Oct 24, 2020
1 parent 80089ff commit 529c6cc
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
2 changes: 1 addition & 1 deletion extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ services:
- phpstan.broker.dynamicMethodReturnTypeExtension

-
class: NunoMaduro\Larastan\ReturnTypes\RelationExtension
class: NunoMaduro\Larastan\ReturnTypes\RelationCollectionExtension
tags:
- phpstan.broker.dynamicMethodReturnTypeExtension

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PhpParser\Node\Expr\MethodCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\Generic\GenericObjectType;
use PHPStan\Type\ObjectType;
Expand All @@ -19,7 +20,7 @@
/**
* @internal
*/
final class RelationExtension implements DynamicMethodReturnTypeExtension
final class RelationCollectionExtension implements DynamicMethodReturnTypeExtension
{
/** @var BuilderHelper */
private $builderHelper;
Expand Down Expand Up @@ -52,6 +53,12 @@ public function isMethodSupported(MethodReflection $methodReflection): bool
return false;
}

$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if (! in_array(Collection::class, $returnType->getReferencedClasses(), true)) {
return false;
}

return $methodReflection->getDeclaringClass()->hasNativeMethod($methodReflection->getName());
}

Expand All @@ -66,7 +73,7 @@ public function getTypeFromMethodCall(
/** @var ObjectType $modelType */
$modelType = $methodReflection->getDeclaringClass()->getActiveTemplateTypeMap()->getType('TRelatedModel');

$returnType = $methodReflection->getVariants()[0]->getReturnType();
$returnType = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType();

if (in_array(Collection::class, $returnType->getReferencedClasses(), true)) {
$collectionClassName = $this->builderHelper->determineCollectionClassName($modelType->getClassname());
Expand Down
51 changes: 31 additions & 20 deletions tests/Features/Models/Relations.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

class Relations
{
Expand Down Expand Up @@ -186,6 +187,22 @@ public function testWithoutTrashedWithBelongsToRelation(User $user): BelongsTo
{
return $user->group()->withoutTrashed();
}

/**
* @phpstan-return MorphToMany<Address>
*/
public function testMorphToManyWithTimestamps(Tag $tag): MorphToMany
{
return $tag->addresses();
}

/**
* @phpstan-return MorphToMany<Address>
*/
public function testMorphToManyWithPivot(Tag $tag): MorphToMany
{
return $tag->addresses();
}
}

/**
Expand All @@ -210,33 +227,27 @@ public function relation(): HasMany
{
return $this->hasMany(User::class);
}

public function addRelation(): User
{
return $this->relation()->create([]);
}
}

class TestRelationCreateOnExistingModel
class Tag extends Model
{
/** @var User */
private $user;

public function testRelationCreateOnExistingModel(): Account
/**
* @phpstan-return MorphToMany<Address>
*/
public function addresses(): MorphToMany
{
return $this->user->accounts()->create();
return $this->morphToMany(Address::class, 'taggable')->withTimestamps();
}
}

class Post extends Model
{
public function author(): BelongsTo
/**
* @phpstan-return MorphToMany<Address>
*/
public function addressesWithPivot(): MorphToMany
{
return $this->belongsTo(User::class);
return $this->morphToMany(Address::class, 'taggable')->withPivot('foo');
}
}

public function addUser(User $user): self
{
return $this->author()->associate($user);
}
class Address extends Model
{
}

0 comments on commit 529c6cc

Please sign in to comment.