Reputation: 179
What is the smartest solution to work with multiple levels of subcategories in Codeigniter? I want to make a web site for travel agency with travel offers, and the structure will look something like this:
- Cat1
- Cat2
--- Subcat1
--- Subcat2
------ Subcat1
--------- Subcat1
--------- Subcat2
------------ Subcat1
------------ Subcat2
--------------- offer1
--------------- offer2
--------------- offer3
--------------- offerN
------------ Subcat3
--------- SubcatN
------ Subcat2
------ SubcatN
--- Subcat3
--- SubcatN
- Cat3
--- offer1
--- offer2
--- offer3
--- offerN
- CatN
This is an example of the nested categories. Every (sub)category should have: Main picture, Description, and list of subcategories OR list of the offers.
I have some idea to do that with a table called Categories (ID, cat_name, parent) and if the parent is 0, that it is top level category, if the parent is some int, than that value is the ID of the parent category...
But I don't have idea how to solve the routing with the controller? I know how to do that with only 2 levels (main category and subcategories) but they are manually added to the routes. I don't know how to do that dynamically so there can be added more categories and subcategories in future through the admin panel.
Of course I will have another table for my offers, I know that, and I don’t have problems with that. The problem is how the controller(s) structure will look like?
For my present project with only 1 level of subcategory and without option to dynamically add subcategories, here is what I have in routes.php
$route[‘cat1’] = “category”;
$route[‘cat1/(:any)’] = “category/subcategory”;
$route[‘cat2’] = “category”;
$route[‘cat2/(:any)’] = “category/subcategory”;
$route[‘cat3’] = “category”;
$route[‘cat3/(:any)’] = “category/subcategory”;
$route[‘cat4’] = “category”;
$route[‘cat4/(:any)’] = “category/subcategory”;
$route[‘cat5’] = “category”;
In other words, cat1,2,3,4,5 are real names of the categories, and :any represents all of their subcategories and when the visitors types example.com/pc_news than it is redirected to the controller named category and it’s index function. if he types example.com/pc_news/hardware than he hell be redirected to the method subcategory of the controller category.
If I want to add more categories and subcategories, I will do that manually at the routes, but if I want to add subsubcategory (example.com/pc_news/hardware/something) I don’t know how to achieve that.
On the new project I want to do, I will have something like:
example.com/summer/turkey/airplane/alanya/hotels # and it will list all the offers
example.com/summer/turkey/airplane/alanya/apartments
example.com/summer/turkey/bus/kushadasi
example.com/winter/bus/france/hotels
example.com/winter/airplane/france/hotels
Anybody with some idea how to do this?
Upvotes: 1
Views: 2434
Reputation: 20753
As for the routing, i would just use the routes config to send everything to a method where you can implement any logic you want, if you have methods you still want to access inside that controller, you have to list them before the "catch any" line something like this:
$route['products/save/(.*)'] = 'products/save/$1';
$route['products/(.*)'] = 'products/index/$1';
Once you have this set up, you will get every parameter inside the Products::index
method:
class Products extends CI_Controller {
public function index() {
$args = func_get_args();
// now $args holds the url segments
$categories = array();
foreach ($args as $cat_name) {
$categories[] = $this->db
->from('categories')
->where('cat_name', $cat_name)
->get()
->row();
}
}
}
As for storing the categories, if you only have the parent_id
in rows you will have to loop or use a bunch of joins to get every category. If you have only 3-4 levels it probably not really a problem, also probably won't change too often so it could be easily cached. If you want a more efficient solution look into the nested set models.
You can use the special 404_override
key (at the bottom of the page) to make every request go to a specific controller's index
method. Don't forget that you will need to handle 404 url's inside the Products
controller!:
$route['404_override'] = 'products';
The original answer can be expanded to do this, whitelist everything you don't want to send to the Products
controller (every other controller's name basically) and have a catch-all route at the end to send other's to the Products
controller. 404 url's still need to be handled.
// place any specific rules on top
$route['about'] = 'main/about';
// have whitelist existing controllers, make them go to their original place like it normaly would
$route['(controller1|controller2|controller3)(/?.*)'] = '$1$2';
$route['(:any)'] = 'products/index/$1'; // the last "catch all" row goes here
Upvotes: 2