Setting routes in application.ini in Zend Framework - zend-framework

I'm a Zend Framework newbie, and I'm trying to work out how to add another route to my application.ini file.
I currently have my routes set up as follows:
resources.router.routes.artists.route = /artists/:stub
resources.router.routes.artists.defaults.controller = artists
resources.router.routes.artists.defaults.action = display
...so that /artists/joe-bloggs uses the "display" action of the "artists" controller to dipslay the profile the artist in question - that works fine.
What I want to do now is to set up another route so that /artists/joe-bloggs/random-gallery-name goes to the "galleries" action of the "artists" controller.
I tried adding an additional block to the application.ini file (beneath the block above) like so:
resources.router.routes.artists.route = /artists/:stub/:gallery
resources.router.routes.artists.defaults.controller = artists
resources.router.routes.artists.defaults.action = galleries
...but when I do that the page at /artists/joe-bloggs no longer works (Zend tries to route it to the "joe-bloggs" controller).
How do I set up the routes in application.ini so that I can change the action of the "artists" controller depending on whether "/:gallery" exists?
I realise I'm probably making a really stupid mistake, so please point out my stupidity and set me on the right path (no pun intended).

Try reversing the order of the routes. ZF matches routes in the opposite order they are added (so that the default route is the last to be matched)
If that doesn't work, you'll probably have to investigate regex routes with optional components.

Your second block needs to have a different route name, rename the 'artists' word to something similar to this for your new block:
resources.router.routes.artists-gal.route = /artists/:stub/:gallery
resources.router.routes.artists-gal.defaults.controller = artists
resources.router.routes.artists-gal.defaults.action = galleries

I usually setup my routes in application/Bootstrap.php (or wherever your Bootstrap.php file is)
add a method like the one below:
protected function _initRoutes()
{
$ctrl = Zend_Controller_Front::getInstance();
$router = $ctrl->getRouter();
$router->addRoute(
'artist_detail',
new Zend_Controller_Router_Route('artists/:stub',
array('controller' => 'artists',
'action' => 'display'))
);
$router->addRoute(
'artist_detail_gallery',
new Zend_Controller_Router_Route('artists/:stub/:gallery',
array('controller' => 'artists',
'action' => 'gallery'))
);
}
As far as checking weather an specific artist has a gallery, in the case of my example, i would have a galleryAction method in the ArtistsController
do a check if a gallery exists for the 'stub' request paramater, if it doesnt throw a 404:
throw new Zend_Controller_Action_Exception("Object does not exist", 404);
or redirect them to some other page:
return $this->_helper->redirector('index', 'index'); //redirect to index action of index controller
Hope this helps.

Related

zend framework this->url get different url on the same page but different url

in application\modules\admin\layouts\scripts\layout.phtml
<?php echo $this->url(array('action'=>'logout','controller'=>'user','module'=>'admin'),null,true);?>
when I visited zfmul/public/admin-cate/ , It return
/zfmul/public/admin-cate/logout
but when I visited zfmul/public/admin/categories, It return
/zfmul/public/admin/user/logout
and the two url is render to the same module, same controller, same action, I wonder why it retrun different result?
I didi some configs in application.ini,
resources.router.routes.admincategories.route = "admin-cate/:action/:id"
resources.router.routes.admincategories.defaults.module = "admin"
resources.router.routes.admincategories.defaults.controller = "categories"
resources.router.routes.admincategories.defaults.action = "index"
resources.router.routes.admincategories.reqs.action = "save|edit|index|new"
resources.router.routes.admincategories.defaults.id = "1"
resources.router.routes.admincategories.reqs.id = "\d+"
When you use $this->url, you're in fact using function url from library/Zend/View/Helper/Url.php, whose 1st line is:
$router = Zend_Controller_Front::getInstance()->getRouter();
Since you declared a custom admincategories route, you now have 2 to access those particular module/controller/actions:
Default - accessible via zfmul/public/admin/categories;
Custom - accessible via zfmul/public/admin-cate/.
Depending on the URL you use to access, the $router variable value will change accordingly and so will the result of the $this->url call as you're experiencing.
Here are a few references to questions on SO that might help you work around that behaviour:
Zend Framework: How to disable default routing?;
Zend framework: Removing default routes.

