Issues

ZF-7746: Zend_Controller_Action_Helper_Url

Description

I'm getting inconsistent behavior from the url router helper and I'm not sure what is causing it. Or maybe I'm just misunderstanding what it is trying to do.

I have the following route (FYI, I'm only using the location_id in my Controller for a lookup, the rest is just for a pretty URL).

{quote} $router->addRoute( 'location', new Zend_Controller_Router_Route( 'location/:location_id/:state/:city/:name', array( 'controller' => 'locations', 'action' => 'view', 'location_id' => 1,
'state' => 'TN', 'city' => 'Nashville', 'name' => 'test' )
)
);{quote}

In view.phtml {quote}<?php echo $this->url(array('controller' => 'deals', 'action' => 'create'),null,true) ?>{quote}

When I access it from the standard mvc route: /locations/view/location_id/1/ I get the correct output {quote}/deals/create{quote}

However, if I access it via its alternate route /location/1/TN/Nashville/test I get just {quote}/location{quote} This just an example. All calls to the url helper function return the same (wrong) value unless they provide a named/static route, ie. no MVC urls are correctly created.

Additionally, if I get rid of the default values for the route parameters (below)

{quote} $router->addRoute( 'location', new Zend_Controller_Router_Route( 'location/:location_id/:state/:city/:name', array( 'controller' => 'locations', 'action' => 'view' )
)
); {quote}

Then I get the following error {quote}Application error Exception information:

Message: location_id is not specified Stack trace:

0 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Router/Rewrite.php(441): Zend_Controller_Router_Route->assemble(Array, true, true)

1 /usr/local/src/ZendFramework-1.9.0/library/Zend/View/Helper/Url.php(49): Zend_Controller_Router_Rewrite->assemble(Array, NULL, true, true)

2 [internal function]: Zend_View_Helper_Url->url(Array, NULL, true)

3 /usr/local/src/ZendFramework-1.9.0/library/Zend/View/Abstract.php(342): call_user_func_array(Array, Array)

4 [internal function]: Zend_View_Abstract->__call('url', Array)

5 /var/happyhour/application/views/scripts/locations/view.phtml(7): Zend_View->url(Array, NULL, true)

6 /usr/local/src/ZendFramework-1.9.0/library/Zend/View.php(108): include('/var/happyhour/...')

7 /usr/local/src/ZendFramework-1.9.0/library/Zend/View/Abstract.php(833): Zend_View->_run('/var/happyhour/...')

8 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Action/Helper/ViewRenderer.php(903): Zend_View_Abstract->render('locations/view....')

9 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Action/Helper/ViewRenderer.php(924): Zend_Controller_Action_Helper_ViewRenderer->renderScript('locations/view....', NULL)

10 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Action/Helper/ViewRenderer.php(963): Zend_Controller_Action_Helper_ViewRenderer->render()

11 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Action/HelperBroker.php(277): Zend_Controller_Action_Helper_ViewRenderer->postDispatch()

12 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Action.php(523): Zend_Controller_Action_HelperBroker->notifyPostDispatch()

13 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('viewAction')

14 /usr/local/src/ZendFramework-1.9.0/library/Zend/Controller/Front.php(946): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))

15 /usr/local/src/ZendFramework-1.9.0/library/Zend/Application/Bootstrap/Bootstrap.php(77): Zend_Controller_Front->dispatch()

16 /usr/local/src/ZendFramework-1.9.0/library/Zend/Application.php(335): Zend_Application_Bootstrap_Bootstrap->run()

17 /var/happyhour/public/index.php(26): Zend_Application->run()

18 {main}

Request Parameters:

array ( 'location_id' => '1', 'state' => 'TN', 'city' => 'Nashville', 'name' => 'test', 'controller' => 'locations', 'action' => 'view', ) {quote}

That is unless I do the following {quote}<?php echo $this->url(array('controller' => 'deals', 'action' => 'create'),null,false) ?>{quote} Which just returns the current url {quote}/location/1/TN/Nashville/test{quote}

strongSo, it seems to me that when you are on a non MVC url, if you use the url helper function, it interjects the current route (in this case the 'location' route) being used/viewed instead of what is passed in to the function (controller and action). Is this not a bug? Is there a workaround?strong

Comments

This is not a bug. Than you call URL view helper bq.<?php echo $this->url(array('controller' => 'deals', 'action' => 'create'),null,true) ?> you pass null as a route name. But if the route name is not provided router's assemble method uses current route. Thus, when you access the page via /locations/view/location_id/1/ the router uses default route which is Module, but when you access the page via /location/1/TN/Nashville/test it uses your location route with no :location_id, :state, :city or :name parameters provided.

I still do consider this a bug.

I've since moved on since it doesn't really make sense to use the URL view helper when calling a static route (ex. "/deal/create").

However, the real reason that I was posting this as an issue is because I cannot use MVC routes with Zend_Navigation. Zend_Navigation will have the same "bug" as demonstrated above when you access it via a non-MVC route (which I use quite frequently). There is no way for you to have it use the Controller and Action (that could be derived) from a non-MVC route.

Just to make sure I am being completely clear. If I use Zend_Navigation_Page_Mvc and access any page via a non-MVC route, then I will get the errors described above.

@Jonathan: If you need to access a non-MVC route... why aren't you using Zend_Navigation_Page_Uri instead? The MVC page is intended for use with the standard rewrite router, while the URI page is intended for anything that is not served by the ZF MVC.

This is not a bug it is the expected behaviour. with Zend_Navigation, you may specify the route to use with the "route" parameter (see http://framework.zend.com/manual/en/…).

I have ended up using Zend_Navigation_Page_Uri, but it seems to defeat (some of) the point of using Zend_Navigation...since it is possible to get to pages using the MVC and non-MVC routes I can only choose one for it to correct be able to identify with isActive.

@Matthew - I guess it just feels "wrong" to only be able to use one or the other. If I choose to ONLY use MVC then I end up with ugly URLs. If I choose to use a hybrid (which my site does), then I cannot use Zend_Navigation fully without getting the errors.

I don't know what the most elegant way to solve this issue would be, but I feel like there should be a way to tell the URL view helper (which is what causes Zend_Navigation to fail) that you want it to do a MVC lookup of the current route. Using my example above, when I go to my 'location ' route, it "knows" that I am accessing the location controller and the view action...so why can't that information be passed to the URL view helper?

@Jonathan Honestly, I actually tell people in my presentations to be deliberate when mapping URLs to the application behaviors they want to expose. Doing so has several benefits: first, you know your URLs; second, you can change the schema later, but still reference the same routes without refactoring code; third, things like Zend_Navigation become simple.

When you start expecting the router to "just figure it out," you run into problems. It's next to impossible for us to hit all the edge cases when testing, and the more flexibility and "magic" we program into the component, the less performant and more buggy it becomes. Explicitness is almost always better than magic when it comes to programming.

@Matthew - I can drop this since I have found a workaround (although not ideal). Also, thanks for taking the time to respond. I promise I'm not trying to be argumentative. I greatly appreciated all of the work you guys do!

However, I still think this is a bug. I'm not asking it to "figure it out". I'm wanting an option to be able to tell it to determine what the current MVC is of a user defined route. Again, this means that if you want to use any user defined routes, then you cannot use Zend_Navigation to its fullest...even if you deliberately planned out your routes. Its either 100% MVC routes or none. I think that is a shortcoming, sorry.

If I get some time I'll look into creating a patch that would allow this. My biggest question is how you would/should specify it to do the lookup because I do understand it would be a performance impact.