Feature: Eloquent Relation Types Illuminate\Database\Eloquent\Relations have type support Background: Given I have the following config """ """ And I have the following code preamble """ */ public function getPhoneRelationship(User $user): HasOne { return $user->phone(); } /** * @psalm-return BelongsTo */ public function getUserRelationship(Phone $phone): BelongsTo { return $phone->user(); } } """ When I run Psalm Then I see no errors Scenario: Models can declare one to many relationships Given I have the following code """ final class Repository { /** * @psalm-return BelongsTo */ public function getPostRelationship(Comment $comment): BelongsTo { return $comment->post(); } /** * @psalm-return HasMany */ public function getCommentsRelationship(Post $post): HasMany { return $post->comments(); } } """ When I run Psalm Then I see no errors Scenario: Models can declare many to many relationships Given I have the following code """ final class Repository { /** * @psalm-return BelongsToMany */ public function getRolesRelationship(User $user): BelongsToMany { return $user->roles(); } /** * @psalm-return BelongsToMany */ public function getUserRelationship(Role $role): BelongsToMany { return $role->users(); } } """ When I run Psalm Then I see no errors Scenario: Models can declare has through relationships Given I have the following code """ final class Repository { /** * @psalm-return HasManyThrough */ public function getCarsAtMechanicRelationship(User $user): HasManyThrough { return $user->carsAtMechanic(); } /** * @psalm-return HasOneThrough */ public function getCarsOwner(Mechanic $mechanic): HasOneThrough { return $mechanic->carOwner(); } } """ When I run Psalm Then I see no errors Scenario: Models can declare polymorphic relationships Given I have the following code """ final class Repository { public function getPostsImageDynamicProperty(Post $post): Image { return $post->image; } /** * @todo: support for morphTo dynamic property * @psalm-return mixed */ public function getImageableProperty(Image $image) { return $image->imageable; } /** * @todo: better support for morphTo relationships * @psalm-return MorphTo */ public function getImageableRelationship(Image $image): MorphTo { return $image->imageable(); } } """ When I run Psalm Then I see no errors Scenario: Models can declare one to many polymorphic relationships Given I have the following code """ final class Repository { /** * @psalm-return MorphMany */ public function getCommentsRelation(Video $video): MorphMany { return $video->comments(); } /** * @psalm-return Collection */ public function getComments(Video $video): Collection { return $video->comments; } } """ When I run Psalm Then I see no errors Scenario: Models can declare many to many polymorphic relationships Given I have the following code """ final class Repository { /** * @psalm-return MorphToMany */ public function getTagsRelation(Post $post): MorphToMany { return $post->tags(); } /** * @psalm-return Collection */ public function getTags(Post $post): Collection { return $post->tags; } } """ When I run Psalm Then I see no errors Scenario: Polymorphic models can retrieve their inverse relation Given I have the following code """ final class Repository { /** * todo: this should be a union of possible types... * @psalm-return mixed */ public function getCommentable(Comment $comment) { return $comment->commentable; } } """ When I run Psalm Then I see no errors Scenario: Relationships can be accessed via a property Given I have the following code """ function testGetPhone(User $user): Phone { return $user->phone; } function testGetUser(Phone $phone): User { return $phone->user; } """ When I run Psalm Then I see no errors Scenario: Relationships can be filtered via dynamic property Given I have the following code """ function testFilterRelationshipFromDynamicProperty(User $user): Phone { return $user->phone->where('active', 1)->firstOrFail(); } """ When I run Psalm Then I see no errors Scenario: Relationships can be further constrained via method Given I have the following code """ function testFilterRelationshipFromMethod(User $user): Phone { return $user->phone()->where('active', 1)->firstOrFail(); } """ When I run Psalm Then I see no errors Scenario: Relationships return themselves when the underlying method returns a builder Given I have the following code """ /** * @param HasOne $relationship * @psalm-return HasOne */ function testRelationshipsReturnThemselvesInsteadOfBuilders(HasOne $relationship): HasOne { return $relationship->where('active', 1); } /** * @psalm-return BelongsTo */ function testAnother(Phone $phone): BelongsTo { return $phone->user()->where('active', 1); } """ When I run Psalm Then I see no errors Scenario: Relationships return themselves when the proxied method is a query builder method Given I have the following code """ /** * @param HasOne $relationship * @psalm-return HasOne */ function test(HasOne $relationship): HasOne { return $relationship->orderBy('id', 'ASC'); } """ When I run Psalm Then I see no errors