zend router with arbitrary paths - php

so I'm setting up a router
protected function _initRoutes(){
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter();
$routerInfo = array('action' => 'theaction',
'controller' => 'thecontroller',);
$route = new Zend_Controller_Router_Route(
'some/path',
$routerInfo
);
$router->addRoute('some/path', $route);
return $router;
}
so controller 'some' and action 'path' doesn't really exist. instead, when the user goes to /some/path, it should redirect to 'theaction/thecontroller' instead....
my question is...how do I set it so that I can accept an abitrary number of parameters after the /some/path...for instance, I want /some/path/other/param to also redirect to the same page...so as long as the first segment of the path is /some/path, regardless of what follows I want them all to redirect to the same controller and action
I know that you can do /some/path/*/*....but that'll only work if there's only 2 other path items after /some/path.....I want this to work for an arbitrary number of parameters....so /some/path/param1/value1/param2/value2/param3/value3 should also still work and it'll be as if the user typed thecontroller/theaction/param1/value1/param2/value2/param3/valu3...

You simply use a single asterisk, eg
$route = new Zend_Controller_Router_Route(
'some/path/*',
array(
'action' => 'theaction',
'controller' => 'thecontroller',
'module' => 'default'
)
);
// can't say for sure but a slash in the route name is probably a bad idea
// try a hyphen instead
$router->addRoute('some-path', $route);
See the 3rd example here - http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.standard
FYI, don't get the FrontController resource like that in your Bootstrap methods. Use this instead...
$this->bootstrap('FrontController');
$front = $this->getResource('FrontController');

Related

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.

Kohana: Requested URL was Not Found

So I'm trying to install and get running Kohana. I am very new to it and frameworks in general (though I have used CakePHP a little bit).
Anyways...in my bootstrap file I have this:
// GET PARAMS -- This basically splits domain.com/kohana/controller/action/param1/etc
// into: controller | action | param1 | etc
$requestURI = explode('/', $_SERVER['REQUEST_URI']);
$scriptName = explode('/',$_SERVER['SCRIPT_NAME']);
for($i= 0;$i < sizeof($scriptName);$i++){
if ($requestURI[$i] == $scriptName[$i]){
unset($requestURI[$i]);
}
}
$param = array_values($requestURI);
$controller = # $param[0];
$action = # $param[1];
$param1 = # $param[2];
$param2 = # $param[3];
$param3 = # $param[4];
$param4 = # $param[5];
$param5 = # $param[6];
$param6 = # $param[7];
Now, I want to connect to my database and basically see if the first param aka $param[0] aka $controller is equal to one of my pages "categories" (corresponds to my categories_pages table). If it IS a category then I want to use the default "categories" controller otherwise, the controller should be whatever $param[0] is. This means if I go to domain.com/kohana/movies or domain.com/kohana/games it will display the categories controller otherwise domain.com/kohana/users will display the users controller.
$db = Database::instance();
$getiscategory = DB::select('*')->from('categories_pages')->where('directory', '=', $controller)->execute();
$is_category = $getiscategory->count();
if($is_category){
$controller = "categories";
}
$controller = (empty($controller)) ? 'index' : $controller;
$action = (empty($action)) ? 'index' : $action;
What I wanted to accomplish above works. If I echo $is_category I see that the value 1 is returned when there is a category match and if I echo $controller, I see that "categories" is set to be the controller.
Here is my code for the actual routing method...
Route::set(
'custom',
'(<controller>(/<action>(/<param1>)(/<param2>(/<param3>(/<param4>(/<param5>(/<param6>)))))))'
)->defaults(array(
'controller' => $controller,
'action' => $action,
'param1' => $param1,
'param2' => $param2,
'param3' => $param3,
'param4' => $param4,
'param5' => $param5,
'param6' => $param6,
));
Unfortunately, I'm not sure where it's routing to. As I mentioned $controller is returned previously as categories which is correct but yet I receive the error message "HTTP_Exception_404 [404]: The Requested URL $param[0] (movies or games, etc) was not found on this server."
Keep in mind I do not have a controller class for $param[0] if it matches a category because I want to use the "categories" controller class. If I go to domain.com/kohana/categories it works fine.
Anyone have any ideas/know a work-around?
Addition #1
I figured out that even though the categories controller is called and the correct action is called, it still is requiring the "shows" controller to display. I added a shows controller with the very basic info (template, content, etc) and it showed correctly. Is there a work around in the routing class to make the designated controller show? Like I said, I tell it what controller to go to and it acknowledges it but it doesn't actually go to it.
You're overcomplicating things I think. Also your code would force a limit of 6 parameters on every request.
I'll probably be easier to use two different routes, and if it doesn't match the first, then it can fall back to the second.
Route::set(
'categories',
'(<category>(/<action>(/<param1>)(/<param2>(/<param3>(/<param4>(/<param5>(/<param6>)))))))',
array('category' => '(movies|games)')
)->defaults(array(
'controller' => 'category',
'action' => 'index',
));
Route::set(
'users',
'<username>(/<action>(/<param1>)(/<param2>(/<param3>(/<param4>(/<param5>(/<param6>))))))'
)->defaults(array(
'controller' => 'users',
'action' => 'index',
));
If you only have one or two categories you could build them into the regex string, with some caching of course.
Otherwise, look up lambda routes, they're the means by which you can have dynamic routes like this.

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 can I setup a simple custom route using Zend Framework?

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"

Categories