I am trying to set a custom route for friendly url when loading a tag, by that I mean that I want to convert this: http://test.com/en/results?search_query=data&search=tag to this http://test.com/en/tag/data
Tried to do so by setting this in my routes.php:
$route['^(en|es|ro)/tag/(:any)'] = "fetch/results?search_query=$1&search=tag";
But no success, am I doing it wrong?
My routes.php:
$route['default_controller'] = "home";
// URI like '/en/about' -> use controller 'about'
$route['^(en|es|ro)/video/(.+)$'] = "video/id/$2";
$route['^(en|es|ro)/results$'] = "fetch/results$2";
$route['(en|es|ro)/tag/(:any)'] = "fetch/results?search_query=$2&search=tag";
$route['^(en|es|ro)/(.+)$'] = "$2";
// '/en', '/de', '/fr' and '/nl' URIs -> use default controller
$route['^(en|es|ro)$'] = $route['default_controller'];
$route['404_override'] = '';
I'm fairly sure the ^ is not necessary. Try without it:
$route['(en|es|ro)/tag/(:any)'] = "fetch/results?search_query=$1&search=tag";
In that context, ^ will be treated as a literal string. If you wanted top use a regex, I believe you'd have to wrap the regex itself in parentheses, like so:
$route['(^(en|es|ro))/tag/(:any)'] = "fetch/results?search_query=$1&search=tag";
I'm not 100% certain on that, but if I'm correct both should work. However, routes always assume the first part of the pattern is what the string should start with, so the ^ shouldn't be necessary anyways.
One more thing: You aren't using the second match, but the first. I believe you want to replace $1 with $2 in your route.
$route['(en|es|ro)/tag/(:any)'] = "fetch/results?search_query=$2&search=tag";
// ^^^1^^^^ ^^^2^^ ^^
EDIT: Upon further investigation and testing, it seems that Codeigniter cannot properly handle routes that use a query string like ?key=value. If you use a slash before the ? question mark, you can at least get it to route to the right controller and method:
$route['(en|es|ro)/tag/(:any)'] = "fetch/results/?search_query=$2&search=tag";
A url like this:
http://example.com/es/tag/Codeigniter's Router
...will be routed to the results method with this string as an argument, but $_GET will be empty:
?search_query=Codeigniter%27s%20Router&search=tag
So, you could pick apart the argument with parse_str():
function results($request)
{
$request = ltrim($request, '?');
parse_str($request, $get);
// echo $get['search_query']
}
You could always use .htaccess of course, but I understand the desire to keep all the routing logic in one place. Sorry if this isn't the answer you hoped for, but I'm afraid that without writing a custom router it's not possible to do this the obvious way in Codeigniter. My suggestion would probably be to find another way to handle your routing and the way you're accessing data from the URL.
You may need to escape the forwardslashes around tag. So it should look like this:
$route['^(en|es|ro)\/tag\/(:any)']
I have something similar, and it looks like
$route['(:any)/something/(:any)'] = "real/$2/path/$1";
Related
I saw this route I downloaded from sample module at pyrocms
$route['sample(/:num)?'] = 'sample/index$1';
I tried to removed the '$1' above and the site runs smooth. I am wondering what's that for, and can I remove it.
$1 would be whatever matched by (:num) group - which is, really, any valid numbers. Whatever you add will get passed as the parameter for view method in pages controller. for example
$route['sample(/:num)?'] = 'sample/index/$1';
now in sample controller
function index($id){
// $id something that matched by group (:num)
}
$1 in the sense anything comes dynamically after the url sample/index
I've built my first RESTful API ever and used Slim as my framework. It works well so far.
Now I have seen a great API Design Guide which explained, the best way to build an API is to keep the levels flat. I want to do that and try to figure out how to build an URI like this:
my-domain.int/groups/search?q=my_query
The /groups part already works with GET, POST, PUT, DELETE and also the search query works like this:
my-domain.int/groups/search/my_query
This is the code I use for the routing in PHP:
$app->get('/groups/search/:query', 'findByName');
I just can't figure out how to build optional parameters with an question mark in Slim. I wasn't able to find anything on Google.
EDIT:
Since the search not seems to be suitable for my scenario I try to show another way of what I want to realize:
Let's say I want to get a partial response from the API. The request should look like that:
my-domain.int/groups?fields=name,description
Not like that:
my-domain.int/groups/fields/name/description
How do I realize that in the routing?
The parameters supplied with the query string, the GET parameters, don't have to be specified in the route parameter. The framework will try to match the URI without those values. To access the GET parameters you can use the standard php approach, which is using the superglobal $_GET:
$app->get('/groups/test/', function() use ($app) {
if (isset($_GET['fields']){
$test = $_GET('fields');
echo "This is a GET route with $test";
}
});
Or you can use the framework's approach, as #Raphael mentioned in his answer:
$app->get('/groups/test/', function() use ($app) {
$test = $app->request()->get('fields');
echo "This is a GET route with $test";
});
Ok I found an example that does what I need on http://help.slimframework.com/discussions/problems/844-instead
If you want to construct an URI Style like
home.int/groups/test?fields=name,description
you need to build a rout like this
$app->get('/groups/test/', function() use ($app) {
$test = $app->request()->get('fields');
echo "This is a GET route with $test";
});
It echoes:
This is a GET route with name,description
Even though it's not an array at least I can use the question mark. With Wildcards I have to use /
You may also have optional route parameters. These are ideal for using one route for a blog archive. To declare optional route parameters, specify your route pattern like this:
<?php
$app = new Slim();
$app->get('/archive(/:year(/:month(/:day)))', function ($year = 2010, $month = 12, $day = 05) {
echo sprintf('%s-%s-%s', $year, $month, $day);
});
Each subsequent route segment is optional. This route will accept HTTP requests for:
/archive
/archive/2010
/archive/2010/12
/archive/2010/12/05
If an optional route segment is omitted from the HTTP request, the default values in the callback signature are used instead.
Search query is not suitable for url parameters, as the search string might contain url separator (/ in your case). There's nothing wrong to keep it as query parameter, you don't have to push this concept everywhere.
But to answer your question, optional parameters are solved as another url:
$app->get('/groups/search/:query', 'findByName');
$app->get('/groups/search/strict/:query', 'findByNameStrict');
EDIT: It seems you want to use Slim's wildcard routes. You just need to make sure there's only one interpratation of the route.
$app->get('/groups/fields/:fields+', 'getGroupsFiltered');
Parameter $fields will be an array.
I have these routes:
$route['shop/(:any)/(:any)'] = 'product/category_listing/$1/$2';
$route['shop/(:any)/(:any)/(:any)'] = 'product/product_listing/$1/$2/$3';
When I call this url:
http://mysite.com/shop/mens/trainers/a-product
the product_listing method should be called but instead the first method (category_listing) gets called and product_listing is never invoked.
How can I make this work as required?
Order of array elements matters!
Keyword (:any) matches everything, even slashes, so in your example CodeIgniter finds the first matching route and doesn't look any further.
So, if we do like this:
$route['shop/(:any)/(:any)/(:any)'] = 'product/product_listing/$1/$2/$3';
$route['shop/(:any)/(:any)'] = 'product/category_listing/$1/$2';
...then product listing is matched first, then everything else.
Even more, you can use regular expressions (e.g. ([a-z0-9]+)) to create rules you need.
So, I'm struggeling with this problem.
I got these two types of URLS:
localhost/en/women
localhost/en/women/products
And I'm trying to tell CodeIgniter to use route X if its localhost/en/women but use route Y if its localhost/en/women/products, but It always uses the X route instead.
I tried to exclude the /products segment by using regex like this:
$route['^en/women(?!products)(.*)'] = "women";
$route['^en/women/products'] = "products";
But I can't seem to get it to work.
I hope you get what I'm looking for here.
Any feedback is appriciated.
$route['en/women/?'] = "women";
$route['en/women/products'] = "products";
Should solve this?
Basicly ^ and $ exist in the regexp by default.
Or maybe you need a:
$route['^en/women/products'] = "products";
$route['^en/women/?'] = "women";
Just have the products above, and it should override.
Use CI's WildCards!
$route['en/women'] = "women";
$route['en/women/(:any)'] = "products";
I'm using URI re-routing in CI to make better URLS. An example here would be:
$route['users/(:any)'] = "users/index/$1";
The aim here is to get rid of the index from URL. This works well. However it stops me from being able to access any functions in the users controller, for example
mywebsite.com/users/messages
Just redirects to the users/index. Is there a way around this?
Define the list of methods you wish to keep then let the rest wildcard match:
$route['users/(messages|login|something)'] = "users/$1";
$route['users/(:any)'] = "users/index/$1";
Hi I'm not familiar with CI but i have a similar routing system. The (:any) works as a sort of catch all. When my router checks the routing rules it stops checking if it has found an exact match. So then the answer would be to just add another functions route before the catch all. Like
$route['users'] = "users/index/";
$route['users/messages/(:any)'] = "users/checkmessages/$1";
$route['users/(:any)'] = "users/$1";
Not sure how CI handles this but i can think of something like the first URL part is the class and the second the function. The router or the controller module should have the intelligence to start calling the function even without the routing table.
The routing table should only be used in case of "other callable names" like i did above with the messages/checkmessages thingy.
hope that gets you going.