diff --git a/src/Exceptions/CannotCreateData.php b/src/Exceptions/CannotCreateData.php index 11a2d2c0..b867f224 100644 --- a/src/Exceptions/CannotCreateData.php +++ b/src/Exceptions/CannotCreateData.php @@ -24,7 +24,6 @@ public static function noNormalizerFound(string $dataClass, mixed $value): self public static function constructorMissingParameters( DataClass $dataClass, array $parameters, - Throwable $previous, ): self { $parameters = collect($parameters); @@ -42,6 +41,6 @@ public static function constructorMissingParameters( ->map(fn (DataProperty|DataParameter $parameter) => $parameter->name) ->join(', ')}."; - return new self($message, previous: $previous); + return new self($message); } } diff --git a/src/Resolvers/DataFromArrayResolver.php b/src/Resolvers/DataFromArrayResolver.php index 825ded0c..0a241ff4 100644 --- a/src/Resolvers/DataFromArrayResolver.php +++ b/src/Resolvers/DataFromArrayResolver.php @@ -9,6 +9,8 @@ use Spatie\LaravelData\Optional; use Spatie\LaravelData\Support\DataClass; use Spatie\LaravelData\Support\DataConfig; +use Spatie\LaravelData\Support\DataParameter; +use Spatie\LaravelData\Support\DataProperty; /** * @template TData of BaseData @@ -91,14 +93,24 @@ protected function createData( } } - try { - return new $dataClass->name(...$parameters); - } catch (ArgumentCountError $error) { + if ($this->isAnyParameterMissing($dataClass, array_keys($parameters))) { throw CannotCreateData::constructorMissingParameters( $dataClass, $parameters, - $error ); } + + return new $dataClass->name(...$parameters); + } + + protected function isAnyParameterMissing(DataClass $dataClass, array $parameters): bool + { + return $dataClass + ->constructorMethod + ->parameters + ->filter(fn (DataParameter|DataProperty $parameter) => ! $parameter->hasDefaultValue) + ->pluck('name') + ->diff($parameters) + ->isNotEmpty(); } } diff --git a/tests/CreationTest.php b/tests/CreationTest.php index d8bc3c55..9768577e 100644 --- a/tests/CreationTest.php +++ b/tests/CreationTest.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Validation\ValidationException; +use Spatie\LaravelData\Tests\Fakes\DataWithArgumentCountErrorException; use function Pest\Laravel\postJson; use Spatie\LaravelData\Attributes\Computed; @@ -751,6 +752,18 @@ public function __construct( yield 'one param' => [['first' => 'First'], 'Could not create `Spatie\LaravelData\Tests\Fakes\MultiData`: the constructor requires 2 parameters, 1 given. Parameters given: first. Parameters missing: second.'], ]); +it('throws a readable exception message when the ArgumentCountError exception is thrown in the constructor', function () { + try { + DataWithArgumentCountErrorException::from(['string' => 'string']); + } catch (ArgumentCountError $e) { + expect($e->getMessage())->toBe('This function expects exactly 2 arguments, 1 given.'); + expect($e->getFile())->toContain('/tests/Fakes/DataWithArgumentCountErrorException.php'); + expect($e->getLine())->toBe(14); + + return; + } +}); + it('throws a readable exception message when the constructor of a nested data object fails', function () { expect(fn () => NestedData::from([ 'simple' => [], diff --git a/tests/Fakes/DataWithArgumentCountErrorException.php b/tests/Fakes/DataWithArgumentCountErrorException.php new file mode 100644 index 00000000..5cd8fdd0 --- /dev/null +++ b/tests/Fakes/DataWithArgumentCountErrorException.php @@ -0,0 +1,16 @@ +