i am developing a Rest Controller with Zend and i am confused with the mapping of urls to the Router.
Basically i read about Zend Router and i could not plan my urls in order to satisfy the mentioned routes.
These are some of my urls that should be mapped to Routers.
http://localhost/api/v1/tags.xml
http://localhost/api/v1/tags.xml?abc=true (param: abc=true)
http://localhost/api/v1/tags/123456.xml (param: 123456.xml)
http://localhost/api/v1/tags/123456/pings.xml (params: 123456, pings.xml)
http://localhost/api/v1/tags/123456/pings.xml?a=1&b=2 (params: 123456, pings.xml, a=1, b=2)
http://localhost/api/v1/tags/123456/pings/count.xml (params: 123456, pings, count.xml)
I am planning such that for the url patterns 1 to 3, "tags" should be the controller and for the url patterns 4 to 6, "pings" should be the controller.
Now i am unsure about how to configure the routers such that the above scenarios will work. Note that i cannot change these urls. I can offer 100 of my reputation score to the good answer.
First two URLs can be combined to one router.
$r = new Zend_Controller_Router_Route_Regex('api/v1/tags.xml',
array('controller' => 'tags', 'action' => 'index'));
$router->addRoute('route1', $r);
To differentiate the first two routes, check for the presence of the abc parameter in your tags controller. Add the following in your tags controller, index action.
if($this->_getParam('abc') == "true")
{
//route 2
} else {
// route 1
}
Similarly, routes 4 and 5 can be combined into one route.
I have explained for Route 6. For route 3, you can use the same logic.
$r = new Zend_Controller_Router_Route_Regex('api/v1/tags/(.*)/pings/(.*)',
array('controller' => 'pings', 'action' => 'index'),
array(1 => 'param1',2=>'param2')
);
$router->addRoute('route6', $r);
The parameters can then accessed like the following in pings controller.
$this->_getParam('param1') and $this->_getParam('param2')
For Route 5 :
$r = new Zend_Controller_Router_Route_Regex('api/v1/tags/(.*)/pings.xml',
array('controller' => 'pings', 'action' => 'index'),
array(1 => 'param1')
);
$router->addRoute('route5', $r);
The parameters (part of the URL after ?) will not be handled in the Router. By default, they will be passed to your controller.
To get a specifc parameter value passed in your URL, use the following in your controller.
$this->_getParam('a');
The logic is use (.*) in your route and assign them a parameter name and access them in your controller
Here's a starter for a piece of algorithm that distills the controller, indexed params, and extension from the request, which you could incorporate into an extended version of Zend_Rest_Route::match()
:
public function match( $request )
{
$path = $request->getPathInfo();
// distill extension (if any) and the remaining path
preg_match( '~(?U:(?<path>.*))(?:\.(?<extension>[^\.]*))?$~', $path, $matches );
$this->_values[ '_extension' ] = isset( $matches[ 'extension' ] ) ? $matches[ 'extension' ] : null;
$path = isset( $matches[ 'path' ] ) ? $matches[ 'path' ] : '';
// split the path into segments
$pathSegments = preg_split( '~' . self::URI_DELIMITER . '~', $path, -1, PREG_SPLIT_NO_EMPTY );
// leave if no path segments found? up to you to decide, but I put it in anyway
if( 0 == ( $length = count( $pathSegments ) ) )
{
return false;
}
// initialize some vars
$params = array();
$controller = null;
// start finding the controller
// (presumes controller found at segment 0, 2, 4, etc...)
for( $i = 0; $i < $length; $i += 2 )
{
// you should probably check here if this is a valid REST controller
// (see Zend_Rest_Route::_checkRestfulController() )
$controller = $params[] = $pathSegments[ $i ];
if( isset( $pathSegments[ $i + 1 ] ) )
{
$params[] = $pathSegments[ $i + 1 ];
}
}
// remove the param which is the actual controller
array_splice( $params, $i - 2, 1 );
// set the controller
$this->_values[ 'controller' ] = $controller;
// merge the params and defaults
$this->_values = array_merge( $this->_values, $params, $this->_defaults );
return $this->_values;
}
It's hardly tested, and thus not production material of course. But it should get you started.
What this DOES give you so far is:
The controller
The extension
The indexed parameters
What this DOES NOT give you is:
The action (post, put, delete, etc. The algorithm for this is already in Zend_Rest_Route::match()
)
The named parameters (Zend_Controller_Request_Http
takes care of that already)
EDIT
I realize this answer might be considered a bit vague so far. The point is to merge this algorithm with the match()
algorithm of Zend_Rest_Route
. But this above code still needs a lot of attention; you want to account for modules too probably (as does Zend_Rest_Route
), and maybe even an optional baseUrl (not sure how ZF deals with this internally actually).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With