Solved

CoeIgniter duplicate my menu links

Posted on 2015-01-10
30
109 Views
Last Modified: 2015-01-11
Hi all again.
I build a dynamic menu pulling out categories and subcategories from a database. Here's the code:

menu_model
	public function build_menu()
	{
		$menu = array();
		$first_level_items = array();
		$second_level_items = array();
		$first_level_items = $this->products_model->get_categories();
		foreach ($first_level_items as $items)
		{
			$cat_id = $items['category_id'];
			$cat_name = $items['category_name'];
			
			$second_level_items = $this->products_model->get_subcategories_by_category($cat_id);

			if (is_array($second_level_items) && count($second_level_items)>0 && $second_level_items[0] != '')
			{
				$menu[$cat_name] = $second_level_items;
			}
			else
			{
				$menu[$cat_name] = '';
			}
		}
		return $menu;
	}

Open in new window

The view for this menu:
<?php
$built_menu = '';
$built_menu = "<li class=\"active\"><a href=\"home\">Home</a></li>";
foreach ($menu as $k=>$v)
{
	if (is_array($v))
	{
		$class = "dropdown";
		$built_menu .= "<li class=\"$class\"><a href=\"".base_url."products/$k\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">{$k} <span class=\"caret\"></span></a>";
		$built_menu .= "<ul class=\"dropdown-menu\" role=\"menu\">";
		foreach ($v as $v2)
		{
			$built_menu .= "<li><a href=\"products/{$k}/{$v2['subcategory_name']}\">{$v2['subcategory_name']}</a></li>";
		}
		$built_menu .= "</ul>";//end of submenu
		$built_menu .= "</li>";//end of item
	}
	else
	{
		$built_menu .= "<li><a href=\"products/{$k}\">{$k}</a></li>";
	}
}
$built_menu .= "<li><a href=\"contact\">Contact</a></li>";
echo $built_menu;

Open in new window


The routes value for this:
$route['products/(.+/)?(.+)?'] = 'Products/process_data/$1/$2';

Open in new window


Loading the home page all works fine: the menu is exactly as it is expected to be and does what it is expected to do. Let's say the first Item with a submenu is the category Furniture and its subitems are Bar Stools, Bedroom and so on.
Hovering the mouse I see "www.example.com/products/Furmiture/Bar Stools".
I click and teh new page is correctly show with all products from that subcategory. But now if hover on the same menu item I see "www.example.com/products/Furmiture/products/Furmiture/Bar Stools"

Obviously this breaks the app. I just can't figure out where is the problem: what am I missing here about CI?

Please, don't leave me alone :-)
0
Comment
Question by:Marco Gasi
  • 16
  • 9
  • 5
30 Comments
 
LVL 8

Expert Comment

by:Ahmed Merghani
ID: 40542239
Hi Marco,

Change the line number 13 at your view with this line:
$built_menu .= "<li><a href=\"".base_url."products/{$k}/{$v2['subcategory_name']}\">{$v2['subcategory_name']}</a></li>";

Open in new window

I just add ".base_url." before the "products".

EE experts will not leave you alone :-)
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542258
Thanks Ahmed for your reply. I know EE are still present but sometimes... ;-)
Anyway, as you can see in line 9 of my snippet I yet added that. I added it now to all the rest of links but unfortunately this hasn't olved the problem...
0
 
LVL 8

Accepted Solution

by:
Ahmed Merghani earned 250 total points
ID: 40542265
Yes forgot to mention lines "20" and "23". Also I did another mistake. It is "base_url()" not "base_url". Wish this solve the problem.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542270
:-( Sorry, but it doesn't fix
0
 
LVL 8

Expert Comment

by:Ahmed Merghani
ID: 40542287
I do not see any issue with your view. And surely not the routes value. So, are you sure the data came form the model is well structured?
Also try with another browser or clear the cache of the used browser.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542297
Yes, Ahmed, I'm sure the data are well structured. Looking at the source I see the links in the menu are right:

products/Furniture/Bar Stools
products/Furniture/Bedroom
products/Furniture/Beds

and so on. Obviously I'm talking about the source code of the page where I get the issue: the source shows
products/Furniture/Bar Stools
and the ffx tooltip shows:
products/Furniture/products/Furniture/Bar Stools

But why base_url() doesn't write something in the source code?
0
 
LVL 8

Expert Comment

by:Ahmed Merghani
ID: 40542307
Did you load the url helper library?
What about the controller content? Are you sure we are working on the right view :) ?
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542316
url helper loaded.
I post here the Controller's code: keep calm, it's only a few line of code :-)
<?php
class Products extends CI_Controller
{

