CodeIgniter handle URL segments - codeigniter

I keep thinking about how to deal with URLs and pages with CI but I can't think to a good way to do this.
I'm trying to handle url like this:
site.com/shop (shop is my controller)
site.com/shop/3 (page 3)
site.com/shop/cat/4 (categorie and page 4)
site.com/shop/cat/subcat/3 (cat & subcat & page)
Is there any good way to do this ?

You could create controller functions to handle:
shop and shop pages
categories and category pages
subcategories and subcategory pages
Controller functions
In your shop controller you could have the following functions:
function index($page = NULL)
{
if ($page === NULL)
{
//load default shop page
}
else //check if $page is number (valid parameter)
{
//load shop page supplied as parameter
}
}
function category($category = NULL, $page = 1)
{
//$page is page number to be displayed, default 1
//don't trust the values in the URL, so validate them
}
function subcategory($category = NULL, $subcategory = NULL, $page = 1)
{
//$page is page number to be displayed, default 1
//don't trust the values in the URL, so validate them
}
Routing
You could then setup the following routes in application/config/routes.php. These routes will map the URLs to the appropriate controller functions. The regex will allow look for values
//you may want to change the regex, depending on what category values are allowed
//Example: site.com/shop/1
$route['shop/(:num)'] = "shop/index/$1";
//Example: site.com/shop/electronics
$route['shop/([a-z]+)'] = "shop/category/$1";
//Example: site.com/shop/electronics/2
$route['shop/([a-z]+)/(:num)'] = "shop/category/$1/$2";
//Example: site.com/shop/electronics/computers
$route['shop/([a-z]+)/([a-z]+)'] = "shop/subcategory/$1/$2";
//Example: site.com/shop/electronics/computers/4
$route['shop/([a-z]+)/([a-z]+)/(:num)'] = "shop/subcategory/$1/$2/$3";

Related

Codeigniter load different site content foreach possible filter selection

I have 2 input fields. In the first filter user can select category, subcategory and in the second filter user can choose product.
Upon submitting the form, the user gets redirected to the site based on his selection in the input fields.
$category = $this->input->post('category', true);
$product = $this->input->post('product', true);
if(isset($category) && $sub_category == ''){
redirect(base_url().'/category/'.$category);
}elseif(isset($category) && isset($product)){
redirect(base_url().'/category/'.$category.'/product/'.$product);
}else{
$this->session->set_flashdata('error', 'You must select a category');
redirect($_SERVER['HTTP_REFERER']);
}
Creating the urls and redirecting to them based on the user's input selection works fine. What I cannot get my head around is how to get a different view-content for each site. Each possible combination of category and product has its own content. How can I load the individual content for each possible url?
Thanks for any hint!
try this to get url
$category = $this->input->post('category', true);
$product = $this->input->post('product', true);
$url =array();
if($category){
$url[] = 'category/'.$category;
}
if($product){
$url[] ='product/'.$product;
}
$newurl = implode('/',$url);
redirect($newurl);

Loading page dynamically from database via id in controller

I am trying to load a page dynamically based on the database results however I have no idea how to implement this into codeigniter.
I have got a controller:
function history()
{
//here is code that gets all rows in database where uid = myid
}
Now in the view for this controller I would like to have a link for each of these rows that will open say website.com/page/history?fid=myuniquestring however where I am getting is stuck is how exactly I can load up this page and have the controller get the string. And then do a database query and load a different view if the string exsists, and also retrieve that string.
So something like:
function history$somestring()
{
if($somestring){
//I will load a different view and pass $somestring into it
} else {
//here is code that gets all rows in database where uid = myid
}
}
What I don't understand is how I can detect if $somestring is at the end of the url for this controller and then be able to work with it if it exists.
Any help/advice greatly appreciated.
For example, if your url is :
http://base_url/controller/history/1
Say, 1 be the id, then you retrieve the id as follows:
function history(){
if( $this->uri->segment(3) ){ #if you get an id in the third segment of the url
// load your page here
$id = $this->uri->segment(3); #get the id from the url and load the page
}else{
//here is code that gets all rows in database where uid = myid and load the listing view
}
}
You should generate urls like website.com/page/history/myuniquestring and then declare controller action as:
function history($somestring)
{
if($somestring){
//I will load a different view and pass $somestring into it
} else {
//here is code that gets all rows in database where uid = myid
}
}
There are a lot of ways you can just expect this from your URI segments, I'm going to give a very generic example. Below, we have a controller function that takes two optional arguments from the given URI, a string, and an ID:
public function history($string = NULL, $uid = NULL)
{
$viewData = array('uid' => NULL, 'string' => NULL);
$viewName = 'default';
if ($string !== NULL) {
$vieData['string'] = $string;
$viewName = 'test_one';
}
if ($uid !== NULL) {
$viewData['uid'] = $uid;
}
$this->load->view($viewName, $viewData);
}
The actual URL would be something like:
example.com/history/somestring/123
You then know clearly both in your controller and view which, if any were set (perhaps you need to load a model and do a query if a string is passed, etc.
You could also do this in an if / else if / else block if that made more sense, I couldn't quite tell what you were trying to put together from your example. Just be careful to deal with none, one or both values being passed.
The more efficient version of that function is:
public function history($string = NULL, $uid = NULL)
{
if ($string !== NULL):
$viewName = 'test_one';
// load a model? do a query?
else:
$viewName = 'default';
endif;
// Make sure to also deal with neither being set - this is just example code
$this->load->view($viewName, array('string' => $string, 'uid' => $uid));
}
The expanded version just does a simpler job at illustrating how segments work. You can also examine the given URI directly using the CI URI Class (segment() being the most common method). Using that to see if a given segment was passed, you don't have to set default arguments in the controller method.
As I said, a bunch of ways of going about it :)

