I'm trying to make a route rule to make my request to the main page in kohana. It's sth of this kind: http://my_site/
And got into trouble here. In docs they write i can make this or that, lots of variants, but no example for mine. Simply saying if i try to do this way
Route::set('main/index', '')
->defaults(array(
'controller' => 'main',
'action' => 'index',
));
then if i write Route::get('main/index')->uri() on page http://my_site/hi i get a link to the same page. If i do it this way
Route::set('main/index', null)
->defaults(array(
'controller' => 'main',
'action' => 'index',
));
No result again, uri callback should have a valid value.
In official manual they suggest this variant
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'welcome',
'action' => 'index',
));
But i need a rule with a strict match i.e. just http://my_site/, not http://my_site/(<controller>(/<action>(/<id>)))
Is there a way to help me out from this without rewriting Route class?
Thanks in advance
Route::set('main/index', '')
->defaults(array(
'controller' => 'main',
'action' => 'index',
));
Works just for for me if I make sure that route is set before any other route that may match an empty uri. Routes are checked for a match in the order they are added.
If you want to know what if your route was matched (on a development server) you can set the default controller to a non-existing one like 'bogus'. Then Kohana wil throw a Http_Exception_404 and the exception handler will serve you an error page. (Turn on kohana errors if it does not.) On that page click on the 'arguments' link of the first trace of the stack trace. You should then see something like the following:
object Request(18) {
...snip...
protected _route => object Route(5) {
protected _callback => NULL
protected _uri => string(0) ""
protected _regex => array(0)
protected _defaults => array(1) (
"controller" => string(5) "bogus" // the non-existing bogus controller default
)
protected _route_regex => string(6) "#^$#uD"
}
...snip...
}
I got the above by placing the following route before I add any other route (which could match that uri too):
Route::set('main/index', '')
->defaults(array(
'controller' => 'bogus',
));
Also make sure no other route uses the 'main/index' name as it will overwrite the older one. Actually, I just took a look at the code of Route::uri() and guess what. Static routes (routes that have no '<' or '(' in them) should return the current url. Since an empty string is a static route the result Route::uri of that route would always be only the host. Which suggests me you are overriding the 'main/index' route assuming the uri was set to an empty string.
Also when using a NULL as the uri for a route it is assumed it came from the cache and you end up whith an empty route when it did not came from the cache.
Your Route::get('main/index')->uri() returns a relative uri, which in this case would be an empty string. What you want to do is use the url method of the Route class: Route::url('main/index'). This will give you an url that has gone through Url::site as well.
Related
I recently started working with the kohana 3.3.1 framework and ran into some problems.
I want to create different routes for different entry points. Right now, this is the default route, which seems to work fine(I think):
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'welcome',
'action' => 'index',
));
When I go to the website, it displays 'hello, world!'.
I have a controller called Street, located in application/classes/Controller/Street.php.
The code to this controller is:
<?php defined('SYSPATH') or die('No direct script access.');
class Controller_Street extends Controller {
public function action_index()
{
$this->response->body('hello, street!');
}
The problem is, that I want to type /something behind the URI, and it should redirect to the defined controller, and action. But it doesn't seem to work. I get 404 error's when I type ANYTHING behind the default URI.
For routes, i use this
/**
* Set the routes. Each route must have a minimum of a name, a URI and a set of
* defaults for the URI.
*/
Route::set('test1', 'street/<id>')
->defaults(array(
'controller' => 'street',
'action' => 'index',
));
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'welcome',
'action' => 'index',
));
Any help would be gladly appreciated.
EDIT
I just tried #Darsstar 's instruction to go to /index.php/street, and it worked!
But now, when I try to go to /index.php/street/derp, I get an error saying
The requested URL derp was not found on this server.
So it's not yet working properly I guess
Since the /index.php/street version works go and read the Clean URLs tutorial if you haven't already. If you have, double check everything!
If you have just those two routes, in that order, /index.php/street/derp should have matched the route 'test1'.
The error message 'The requested URL derp was not found on this server.' says you went to /index.php/derp, not index.php/street/derp. Which would match the default route and be dispatched to Controller_Derp::action_index(), but it doesn't exist so Request_Internal::execute() throws a HTTP_Exception_404.
The default route is more of and example. The is a discussion on Kohana's issue tracker to remove it since a catchall default route is a bad practice. Routes should be specific. I recommend to remove it.
And if you think having a catchall route is a good way to catch all 404 requests, please let the Custom Error Pages tutorial prove you wrong.
In Kohana 3.2 I'm using the default route for a simple controller/action/id setup:
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'home',
'action' => 'index',
'id' => '0',
));
Per the documentation it's pretty easy to wire up controllers and actions to a simple route like this, but route parameters (in this case id) are never accessible in the controllers.
So for example I have a route:
/user/info/123
And the controller handling that route gets called successfully:
public function action_info()
{
$id = $this->request->param('id');
echo "id=" . $id; //nothing
echo "is_null=" . is_null($this->request->param('id')); //1
}
But $this->request->param('id') is always set to null.
This seems like about the simplest example I can come up with, what could I be doing wrong here?
Turns out the company I'm working with extended Kohana with a request->param() function to do something without realizing that was already a function in Kohana, and this broke the built in functionality. Using the built in Kohana request function fixes this problem.
So this turns out to be a non-question as this is the correct way to get request parameters after all. :)
Have you tried this?
Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
'controller' => 'home',
'action' => 'index',
'id' => '\d+',
));
I am using PHP 5.5 and Kohana 3.3
I am developing a website structure that always has the language preference of the user as the first "item" of a uri.
For example:
mydomain.com/en/products
mydomain.com/de/store
Now, I am sure that some users will try and be clever and type things in like:
mydomain.com/products
which is fine, I just would like them to be rerouted to
mydomain.com/en/products to keep everything consistent.
The code I have below is working as long as the uri has only one "directory" in the URI e.g.
mydomain.com/products
mydomain.com/store
but not for uris like down further subdirectories like:
mydomain.com/products/something
mydomain.com/store/purchase/info
Here are my routes:
Route::set('home_page', '(<lang>)')
->defaults(array(
'controller' => 'Index'
));
Route::set('default', '(<lang>(/<controller>(/<action>(/<subfolder>))))')
->defaults(array(
'controller' => 'Index',
'action' => 'index'
));
Here is the code in my parent controller that every other controller inherits from:
public function before()
{
$this->uri = $this->request->uri();
$this->lang = $this->request->param('lang');
//If user directly inputted url mydomain.com without language information, redirect them to language version of site
//TODO use cookie information to guess language preferences if possible
if(!isset($this->lang))
{
$this->redirect('en/', 302);
}
//If the first part of path does not match a language redirect to english version of uri
if(!in_array($this->lang, ContentManager::getSupportedLangs()))
{
$this->redirect('en/'.$this->uri, 302);
}
}
You could replace the two routes given with this one:
Route::set('default', '(<lang>/)(<controller>(/<action>(/<subfolder>)))',
array(
'lang' => '(en|fr|pl)'
))
->defaults(array(
'controller' => 'Index',
'action' => 'index'
));
where the string (en|fr|pl) is the concatenation of your supported languages, i.e. '('.implode('|', ContentManager::getSupportedLangs()).')'.
If this solution remains obscure I'm happy to explain it in more detail but I hope you can see on reflection that your problem arose because your first route, home_page, was being matched by e.g. mydomain.com/products.
Your controllers' before() function should be revised as well. The redirects won't work as things stand because you're going to end up redirecting to e.g. en/ru/Index. So why not keep it simple and use:
public function before()
{
$default_lang = 'en';
$this->lang = $this->request->param('lang', $default_lang);
}
I believe I know how to do this, but wanted to verify with my awesome community peeps. =)
Here's an example:
I have a Controller class called 'tami', with an action 'index'.
I know that if I want someone to access that controller/action combo via an URL other than "/tami/" or "/tami/index", then I should add a route, via something like this:
Route::set('pretty_tami', 'these-are-my-initials(/<action>)')
->defaults(array(
'controller' => 'tami',
'action' => 'index',
));
But, users can still access this page via /tami/.
How can I turn off the default routing, so that the only valid routes are the ones I define?
I assume I can just remove the default route found in kohana/application/bootstrap.php. Is that correct? Or would that break something else?
I'd say exactly the same as #simshaun — either remove the default route (leaving other controllers unreachable) or check in the before() function in Controller_Tami for the uri to see if it's what you're after.
If you're using Kohana 3.1, you can now use lambda logic/anonymous functions to define your routes.
Something like this would take the extra routing logic out of the controller (which is good as we're keeping it in one place):
Route::set('default', function($uri)
{
if ($uri == 'tami' OR $uri == 'tami/index')
{
// Route not allowed by the default methods
throw new Kohana_404_Exception("Route not permitted");
}
},
'(<controller>(/<action>(/<id>)))'
);
Something I haven't yet used but it looks amazingly powerful.
I think the easiest way would be to remove the default route in your bootstrap file, yes. However, any controllers that you have not manually specified a route for can no longer be accessed.
What I would do is create a class, e.g. Controller_Derouter that Controller_Tami extends. Use the before() method in Controller_Derouter to test if the controller was accessed from the default route, and if so, throw a 404. I think you should be able to do that by comparing $this->request->controller against the first URI segment.
Edit: The solution mentioned above is unnecessary if you ever only plan on disabling the default route for just the Tami controller. If that's the case, you could just implement the before() method directly in the Tami controller.
Maybe like this?
Route::set('pretty_tami', 'these-are-my-initials/<action>')
->defaults(array(
'controller' => 'tami',
));
So there wouldn't be a default action. And you probably want to update the default route (if you still have one) with a regex to exclude tami.
Route::set('default', '(<controller>(/<action>(/<id>)))', array('controller' => '/^(?!tami)/'))
->defaults(array(
'controller' => 'welcome',
'action' => 'index',
));
When I access my site on MAMP like so, it works great
localhost/site/about-us/
When I upload it to my remote server, and access it like this
http://www.server.com/site/about-us/
all requests go back to the 'default' set up in bootstrap.php.
Here is my route setting.
Route::set('default', '(<page>)')
->defaults(array(
'page' => 'home',
'controller' => 'page',
'action' => 'index',
));
The problem is, whenever it gets uploaded to my server, any request like /about-us/ is always defaulting to home as specified when setting the route. If I change that default to 'about-us', every page goes to 'about us'.
Does anyone know what may be causing this? Thanks
UPDATE
Here is a hack that works, but is sure ugly as hell. Still I'd prefer to know why it doesn't work as per expected.
// Hack because I can not get it to go to anything except 'default' below...
$uri = $_SERVER['REQUEST_URI'];
$uri = str_replace(url::base(), '', $uri);
$page = trim($uri, '/');
if ( ! $page) $page = 'home';
Route::set('default', '(<page>)')
->defaults(array(
'page' => $page,
'controller' => 'page',
'action' => 'index',
));
Your code is basically a catch all route (it's being matched for all requests). You should restrict it like so.
Route::set('static', '(<page>)', array('page' => 'about-us'))
->defaults(array(
'controller' => 'page',
'action' => 'index',
));
The 3rd parameter is a regular expression which defines what the route should match.
That route will route everything matched in the regular expression to the page controller and its index action.
You can then use $page = $this->request->param('page'); in your action.
Are you not mistaking $page for $action?
If I try this, it works just fine. Here's my controllers action method:
public function action_index($page = NULL)
{
var_dump($page);
}
If I browse to
localhost/site/blup
I see see a nice
string(4) "blup"
being echo'd. I have the default route setup identical to yours.
It sounds like Kohana's auto-detection of the URL isn't working for your server setup... What web server is it failing on?
You could alter the Request::instance()->execute()... line in the bootstrap to start with:
Request::instance($_SERVER['REQUEST_URI'])->execute()...
That will ensure it uses the correct URI..
That being said ... as The Pixel Developer says, your route looks.. odd .. to me ;)
But - since it works on MAMP - The route is likely not the issue.