willdurand / Hateoas

A PHP library to support implementing representations for HATEOAS REST web services.
https://williamdurand.fr/Hateoas/
Other
1.03k stars 118 forks source link

PaginatedRepresentation and CollectionRepresentation don't work with serializationGroup #141

Open mgiustiniani opened 10 years ago

willdurand commented 10 years ago

Can you provide a test or something a bit more detailled?

mgiustiniani commented 10 years ago

With Symfony2 Project and FosRestBundle i can't use Hateoas Collection because these models havent' groups serialization.

i resolve this bug (limitation is more correctly) with override configuration (in Symfony2 Project):

jms_serializer:
    metadata:
        directories:
            Hateoas:
                namespace_prefix: "Hateoas\\Representation"
                path: "%kernel.root_dir%/serializer/Hateoas/"

PaginatedRepresentation.yml:

Hateoas\Representation\PaginatedRepresentation:
    relations:
      - rel: self
        href:
          route: expr(object.getRoute())
          parameters:
          parameters:
            page: expr(object.getPage())
            _format: json
          absolute: expr(object.isAbsolute())
        exclusion:
          groups: [list, detail]
      - rel: first
        href:
          route: expr(object.getRoute())
          parameters:
            page: 1
            _format: json
          absolute: expr(object.isAbsolute())
        exclusion:
          groups: [list, detail]
      - rel: last
        href:
          route: expr(object.getRoute())
          parameters:
            page: expr(object.getPages())
            _format: json
          absolute: expr(object.isAbsolute())
        exclusion:
          groups: [list, detail]
          exclude_if: expr(object.getPages() === null)
      - rel: next
        href:
          route: expr(object.getRoute())
          parameters:
            page: expr(object.getPage()+1)
            _format: json
          absolute: expr(object.isAbsolute())
        exclusion:
          groups: [list, detail]
          exclude_if: expr(object.getPages() !== null && (object.getPage() + 1) > object.getPages())
      - rel: previous
        href:
          route: expr(object.getRoute())
          parameters:
            page: expr(object.getPage()-1)
            _format: json
          absolute: expr(object.isAbsolute())
        exclusion:
          groups: [list, detail]
          exclude_if: expr((object.getPage() - 1) < 1)
    properties:
       page:
         groups: [list, detail]
       limit:
         groups: [list, detail]
       pages:
         groups: [list, detail]

RouteAwareRepresentation.yml

Hateoas\Representation\RouteAwareRepresentation:
    properties:
       inline:
         groups: [list, detail]
         inline: true
MrHash commented 10 years ago

I just came a similar issue to this also which may be related. The '_links' (and probably '_embedded') are not included in the serialization i think because the event subscriber sends the custom context into the InlineDeferrer::handleItems method.

$hateoas = HateoasBuilder::create()->build();
$json = $hateoas->serialize($object, 'json', SerializationContext::create()->setGroups(['public']));
MrHash commented 10 years ago

Quick messing about seems to solve the issue by adding 'Default' into the groups array to include non-grouped object attributes.

ktounet commented 10 years ago

Same issue, serializer groups doesn't works with CollectionRepresentation :/

mvrhov commented 10 years ago

Yep, I'm also hitting this one. IMO all represenations should have "groups" e.g pager pager, collection, collection ...

mgiustiniani commented 10 years ago

i added a PR in jms serializer for risolve this issue, after this we can create PR for resolve links object serialization

mvrhov commented 10 years ago

@mgiustiniani: There is no need for that. All that has to be done is add groups into all default Hateoas configurations. e.g Paginated representation configuration gets put into hateoas_paginated group, route aware into hateoas_route.

Now this will break BC, but IMO there is no way around it as this was broken from the start.

mgiustiniani commented 10 years ago

