Repository navigation
Conversation
Reading a hasOne, belongsTo, morphOne, or hasOneThrough relationship as a property gave the related model, although the related row may not exist and the property is then null. Laravel declares these relations with a nullable result (BelongsTo extends Relation<TRelatedModel, TDeclaringModel, ?TRelatedModel>), and Larastan types the property from that result. The property is now ?Related, as the comment on build_property_type already said.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Types singular relationship properties as nullable. Reading a
hasOne,belongsTo,morphOne, orhasOneThroughrelationship as a property, such as$post->author, gaveAuthor. When the related row does not exist the property isnull, so it is now?Author.This matches how the framework and Larastan type it:
BelongsTois@extends Relation<TRelatedModel, TDeclaringModel, ?TRelatedModel>, andHasOne,MorphOne, andHasOneThroughpass?TRelatedModelthe same way.ModelRelationsExtensionreads the property type from thatTResult, so PHPStan already sees?Author.build_property_typealready said singular relationships are nullable; the code returned the bare type.It also matters because the Laravel model provider outranks
@propertytags, so a model whose docblock says@property-read null|Author $authorstill gotAuthor.Behaviour change to be aware of: code that reads straight through a relation, such as
$post->author->name, or passes$post->authorto a parameter typedAuthor, can now get the nullable reports that a?Authorfrom any other source already gets.Why not use the foreign key column's nullability: PHPantom reads the schema, so a
belongsTowhose key isNOT NULLcould in principle stay non-null. I left that out because a non-null key does not guarantee the related row loads: the related model may be soft-deleted or filtered out by a global scope, and without a foreign key constraint the row may simply be gone. ForhasOne,morphOne, andhasOneThroughthe key lives on the other table. Larastan has the same schema information and does not narrow here either. Happy to add the narrowing forbelongsTo+NOT NULLkey if you want it.Checks
cargo test: all pass, with the four unit tests that asserted the non-null type updatedcargo clippy --all-targets -- -D warningsandcargo fmt --check: cleanphpantom_lsp analyze --project-root examples/laravel: exactly the 4 expected errorsphp examples/laravel/assertions.php: all 369 assertions passChecklist
CHANGELOG.mdREADME.md,docs/,examples/)config-schema.json)the changes and why they are needed.
the changelog, and other user-facing content, and removed or corrected
anything inaccurate, unclear, or unnecessary.