api-platform / core

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

PUT or PATCH with null values doesn't clear the value of nullable ManyToOne property of ORM entity #6497

Open VictorKrasnov opened 1 month ago

VictorKrasnov commented 1 month ago

API Platform version(s) affected: 3.3.2

Description
If you have some ORM entity with ManyToOne relation, no way to clear this relations. Or I can't find this possibility.

How to reproduce

  1. Add entity like this:

    #[ORM\Entity(repositoryClass: OrderRepository::class)]
    #[ORM\Table('orders')]
    class Order
    {
    # ..... other properties is here
    
    #[ORM\ManyToOne(targetEntity: ...)]
    #[ORM\JoinColumn(nullable: true)]
    #[Groups(...)]
    protected ?TradingContractInterface $tradingContract = null;
    
    public function getTradingContract(): ?TradingContractInterface
    {
        return $this->tradingContract;
    }
    
    public function setTradingContract(?TradingContractInterface $tradingContract = null): static
    {
        $this->tradingContract = $tradingContract;
        return $this;
    }
    }
  2. Publish REST methods with API Platform (in my case I did it with yaml):

    
    resources:
    App\Order:
    shortName: Order
    description: Order entity.
    operations:
      - class: ApiPlatform\Metadata\GetCollection
        uriTemplate: /orders
        normalizationContext: { groups: ['order:list', 'reference'] }
        createdAt:
          createdAt: 'DESC'
        paginationItemsPerPage: 20
      - class: ApiPlatform\Metadata\Get
        uriTemplate: /orders/{id}
        normalizationContext: { groups: ['order:read', 'reference'] }
      - class: ApiPlatform\Metadata\Post
        uriTemplate: /orders
        normalizationContext: { groups: ['order:read', 'reference'] }
        denormalizationContext: { groups: ['order:create'] }
        processor: Ecomla\SalesBundle\ApiPlatform\State\Order\OrderCreateProcessor
      - class: ApiPlatform\Metadata\Patch
        uriTemplate: /admin/orders/{id}
        normalizationContext: { groups: ['order:read', 'reference'] }
        denormalizationContext: { groups: ['order:update', 'reference'] }
        processor: Ecomla\SalesBundle\ApiPlatform\State\Order\OrderUpdateProcessor
      - class: ApiPlatform\Metadata\Put
        uriTemplate: /admin/orders/{id}
        normalizationContext: { groups: ['order:read', 'reference'] }
        denormalizationContext: { groups: ['order:update', 'reference'] }
        processor: Ecomla\SalesBundle\ApiPlatform\State\Order\OrderUpdateProcessor
      - class: ApiPlatform\Metadata\Delete
        uriTemplate: /admin/orders/{id}
        normalizationContext: { groups: ['order:read', 'reference'] }
    routePrefix: ....

3. Try to update entity with PATCH or PUT /admin/orders/{id} with json like:
```json
{
   # ...other properties
   tradingContract: null
}

Expected behaviour: PATCH and PUT methods should clear current value of property tradingContract end return json without tradingContract property (due to skip_null_values option with value true passed to normaliser).

Actual behaviour: Property did not set to null, and the response includes property tradingContract with old data.

Possible Solution
I think you should change current logic of default denormaliser or add some config options to switch this behaviour.

soyuka commented 1 month ago

Can't you set skip_null_values to false in the denormalizer context? Maybe that it should be the default during denormalization (@dunglas)