Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be more intelligent in determining property writable/readable link. #1974

Merged
merged 1 commit into from
Apr 6, 2019
Merged

Be more intelligent in determining property writable/readable link. #1974

merged 1 commit into from
Apr 6, 2019

Conversation

bendavies
Copy link
Contributor

@bendavies bendavies commented May 24, 2018

Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? N/A yet
Fixed tickets
License MIT
Doc PR

I've come across an issue where I cannot prevent a property being a readable link, given sane looking serialization Group configuration.

Consider the following Resources:

/**
 * @ApiResource(
 *     attributes={
 *         "normalization_context": {"groups": {"foo-read", "bar-read"}},
 *     }
 * )
 */
class Foo
{
    /**
     * @Groups("foo-read")
     *
     * @var Bar
     */
    public $id;

    /**
     * @Groups("foo-read")
     *
     * @var Bar
     */
    public $bar;
}

/**
 * @ApiResource()
 */
class Bar
{
    /**
     * @Groups("foo-read")
     *
     * @var Bar
     */
    public $id;

    /**
     * @Groups("bar-read")
     *
     * @var Foo
     */
    public $foo;
}

Given:

$foo = new Foo();
$foo->id = 1;

$bar = new Bar();
$bar->id = 1;

$foo->bar = $bar;
$bar->foo = $foo;

Consider normalizing $foo.

What i want (and would expect) is
Foo::bar to be readable: true readableLink: true
Foo::bar:foo to be readable: true readableLink: false

but what currently is returned is
Foo::bar to be readable: true readableLink: true
Foo::bar:foo to be readable: true readableLink: true

I need Foo::bar:foo readableLink: false so the normalization does not recurse back to Foo: Foo->Bar->Foo, it should stop at Foo->Bar.

SerializerPropertyMetadataFactory::transformLinkStatus does not consider the groups on the property it is evaluating the link status of. I think that would be expected, and this change would give my desired outcome.

@bendavies bendavies changed the title Be more intelligent and Be more intelligent in determining property writable/readable link. May 24, 2018
@dunglas
Copy link
Member

dunglas commented May 24, 2018

I gave only a quick look but looks legit. ping @api-platform/core-team

@soyuka
Copy link
Member

soyuka commented May 24, 2018

This looks good to me indeed. I'd see this as a bug fix (target 2.2) though.

@bendavies
Copy link
Contributor Author

Ah I did mean to target 2.2. 👍

@bendavies
Copy link
Contributor Author

I'll work on the tests.

@bendavies bendavies changed the base branch from master to 2.2 May 24, 2018 19:47
@antograssiot
Copy link
Contributor

working on finishing this one

@bendavies
Copy link
Contributor Author

Wow forgot about this one - thanks!

@antograssiot antograssiot changed the base branch from 2.2 to master April 6, 2019 13:16
@antograssiot
Copy link
Contributor

targeting master as discussed with @soyuka.
Even if we think it is a bug fix, it might be totally misleading to people relying up to now on this "faulty" behavior

@soyuka soyuka merged commit e03b925 into api-platform:master Apr 6, 2019
@soyuka
Copy link
Member

soyuka commented Apr 6, 2019

thanks @bendavies @antograssiot

@bendavies
Copy link
Contributor Author

Any tests added for this?

@bendavies
Copy link
Contributor Author

Commit php-cs-fixer by accident?

@soyuka
Copy link
Member

soyuka commented Apr 6, 2019

Any tests added for this?

Yes in fact it fixes a bad behavior that is shown by the modified groups (behat functional tests).

@vincentchalamon vincentchalamon mentioned this pull request Apr 6, 2019
@teohhanhui
Copy link
Contributor

Any tests added for this?

Hmm... I don't see any?

@teohhanhui
Copy link
Contributor

@bendavies And I assume this line in your OP:

 *         "normalization_context": {"groups": {"foo-read", "bar-read"}},

was actually meant to be:

 *         "normalization_context": {"groups": {"foo-read"}},

?

If so, I think this ought to be merged in 2.4 and not master. It's a clear bug.

@teohhanhui
Copy link
Contributor

Hmm... No, this does not make sense to me. I must be misunderstanding something or is there something I've overlooked?

@teohhanhui
Copy link
Contributor

teohhanhui commented May 25, 2019

Okay, I understand now. I think this is a misfeature and should be reverted. That's not how serializer groups should be interpreted. If we need more control, it should be provided at the Symfony Serializer level.

@bendavies
Copy link
Contributor Author

@bendavies And I assume this line in your OP:

 *         "normalization_context": {"groups": {"foo-read", "bar-read"}},

