How can I setup a simple custom route using Zend Framework? - php

I'm looking to setup a custom route which supplies implicit parameter names to a Zend_Application. Essentially, I have an incoming URL which looks like this:
/StandardSystems/Dell/LatitudeE6500
I'd like that to be mapped to the StandardsystemsController, and I'd like that controller to be passed parameters "make" => "Dell" and "model" => "LatitudeE6500".
How can I setup such a system using Zend_Application and Zend_Controller_Router?
EDIT: I didn't explain myself all that clearly I guess -- if make and model aren't present I'd like to redirect the user to another action on the StandardsystemsController. currently, using Ballsacian1's answer with this in application.ini:
resources.router.routes.StandardSystem.route = "/StandardSystem/:make/:model"
resources.router.routes.StandardSystem.defaults.controller = "StandardSystem"
resources.router.routes.StandardSystem.defaults.action = "system"
resources.router.routes.StandardSystem.defaults.make = ""
resources.router.routes.StandardSystem.defaults.model = ""
resources.router.routes.StandardSystemDefault.route = "/StandardSystem"
resources.router.routes.StandardSystemDefault.defaults.controller = "StandardSystem"
resources.router.routes.StandardSystemDefault.defaults.action = "index"

You would first instantiate a new Zend_Controller_Router_Route to create your route.
$stdsys_route = new Zend_Controller_Router_Route(
'/StandardSystems/:make/:model',
array(
'controller' => 'StandardsystemsController',
'action' => 'myaction'
);
);
This route then needs to be added to your router.
$front_controller = Zend_Controller_Front::getInstance();
$front_controller->getRouter()->addRoute('stdsys', $stdsys_route);
Now when you dispatch, the route should take effect.
References:
http://framework.zend.com/manual/en/zend.controller.router.html

Resources:
resources.router.routes.StandardSystems.route = "/StandardSystems/:make/:model"
resources.router.routes.StandardSystems.defaults.controller = "standardsystems"
resources.router.routes.StandardSystems.defaults.action = "index"

Related

Default routing in Zend Framework after defining some routes

