Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Serializer] Fix MissingConstructorArgumentsException returning missing argument one by one #49832

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion UPGRADE-6.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ Validator
Serializer
----------

* Deprecate `MissingConstructorArgumentsException` in favor of `MissingConstructorArgumentException`
* Deprecate `CacheableSupportsMethodInterface` in favor of the new `getSupportedTypes(?string $format)` methods
* The following Normalizer classes will become final in 7.0:
* `ConstraintViolationListNormalizer`
Expand Down
1 change: 0 additions & 1 deletion src/Symfony/Component/Serializer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ CHANGELOG
* Add `UnsupportedFormatException` which is thrown when there is no decoder for a given format
* Add method `getSupportedTypes(?string $format)` to `NormalizerInterface` and `DenormalizerInterface`
* Make `ProblemNormalizer` give details about `ValidationFailedException` and `PartialDenormalizationException`
* Deprecate `MissingConstructorArgumentsException` in favor of `MissingConstructorArgumentException`
* Deprecate `CacheableSupportsMethodInterface` in favor of the new `getSupportedTypes(?string $format)` methods
* The following Normalizer classes will become final in 7.0:
* `ConstraintViolationListNormalizer`
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,37 @@
namespace Symfony\Component\Serializer\Exception;

/**
* @deprecated since Symfony 6.3, use {@see MissingConstructorArgumentException} instead
*
* @author Maxime VEBER <[email protected]>
*/
class MissingConstructorArgumentsException extends RuntimeException
{
/**
* @var string[]
* @param string[] $missingArguments
* @param class-string|null $class
*/
private $missingArguments;

public function __construct(string $message, int $code = 0, \Throwable $previous = null, array $missingArguments = [])
{
if (!$this instanceof MissingConstructorArgumentException) {
trigger_deprecation('symfony/serializer', '6.3', 'The "%s" class is deprecated, use "%s" instead.', __CLASS__, MissingConstructorArgumentException::class);
}

$this->missingArguments = $missingArguments;

public function __construct(
string $message,
int $code = 0,
\Throwable $previous = null,
private array $missingArguments = [],
private ?string $class = null,
) {
parent::__construct($message, $code, $previous);
}

/**
* @deprecated since Symfony 6.3, use {@see MissingConstructorArgumentException::getMissingArgument()} instead
*
* @return string[]
*/
public function getMissingConstructorArguments(): array
{
trigger_deprecation('symfony/serializer', '6.3', 'The "%s()" method is deprecated, use "%s::getMissingArgument()" instead.', __METHOD__, MissingConstructorArgumentException::class);

return $this->missingArguments;
}

/**
* @return class-string|null
*/
public function getClass(): ?string
{
return $this->class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
Expand Down Expand Up @@ -313,7 +313,7 @@ protected function getConstructor(array &$data, string $class, array &$context,
* @return object
*
* @throws RuntimeException
* @throws MissingConstructorArgumentException
* @throws MissingConstructorArgumentsException
*/
protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null)
{
Expand All @@ -332,7 +332,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex
}

$constructorParameters = $constructor->getParameters();

$missingConstructorArguments = [];
$params = [];
foreach ($constructorParameters as $constructorParameter) {
$paramName = $constructorParameter->name;
Expand Down Expand Up @@ -386,7 +386,8 @@ protected function instantiateObject(array &$data, string $class, array &$contex
$params[] = null;
} else {
if (!isset($context['not_normalizable_value_exceptions'])) {
throw new MissingConstructorArgumentException($class, $constructorParameter->name);
$missingConstructorArguments[] = $constructorParameter->name;
continue;
}

$exception = NotNormalizableValueException::createForUnexpectedDataType(
Expand All @@ -402,19 +403,23 @@ protected function instantiateObject(array &$data, string $class, array &$contex
}
}

if ($constructor->isConstructor()) {
try {
return $reflectionClass->newInstanceArgs($params);
} catch (\TypeError $e) {
if (!isset($context['not_normalizable_value_exceptions'])) {
throw $e;
}
if ($missingConstructorArguments) {
throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments, $class);
}

return $reflectionClass->newInstanceWithoutConstructor();
}
} else {
if (!$constructor->isConstructor()) {
return $constructor->invokeArgs(null, $params);
}

try {
return $reflectionClass->newInstanceArgs($params);
} catch (\TypeError $e) {
if (!isset($context['not_normalizable_value_exceptions'])) {
throw $e;
}

return $reflectionClass->newInstanceWithoutConstructor();
}
}

return new $class();
Expand All @@ -438,7 +443,7 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara
}
} catch (\ReflectionException $e) {
throw new RuntimeException(sprintf('Could not determine the class of the parameter "%s".', $parameterName), 0, $e);
} catch (MissingConstructorArgumentException $e) {
} catch (MissingConstructorArgumentsException $e) {
if (!$parameter->getType()->allowsNull()) {
throw $e;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Exception\ExtraAttributesException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Mapping\AttributeMetadataInterface;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
Expand Down Expand Up @@ -419,15 +419,15 @@ abstract protected function setAttributeValue(object $object, string $attribute,
*
* @throws NotNormalizableValueException
* @throws ExtraAttributesException
* @throws MissingConstructorArgumentException
* @throws MissingConstructorArgumentsException
* @throws LogicException
*/
private function validateAndDenormalize(array $types, string $currentClass, string $attribute, mixed $data, ?string $format, array $context): mixed
{
$expectedTypes = [];
$isUnionType = \count($types) > 1;
$extraAttributesException = null;
$missingConstructorArgumentException = null;
$missingConstructorArgumentsException = null;
foreach ($types as $type) {
if (null === $data && $type->isNullable()) {
return null;
Expand Down Expand Up @@ -567,21 +567,21 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
}

$extraAttributesException ??= $e;
} catch (MissingConstructorArgumentException $e) {
} catch (MissingConstructorArgumentsException $e) {
if (!$isUnionType) {
throw $e;
}

$missingConstructorArgumentException ??= $e;
$missingConstructorArgumentsException ??= $e;
}
}

if ($extraAttributesException) {
throw $extraAttributesException;
}

if ($missingConstructorArgumentException) {
throw $missingConstructorArgumentException;
if ($missingConstructorArgumentsException) {
throw $missingConstructorArgumentsException;
}

if ($context[self::DISABLE_TYPE_ENFORCEMENT] ?? $this->defaultContext[self::DISABLE_TYPE_ENFORCEMENT] ?? false) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Symfony\Component\Serializer\Tests\Normalizer\Features;

use Symfony\Component\Serializer\Exception\MissingConstructorArgumentException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Tests\Fixtures\NotSerializedConstructorArgumentDummy;

Expand Down Expand Up @@ -62,14 +62,13 @@ public function testConstructorWithMissingData()
];

$normalizer = $this->getDenormalizerForConstructArguments();

try {
$normalizer->denormalize($data, ConstructorArgumentsObject::class);
self::fail(sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentException::class));
} catch (MissingConstructorArgumentException $e) {
self::assertSame(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires parameter "bar" to be present.', ConstructorArgumentsObject::class), $e->getMessage());
self::fail(sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentsException::class));
} catch (MissingConstructorArgumentsException $e) {
self::assertSame(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$bar", "$baz".', ConstructorArgumentsObject::class), $e->getMessage());
self::assertSame(ConstructorArgumentsObject::class, $e->getClass());
self::assertSame('bar', $e->getMissingArgument());
self::assertSame(['bar', 'baz'], $e->getMissingConstructorArguments());
}
}
}