-
-
Notifications
You must be signed in to change notification settings - Fork 211
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
Point to the right problem on ArgumentCountError exception #884
base: main
Are you sure you want to change the base?
Conversation
…own in the constructor
You could also just check the trace of the exception and run some reflection in the catch to decide wether to throw the original error or not https://onlinephp.io?s=zZBBS8NAEIXPDeQ_jBCaDVTqOTVKWnvUg3grpaybSVNJdsNkYi3S_-5mY0t68STispfdee_xzbu9r4va96ZTWGpGgoNpCZTJEAoknADqN3O48j1VyqaBFD59b5S3WvHOaNhslNENU6tYBHICwWvkBEffs_dkmgN-MOrsR3tvHNWSUHMcX4xmg0jfYzo4rcY9pG54BCVZFSBS2raV9S9Mq3lJZAgC7JMDJqkQEvtxfbdFfumeIlrdrLv0XQ6iV6zCE164hiRJIByghDAew0nnlvsWiQ7mGfMSnfURuTCZSOPYiSaXIVHkCB7QDmmnt4tOI_rPJ1lZqh4Z7HmXtMnaqhZ2D1cDYNlg3xUXZPZ2n2E9w3Lm_7qc-d-X43tnx28zzb4A&v=8.3.8%2C8.2.20%2C8.1.29 Because right now the |
try { | ||
return new $dataClass->name(...$parameters); | ||
} catch (ArgumentCountError $error) { | ||
if ($this->isAnyParameterMissing($dataClass, array_keys($parameters))) { |
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.
if ($this->isAnyParameterMissing($dataClass, array_keys($parameters))) { | |
try { | |
return new $dataClass->name(...$parameters); | |
} catch (ArgumentCountError $error) { | |
$trace = current($error->getTrace()); | |
if ($trace && $trace['function'] === '__construct' && $trace['class'] === (new \ReflectionMethod($dataClass->name, '__construct'))->getDeclaringClass()->getName()) { | |
throw CannotCreateData::constructorMissingParameters( | |
$dataClass, | |
$parameters, | |
$error | |
); | |
} else { | |
throw $error; | |
} | |
} |
@Tofandel That was my first idea, to check the trace. But this approach looked cleaner. But yeah, I didn't take optional or variadic parameters into account. I'll take a look. Thanks for the review 👍 |
@Tofandel Optional parameters should work actually. Hence all optinal parameters have a default value and they are present in As for variadic parameters, I really couldn't figure out how would it create problems? Can you please show me an example? On the other hand if you're really against this approach, I could check the trace and rethrow the exception. |
That is only the case for non promoted parameters, promoted parameters do not appear in the array, according to the code, this would cause issues and throw exception where it was not previousy throwing (can you check your new test case? It should definitely not pass) Same for variadic parameters which are ALWAYS optional You would need to filter out optional and variadic params before plucking the name and diffing, but the DataParameter does not contain the isVariadic (or isOptional) information |
return $dataClass | ||
->constructorMethod | ||
->parameters | ||
->pluck('name') |
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.
->pluck('name') | |
->filter(fn (\Spatie\LaravelData\Support\DataParameter $p) => !$parameter->hasDefaultValue) | |
->pluck('name') |
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.
Wouldn't this filter out required parameters as well, which do not have a default value?
It would keep only parameters without default values aka required ones, though there is one obscure area, is if you have a default value before a required param (which normally emits a warning)
Which is why filtering on is optional would provide the perfect solution, as it would work with variadic parameters, but it would need to be added to the DataParameter class and factory..
Or a new Reflection needs to be made on the spot
@Tofandel Wow, needed some time to wrap my head around this :) Sorry for the late reply.
I can now see the confusion. They do appear. They are passed to
I did run my test case, and it passed. I think that the optional parameters are covered. In the example you provided, promoted parameter was private, that's why it didn't show up in Variadic parameter on the other hand is a problem. As you stated, they are always optional, and if not supplied, they are not present in the
Wouldn't this filter out required parameters as well, which do not have a default value? Having all this in mind I think I'll have to switch back to checking the stack trace. Great catch btw 👍 |
So I switched back to checking the trace, but it's not that straightforward either.
As you can see, they are basically identical. So the only Idea I have is to check the exceptions message. But that feels kind of hacky. I'll push those changes, please tell me what do you think. |
I think it does not need to be 100% foolproof to the exact same exception thrown in the body of the same function, because in real life it will happen somewhere else or on another function, because in the end it's just exception wrapping meant for debugging. I do wonder if maybe the laravel utils just don't provide a way out of the box to check the parameters of a class (but it might have the side effects of adding dependency injection to the constructor, which is not necessarily a bad thing) |
@Tofandel I reverted the code back to check the parameters and added the filtering you suggested. Is this what you meant? Tests are passing for me locally |
@Tofandel just checking if the PR is still alive :) |
@@ -42,6 +41,6 @@ public static function constructorMissingParameters( | |||
->map(fn (DataProperty|DataParameter $parameter) => $parameter->name) | |||
->join(', ')}."; | |||
|
|||
return new self($message, previous: $previous); |
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.
Looks good to me, except this deletion
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.
Previously ArgumentCountError
was thrown, but now hence we do the checks based on the data class properties, I had to remove that because there is no previous error.
Fixes #882