was actually meant to be:

 *         "normalization_context": {"groups": {"foo-read"}},

?

If so, I think this ought to be merged in 2.4 and not master. It's a clear bug.

no, i think OP was correct.

@bendavies
Copy link
Contributor Author

Okay, I understand now. I think this is a misfeature and should be reverted. That's not how serializer groups should be interpreted. If we need more control, it should be provided at the Symfony Serializer level.

can you explain why you think it's a misfeature? seemed like a pretty obvious bug in readableLink determination to me.

@teohhanhui
Copy link
Contributor

Why should the serializer group(s) used on the property have any effect on readable/writable link status? The user can use any combination of serializer groups as they see fit, and it should not change the traversal.

Serializer groups should only be considered together, as a union. Determining traversability based on the specific serializer groups that happen to be on the property is unexpected behaviour.

@teohhanhui
Copy link
Contributor

teohhanhui commented May 25, 2019

You're treating serializer groups as multiple possible paths of traversal, which they're not. They just mean expose / don't expose, include / don't include.

@bendavies
Copy link
Contributor Author

bendavies commented May 25, 2019

Well, it's a long time since I looked at this so my memory might be hazy, but the link between serialiser groups and how api platform work is not a 1 to 1 here.

APIP has 2 levels of "inclusion" of an attributes which are resources.

  • readable - whether to include the resource as a linked uri or not.
  • readableLink whether to embed the resource or not.

I'm happy to be wrong and the proper approach be suggested to solve my use case, of course!

@teohhanhui
Copy link
Contributor

APIP has 2 levels of "inclusion" of an attributes which are resources.

  • readable - whether to include the resource as a linked uri or not.
  • readableLInk whether to embed the resource or not.

Yes, my comments are made with these points in mind.

the proper approach be suggested to solve my use case

Unfortunately, I could only suggest accepting this as a limitation. Because as I've argued above, I think this is a misfeature. If we have property-level serializer groups, it could do what you want. Yup - it's your issue at #1922 😆

@teohhanhui
Copy link
Contributor

You're treating serializer groups as multiple possible paths of traversal, which they're not. They just mean expose / don't expose, include / don't include.

To further illustrate:

This is how I think it should be (previous behaviour):
"Follow the unbroken blue/green line (any combination)"

Instead of (behaviour after this PR):
"Follow the unbroken blue line, OR follow the unbroken green line (only the same type)"

@bendavies
Copy link
Contributor Author

bendavies commented May 25, 2019

Not sure I follow, but just to add further context:
I think i raised this issue because i was having trouble preventing recursion of an object graph. if we had more control in that situation somehow that would help (maybe we do now?), so we could easily serialize a response like:
Foo -> Bar -> Foo

{
  "id":1,
  "bar":{
    "id":1,
    "_links":{
      "self":"/bar/1",
      "foo":"/foo/1"
    }
  },
  "_links":{
    "self":"/foo/1"
  }
}

@bendavies
Copy link
Contributor Author

I also don't think I ever used this feature after it was merged. I still have my custom normalisers.

@teohhanhui
Copy link
Contributor

teohhanhui commented May 25, 2019

i was having trouble preventing recursion of an object graph. if we had more control in that situation somehow that would help (maybe we do now?)

Our circular reference handler should already do that out of the box.

@bendavies
Copy link
Contributor Author

bendavies commented May 25, 2019

are you sure, in the case of hal, it would be added to _links?

@bendavies
Copy link
Contributor Author

bendavies commented May 25, 2019

as far as i can see you'd get this. which is sort of "invalid".

{
  "id":1,
  "bar":{
    "id":1,
    "foo":"/foo/1",
    "_links":{
      "self":"/bar/1"
    }
  },
  "_links":{
    "self":"/foo/1"
  }
}

PR's welcome i guess :)

@bendavies
Copy link
Contributor Author

bendavies commented May 25, 2019

by the way, i think it's still not possible to serialize the non resursive case, without this PR

Foo(1) -> Bar(1) -> Foo(2)`

{
  "id":1,
  "bar":{
    "id":1,
    "_links":{
      "self":"/bar/1",
      "another_foo":"/foo/2"
    }
  },
  "_links":{
    "self":"/foo/1"
  }
}

@teohhanhui
Copy link
Contributor

teohhanhui commented May 25, 2019

are you sure, in the case of hal

Yeah, I think you're right. Support for those formats is probably lacking. 😄

by the way, i think it's still not possible to serialize the non resursive case, without this PR

Hmm... I don't understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants