Seo-friendly url in CodeIgniter - php

I've created a filter method for filtering the products list. This is my URL:
localhost/myshop/products/filter?category=shirts&color=blue&page=1
But I want to show this way:
localhost/myshop/products/shirts/blue/1
How can I achieve it?

Assuming that Products::filter() is responsible for handling the request, you can rewrite the method to accept parameters in its signature. So, if the current logic is something like this:
class Products extends CI_Controller
{
public function filter()
{
// Retrieve data from GET params
$page = $this->input->get('page');
$color = $this->input->get('color');
$category = $this->input->get('category');
// Do the filtering with $category, $color and $page...
}
}
You can simply refactor it to accept parameters through URL segments:
public function filter($category, $color, $page)
{
// Do the filtering with $category, $color and $page...
}
With this in place, your current URL is:
localhost/myshop/products/filter/shirts/blue/1
We need to get rid of that extra filter/ and we're done, right? Quoting from the docs:
Typically there is a one-to-one relationship between a URL string and its corresponding controller class/method. The segments in a URI normally follow this pattern:
example.com/class/method/param1/param2
In some instances, however, you may want to remap this relationship so that a different class/method can be called instead of the one corresponding to the URL.
OK, so we need to remap the current route. You have a few options:
First, is to update your application/config/routes.php file with a new entry:
$route['products/(:any)'] = 'products/filter/$1';
It says that if a URL starts with products/, remap it to the filter method of products class.
Here you can use wildcards and regex patterns to be even more precise about the type of parameters your method accepts.
Another option is that you might want to implement a _remap() method in your controller in order to do the route remapping for you.

in routes.php file, you can write following line
$route['products/(:any)/(:any)/(:num)'] = 'products/filter/$1/$2/$3';
and function will be like following
public function filter($category, $color, $page)
{
echo $category.'<br>';
echo $color.'<br>';
echo $page.'<br>';
}

Related

Codeigniter - How to get url variable value inside contoller function?

I have URL like this: http://localhost/sitename/some-post-title/code=24639204963309423
Now I have one findUser function in my controller file
public function findUser() {
// I have tried with $_GET['code']
}
and I am trying to get code variable value inside this function. I have tried with $_GET['code'] but did not worked.
Any Idea how to get value inside controller function?
Thanks.
Are you trying to get a path segment variable or a GET variable? It looks like you're going for a bit of both.
Natively in CI, you can use $this->input->get if you update your url to look more like
http://localhost/sitename/some-post-title/?code=24639204963309423
(Note the question mark).
Alternatively, you can modify your URL to look like this
http://localhost/sitename/some-post-title/code/24639204963309423
And then use URI segments like so
$data = $this->uri->uri_to_assoc();
$code = $data['code'];
If you do not want to change your URL, you will have to break that string up manually like so
$data = $this->uri->segment(3);
$data = explode($data, '=');
$code = $data[1];
I would argue the second option is the most SEO-friendly and pretty solution. But each of these should be functionally identical.
If your URI contains more then two segments they will be passed to your function as parameters.
For example, lets say you have a URI like this:
example.com/index.php/products/shoes/sandals/123
Your function will be passed URI segments 3 and 4 ("sandals" and "123"):
<?php
class Products extends CI_Controller {
public function shoes($sandals, $id)
{
echo $sandals;
echo $id;
}
}
?>
If you are using GET to get parameters, you can do like this:
$this->input->get('get_parameter_name');
Typically there is a one-to-one relationship between a URL string and its corresponding controller class/method. The segments in a URI normally follow this pattern:
example.com/class/function/id/
More details for Controllers find here and for GET find here

How to create optional REST parameter in Laravel

I'd like my API to handle calls of the such:
/teams/colors
/teams/1/colors
The first would return all colors of all teams, the second would return colors of team 1 only.
How would I write a route rule for this in Laravel?
This should be simple using a laravel route.
Route::pattern('teamid', '[0-9]+');
Route::get('/teams/{teamid}/colors', 'controller#method');
Route::get('/teams/colors', 'controller#method');
Using the pattern, it lets you specify that a route variable must match a specific pattern. This would be possible without the pattern also.
I noticed you mentioned REST in the title. Note that my response is not using Laravel's restful routes system, but its normal routes system, but I'm sure this could be adapted to be restul, or work with the restful system.
Hope this helps.
Edit:
After a bit of looking around, you may be able to use this if you are using Route::resource or Route::controller.
Route::resource('teams', 'TeamsController');
Route::any('teams/{teamid}/colors', 'TeamsController#Method');
// Or to use a different route for post, get and so on.
Route::get('teams/{teamid}/colors', 'TeamsController#getMethod');
Route::post('teams/{teamid}/colors', 'TeamsController#postMethod');
Note: the resource word above can be replaced with ::controller.
*Note 2: I have not tested this and am unable to guarantee it would work, but it does seem possible.*
You may try something like this:
class TeamsController extends BaseController {
// GET : http://example.com/teams
public function getIndex()
{
dd('Colors of all teams');
}
// GET : http://example.com/teams/1/colors
public function getColorsById($id)
{
dd("Colors of team $id");
}
// This method will call the "getColorsById" method
public function missingMethod($parameter = array())
{
if(count($parameter) == 2) {
return call_user_func_array(array($this, 'getColorsById'), $parameter);
}
// You may throw not found exception
}
}
Declare a single route for both methods:
Route::controller('/teams', 'TeamsController');

