3

I'm using Zend Framework, and am trying to set up some custom routes. These seem to be working fine during dispatch, but the reverse matching isn't working at all.

These are the routes I've set up.

$router->addRoute('category', new Zend_Controller_Router_Route(
    'categories/:category',
    array(
        'controller' => 'category',
        'action' => 'modify',
    )
));

$router->addRoute('categories', new Zend_Controller_Router_Route_Static(
    'categories',
    array(
        'controller' => 'category',
        'action' => 'index'
    )
));

If I now go to http://example.com/categories, the correct controller and action are executed (category.index). If I go to http://example.com/categories/5, I get the following error:

Fatal error: Uncaught exception 'Zend_Controller_Router_Exception' with 
message 'category is not specified'

Adding a default value to :category fixes this problem for reason (suggestions welcome). That is not the major problem though.

Whenever my application executes $this->url(...), the returned value is always the current URL. So, on http://example.com/categories, if I run

echo $this->url(
    array('controller' => 'category', 'action' => 'modify', 'category' => 5)
);

The returned value is http://example.com/categories. I am completely stumped..

The problem persists even if I try to bypass the default router and do

$router->removeDefaultRoutes();
$router->addRoute('default', new Zend_Controller_Router_Route(
    '*', 
    array('controller' => 'index', 'action' => 'index')
));

Does anyone with a bit more experience with Zend routing want to have a crack at this?

Cheers, Jon

Yes Barry
  • 9,514
  • 5
  • 50
  • 69
Jon Gjengset
  • 4,078
  • 3
  • 30
  • 43
  • Can you try to switch the two routes? – PeeHaa Dec 01 '11 at 17:03
  • Switching the routes did not change much. URLs map to the standard Zend pattern. I can access /categories directly and get the correct page, but /categories/2 yields "category is not specified"... EDIT: Turns out the category is not specified comes whenever calling $this->url without specifying 'category' => ..., even when I'm trying to link to a different controller/action..? – Jon Gjengset Dec 05 '11 at 09:55

2 Answers2

4

Try changing this line

echo $this->url(array('controller' => 'category', 'action' => 'modify', 'category' => 5))

into

echo $this->url(array('controller' => 'category', 'action' => 'modify', 'category' => 5), 'category')

the second parameter is route name that url function should use. If its not passed helper will user current route.

@Edit

After deeper research I have found another solution for your problem, if you dont want to pass each time router name your code should looke like this:

$router->addRoute('category', new Zend_Controller_Router_Route(
    'categories/:id',
    array(
        'controller' => 'category',
        'action' => 'modify',
        'id' => 0
    ),
    array(
      'id' => '\d+'
    )
 ));

$router->addRoute('categories', new Zend_Controller_Router_Route_Static(
    'categories',
    array(
        'controller' => 'categories',
        'action' => 'index'
    )
)); 

This will be setting the router part, now call url helper in view.

<?php echo $this->url(array('controller' => 'category', 'action' => 'modify', 'id' => 5), null, true);?><br/>
<?php echo $this->url(array('controller' => 'category', 'action' => 'index'), null, true);?><br/>

The output should be:

/categories/5

/categories

Norbert Orzechowicz
  • 1,329
  • 9
  • 20
  • Yeah, I know that I can specify the route manually, but I'd prefer to have a solution where I do not have to specify this manually everywhere in order to get url() to work at all.. – Jon Gjengset Dec 01 '11 at 23:18
  • @Jonhoo It will work if 'category' is the current route being applied. Check this to know the current route - http://stackoverflow.com/questions/1373573/how-to-get-the-dispatched-route-name-in-zend-framework – Raj Dec 02 '11 at 06:22
  • But I'm not always going to be linking only to the current route? – Jon Gjengset Dec 02 '11 at 07:34
  • So you need to pass route name, check Zend/View/Helper/Url.php and you will see that if you will not pass route name zend will take the current one. Ofcourse you can write your own view url helper. – Norbert Orzechowicz Dec 02 '11 at 07:39
  • But I don't want to pass the route name every time I call url(). That is the whole point of reverse matching on routes... – Jon Gjengset Dec 02 '11 at 09:49
  • I am pretty sure I've tried this before as well, but I'll try it tomorrow when I get back to work. I'll give you the bounty for your research anyway =) – Jon Gjengset Dec 11 '11 at 12:44
  • Your edited version still does not seem to work, but I believe this is because of an inherent flaw in Zend. When specifying controller and action in url(), Zend does not use this information to limit the possible routes it could reverse-match to, causing it to use any route for which no filters are defined. – Jon Gjengset Dec 12 '11 at 10:08
0

For that you have to specify the reverse URL while setting up your router. Like explained here.

I have done this in my project, but using INI file config. Like shown below:

routes.myroute.type = "Zend_Controller_Router_Route_Regex"
routes.myroute.route = "devices/page/(\d+)"
routes.myroute.defaults.controller = "index"
routes.myroute.defaults.action = "devicesindex"
routes.myroute.map.1 = "page"
routes.myroute.reverse="devices/page/%d"

Save this as an INI file in your config folder or somewhere in your APP root.

In your bootstrap, have something like:

public static function setupCustomRoutes() {
    $router = self::$frontController->getRouter();
    $config = new Zend_Config_Ini(dirname(__FILE__) . '/config/routes.ini');
    $router->addConfig($config, 'routes');
}

Use the following code to generate the reverse URL in your view scripts:

$this->url(array('page' => 3));

which will generate

/devices/page/3/

I believe you can modify your code like the following to make the reverse URL to work:

$router->addRoute('category', new Zend_Controller_Router_Route (
  'categories/:category',
  array(
    'controller' => 'category',
    'action' => 'modify',
  ),
  array('category' => 'category'),   //Not sure about this line. Do experiment.
  'categories/%d'
));
Raj
  • 22,346
  • 14
  • 99
  • 142
  • Hmm.. According to the Zend manual (http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.regex), this should only be needed for Regex router? "Since regex patterns are not easily reversed, you will need to prepare a reverse URL if you wish to use a URL helper or even an assemble method of this class." – Jon Gjengset Dec 01 '11 at 23:20
  • Nope, this doesn't work for Route_Route. I get: "Catchable fatal error: Argument 4 passed to Zend_Controller_Router_Route::__construct() must be an instance of Zend_Translate, string given" – Jon Gjengset Dec 02 '11 at 08:15