	public function __construct()
	{
		parent::__construct();
		$this->load->model( 'products_model' );
		$this->load->model( 'menu_model' );
		$this->load->helper( 'url' );
	}


	public function index($data)
	{
	}

	public function process_data($route)
	{
		$subcategory_name = end($route);
		$subcategory_data = $this->products_model->get_subcategory_id($subcategory_name);
		$data['products'] = $this->products_model->get_products_by_subcategory($subcategory_data[0]['subcategory_id']);		
		$data['title'] = end($route);
		$data["breadcrumbs"] = $route;
		$data['menu'] = array();
		$data["menu"] = $this->menu_model->build_menu();
		$this->load->view( 'templates/header', $data );
		$this->load->view( "products/v_list_products_by_subcategory" , $data );
		$this->load->view( 'templates/footer', $data );
	}
	
	public function _remap($method, $params = array())
  {
    $map = array();
		/*following commented piece of code creates an associative array where the 
		 * first key is the first param and the relative value the second param, then
		 * the second key is the third param and so on...
 		 */
//    for( $i = 1; $i < count( $params ); $i = $i + 2 )
//    {
//        $map[$params[$i-1]] = $params[$i];
//    }
		foreach ($params as $p)
		{
			$map[] = urldecode($p);
		}

    if( $method[0] != '_' && method_exists( $this, $method ))
		{
        return $this->$method( $map );
		}
    show_404();
  }

	public function list_categories()
	{
		$this->load->helper( 'url' );
		$data["categories"] = $this->poducts_model->get_categories();
		$this->load->view( 'templates/header', $data );
		$this->load->view( 'products/v_list_categories', $data );
		$this->load->view( 'templates/footer' );
	}
	
	public function list_subcategories()
	{
		$this->load->helper( 'url' );
		$cat_id = $this->input->post( 'cat_id' );
		$subcategories = $this->products_model->get_subcategories_by_category( $cat_id );
		$data["subcategories"] = $subcategories;
		$this->load->view( 'products/v_list_subcategories', $data );
	}

}

Open in new window

0
 
LVL 8

Expert Comment

by:Ahmed Merghani
ID: 40542369
I am very calm :)
I do not see any issue also in the controller. Are we working on "v_list_products_by_subcategory" view? No call for other methods "list_categories()" and "list_subcategories()" till now appeared just "process_data()" ?
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542373
Yes, in this issue only process_data() is involved. But I have some doubt the code is wrong. After all, the menu I see in Firefox (source and generated source) and in Firebug is right, is the way CI processes it that's wrong. Are you sure it's not the route?
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542383
Why does your process_data() function only accept one argument when 2 are being passed?

and the ffx tooltip shows:
products/Furniture/products/Furniture/Bar Stools
That's because your router is missing a slash (/)
$route['/products/(.+/)?(.+)?'] = 'Products/process_data/$1/$2';
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542385
public function process_data($route)

should be

public function process_data($sub_cat1, $sub_cat2)
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542397
Rob, adding the slash it gives me a 404 error? About the only one argument, it was because for some reason I believed CI params were passed as an array... I corrected the issue, but now the page doesn't exists...
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542419
Sorry you're right, there shouldn't be a leading slash. I've got mixed up with my other mvc routing :s
But as for the passing routes to your controller:
https://ellislab.com/codeigniter/user-guide/general/controllers.html#passinguri
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542562
Ooops what a stupid!!! I'm using _remap function in my controller (see code above): the remap function accept parameters as array and there they are used to build another array which is passed to process_data function.
So I came back to my original code and still have my original problem: once I click an item menu, in the new menu links have a duplicated part but the plain source code is right!!!
Am I really the first?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542596
What an I missing because where do your routes indicate the _remap function? Or is that via the url_helper plugin?
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542735
I load the url helper plugin but I don't explicitely indicate _remap function... When I read about it I didn't find I hd to declare it somwhere
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542749
Yeah doesn't look like you need to. If you have it in your controller it will always be called. Sorry I'm just not that familiar with codeigniter, more cakephp but they do have a lot of similarities.
Do you need to have the _remap function? What is its purpose for you specifically?
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542750
Without it it just didn't work and I always got 404 error :-)
0
 