zend routes ini load routes by order according to priority.

Zend Project with multiple modules and every modules have its own routes.ini defined inside it. and every routes.ini file is being loaded using following script in module based bootstrap files.
protected function _initRoutes() {
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$routerDir = realpath(dirname(__FILE__)). "/configs/routes/moduleRoutes.ini";
$config = new Zend_Config_Ini($routerDir,'production');
$router->addConfig($config,'routes');
}
and All routes are being loaded without order. because Routes are checked in reverse order of loaded sequence and it check/execute those routes first which it should check/execute later.
Is there a way that I can add a orderBy bit (1,2,3,4...) with every route in routes.ini file of each module and load them in specific order so that It will check the routes in sequence I define.
typical routes.ini file of modules looks like this.
routes.frontindex.type = "Zend_Controller_Router_Route_Regex"
routes.frontindex.route = "/?(?!login/)([a-zA-Z0-9_-]+)?/?([a-zA-Z0-9_-]+)?/?([0-9_-]+)?"
routes.frontindex.defaults.module = mymodule1
routes.frontindex.defaults.controller = mycontroller1
routes.frontindex.map.page = 1
routes.siteimage.type = "Zend_Controller_Router_Route_Regex"
routes.siteimage.route = "siteimage/?([a-zA-Z0-9_-]+)?/?(jpg|png|gif)?"
routes.siteimage.defaults.module = mymodule1
routes.siteimage.defaults.controller = mycontroller2
routes.siteimage.defaults.action = getimage
routes.siteimage.map.imageid = 1
routes.sitemapseo.type = "Zend_Controller_Router_Route_Static"
routes.sitemapseo.route = "sitemap.xml"
routes.sitemapseo.defaults.module = mymodule1
routes.sitemapseo.defaults.controller = mycontroller3
routes.sitemapseo.defaults.action = sitemap
It can be done, but it will take some work and you'll need to be fairly comfortable with ZF.
You'll need to extend Zend_Controller_Router_Rewrite to make your own router class (which you will need to set using the front controller's setRouter() method in the bootstrap). In your router class, you'll want to:
Extend the addRoute method to add a third parameter indicating priority. (This could be a constant like Your_Router::HIGH_PRIORITY, Your_Router::MEDIUM_PRIORITY etc. or simply a number). You'll see that the existing method stores routes in an array called _routes. You could instead store routes in different array depending on the priority param ($this->_highPriorityRoutes, $this->_lowPriorityRoutes etc.)
Extend the route() method. Most of that unfortunately will be cut and paste. But you'll see that it calls array_reverse on $this->_routes and then loops though these to do the matching. You'll want to merge together your route arrays so that the end result is an array with your highest priority routes first. So you might end up with something like:
$routes = array_merge($this->_lowPriorityRoutes, $this->_highPriorityRoutes);
$routes = array_reverse($routes, true);
foreach ($routes as $name => $route) {
(...as before)
Update your ini files to add a parameter to your routes indicating the priority. Then extend the addConfig() method in the router class so it passes this parameter to the addRoute() method.
Good luck!
I don't believe you can specify an order. You'd have to write your own code to do this. I'm sure there's multiple ways, but have you considered writing a custom Zend Controller Plugin? You could make one and assemble your routes inside the routeStartup() method.
I also tried to set a priority to the routes in application.ini.
For it I readed the code of Zend_Controller_Router_Rewrite. The important functions are addRoute() and route(). My conclusion is very simple : The routes are evaluated in the oposit order compare the order in application.ini.
Example :
If I write in application.ini
routeA
routeB
routeC
routeC will be checked first, and routeB after and routeA the last.
priority routeC > priority routeB > priority routeA

How do I read the url parameters from a ZendFramework Controller

I have a ZendFramework controller whose view forms a framework similar to this:
http://foo.com/#/controler/someaction/state/city/address/
The action looks like this:
public function someactionAction()
{
$this->view->someaction = App_Model_WebService_Menu::getInstance()->getRows(array(
'address' => '1600 Pennsylvania Ave',
'returnRecordsLimit' => 1,
));
}
Is there a way where I can access state, city and address as parameters?
From Zend_Controller_Request documentation
$state = $this->getRequest()->getParam('state');
$city = $this->getRequest()->getParam('city');
$address = $this->getRequest()->getParam('address');
Ignoring the URL fragment part which I assume is reliant on some JavaScript configuration, that looks like it would be part of a custom route, ie
:controller/:action/:state/:city/:address
You will have to look into the route definition to discover the actual parameter names, after which you simply use (from your controller)
$state = $this->_getParam('state-param-name');

Zend overwrite default view object

How can I overwrite the default view object in zend framework so I could have the custom one?
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
function _initViewHelpers() {
$this->bootstrap('view');
$view = $this->getResource('view');
$view->doctype('HTML4_STRICT');
$view->setHelperPath(APPLICATION_PATH . '/helpers', '');
$view->headMeta()->appendHttpEquiv('Content-type', 'text/html;charset=utf-8')
->appendName('description', 'Zend Framework');
$view->headTitle()->setSeparator(' - ');
$view->headTitle('Zend Custom View');
$view->setScriptPath(APPLICATION_PATH . '/themes/admin');
return $view;
}
}
The default view contains default script path for module. I want one path for all modules, to enable template system. The setScriptPath method should overwrite the default path generated by the view object, but it doesn't.
array(2) { [0]=> string(66) "C:/xampp/htdocs/NEOBBS_v6/application/modules/admin/views\scripts/" [1]=> string(51) "C:\xampp\htdocs\NEOBBS_v6\application/themes/admin/" }
it has two scriptPaths. Can this be done by overwriting the default view object?
What ArneRie posted is correct, however the ViewRenderer checks to see whether the standard script path is set and adds it if not. Since the paths are checked LIFO, what's happening is that the ViewRenderer is adding the standard path after your one and then always using that one.
What worked for me was to set both the standard path and my custom path at the same time, with the custom one being last, something like:
$view->setScriptPath(array(
APPLICATION_PATH . '/views/scripts/', // or whatever the standard path is
APPLICATION_PATH . '/themes/admin'
));
there may be a better solution for this though.
Try to add:
$viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
$viewRenderer->setView($view);
Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);