I've been writing a project since some time and I've used the default routing, the :module\:controller:\:action.
After some time, I've added some routers to my config like:
resources.router.routes.page.route = "page/:slug"
resources.router.routes.page.defaults.module = "default"
resources.router.routes.page.defaults.controller = "pages"
resources.router.routes.page.defaults.action = "view"
resources.router.routes.page.defaults.slug = ""
But, after that, when I click on some link generated by view URL helper with one of the new routes all other links ignore some of given paramters. Example, I've got route:
resources.router.routes.project.route = "project/:slug"
resources.router.routes.project.defaults.module = "projects"
resources.router.routes.project.defaults.controller = "projects"
resources.router.routes.project.defaults.action = "view"
resources.router.routes.project.defaults.slug = ""
If I go to a link /project/test then link like this:
$this->url(
array('module' => 'admin', 'action' => 'list-users', 'controller' => 'users')
, null,true
);
will point to "/project"
Is there any possibility to maintain the default routing on top of custom routes? Can I add some default router that will work the same as the default one? It's probably something simple but I maybe missed the point. Thanks for all the help.
I've added something like this but with no effect:
resources.router.routes.default.route = ":module/:controller/:action"
resources.router.routes.default.defaults.module = "default"
resources.router.routes.default.defaults.controller = "pages"
resources.router.routes.default.defaults.action = "view"
resources.router.routes.default.defaults.slug = ""
In order for you to set your custom routing, you need to get the router component and pass your routes into it.
This is how I did mine in a project I am working on. In your Bootstrap class, you create the following function
protected function _initRoutes()
{
$this->bootstrap('frontcontroller');
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$myRoutes = new Zend_Config_Ini(APPLICATION_PATH . '/configs/routes.ini','production');
$router->addConfig($myRoutes,'routes');
This calls the front controller and gets the router from it. I then pass my routes config into it.
I hope this answers your question.
The problem is that the options for url helper are as follows:
url($urlOptions, $name, $reset)
Therefore, when you set $name to null, current route ('project') is used. Not event setting $reset to true will help. Replace null with 'default' and it should work.

Zend - routing rules based on parameters number

in my project I'm using zend to handle routing. Atm we've got routing rules which looks like this:
array(
'match' => 'page',
'params' => array('page', 'idConfiguration'),
'controller' => 'controler1',
'action' => 'action1'
)
So we access this action by: http://base_url/page/1/1223324 for example.
Is there a simple solution to create rules so i can determine which action is called based on number of params?
I'd like it to look the following way:
http://base_url/ - action 0
http://base_url/pageNumber - action 1
http://base_url/pageNumber/idConfiguration - action 2
http://base_url/pageNumber/idConfiguration/someotherparam - action 3
Thank you in advance for help
Ini-based solution (hope I understand what you want):
routes.action0.route = "/:pageNumber"
routes.action0.defaults.controller = "controller0"
routes.action0.defaults.action = "action0"
routes.action0.reqs.pageNumber = "\d+"
routes.action1.route = "/:pageNumber/:idConfiguration"
routes.action1.defaults.controller = "controller1"
routes.action1.defaults.action = "action1"
routes.action1.reqs.pageNumber = "\d+"
routes.action1.reqs.idConfiguration= "\d+"
routes.action2.route = "/:pageNumber/:idConfiguration/:someOtherParam"
routes.action2.defaults.controller = "controller2"
routes.action2.defaults.action = "action2"
routes.action2.reqs.pageNumber = "\d+"
routes.action2.reqs.idConfiguration= "\d+"
routes.action2.reqs.someOtherParam = "someOtherRegEx"
You can subclass Zend_Controller_Router_Route and create the routing behaviour you like. Of the top of my head, and without testing it you can try something like this:
class MyRoute extends Zend_Controller_Router_Route
{
public function match($path)
{
$result = array(
'controller' => 'index',
'action' => substr_count($path, '/'),
);
return $result;
}
}
You would need to add validations, of course. Also you should return FALSE if the URL doesn't match and you want it to be tested with other routes. But this should give you a general idea on how to work this out.

Append param to current URL with view helper in Zend

In my layout-script I wish to create a link, appending [?|&]lang=en to the current url, using the url view helper. So, I want this to happen:
http://localhost/user/edit/1 => http://localhost/user/edit/1?lang=en
http://localhost/index?page=2 => http://localhost/index?page=2&lang=en
I have tried the solution suggested Zend Framework: Append query strings to current page url, accessing the router directly, but that does work.
My layout-script contains:
English
If the default route is used, it will append /lang/en, but when another route is used, nothing is appended at all.
So, is there any way to do this with in Zend without me having to parse the url?
Edit
Sorry for my faulty explanation. No, I haven't made a custom router. I have just added other routes. My bad. One route that doesn't work is:
$Routes = array(
'user' => array(
'route' => 'admin/user/:mode/:id',
'defaults' => array('controller' => 'admin', 'action' => 'user', 'mode'=>'', 'id' => 0)
)
);
foreach( $Routes as $k=>$v ) {
$route = new Zend_Controller_Router_Route($v['route'], $v['defaults']);
$router->addRoute($k, $route);
}
Upd:
You must add wildcard to your route or define 'lang' parameter explicitly.
'admin/user/:mode/:id/*'
Additionally, according to your comment, you can do something like this:
class controllerplugin extends Zend_Controller_Plugin_Abstract
{
function routeShutdown($request)
{
if($request->getParam('lang', false) {
//store lang
Zend_Controller_Front::getInstance()->getRouter()->setGlobalParam('lang', NULL); //check if this will remove lang from wildcard parameters, have no working zf installation here to check.
}
}
}

Zend Framework Router dynamic routes

I bumped into a problem and I can't seem to find a good solution to make it work. I have to make some dynamic routes into a Zend Framework project. I'll explain shortly what my problem is:
I need to have dynamic custom routes that "extend" the default route (module/controller/action/params). The project I'm working for has several partners and the routes have to work with those.
To store the partners I've made a static class and it looks like this.
<?php
class App_Partner
{
static public $partners = array(
array(
'name' => 'partner1',
'picture' => 'partner1.jpg'
),
array(
'name' => 'partner2',
'picture' => 'partner2.jpg'
),
array(
'name' => 'partner3',
'picture' => 'partner3.jpg'
)
);
static public function routePartners() {
$partners = array();
foreach(self::$partners as $partner) {
array_push($partners, strtolower($partner['name']));
}
$regex = '(' . implode('|', $partners) . ')';
return $regex;
}
}
So App_Partner::routePartners() return me a string like (partner1|partner2|partner3) which I use to create the right routes. My goal is to have the custom routes for each partner for every route I have set in the Bootstrap. So if I have a route add-product.html set I want it to work for each partner as partner1/add-product.html, partner2/add-product.html and partner3/add-product.html.
Also, partner1/, partner2/, partner3 should route to default/index/index.
In fact, I made this thing to work using routes like the one below.
<?php
$routeProposal = new Zend_Controller_Router_Route_Regex(
App_Partner::routePartners() . '?/?proposals.html',
array(
'module' => 'default',
'controller' => 'proposal',
'action' => 'index',
'page' => 1
),
array( 1 => 'partner'),
"%s/proposals.html"
);
$router->addRoute('proposal', $routeProposal);
The problem
The above route works fine if I use a partner in the request URI, but if I don't, I get double slashes like public//proposals.html because of the reverse route set in the route above to be "%s/proposals.html". I can't seem to find a way to avoid this reverse route because I build my urls using the url view helper and if the reverse route isn't set I get an exception stating this.
I also need the routes to work without a partner set, which will be the default way (add-product.html, proposals.html etc).
From your description, it seems like you're looking for a zend router chain, where your partner is an optional chain.
Here's a similar question, but using a hostname route : Zend Framework: get subdomain parameter from route. I adapted it to solve your problem, just put the following in your Bootstrap.php to initialize the routing :
protected function _initRoute()
{
$this->bootstrap('FrontController');
$router = $this->getResource('FrontController')->getRouter();
// Default route
$router->removeDefaultRoutes();
$defaultRoute = new Zend_Controller_Router_Route(
':controller/:action/*',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index',
)
);
$router->addRoute('default', $defaultRoute);
$partnerRoute = new Zend_Controller_Router_Route(
':partner',
array('partner' => 'none'),
array('partner' => '^(partner1|partner2|partner3)$')
);
$router->addRoute('partner', $partnerRoute->chain($defaultRoute));
}
Change as you see fit. In your controllers you will only get a value for the partner parameter if it was actually specified AND valid (you will get a routing error if the partner doesn't exist)...
I use a similar process to detech lang, in my route (but with a ini file).
You can use a default value for you partners parameter to make the route working without partner, and add a ? to your regex.
But actually, I don't know how to avoid the double //...
Hope that helps.
EDIT: For your information, here is a simplified version of my route with language:
routes.lang.type = "Zend_Controller_Router_Route"
routes.lang.route = "lang/:language/*"
routes.lang.reqs.language = "^(en|fr|nl|de)?$"
routes.lang.defaults.language = none
routes.lang.defaults.module = default
routes.lang.defaults.controller = index
routes.lang.defaults.action = language

How to set up Hierarchical Zend Rest Routes?

With the Zend Framework, I am trying to build routes for a REST api on resources organized in the following pattern:
http://example.org/users/
http://example.org/users/234
http://example.org/users/234/items
http://example.org/users/234/items/34
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?
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']));
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');
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.

Categories