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

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions