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

Exclude / Expose based on value of its relationship #722

Closed
hsb1007 opened this issue Feb 17, 2019 · 15 comments
Closed

Exclude / Expose based on value of its relationship #722

hsb1007 opened this issue Feb 17, 2019 · 15 comments

Comments

@hsb1007
Copy link

hsb1007 commented Feb 17, 2019

I have a social Post / Comment entity and its User entity (creator of the post)

Depending on the Post privacy setting, I want to control what user detail gets return.

I have checked

  • Exclude/Expose with if expression but could not access to its parent entity in relation (Post / Comment)

  • Preserialize Event - For some reason, it doesn't event get called at the moment and unsure whether I can set 'Dynamic' Groups for User entity on 'Preserialize' event.

  • Custom Exclusion Policy - Still unsure how I can access to Post / Comment from User

Does anyone have any idea?

I am scratching my head for hours..

@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019

Exclusion strategies based on expression language were created exactly for that case.

More info on http://jmsyst.com/libs/serializer/master/cookbook/exclusion_strategies#dynamic-exclusion-strategy.

  • Exclude/Expose with if expression but could not access to its parent entity in relation (Post / Comment)

Your object ("Comment" in this case) must expose a method as "getPost" that can be used in the expression to compute the privacy settings.

@goetas goetas closed this as completed Feb 17, 2019
@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019

On the slide of a presentation I did years ago https://slides.com/goetas/berlin-symfony-user-group-boring-api-and-symfony-2017/live#/22/1 you have exactly covered your case

@hsb1007
Copy link
Author

hsb1007 commented Feb 17, 2019

@goetas thanks for quick response!

But each user has multiple posts and comments so not sure how i can get what Post i am serialising.

I am serialising a Post and wanting to control what User fields returns based on Post property.

But user has multiple Posts hence i cant reference or havent found how

@hsb1007
Copy link
Author

hsb1007 commented Feb 17, 2019

@goetas

Good to know that i can reference to other service.. but the ‘object’ you are parsing, isnt it User object?
I would need its original Post object i am serialising..

Maybe i am missing something but the case you detailed doesnt cover my case i believe

@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019

  • 'object' is the current object being serialized (maybe the comment)
  • if you need the post you can have a method 'getPost' in the comment, so you will do something as 'object.getPost()'
  • if you need the author of the post post you can have a method 'getAuthor' in the post, so you will do something as 'object.getPost().getAuthor()'
  • if you need the "currently logged user" you can use a service that provides you the current user as example 'service('currrent_user').getUser()' (symfony security has already that, but do not remember the name of the service)

@hsb1007
Copy link
Author

hsb1007 commented Feb 17, 2019

@goetas For some reason, for object I am parsing, I get 'User' object in User Property's Exclude(if="something(object)") even though I am serialising 'Post'...

Unless the 'object' is Post, I can't use Exclude / Expose to control 'User'...

Is there any way I can get the Original Entity that's being serialised from its Context?

I can see the original object in 'VisitingSet' along with other Entities in its relations..

Thank you so much for your help Goetas.

So much appreciated

@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019 via email

@hsb1007
Copy link
Author

hsb1007 commented Feb 17, 2019

@goetas Thank you so much for your support again!

Below is where I pass array of Post for serialisation.
image

And below is an annotation in 'User' Entity.
image

From User, I would like to 'Exclude' or 'Expose' based on its parent Entity in OneToMany relationship e.g) Posts / Comments

Because it is OneToMany, I can not do something like below from User as I would get many posts..

image

Perhaps Exclude / Expose isn't the way to go?

Thank you so much again @goetas for your help on this one!

@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019

Well, I think there is a problem with your architecture.... what if a user has two posts, for one isAnonymosPost() is true, and another one is isAnonymosPost() is false... What should happen then? should the email of the user be serialized...?

@goetas
Copy link
Collaborator

goetas commented Feb 17, 2019 via email

@hsb1007
Copy link
Author

hsb1007 commented Feb 17, 2019

@goetas

The array I am serialising is in below structure (Think of it as Facebook timeline)

- Post
-- id - 221
-- content
-- isAnonymousPost = false
-- createdBy
-----User
------- id - 242
------- email - user1@gmail.com
------- firstName - Mike

- Post
-- id - 220
-- content
-- isAnonymousPost = true
-- createdBy
----- User
------- nickName - userNickName

- Post
-- id - 219
-- content
-- isAnonymousPost = false
-- createdBy
----- User
------- id - 194
------- email - user39@gmail.com
------- firstName - Pete

And the list goes on.

The second post in the array is 'anonymous' post which means its child entity 'User' should not have all the details about the user to hide who created the post.

Yes user can create multiple Posts, which is why I don't believe I can use Expose / Exclude or was hoping there was a way..

If it can't be done via Expose / Exclude, what other way can achieve this ?

Hope it makes it clearer!

Thanks again!

@goetas
Copy link
Collaborator

goetas commented Feb 18, 2019 via email

@hsb1007
Copy link
Author

hsb1007 commented Feb 18, 2019

@goetas

Thank you for the response!

Just going back to the virtualProperty idea..

Is there anyway i can create an nested object as virtual property?

With the current virtualObject i can only do

Post.userIncognito

But any workaround to achieve

Post.user.incognitoName?

Perhaps i need to get Preserialise or Post serialise working to add those property instead?

@hsb1007
Copy link
Author

hsb1007 commented Feb 19, 2019

@goetas

Sorry to bother you again!

Would below work?

@JMS\Exclude(if="object.getIsIncognito() || service('security.token_storage').getToken().getUser().getId() == object.getUser().getId()")

I get below error

The function 'service' does not exist around position 1 for expression `service('security.token_storage').getToken().getUser().getId() == object.getUser().getId()

@hsb1007
Copy link
Author

hsb1007 commented Feb 19, 2019

I have had to manually register the BaseSerializerFunctionProvider like below

$expressionLanguage = new ExpressionLanguage();
        $expressionLanguage->registerProvider(new BasicSerializerFunctionsProvider());
        $data = SerializerBuilder::create()
            ->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy())
            ->setExpressionEvaluator(new ExpressionEvaluator($expressionLanguage))
            ->build()->serialize($object, $format, $context);

But I don't get the right value in the function... ...

image

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

No branches or pull requests

2 participants