Core: Tree : use IRI instead of normalization context

Created on 18 May 2017  路  16Comments  路  Source: api-platform/core

Hello !

I've got an entity with a tree :

/**
 * @ApiResource(
 *     itemOperations={
 *          "get"={"method"="GET", "normalization_context"={"groups"={"read"}}},
 *     }
 *  )
 */
class Comment {
    /**
     * @var string
     * @Groups({"read"})
     */
    private $title;

    /**
     * @var Comment
     * @Groups({"read"})
     */
    private $parent;
}

I'd like to have the IRI parent, not the content.
The problem here is that I get :

{
    "title": "My first post",
    "parent": {
        "title": "My second post"
    }
}

instead of :

{
    "title": "My first post",
    "parent": "/posts/2"
}

I know that there is the @MaxDepth annotation, but it doesn't generate IRI. Is there another solution ?

enhancement question

Most helpful comment

Also, For a generic example to get the IRI you may want to inject the IriConverter class https://github.com/api-platform/core/blob/master/src/Bridge/Symfony/Routing/IriConverter.php

...
use ApiPlatform\Core\Bridge\Symfony\Routing\IriConverter;
...
public function __construct(NormalizerInterface $normalizer, IriConverter $iriConverter)
{
    ...
    $normalizer->setMaxDepthHandler(function ($foo) use ($iriConverter) {
        return $iriConverter->getIriFromItem($foo);
    });
    $this->normalizer = $normalizer;
}

Very rough just to give you and others a general idea but hopefully you get the gist.

All 16 comments

Dooh, I had the same issue yesterday. The solution would be to implement the circular_reference_handler configuration in symfony.

I can't give you my implementation because I use another normalization implementation :/.

@soyuka circular_reference_handler is when the serializer finds a circle. But in my case, there is no circle.

Oh my bad, thought you had children too. For this to work you need to use some kind of dynamic group.

Or maybe we're missing something for the MaxDepth implementation to do what you said. I'll look into this because I also expected that result and it didn't happend.

Another solution is to use some kind of dynamic group. Indeed you serialize with read on Comment and because parent is also an instance of Comment you'll get the same fields.

Related (same?): api-platform/core#1001

@teohhanhui Yes you're right : it's the same question. I still don't have a good solution for this ...

Unfortunately, I don't have a good solution for this either... We'll need to put our minds (and fingers) together to come up with something...

This can be closed as https://github.com/api-platform/core/pull/1528 is merged

Since alwaysIdentifier` doesn't exist now and the Max Depth Handler is only a function and there is no parameter, how can we solve this problem ?
Thanks !

For history :
@dunglas Added alwaysIdentifier which was a great feature : #1528
Then @dunglar reverted in #1696 for https://github.com/symfony/symfony/pull/26108 but it was closed and we don't know what to do ...

You may be looking for
https://symfony.com/blog/new-in-symfony-4-1-serializer-improvements#added-a-maxdepth-handler

It can be implemented now with the latest Symfony Serializer.

Yes but the question is how do I add it to AP ?

Write a custom normalizer
https://api-platform.com/docs/core/content-negotiation/#writing-a-custom-normalizer

and set the handler

$normalizer->setMaxDepthHandler(function ($foo) {
    return '/foos/'.$foo->id;
});

Ok, thanks @silverbackdan

@pierre-H No problem, happy to help!

Also, For a generic example to get the IRI you may want to inject the IriConverter class https://github.com/api-platform/core/blob/master/src/Bridge/Symfony/Routing/IriConverter.php

...
use ApiPlatform\Core\Bridge\Symfony\Routing\IriConverter;
...
public function __construct(NormalizerInterface $normalizer, IriConverter $iriConverter)
{
    ...
    $normalizer->setMaxDepthHandler(function ($foo) use ($iriConverter) {
        return $iriConverter->getIriFromItem($foo);
    });
    $this->normalizer = $normalizer;
}

Very rough just to give you and others a general idea but hopefully you get the gist.

Hi for all!
Is the last solution with setMaxDepthHandler still actual?
I tried it but with no luck. The handler gets array instead of object as first argument, obviously due to maxDepthHandler invoked after relation normalization:

As a result: I can't use $iriConverter->getIriFromItem($object) because it expected resource object.

Also I have an issue with maxDepth, I want set it to 1 (to get parent from example above as IRI on the first level) but it doesn't work because the first invocation of isMaxDepthReached always returns false and parent always embedded on the first level. https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php#L423. Maybe this should be asked on the symfony main repository, I just want to know is it relevant or I'm doing something wrong. Who ever encountered this?

Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rockyweng picture rockyweng  路  3Comments

stipic picture stipic  路  3Comments

theshaunwalker picture theshaunwalker  路  3Comments

kate-kate picture kate-kate  路  3Comments

tezvi picture tezvi  路  3Comments