New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(refactor): ModelProperty casting #1333
Conversation
bef7645
to
60bab86
Compare
@erikgaal Thank you for your contribution! What does |
Hi there! It stands for |
Thank you! (🚊 typo 🚊) |
Thank you for the work here. Just FYI I'm currently on holiday and not available to review until 20th September. |
@canvural Hope you had a great holiday! Would you be available to review this PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I added some comments.
Please also add tests for the cast types that do not have any tests. Like immutable_date
You can do it by adding adding the casts to any model in the Application
folder, and then add a new file to https://github.com/nunomaduro/larastan/blob/4bb0df1aee0d0b8485855f068693688c6f7ae7db/tests/Type/GeneralTypeTest.php and test with assertType
src/Properties/ModelCastHelper.php
Outdated
$attributeType = match ($cast) { | ||
'int', 'integer' => new IntegerType(), | ||
'real', 'float', 'double' => new FloatType(), | ||
'decimal' => new AccessoryNumericStringType(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessory types cannot be used standalone. You need to do TypeCombinator::intersect(new StringType(), new AccessoryNumericStringType())
here
return true; | ||
private function migrationsLoaded(): bool | ||
{ | ||
return ! empty($this->tables); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use count
instead of empty
if (! (new ObjectType(Attribute::class))->isSuperTypeOf($returnType)->yes()) { | ||
return false; | ||
} | ||
|
||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can simplify it to return (new ObjectType(Attribute::class))->isSuperTypeOf($returnType)->yes()
src/Properties/ModelCastHelper.php
Outdated
'string' => new StringType(), | ||
'bool', 'boolean' => TypeCombinator::union(new BooleanType(), new ConstantIntegerType(0), new ConstantIntegerType(1)), | ||
'object' => new ObjectType('stdClass'), | ||
'array', 'json' => new ArrayType(new MixedType(), new MixedType()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do better than mixed
for the array key here. Try new BenevolentUnionType([new IntegerType(), new StringType()])
{ | ||
$propertyNameStudlyCase = Str::studly($propertyName); | ||
|
||
if ($classReflection->hasNativeMethod("get{$propertyNameStudlyCase}Attribute")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use sprintf
here instead.
declaringClass: $classReflection, | ||
readableType: $this->stringResolver->resolve($modelInstance->getKeyType()), | ||
writableType: $this->stringResolver->resolve($modelInstance->getKeyType()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use named arguments.
cast: $cast, | ||
originalType: $this->stringResolver->resolve($column->readableType), | ||
); | ||
$writeableType = $this->modelCastHelper->getWriteableType( | ||
cast: $cast, | ||
originalType: $this->stringResolver->resolve($column->writeableType), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use named arguments.
declaringClass: $classReflection, | ||
readableType: $readableType, | ||
writableType: $writeableType, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use named arguments.
6e390bd
to
325d2f3
Compare
2c4c18a
to
3611020
Compare
Hi @canvural! Sorry for taking so long to continue, but I've implemented most of your comments. Please also advise what to do with Kind regards, |
Thank you! |
I was just thinking back about this PR and that I noted no breaking changes. However, that's not entirely true. If developers were relying on the old behaviour that typed |
@erikgaal That's fine. More precise types leading to errors is acceptable. It's also in PHPStan's BC promise page: https://phpstan.org/user-guide/backward-compatibility-promise#type-inference-capabilities Just FYI: this PR discovered an issue. https://github.com/nunomaduro/larastan/blob/master/src/Properties/SchemaAggregator.php#L368 this now leads to a object with |
Ah it didn't discover an error. It broke it 😅 In the latest release |
Reason is that https://github.com/nunomaduro/larastan/blob/2.2.9/src/Properties/ModelPropertyExtension.php#L190-L222 this code was removed. |
Fixes #890
Changes
Adds better support for casting using
CastsAttributes
,CastsInboundAttributes
andCastable
. Also refactored theModelPropertyExtension
and extracted aModelCastHelper
that can convert Eloquent casts to PHPStan types.Breaking changes