Organizing URI segments in codeigniter

function orders(){
$order_id = $this->uri->segment(3);
if($order_id){
$data['main_content'] = "admin-order-page";
$data['order_id'] = $order_id;
$this->load->view("includes/cp-template",$data);
}else{
$data['main_content'] = "admin-orders";
$this->load->view("includes/cp-template",$data);
}
}
Above is my orders method in my controller, so www.myexample.com/orders
I'm wondering what is the proper way of handling information passed in the url. In my example, you have just /orders going to a particular view, and if a id is appended, /orders/23, it will go to a product page.
I now want to add pagination on my /orders view, and will want to pass the page number in the url, like /orders/page/2. Should I just add some more logic looking for the uri of "page"?
Is there a better way of organizing all of this?
If you have an url like www.myexample.com/orders/page/2/4 you can read the arguments as example below:
class Orders extends CI_Controller{
public function __contruct()
{
parent::__contruct();
}
public function page($page_number, $limit)
{
echo 'page number ' . $page_number . ' with limit of ' . $limit;
//the above line prints: "page number 2 with limit of 4"
}
}
Remember that the URI patter is builded according to:
domain.com/{controller}/{function}/{parameter 1} ... , {parameter N}

Magento : How to get full product URL using category

I am trying to find a solution for making sure that Magento always shows the complete URL of every product including the category path.
I want the complete url to also be there in search results also.
For this i have put every product in only one category.
Can this be done by Url Rewrite custom through magento?
Is 301 redirect using .htaccess, for /product.html to category/subcategory/product.html a good idea?
Thanks
Moody
What we do to get full category in products url is using a helper that'll try to get you a product URL with the category. You could also rewrite the product method but its kind of a pain whenever another module rewrites some product stuff, this is why we use the helper approach.
Here's our method:
public static function getFullUrl (Mage_Catalog_Model_Product $product ,
Mage_Catalog_Model_Category $category = null ,
$mustBeIncludedInNavigation = true ){
// Try to find url matching provided category
if( $category != null){
// Category is no match then we'll try to find some other category later
if( !in_array($product->getId() , $category->getProductCollection()->getAllIds() )
|| !self::isCategoryAcceptable($category , $mustBeIncludedInNavigation )){
$category = null;
}
}
if ($category == null) {
if( is_null($product->getCategoryIds() )){
return $product->getProductUrl();
}
$catCount = 0;
$productCategories = $product->getCategoryIds();
// Go through all product's categories
while( $catCount < count($productCategories) && $category == null ) {
$tmpCategory = Mage::getModel('catalog/category')->load($productCategories[$catCount]);
// See if category fits (active, url key, included in menu)
if ( !self::isCategoryAcceptable($tmpCategory , $mustBeIncludedInNavigation ) ) {
$catCount++;
}else{
$category = Mage::getModel('catalog/category')->load($productCategories[$catCount]);
}
}
}
$url = (!is_null( $product->getUrlPath($category))) ? Mage::getBaseUrl() . $product->getUrlPath($category) : $product->getProductUrl();
return $url;
}
/**
* Checks if a category matches criteria: active && url_key not null && included in menu if it has to
*/
protected static function isCategoryAcceptable(Mage_Catalog_Model_Category $category = null, $mustBeIncludedInNavigation = true){
if( !$category->getIsActive() || is_null( $category->getUrlKey() )
|| ( $mustBeIncludedInNavigation && !$category->getIncludeInMenu()) ){
return false;
}
return true;
}
If a category is specified it tries to get a url relative to this one.
If no category is specified or couldn't find a url with provided one, the method tries to get the product URL relative to the first category that the product is attached to, and checks if it's acceptable (active, with a url key and matching navigation criteria).
Finally if it falls back to original $product->getProductUrl() Magento method.
You'll have to use it in templates (categories, cart products, recently viewed etc....) with this call :
echo $this->helper('yourcompany/yourmodule')::getFullProductUrl($_product);
Edit:
I took Zachary's remarks into account and tweaked it up a little by adding some checks and options. Hope it's cool now.
Examples :
echo $this->helper('yourcompany/yourmodule')::getFullProductUrl($_product, $aCategory);
will try to find a product url in $aCategory then fall back to other category urls and finally product base url
echo $this->helper('yourcompany/yourmodule')::getFullProductUrl($_product, someCategory, false);
will also consider categories that are not included in navigation.