Zend_Controller_Router_Route_Regex allow '?' in pattern

Imagine situation, when the url should looks like
/catalog/sectionIdent?page=1
where page param is optional.
Of course, custom route should be defined. Consider the following code:
$route = new Zend_Controller_Router_Route_Regex(
'catalog/([-a-z]+)(?:\?page=([0-9]*))?',
array('controller'=>'catalog','action'=>'list','page'=>''),
array(1=>'section',2=>'page'),
'catalog/%s?page=%d'
);
$router->addRoute('catalog-section-page',$route);
But this route won't be triggered with '?' symbol in url.
Without '?' (for example, by adding escaped '!' symbol to pattern) everything works as it should.
Is there any way to achieve '?' presence in custom defined regex route? Maybe I'm doing something wrong in pattern?
P.S.: Don't offer to use '/' instead of '?', question is exactly about pattern restrictions in Zend_Controller_Router_Route_Regex implementation.
The ZF routing classes operate on the REQUEST_URI with the query string stripped off, so you may have a hard time get this working in the way you are expecting. However, I believe GET parameters are put into the request object by default, so you shouldn't need to cater for them in your routes. I'd suggest changing your route to remove the query string parts:
$route = new Zend_Controller_Router_Route_Regex(
'catalog/([-a-z]+)',
array('controller'=>'catalog','action'=>'list'),
array(1=>'section'),
'catalog/%s'
);
$router->addRoute('catalog-section-page',$route);
You should still be able to access the params in your controller as if they had been populated by the routes:
public function listAction()
{
echo $this->_getParam('page');
}
and you can use the same method to set a default:
public function listAction()
{
$page = $this->_getParam('page', 1); // defaults to 1 if no page in URL
}
You just may need to sanitise them there (make sure they are numeric).
Edit:
Example of URL helper with this route:
echo $this->url(array('section' => 'foo', 'page' => 2), 'catalog-section-page')