Description
API Platform version(s) affected: main
Description
When PropertySchemaCollectionRestriction
attempts to generate the restrictions for the sub-graph, it passes incorrect property metadata.
How to reproduce
Given a validation rule like this:
<property name="someArray">
<constraint name="Collection">
<option name="fields">
<value key="someField">
<constraint name="Optional">
<constraint name="Length">
<option name="min">5</option>
</constraint>
</constraint>
</value>
</option>
</constraint>
</property>
This would be the expected OpenAPI schema:
"Schema": {
"type": "object",
"properties": {
"someArray": {
"type": "object",
"properties": {
"someField": {
"minLength": 5
},
},
"additionalProperties": false,
"items": {
"type": "string"
}
}
}
}
Instead this is the schema generated:
"Schema": {
"type": "object",
"properties": {
"someArray": {
"type": "object",
"properties": {
"someField": [],
},
"additionalProperties": false,
"items": {
"type": "string"
}
}
}
}
This is a) invalid because of the empty array but that one is filed with #5413 but b) it misses the length restriction because of this check in PropertySchemaLengthRestriction::supports()
:
public function supports(Constraint $constraint, ApiProperty $propertyMetadata): bool
{
return $constraint instanceof Length && null !== ($type = $propertyMetadata->getBuiltinTypes()[0] ?? null) && Type::BUILTIN_TYPE_STRING === $type->getBuiltinType();
}
… in combination with PropertySchemaCollectionRestriction::mergeConstraintRestrictions()
:
private function mergeConstraintRestrictions(Required|Optional $constraint, ApiProperty $propertyMetadata): array
{
$propertyRestrictions = [];
$nestedConstraints = $constraint->constraints;
foreach ($nestedConstraints as $nestedConstraint) {
foreach ($this->restrictionsMetadata as $restrictionMetadata) {
if ($restrictionMetadata->supports($nestedConstraint, $propertyMetadata) && !empty($nestedConstraintRestriction = $restrictionMetadata->create($nestedConstraint, $propertyMetadata))) {
$propertyRestrictions[] = $nestedConstraintRestriction;
}
}
}
return array_merge([], ...$propertyRestrictions);
}
In mergeConstraintRestrictions
$propertyMetadata
is the property metadata of the container element (the array) and not the sub-element.
Since it’s an array, the sub elements are fundamentally unknowable. My hunch is, that the restriction implementations should not check at all for matching types and just assume that the validation rules are operating on the right type.