Disable jsonld metadata for @Embedded objects

Viewed 74

I've been looking for an answer to this (seemingly simple) problem but I found none so far.

I have a VatAmount designed like so :

/**
 * ValueObject defining the amount both with and without VAT.
 * @ORM\Embeddable
 * @property int $total
 * @property int|null $withoutVat
 * @Assert\EnableAutoMapping()
 */
class VatAmount
{
    /**
     * TTC
     * @ORM\Column(type="integer")
     * @Assert\NotNull()
     * @Assert\GreaterThanOrEqual(50)
     */
    protected $total = 0;

    /**
     * HT
     * @ORM\Column(type="integer", nullable=true)
     */
    protected $withoutVat;

    ...

Then I use it in multiple Entities :

class Bill
{
    /**
     * @Embedded(class=VatAmount::class)
     */
    private $amount;

    ...
}

Finally, I add it to my serialization groups :

App\Entity\Billing\Bill:
  attributes:
    amount:
      groups: ["bill:read", "order:detail"]
   ...

App\Entity\Embeddable\VatAmount:
  attributes:
    total:
      groups: ["amount:read", "amount:write"]
    withoutVat:
      groups: ["amount:read", "amount:write"]

It means that VatAmount no only isn't an ApiResource, it's not even a real Entity and it has no ID of its own.

Before I upgraded from api-platform 2.5.7 to 2.6.3, jsonld metadata (@id, @context, @type) was present on OpenApi doc but not when I actually fetched the resource. I simply removed the OpenApi fields and all was fine.

But now that I upgraded, whenever I fetch the resource, I get that :

  "amount" => array:4 [
    "@type" => "VatAmount"
    "@id" => "_:46842"
    "total" => 1000
    "withoutVat" => 800
  ]

I'm not even really sure what _:46842 refers to and I want it gone.

So my question is: is there any way to disable these fields for a specific class or nested resource ?

I tried :

  • playing with ApiProperty(jsonldContext={})
  • using ApiResource(hydraContext={})

Both seem like dead ends and I can't find any doc on what fields are accepted in these contexts.

Thanks for your help.

1 Answers

I found where this comes from. Strangely enough, all the code responsible for this feature seems to have been around for a long time so I'm not sure what has changed with the latest updates to make it work.

Whenever an anonymous embedded object is serialized, ObjectNormalizer::normalize() is called. This class is injected with an AnonymousContextBuilderInterface (by default, ContextBuilder) which it will pass down to JsonLdContextTrait to build the context. The ContextBuilder::getAnonymousResourceContext() method will return an array where @id is PHP's internal ID :

'@id' => $context['iri'] ?? '_:'.(\function_exists('spl_object_id') ? spl_object_id($object) : spl_object_hash($object)),

I haven't found any way to configure this behaviour.

With that in mind, I created a VoidContextBuilder which returns an empty array on getAnonymousResourceContext() and injected it in place of ContextBuilder with a compiler pass :

$def = $container->getDefinition('api_platform.jsonld.normalizer.object');
$def->setArgument('$anonymousContextBuilder', new Reference('App\Util\VoidContextBuilder'));

This works but it doesn't seem to fix OpenApi view so I kept the code I had before :

if (substr($name, 0, 9) === 'VatAmount') {
 unset($schema['properties']['@context']);
 unset($schema['properties']['@id']);
 unset($schema['properties']['@type']);
}

Please tell me if there is a better, safer way to get rid of anonymous resources' jsonld context.

Related