Codeigniter - best routes configuration for CMS?

I would like to create a custom CMS within Codeigniter, and I need a mechanism to route general pages to a default controller - for instance:
mydomain.com/about
mydomain.com/services/maintenance
These would be routed through my pagehandler controller. The default routing behaviour in Codeigniter is of course to route to a matching controller and method, so with the above examples it would require an About controller and a Services controller. This is obviously not a practical or even sensible approach.
I've seen the following solution to place in routes.php:
$route['^(?!admin|products).*'] = "pagehandler/$0";
But this poses it's own problems I believe. For example, it simply looks for "products" in the request uri and if found routes to the Products controller - but what if we have services/products as a CMS page? Does this not then get routed to the products controller?
Is there a perfect approach to this? I don't wish to have a routing where all CMS content is prefixed with the controller name, but I also need to be able to generically override the routing for other controllers.
If you use CodeIgniter 2.0 (which has been stable enough to use for months) then you can use:
$route['404_override'] = 'pages';
This will send anything that isn't a controller, method or valid route to your pages controller. Then you can use whatever PHP you like to either show the page or show a much nicer 404 page.
Read me guide explaining how you upgrade to CodeIgniter 2.0. Also, you might be interested in using an existing CMS such as PyroCMS which is now nearing the final v1.0 and has a massive following.
You are in luck. I am developing a CMS myself and it took me ages to find a viable solution to this. Let me explain myself to make sure that we are on the same page here, but I am fairly certain that we area.
Your URLS can be formatted the following ways:
http://www.mydomain.com/about - a top level page with no category
http://www.mydomain.com/services/maintenance - a page with a parent category
http://www.mydomain.com/services/maintenace/server-maintenance - a page with a category and sub category.
In my pages controller I am using the _remap function that basically captures all requests to your controllers and lets you do what you want with them.
Here is my code, commented for your convenience:
<?php
class Pages extends Controller {
// Captures all calls to this controller
public function _remap()
{
// Get out URL segments
$segments = $this->uri->uri_string();
$segments = explode("/", $segments);
// Remove blank segments from array
foreach($segments as $key => $value) {
if($value == "" || $value == "NULL") {
unset($segments[$key]);
}
}
// Store our newly filtered array segments
$segments = array_values($segments);
// Works out what segments we have
switch (count($segments))
{
// We have a category/subcategory/page-name
case 3:
list($cat, $subcat, $page_name) = $segments;
break;
// We have a category/page-name
case 2:
list($cat, $page_name) = $segments;
$subcat = NULL;
break;
// We just have a page name, no categories. So /page-name
default:
list($page_name) = $segments;
$cat = $subcat = NULL;
break;
}
if ($cat == '' && $subcat == '') {
$page = $this->mpages->fetch_page('', '', $page_name);
} else if ($cat != '' && $subcat == '') {
$page = $this->mpages->fetch_page($cat, '', $page_name);
} else if ($category != "" && $sub_category != "") {
$page = $this->mpages->fetch_page($cat, $subcat, $page_name);
}
// $page contains your page data, do with it what you wish.
}
?>
You of course would need to modify your page fetching model function accept 3 parameters and then pass in info depending on what page type you are viewing.
In your application/config/routes.php file simply put what specific URL's you would like to route and at the very bottom put this:
/* Admin routes, login routes etc here first */
$route['(:any)'] = "pages"; // Redirect all requests except for ones defined above to the pages controller.
Let me know if you need any more clarification or downloadable example code.

Resources