phly / PhlyRestfully

ZF2 module for creating RESTful JSON APIs using HAL and API-Problem
108 stars 45 forks source link

SELF links within embeded objects in child routes in a getList #85

Closed schettle closed 11 years ago

schettle commented 11 years ago

I have the following route structure (using child routes)

/client[/:clientId]/user-group[/:userGroupId]/user[/:userd]

When I make a request to

/client/1/user-group/

I would expect a list of user groups - in addition to this I would like to embed the users into each group - this is all fine apart from generating the self links for the users, because the route for the user needs a userGroupId and the request doesn't contain one - it will be different for each user-group in the list.

I can provide more detailed information (code) if needed but I didn't want to clog up the thread.

Any help would be much appreciated.

macnibblet commented 11 years ago

This page should explain how to handle that https://phlyrestfully.readthedocs.org/en/latest/ref/advanced-routing.html

schettle commented 11 years ago

Hey macnibblet,

Could you please be a bit more specific on which part of the page you think answers this, I'm pretty sure non of it does. I've read all the documentation several times now so it could just be a case that I keep missing something!

Just to clarify, all the routing works correctly and I'm using unique identifiers for each segment, it's just the self link generation that fails when in the usergroupid is not in the URL and its trying to build links to get to a user

Thanks

macnibblet commented 11 years ago

@bloofish,This part of the documentation, it explain how do inject other route parameters https://phlyrestfully.readthedocs.org/en/latest/ref/advanced-routing.html#createlink-event

schettle commented 11 years ago

Thanks, but that is only triggered on creating new resources, not listing existing ones...

weierophinney commented 11 years ago

@bloofish "create" in that trigger name has to do with creating the representation, not the act of creating a brand new resource via POST. It will trigger as Antoine suggests.

On Thursday, July 11, 2013, bloofish wrote:

Thanks, but that is only triggered on creating new resources, not listing existing ones...

— Reply to this email directly or view it on GitHubhttps://github.com/weierophinney/PhlyRestfully/issues/85#issuecomment-20804447 .

Matthew Weier O'Phinney matthew@weierophinney.net http://mwop.net/

schettle commented 11 years ago

Thanks for the quick responses guys,

I did try this yesterday before creating this ticket as I thought it might do what you are suggesting, and it never got called. I've have just checked again and this is still not being called for my request.

The documentation does state

"The createLink method is currently called only from PhlyRestfully\ResourceController::create()"

which is only called for POST requests, right?

I've done a bit more debugging and I cannot seem to find anywhere that actually runs HalLinks::createLink which is whats meant to trigger the event we are discussing - even from within the PhlyRestfully\ResourceController::create() it calls HalLinks::fromLink() not HalLinks::createLink()

There error I am getting is generated in HalLinks::fromLink when it tries to build the child missing the parent id ($path = call_user_func())

weierophinney commented 11 years ago

@bloofish My apologies -- I've been on vacation, and away from my computer most of it.

The appropriate way to accomplish this is using metadata. With metadata, you can indicate how any resource should represent itself, including how the "self" relational link should be generated. It assumes, however, that embedded resources are objects of specific types; this was something we had to do to avoid undue complexity and performance overhead. As a resource is rendered, the engine checks to see if a given value is an object, and if that object's type is in the metadata map; if so, it renders it as an embedded resource.

The manual has a section dedicated to metadata mapping, and you should be able to find what you need there.

schettle commented 11 years ago

I still do not believe this is possible using meta data mapping. The only way would be to use the route params - but in the config you do not know what they will be.

I have now stored all of the required route params to build full link backwards - i.e. a user stores both the userGroupId and the clientId

        $links->getEventManager()->attach('renderCollection.resource', function ($e) {
            $eventParams = $e->getParams();
            $resource = $eventParams['resource'];
            $routeParams = $resource->getRouteParams();
            if (!empty($routeParams)) {
                foreach ($routeParams as $key => $value) {
                    $eventParams['routeParams'][$key] = $value;
                }
            }
        });