I have the following route set at the end of the route list for my site which allows a final check on the uri value to provide my site users with a vanity URL (http://example.com/username)
Route::set('profile', '<path>/(<page>)',
array(
"path" => "[a-zA-Z0-9_-]+",
"page" => (blog|photos)))
->defaults(array(
'controller' => 'welcome',
'action' => 'profile'
));
This route directs properly to the welcome controller and the profile method, however I was wondering if there was a way to get the path and page values sent to the method like so:
action_profile($var1, $var2) {
echo $var1 . ' ' . $var2;
}
I don't want to rely on $this->request->uri() and exploding the result into an array unless there is absolutely no other way of doing this.
Read the manuals please: http://kohanaframework.org/3.0/guide/kohana/routing#request-parameters. $this->request->param('param-name') will helps.
Related
I wanted to ask, about strategy, how can i archive this:
I have url: www.mydomain.com/pages
Now, if some if clausure will return true, i want attach this param to all urls:
www.mydomain.com/pages?id=swa or
www.mydomain.com?id=swa
I have no idea how to start,
Thank You for help.
Your best bet would probably be to use a URL filter, it will affect all URLs that are being generated using the core helpers or the Router class, as long as they are being passed as routing arrays, ie
['controller' => 'abc', 'action' => 'xyz', /* ... */]
URLs passed as strings, like /abc/xyz will not be affected!
\Cake\Routing\Router::addUrlFilter(function ($params, $request) {
$key = 'id';
$value = 'swa';
if (!array_key_exists($key, $params)) {
$params[$key] = $value;
}
return $params;
});
This would add the parameter to all URLs (unless they already have that parameter set). But be careful, in case there is a matching connected route that defines a route element with the same name, it will steal the parameter and use it for the element instead of adding it to the query string!
Also note that this will only affect form actions that do explicitly define an action URL, if you'd wanted it to affect the ones that pick up the current URL too, then you'd also have to modify $request->query
$request->query[$key] = $value;
See also
Cookbook > Routing > Creating Persistent URL Parameters
API > \Core\Routing\Router::addUrlFilter()
If it is a one off you can do that using redirects
return $this->redirect(['controller' => 'Pages', 'action' => 'display', $pageId]);
or via html helper
echo $this->Html->link(
'Page 1',
['controller' => 'Pages', 'action' => 'display', 1]
);
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.
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.
}
}
}
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
I'm new to cakephp...and I have a page with a url this:
http://localhost/books/filteredByAuthor/John-Doe
so the controller is ´books´, the action is ´filteredByAuthor´ and ´John-Doe´ is a parameter.. but the url looks ugly so i've added a Route like this:
Router::connect('/author/:name', array( 'controller' => 'books','action' => 'filteredByAuthor'), array('pass'=>array('name'),'name'=>".*"));
and now my link is:
http://localhost/author/John-Doe
the problem is that the view has a paginator and when i change the page (by clicking on the next or prev button).. the paginator won't consider my routing... and will change the url to this
http://localhost/books/filteredByAuthor/John-Doe/page:2
the code on my view is just:
<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
the documentation doesn't say anything about avoiding this and i've spent hours reading the paginators source code and api.. and in the end i just want my links to be something like this: (with the sort and direction included on the url)
http://localhost/author/John-Doe/1/name/asc
Is it possible to do that and how?
hate to answer my own question... but this might save some time to another developper =) (is all about getting good karma)
i found out that you can pass an "options" array to the paginator, and inside that array you can specify the url (an array of: controller, action and parameters) that the paginator will use to create the links.. so you have to write all the possible routes in the routes.php file. Basically there are 3 possibilities:
when the "page" is not defined
For example:
http://localhost/author/John-Doe
the paginator will assume that the it's the first page. The corresponding route would be:
Router::connect('/author/:name', array( 'controller' => 'books','action' => 'filteredByAuthor'),array('pass'=>array('name'),'name'=>'[a-zA-Z\-]+'));
when the "page" is defined
For example:
http://localhost/author/John-Doe/3 (page 3)
The route would be:
Router::connect('/author/:name/:page', array( 'controller' => 'books','action' => 'filteredByAuthor'),array('pass'=>array('name','page'),'name'=>'[a-zA-Z\-]+','page'=>'[0-9]+'));
finally when the page and the sort is defined on the url (by clicking on the sort links created by the paginator).
For example:
http://localhost/author/John-Doe/3/title/desc (John Doe's books ordered desc by title)
The route is:
Router::connect('/author/:name/:page/:sort/:direction', array( 'controller' => 'books','action' => 'filteredByAuthor'),
array('pass'=>array('name','page','sort','direction'),
'name'=>"[a-zA-Z\-]+",
'page'=>'[0-9]*',
'sort'=>'[a-zA-Z\.]+',
'direction'=>'[a-z]+',
));
on the view you have to unset the url created by the paginator, cause you'll specify your own url array on the controller:
Controller:
function filteredByAuthor($name = null,$page = null , $sort = null , $direction = null){
$option_url = array('controller'=>'books','action'=>'filteredByAuthor','name'=>$name);
if($sort){
$this->passedArgs['sort'] = $sort;
$options_url['sort'] = $sort;
}
if($direction){
$this->passedArgs['direction'] = $direction;
$options_url['direction'] = $direction;
}
Send the variable $options_url to the view using set()... so in the view you'll need to do this:
View:
unset($this->Paginator->options['url']);
echo $this->Paginator->prev(__('« Précédente', true), array('url'=>$options_url), null, array('class'=>'disabled'));
echo $this->Paginator->numbers(array('separator'=>'','url'=>$options_url));
echo $this->Paginator->next(__('Suivante »', true), array('url'=>$options_url), null, array('class' => 'disabled'));
Now, on the sort links you'll need to unset the variables 'sort' and 'direction'. We already used them to create the links on the paginator, but if we dont delete them, then the sort() function will use them... and we wont be able to sort =)
$options_sort = $options_url;
unset($options_sort['direction']);
unset($options_sort['sort']);
echo $this->Paginator->sort('Produit <span> </span>', 'title',array('escape'=>false,'url'=>$options_sort));
hope this helps =)