api-platform / core

The server component of API Platform: hypermedia and GraphQL APIs in minutes
https://api-platform.com
MIT License
2.4k stars 856 forks source link

PUT queries on a Resource with a composite key fail with a duplicate key error #6234

Open bertrandjamin opened 5 months ago

bertrandjamin commented 5 months ago

API Platform version(s) affected: 3.2.16

Description
After an update in the latest version of ApiPlatform (from v2.7.x) Each PUT calls on Resources with composite keys fail with a duplicate error.

It seems that the detection of the existing object fails and so the doctrine flush() try to create the resource rather than updated it.

The limitation seems known (https://github.com/api-platform/core/blob/5523bf5df93783582bed5591ff35c71e0942a978/src/Doctrine/Common/State/PersistProcessor.php#L58) but I prefer to create an issue so we can follow the resolution.

How to reproduce

Possible Solution

Awaiting a resolution I have added a specific Processor as workaround

<?php

namespace App\State\Processor;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Admin\EntityInterface;
use Doctrine\ORM\EntityManagerInterface;
use Exception;

/**
 * @implements ProcessorInterface<EntityInterface,EntityInterface>
 */
class CompositeIdentifierPutProcessor implements ProcessorInterface
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
    ) {
    }

    /**
     * @throws Exception
     */
    public function process(
        mixed $data,
        Operation $operation,
        array $uriVariables = [],
        array $context = []
    ): EntityInterface {

        if (!$operation instanceof Put) {
            throw new Exception('Invalid Operation');
        }

        if (isset($uriVariables['id']['identifiers']) && count($uriVariables['id']['identifiers']) < 2) {
            throw new Exception('This processor should only be used for a Resource with composite identifier');
        }

        $this->entityManager->flush();
        return $data;
    }

}
stale[bot] commented 3 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.