LVL 42

Assisted Solution

by:Rob Jurd, EE MVE
Rob Jurd, EE MVE earned 250 total points
ID: 40542757
Then I would say there's something wrong with the routing as it should work without it https://ellislab.com/codeigniter/user-guide/general/controllers.html#remapping

Once you get it working without it then determine if you want it in there.  You don't want it hiding other issues
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542777
Okay, thank you: now I'm going to try.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542782
Well, I found that this:
$route['products/(.+/)?(.+)?'] = 'Products/process_data/$1/$2';

Open in new window

doesn't pass the second variable, that is the subcat. If in my Products process_data function (changed to get two params, $cat, $subcat) I write
echo "$cat<br>$subcat<br>";

Open in new window

then I get

Furniture
<br>
<br>

and then obviously my code breaks.
What's wrong with that line of route?
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542805
Let's try something simple:

$route['products/([a-zA-Z ]+)/([a-zA-Z ]+)/?'] = 'Products/process_data/$1/$2';
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542810
Found the issue: is the blank pace in the subcategory name. I alway tried the first menu item Furniture/Bar Stools and I always got the error. But since I use $cat and $subcat for breadcrumbs, I noticed that the $subcat were displayed as Bas%20Stools. I solved this using urldecode but this made me try the second menu item Furniture/Bedrooms and... voilà it worked.
So now I try to see if using urldecode in my controller solves the problem. I'll come back in a minute.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542814
Yes. it does: as first line of my controller I put
$subcategory_name = urldecode($subcat);

Open in new window

and the link works :-)
But now I saw that CI add omething even to static links! My menu builder view  looks like this:
<?php
$built_menu = '';
$built_menu = "<li class=\"active\"><a href=\"home\">Home</a></li>";
foreach ($menu as $k=>$v)
{
	if (is_array($v))
	{
		$class = "dropdown";
		$built_menu .= "<li class=\"$class\"><a href=\"".base_url()."products/list/$k\" class=\"dropdown-toggle\" data-toggle=\"dropdown\">{$k} <span class=\"caret\"></span></a>";
		$built_menu .= "<ul class=\"dropdown-menu\" role=\"menu\">";
		foreach ($v as $v2)
		{
			$built_menu .= "<li><a href=\"".base_url()."products/list/{$k}/{$v2['subcategory_name']}\">{$v2['subcategory_name']}</a></li>";
		}
		$built_menu .= "</ul>";//end of submenu
		$built_menu .= "</li>";//end of item
	}
	else
	{
		$built_menu .= "<li><a href=\"".base_url()."products/list/{$k}\">{$k}</a></li>";
	}
}
$built_menu .= "<li><a href=\"contact\">Contact</a></li>";
echo $built_menu;

Open in new window

Now I see CI adds "products/list" even to home and contacts links: I still have to understand something crucial here.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542820
And not in my route I have set something for static pages:
$route['home'] = "welcome";
$route['contact'] = 'Main/contact_form';

Open in new window

And the link generated in the menu for home is <a href="home">! But hovering it shows www.example.com/products/list/Furniture/home!!!
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542825
base_url()! I had to put base_url before 'home' and 'contacts'!
Well, even this job is done. Thanks guys. How many enjoy this job!
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542832
Awesome!  sounds like the routing is now working as it should, certainly looks better.
0
 
LVL 30

Author Comment

by:Marco Gasi
ID: 40542835
Hey, Rob, what about CakePhp? What are its pros?
0
 
LVL 42

Expert Comment

by:Rob Jurd, EE MVE
ID: 40542978
Cake had been around longer so there's more Plugins, documentation and general help available but that doesn't necessarily make it better. It fell in my lap so to speak so I went with it (inherited it from another project).
I'm currently looking into Nodejs because of all the talk around it and how much faster it supposedly is.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Deprecated and Headed for the Dustbin By now, you have probably heard that some PHP features, while convenient, can also cause PHP security problems.  This article discusses one of those, called register_globals.  It is a thing you do not want.  …
This article discusses four methods for overlaying images in a container on a web page
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now