Skip to content

PUT operation does not work as intended with multiple URI variables #7819

@Kyzegs

Description

@Kyzegs

API Platform version(s) affected: 4.2.12

Description
A PUT operation with multiple URI variables does not seem to work in any way.

How to reproduce

Imagine the following API resource:

#[ApiResource(
    shortName: 'Device',
    operations: [
        new Put(
            uriTemplate: '/users/{userId}/devices/{id}',
            uriVariables: [
                'userId' => new Link(
                    toProperty: 'user',
                    fromClass: UserEntity::class,
                ),
                'id' => new Link(
                    fromClass: DeviceEntity::class,
                ),
            ],
            input: PutDeviceDto::class,
            allowCreate: true,
        ),
    ],
    stateOptions: new Options(entityClass: DeviceEntity::class)
)]
#[Map(source: DeviceEntity::class)]
final class DeviceResource
{
    public Uuid $id;
}

Within the PersistProcessor, we have the following snippet of code:

foreach (array_reverse($links) as $link) {
    if ($link->getExpandedValue() || !$link->getFromClass()) {
        continue;
    }
  
    $identifierProperties = $link->getIdentifiers();
    $hasCompositeIdentifiers = 1 < \count($identifierProperties);
  
    foreach ($identifierProperties as $identifierProperty) {
        $reflectionProperty = $reflectionProperties[$identifierProperty];
        $reflectionProperty->setValue($newData, $this->getIdentifierValue($identifiers, $hasCompositeIdentifiers ? $identifierProperty : null));
    }
}

This will set the value from the actual URL onto the object. There's a few things I found and tried:

  • $link->getIdentifiers() always returns id by default, meaning it'll actually never set the value for the user/userId
  • When providing the identifiers parameter with value ['user'] to the userId Link it'll not take into account that the user variable within my entity needs to be an object of User, not a UUID or int.
  • When providing the identifiers parameter with value ['userId'] to the userId Link it'll just not be able to find that property on the entity, as it does not exist. Which makes sense, since it's a relational object user instead of just the ID userId

No matter what I tried, I end up with the following SQL error:

An exception occurred while executing a query: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"user_id\" of relation \"device\" violates not-null constraint\nDETAIL:  Failing row contains (3, null).

Here's a repo where you can debug the issue yourself: https://github.com/Kyzegs/api-platform/tree/bug-put-overwriting-identifier

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions