-
-
Notifications
You must be signed in to change notification settings - Fork 959
Description
Description
AbstractItemNormalizer::instantiateObject throws MissingConstructorArgumentsException for nullable constructor parameters that don't have an explicit default value (= null), even when the parameter type allows null.
Symfony's base AbstractNormalizer::instantiateObject handles this case at line 390:
} elseif (!($context[self::REQUIRE_ALL_PROPERTIES] ?? $this->defaultContext[self::REQUIRE_ALL_PROPERTIES] ?? false) && $constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) {
$params[$paramName] = null;
}However, API Platform's AbstractItemNormalizer overrides instantiateObject and only checks isDefaultValueAvailable(), missing the nullable fallback:
} elseif ($constructorParameter->isDefaultValueAvailable()) {
$params[] = $constructorParameter->getDefaultValue();
} else {
// throws MissingConstructorArgumentsException or collects error
}How to reproduce
Given a DTO/command class used as API Platform input:
final readonly class RequestActivity
{
public function __construct(
public ActivityId $activityId,
public ?Timeslot $timeslot, // nullable, no default
) {}
}Sending a POST request without the timeslot key in the JSON body results in:
MissingConstructorArgumentsException: Cannot create an instance of
"RequestActivity" from serialized data because its constructor requires
the following parameters to be present : "$timeslot".
Expected behaviour
The serializer should pass null for nullable constructor parameters when the data is missing, consistent with Symfony's AbstractNormalizer behaviour. The workaround is adding = null explicitly, but the serializer should respect ?Type without requiring it.
Versions
- API Platform: 4.2.20
- Symfony Serializer: 8.0.7
- PHP: 8.3+