9

With the Zend Framework, I am trying to build routes for a REST api on resources organized in the following pattern:

How do I set up this with Zend_Rest_Route?

Here is how I have setup the route for the users resource (users/:id) in my bootstrap.php file:

  $this->bootstrap('frontController');
  $frontController = Zend_Controller_Front::getInstance();
  $restRoute = new Zend_Rest_Route($frontController);
  $frontController->getRouter()->addRoute('default', $restRoute);

[As far as I understand, this is a catch all route so users/324/items/34 would results in parameters set as id=324 and items=34 and everything would be mapped to the Users (front module) Model. From there I guess I could just test for the items parameter and retrieve the item #34 for user #324 on a get request.]<=== I just checked it and it doesn't seems to work like that:

Acessing /users/234/items/43 and

var_dump($this->_getAllParams());

in the get action of the rest controller results in the following output:

array(4) {
 ["controller"]=> string(5) "users"
 ["action"]=>  string(3) "get"
 [2]=>  string(5) "items"  ["module"]=>  string(7) "default"]
}

Somehow both ids got lost...

Anyone?

Kenji Baheux
  • 596
  • 4
  • 14

3 Answers3

6

I open sourced the solution into github and as a composer package. see https://github.com/aporat/Application_Rest_Controller_Route.

I added a new class which extends Zend_Controller_Router_Route and adds abiliy to add custom restful routes, such as

$frontController = Zend_Controller_Front::getInstance();
$frontController->getRouter()->addRoute('users-messages', new Application_Rest_Controller_Route($frontController, 'users/:user_id/messages', ['controller' => 'users-messages']));
aporat
  • 5,922
  • 5
  • 32
  • 54
  • Thanks! Funny thing is, I initially wanted to use this for my URL `users/:user_id/messages`, which was the exact URL in your example! – JW. Apr 16 '15 at 17:46
5

AFAIK, there is no feature in Zend_Rest_Route which allows you to do something like this. There is a proposal but not sure when it'll be implemented. You can add this in your Bootstrap to set up this custom route.

$front = $this->getResource('FrontController'); 
$testRoute = new Zend_Controller_Router_Route(
    'users/:user_id/items/:item_id',
    array(
        'controller' => 'users',
        'action' => 'item',
        'module' => 'default'
    )
);

$front->getRouter()->addRoute('test', $testRoute);

user_id or item_id become available in itemAction in UsersController as parameters:

$user_id = $this->_request->getParam('user_id');
Abhinav
  • 38,516
  • 9
  • 41
  • 49
  • 1
    Thanks for your answer. You are right I finally had to give up Zend_Rest_Route as the current implementation does not support such a scheme. I finally went the Zend_Controller_Router_Route with Chains: http://stackoverflow.com/questions/2250353/how-do-i-write-chains-of-chains-of-of-route-in-a-ini-file-for-the-zend-framew – Kenji Baheux Mar 16 '10 at 04:36
3

Zend_Rest_Route maps the first parameter after the controller name to 'id' only when there is 1 parameter.

Best solution I've come up with is to subclass Zend_Rest_Route and override the match() function. Copy Zend_Rest_Route's match function, but add the following just before the "Digest URI Params" comment (about 60 lines in).

if($pathElementCount > 1 && $path[0] != 'id') {
    $params['id'] = urldecode($path[0]);
    array_shift($path);
}  

That should give you the functionality you're looking for.

  • I have done what you say. But then, how do you use it? I was expecting something like this in my routes.init routes.tasktypesstatus.map.1 = "type_id" but it does not work :/ – Olivier Jul 25 '13 at 13:26
  • This solution is perfect. Works like a charm. Just need to create your class to extend the Zend_Rest_Route. Should include the constructor and match functions. – a2ron44 Jul 10 '16 at 19:16