@mvrhov my PR in jms serializer resolve limit for this library and for other libraries (ie: with https://github.com/djlambert/doctrine2-spatial, spatials objects can't serialized with groups)

adrienbrault commented 10 years ago

When using groups with Hateoas, I specify the Default (which will keep all the Hateoas representations properties) group along with my custom groups.

What we could do is add an "Hateoas" group.

You would then specify the Hateoas group along with your custom groups.

EDIT: Adding an Hateoas seems harder than expected.

MrHash commented 10 years ago

Default works for me also so far.

mvrhov commented 10 years ago

@willdurand why did you close this? Usually You don't want a Default group as this means that you have to push a lot of your own property declarations into another group.

willdurand commented 10 years ago

Well, it looked like a decent answer to me... Let's reopen it, but I don't have any solution..

mgiustiniani commented 10 years ago

@mvrhov i've same problem but i haven't considered this functionality:

/**
* @Rest\View(serializerGroups={"list", "Default"})
**/
public function cgetNotesAction(){
// some stuff here
}

I can't test now this solution.

sroze commented 10 years ago

This could be related to #164.

josephdpurcell commented 9 years ago

I don't see this as an issue or limitation.

If you are using serialization groups and want to expose properties generated by PaginatedRepresentation or CollectionRepresentation then you have three options:

  1. Create a metadata configuration for those classes.
  2. Create your own classes that extend those and use annotations.
  3. Add the "Default" serialization group to the SerializationContext.
adrienbrault commented 9 years ago

@mvrhov https://github.com/willdurand/Hateoas/issues/141#issuecomment-38796022 Yes, we could add groups to the hateoas built in representations. However even though all the properties/links will have a hateoas_xxx group, they should also keep the Default group.

dsbaars commented 9 years ago

I got this working with v2.5.0 with the following code (thanks to @mgiustiniani, i modified it only a little) https://gist.github.com/dsbaars/56be85286ebf4f89e4d4

Unfortunately i can't get the per item links working. I can't use the Default serialziation group in some cases. If someone can help me with the metadata configuration to get this working, it'll save me the time creating my own Annotation Listener which is a little overkill to solve this ;)

liverbool commented 9 years ago

Grouping not work for me too.

gnilekaw commented 8 years ago

+1

videni commented 8 years ago

+1

kipit commented 8 years ago

Maybe this design/limitation should be documented, can I submit a documentation PR for this?

willdurand commented 8 years ago

@kipit yes!

bruno-ds commented 7 years ago

@dsbaars : I answered to your gist, I past the missing file here for thoses who won't follow your link (they should because your solution works) :

Hateoas\Representation\AbstractSegmentedRepresentation:
    properties:
        limit:
            expose: true
            groups: [Hateoas]
        total:
            expose: true
            groups: [Hateoas]
jcornide commented 6 years ago

Any news on this? I don't see any clear solution on how to solve this issue

bruno-ds commented 6 years ago

@jcornide dsbaars's comment lead to a gist that let you manually adress this problem . I needed to add an extra conf. that I added in a comment of this gist.

FireLizard commented 6 years ago

I can't figure it out why not these both classes (PaginatedRepresentation and CollectionRepresentation) can't hold the missing "groups"-attribute inside the annotations.

Why should I override the serialization configuration as proposed at the gist?

Maybe someone can me explain this situtation? I think I misunterstood something. ;)

egonolieux commented 6 years ago

I tried creating separate config files as @mgiustiniani suggested, but the serializer still seems to use the annotations of the PaginatedRepresentation and related classes.

Since I'm using Symfony 4.1, my config is a little different:

metadata:
    directories:
        hateoas:
            namespace_prefix: "Hateoas\\Representation"
            path: '%kernel.project_dir%/config/serializer/hateoas'

EDIT:

I was using .yaml instead of .yml for the file extensions. Changing them fixed it :)

tonivdv commented 5 years ago

Hi everyone,

I've spent some hours on this issue too. I tried all workarounds mentioned here by overriding the exclusion rules via metadata, but I wasn't able to get it up and running.

Then I found that you can override groups of deeper branches with the JMS library. But that didn't seem to work until I noticed issue #260 where it does mention that it works.

The thing is, I didn't quite understand how that override worked. I thought you had to use the variable name inline from the RouteAwareRepresentation class, but it's actually the 'rel' name you're passing as argument when building your collection.

See following example:

<?php

use JMS\Serializer\Annotation as Serializer;

/**
 * @Serializer\ExclusionPolicy("all")
 */
final class User {

    /**
     * @Serializer\Expose()
     */
    private $id;

    /**
     * @Serializer\Expose()
     * @Serializer\Groups({"sensitive"})
     */
    private $name;

}

First you define the representation.

$collection = new OffsetRepresentation(
    new CollectionRepresentation(
        $users,
        'my_user_rel'
    ),
    'some_route'
);

The problem we currently have, if we want to return the collection of users with only the sensitive data, is that following will not work, because the collection does not comply with the group exclusion rule.

$jms->serialize($collection, 'json', $jms->serialize($collection, 'json', SerializationContext::create()->setGroups(['sensitive']));

Instead, you should tell the exclusion rule to only be applied on the "User" object itself. This can be done with the "overriding" method of JMS, but, and this is important as I didn't get it immediately, you must use the name you gave to the 'rel' argument. Notice the strange name I gave my_user_rel, this was intentionally for the sake of the example :)

Doing following should solve the groups issue once and for all

$jms->serialize($collection, 'json', SerializationContext::create()->setGroups([
    'Default',
    'my_user_rel' => [
        'sensitive'
    ]
]))

If, for example, you want to also include the other fields then you simply add Default also:

$jms->serialize($collection, 'json', SerializationContext::create()->setGroups([
    'Default',
    'my_user_rel' => [
        'Default',
        'sensitive'
    ]
]))

If we are not going to come with an alternative solution, maybe this could be added to the documentation somewhere? (/cc @willdurand )

Anyway, I hope this will help future devs to not waste hours on this like me ^^

Cheers

JonathanAllegre commented 5 years ago

Youhou tonivdv !!! It works perfectly ! I spent 4 hours looking for a solution! So we can do it with Annotations if we work with FOSRest:

smuralidharan commented 5 years ago

Hi I did the same but i am getting empty response.

$serializer = HateoasBuilder::create() ->setUrlGenerator(null, $queryStringUrlGenerator) ->addMetadataDir(DIR . '/../Resources/config/serializer/Hateoas', 'Hateoas\Representation')->build() $collection = new CollectionRepresentation($users); $json = $serializer->serialize($collection, 'json', SerializationContext::create()->setGroups(['users']));

Metadata FileName: CollectionRepresentation.yml

Hateoas\Representation\CollectionRepresentation: exclusion_policy: none properties: id: type: integer groups: ['users']

Any suggestions please? @willdurand