How to define routes with multiple parameters without pretty urls in Laravel

I am using Laravel. I would like users to be able to perform a search on my website using up to 3 criteria. These criteria are: Class, Brand and Model.
They should be free to use any or all of them when searching. As the relationship between these isn't as simple as Many->1, Many->1, Many->1, and also given the criteria will be numbered if blank, I dont want to use pretty urls to post the search criteria as they would look like this:
/SearchResults/0/BMW/0
which is meaningless to users and search engines. I therefore want to use normal dynamic addresses for this route as follows:
/SearchResults/?Class=0&Brand="BMW"&Model=0
How do I define a route that allows me to extract these three criteria and pass it to a custom method in my resource controller?
I have tried this but it isnt working:
Route::get('/SearchResults/?Class={$class}&Brand={$brand}&Model={$type}', 'AdvertController#searchResults');
Many thanks
The Symfony Routing components fetch the REQUEST_URI server variable for matching routes, and thus Laravel's Route Facade would not pick up URL parameters.
Instead, make use of Input::get() to fetch them.
For example, you would start by checking if the class param exists by using Input::has('class'), and then fetching it with Input::get('class'). Once you have all three, or just some of them, you'd start your model/SQL query so that you may return your results to the user.
You will need to route all to the same method and then, within the controller, reroute that given action to the correct method within the controller.
For that, I recommend using the strategy pattern (read more here).
I would do something like this:
route.php
Route::get('/SearchResults', 'AdvertController#searchResults');
AdvertController.php
use Input;
...
private $strategy = [];
public function __construct(){
$strategy = [
/*class => handler*/
'0'=> $this->class0Handler,
'1'=>$this->class1Handler,
...];
}
private function class0Handler(){
//your handler method
}
public function searchResults(){
if( !array_key_exists(Input::get('class'),$this->strategy))
abort(404);
return $this->strategy[Input::get('class')]();
}
In case you are breaking down search by other types, you define the handler in the $strategy variable.
Strategy pattern has a lot of benefits. I would strongly recommend it.

How to reference a function after an argument in CodeIgniter URLs?

My desired URL structure for a section of a web application is as follows:
/user/FooBar42/edit/privacy, and I would like this to route to controller: user, function: edit, with FooBar42 and privacy as arguments (in that order). How should I accomplish this with CodeIgniter?
Defining this route in application/config/routes.php should work:
$route['user/(:any)/edit/(:any)'] = "user/edit/$1/$2";
However, be aware that (:any) in the above route would match multiple segments. For example, user/one/two/edit/three would call the edit function in the user controller but only pass one as the fist parameter and two as the second.
Replacing the (:any) with the regex ([a-zA-Z0-9]+) will only allow one only alphanumeric values of length at least 1. This mitigates the issue above, where a / would be permitted allowing multiple segments to be allowed. Now, if user/one/two/edit/three was used, a 404 page would be shown.
$route['user/([a-zA-Z0-9]+)/edit/([a-zA-Z0-9]+)'] = "user/edit/$1/$2";
You can also use the remapping option of the CI controller
http://ellislab.com/codeigniter/user-guide/general/controllers.html#remapping
and doing something like this:
public function _remap($method, $params = array())
{
// check if the method exists
if (method_exists($this, $method))
{
// run the method
return call_user_func_array(array($this, $method), $params);
}
else
{
// method does not exists so you can call nay other method you want
$this->edit($params);
}
}

Codeigniter variable-length parameter list

I'm making a tutorialsystem with Codeigniter, but I'm a bit stuck with using subcategories for my tutorials.
The URL-structure is like this: /tutorials/test/123/this-is-a-tutorial
tutorials is the controller
test is a shortcode for the category
123 is the tutorial ID (used in the SQL query)
this-is-a-tutorial is just a slug to prettify the URL
What I do is passing the category as a first parameter and the ID as a second parameter to my controller function:
public function tutorial($category = NULL, $tutorial_id = NULL);
Now, if I want subcategories (unlimited depth), like: /tutorials/test/test2/123/another-tutorial. How would I implement this?
Thanks!
For reading infinite arguments, you have at least two useful tools:
func_get_args()
The URI class
So in your controller:
Pop the last segment/argument (this is your slug, not needed)
Assume the last argument is the tutorial ID
Assume the rest are categories
Something like this:
public function tutorial()
{
$args = func_get_args();
// ...or use $this->uri->segment_array()
$slug = array_pop($args);
$tutorial_id = array_pop($args); // Might want to make sure this is a digit
// $args are your categories in order
// Your code here
}
The rest of the code and the validation depends on what specifically you want to do with the arguments.
If you need variable categories you could use the URI class: $this->uri->uri_to_assoc(n)
Another option you may want to consider is CodeIgniter's controller function remapping functionality which you can use to override the default behaviour. You would be able to define a single function inside a controller that would handle all the calls to that controller and have the remaining URI parameters passed in as an array. You could then do whatever you want with them.
See here for the docs reference on the matter.

Categories