Еще раз про динамическое меню

igortik

Новичок
Еще раз про динамическое меню

Использую для выводв меню функцию:

PHP:
function menu($parent_id, $cnt)
{
  $sql=mysql_query("SELECT `id`,`parent_id`,`hidden`,`name`,`page` FROM `content` WHERE parent_id = ".$parent_id." AND `hidden`='0' ORDER by `pos`");
  while($mas=mysql_fetch_array($sql))
  		{
                // parent_id = 0 означает, что это основной заглавнй раздел и выводим мы его иначе, чем другие разделы
  		if($mas[1] == '0')
  			{
  			printf("<tr><td class=\"main_page\"><a href=\"%s.htm\" class=\"main_page\">%s</a></td></tr>",$mas[4],$mas[3]);
  			}
  			else
                        //выводим подраздел, если имеется
  			{
  			printf("<tr><td class=\"page\">&nbsp;&nbsp;<a href=\"%s.htm\" class=\"page\">%s</a></td></tr>",$mas[4],$mas[3]);
  			}
                //вызываем саму себя
   		menu($mas[0], $cnt+=1);
   		$cnt-=1;
		}
}
Как видно из примера, то ссылка формируется исключительно из `page` и я никаких параметров не дописываю в URL, чтобы через GET скрипт мог разобрать что отправить функции и отправлять ли вообще.

Что есть сейчас:

Меню выводится вида:

Пункт 1
- подпункт 1
- подпункт 2
Пункт 2
- подпункт 1
и т.д.

по нажатию на ссылку меню открывается страница и меню выводится целиком, это верно все.

Теперь задача:

Выводить нужно также, как описано выше с отличием в том, что все подпункты должны быть скрыты.
Хорошо, это можно достичь, урезав содержимое в цикле while (убрать все, что после else)

PHP:
function menu($parent_id, $cnt)
{
  $sql=mysql_query("SELECT `id`,`parent_id`,`hidden`,`name`,`page` FROM `content` WHERE parent_id = ".$parent_id." AND `hidden`='0' ORDER by `pos`");
  while($mas=mysql_fetch_array($sql))
  		{
                // parent_id = 0 означает, что это основной заглавнй раздел и выводим мы его иначе, чем другие разделы
  		if($mas[1] == '0')
  			{
  			printf("<tr><td class=\"main_page\"><a href=\"%s.htm\" class=\"main_page\">%s</a></td></tr>",$mas[4],$mas[3]);
  			}
  			else
                        //подразделы не выводим
  			}
                //вызываем саму себя
   		menu($mas[0], $cnt+=1);
   		$cnt-=1;
		}
Первый шаг завершен (хотя меню можно было вывести обычным циклом)

А вот тперь то, что как раз и вызвало трудности:

Я хочу, чтобы по нажатию ссылки основной рубрики меню (Пункт1, Пункт2 и т.д.) страница перегружалась и открывала то же сокращенное меню, только уже с отображением подразделов.

Например, есть меню:

Пункт 1
Пункт 2
Пункт 3

Нажали на Пункт 1 и получили:

Пункт 1
- подпункт 1
- подпункт 2
Пункт 2
Пункт 3

P.S. Я не хочу что-то добавлять в url из личных соображений, т.к. там перед формированием ссылки перед .html прописывается латинницей название раздела и лишние цифры не нужны.

Прошу подать идею реализации, т.к. я такого начал мудрить, что аж страшно стало (добавил еще 2 цикла внутрь, начал собирать отдельно массив данных, делал подсчеты кол-ва позиций в базе по каждому пункту) и в итоге запутался еще больше.
 

Фанат

oncle terrible
Команда форума
Непонятно, в чем проблема. если гетом ничего не пришло - не разворачиваем ни один пункт. Если пришло - разворачиваем тот пункт, который пришел
 

igortik

Новичок
*****
Да, именно, но

Если мы нажимаем на Пункт 1, то, получив через GET его `page` можно смело развернуть перечень подменю.

PHP:
if($_GET['page']) 
{
$page=mysql_real_escape_string($_GET['page']);
........
}
затем делаем сравнение полученного из GET `page` с тем, что в данный момент обрабатывается в цикле и если есть совпадение, то выводим его дерево.. здесь все ясно.

А вот что делать, если мы нажали не на родительскую ссылку, к примеру, на подпункт 1, то нам механизм который описан выше не подойдет, т.к. в подпункте нет подпунктов, а даже, если есть, у нас стоит задача оставить развернутым именно часть меню, куда входит подпункт 1.
Т.е. нажав на "подпункт 1" я должен получить в браузере:

Пункт 1
- подпункт 1
- подпункт 2
Пункт 2
Пункт 3

равносильно также, нажав на "Пункт 1" я должен получить тоже самое.

Т.е. я должен как-то разограничить основной пункт и его подпункты, чтобы по мере передачи в URL их `page` вызвать тот или иной обработчик, в случае с основным пунктом просто вывести его дерево по его `id`, а в случае с его подпунктами - определить, что это подпункты и, получив их `parent_id`, обратиться к выводу содержимого дерева основного пункта опять же по его `id`, т.к. `id` в этом случае будет равен `parent_id`.


Вот когда начинаю все это в голове прокручивать, то начинаю писать массу левых циклов, что мне аж страшно становится :)
 

Фанат

oncle terrible
Команда форума
никаких левых циклов не нужно. нужен только один левый запрос - парента этой страницы. пейдж этого парента в переменную, а в проверку разворота еще одно условие
 

igortik

Новичок
да, т.е. если парент = 0, то мы дадим понять скрипту, что это основной раздел и разворачиваем ветку по его id, если же парент != 0, то берем сам парент за id разворачиваемого раздела..

я верно понял?

теперь осталось это родить
 

Фанат

oncle terrible
Команда форума
а че там рожать? практически в условие добавить только одну проверку.
Другое дело, что у тебя сама рекурсия сделана странно...
 

igortik

Новичок
*****
я вообще думаю ее не использовать.. рекурсию!
обычный while должен подойти

-~{}~ 29.10.08 17:13:

ппц, все равно не могу понять куда какие проверки далее ставить.... ((((

Упростил и немного доработал функцию

PHP:
function menu($parent_id)
{
  $sql=mysql_query("SELECT `id`,`parent_id`,`hidden`,`name`,`page` FROM `content` WHERE parent_id = ".$parent_id." AND `hidden`='0' ORDER by `pos`");
  while($mas=mysql_fetch_array($sql))
          {
          // parent_id = 0 означает, что это основной заглавнй раздел и выводим мы его иначе, чем другие разделы и в любом случае
          if($mas[1] == '0')
              {
              printf("<tr><td class=\"main_page\"><a href=\"?page=%s\" class=\"main_page\">%s</a></td></tr>",$mas[4],$mas[3]);
              }
              else
			  {
			    //Если page Отправлен через гет
			  	if(@$_GET['page'])
			  	{
				$page = $_GET['page'];
				//Получаем парент той страницы, которая в GET
				$sub_result = mysql_query("SELECT * FROM `content` WHERE `page`='$page'") or die();
				$page_parent = mysql_result($sub_result,0,'parent_id');
				}

			  }
           //вызываем саму себя
		   menu($mas[0]);
        }
}
Не могу понять в каком направлении идти после получения парента страницы, которая в ГЕТ
 

igortik

Новичок
мда... ничего не выходит, просветление есть лишь в том, что если мы отправляем в GET page внутреннего раздела, то видим в перечне основного раздела меню его содержимое.

Как заставить делать тоже самое по нажатию на ссылку самого основного раздела пока что не ясно

P.S.

PHP:
function menu($parent_id)
{
  $sql=mysql_query("SELECT `id`,`parent_id`,`hidden`,`name`,`page` FROM `content` WHERE parent_id = ".$parent_id." AND `hidden`='0' ORDER by `pos`");
  while($mas=mysql_fetch_array($sql))
          {
          // parent_id = 0 означает, что это основной заглавнй раздел и выводим мы его иначе, чем другие разделы и в любом случае
          if($mas[1] == '0')
              {	  
              printf("<tr><td class=\"main_page\"><a href=\"?page=%s\" class=\"main_page\">%s</a></td></tr>",$mas[4],$mas[3]);
			  //  page отправлена через GET
			  if(@$_GET['page'])
                {
                $page = $_GET['page'];
                //Получаем парент той страницы, которая в GET
                $sub_result = mysql_query("SELECT * FROM `content` WHERE `page`='$page'") or die();
                $page_parent = mysql_result($sub_result,0,'parent_id');
					//Если парент полученной через ГЕТ страницы == ID основного раздела
					if($page_parent == $mas[0])
					{
					$res = mysql_query("SELECT * FROM `content` WHERE `parent_id`='$mas[0]'") or die();
					while($r = mysql_fetch_assoc($res))
						{
						$name = $r['name'];
						$page = $r['page'];
						printf("<tr><td class=\"page\"><a href=\"?page=%s\" class=\"page\">%s</a></td></tr>",$page,$name);
						}
					}
					//Если парент страницы из ГЕТ == 0 (значит мы нажали на основной раздел)
					else
					{
					//Пока что пусто 
					}
                }		
              }
              else
              {
			  //Пока что пусто                  
              }
           //вызываем саму себя
           menu($mas[0]);
        }
}
 

Фанат

oncle terrible
Команда форума
Нафига ты этот запрос делаешь внутри меню?!
тебе что - парент надо получать для каждого раздела?

Это надо сделать ДО формирования меню. И получить только одну переменную - ид активного корневого раздела.
И этот ид сравнивать в твоем условии дополнительно
 

Фанат

oncle terrible
Команда форума
хотя постой. если вынести внаружу, то тогда при проверке будут открываться все
 

HraKK

Мудак
Команда форума
Алгоритм в общем такой
получаем id нужного нам раздела, рекурсивно выбираем все родительские id. загоняем это все в массив.

После при отображении делаем проверку
if( $list['id'] in_array( $openId) )
 

igortik

Новичок
пока ничего не выходит...

вариаций вывода не так уж и много для обработки:

- нажали на основной пункт
- нажали на подпункт

при этом всем надо реализовать открытой лишь ту область, где есть основной пункт, в котором лежит подпункт.

ппц.. целый день.

-~{}~ 29.10.08 20:21:

*****
задача усложняется тем, что мы первоначально нажимаем на заглавный пункт меню, парент которого == 0, а также можем нажать по мере открытия и на вложенный пункт, парент которого будет == id своего родителя.

Так вот, чтобы определить id родителя в первом случае, надо его получать по переданному page в GET.


Запутался короче основательно
 

Фанат

oncle terrible
Команда форума
Так вот, чтобы определить id родителя в первом случае, надо выполнить элементарный SQL запрос, по переданному page в GET.
что здесь сложного, для меня - загадка.

после получения родителя задача сводится к предыдущей, уже решенной.
 

igortik

Новичок
мда, я так и думал.. что все будет проще, чем кажется
сейчас выложу

-~{}~ 29.10.08 21:47:

В начале определяем ID родительского элемента (если таковой имеется)

PHP:
//Поучаем запрошенную страницу через GET
if($_GET['page'])
	{
	$page = $_GET['page'];
	$result = mysql_query("SELECT * FROM `content` WHERE `page`='$page'") or die();
        //Вот и наш родитель (парент)
	$selected_id = mysql_result($result,0,'parent_id');

	//Пользователь нажал в меню на один из основных разделов
        //$selected_id в этом случае == 0, т.к. из запроса видно, что вытягиваем id его родителя, а он сам является родителем.. думаю, это ясно
	if($selected_id == '0')
		{

                //Получаем ID парента

		$result = mysql_query("SELECT * FROM `content` WHERE `page`='$page'") or die();
		$selected_id = mysql_result($result,0,'id');
		}	
	}
А вот и сама функция ...

-~{}~ 29.10.08 21:50:

PHP:
//обязательно отправляем $selected_id в функцию

function menu($parent_id,$selected_id)
{
  $sql=mysql_query("SELECT `id`,`parent_id`,`hidden`,`name`,`page` FROM `content` WHERE parent_id = ".$parent_id." AND `hidden`='0' AND `parent_id`='0' ORDER by `pos`");
  while($mas=mysql_fetch_array($sql))
          {
          // parent_id = 0 означает, что это основной заглавнй раздел и выводим мы его иначе, чем другие разделы и первым
          printf("<tr><td class=\"main_page\"><a href=\"?page=%s\" class=\"main_page\">%s</a></td></tr>",$mas[4],$mas[3]);

//Если  парент текущего разбираемого в массиве элемента равен id основного выбранного из массива пункта меню, то цапускаем цикл выборки его детей (вложенных пунктов меню)

		  if($mas[0] == $selected_id)
		  	{
		  	$result = mysql_query("SELECT `page`,`name` FROM `content` WHERE `parent_id`='$selected_id'");
		  	while($row=mysql_fetch_array($result))
		  		{
				printf("<tr><td class=\"page\">&nbsp;&nbsp;<a href=\"?page=%s\" class=\"page\">%s</a></td></tr>",$row[0],$row[1]);
				}
			}
          }
}
-~{}~ 29.10.08 21:51:

вызываем меню следующим образом:

menu(0,$selected_id);

-~{}~ 29.10.08 21:52:

P.S.

Как по мне, то цикл в цикле не очень хорошая конструкция, чисто интуитивное мнение..
может кто предложит что-то лучшее?

p.p.s. я не использовал рекурсию, т.к. с ней запутался основательно

Буду благодарен!
 

Фанат

oncle terrible
Команда форума
сами по себе два цикла ничего ужасного не представляют.
тем более, что каждый исполняется всего по разу.

только не понял, зачем два запросу при получении парента, и почему ты не боишься взлома через SQL
 

igortik

Новичок
*****
ты прав, спасибо, что напомнил, я на локалке делал просто.

По поводу, запросов..

я плохо знаю мускул, может это можно спросить одним, но, выложу пояснение своего варианта:

1. первым запросом мы пытаемся узнать парент той страницы, которую вытянули гетом.
1.1. в моем случае у основной страницы (заглавного пункта меню) парент всегда == 0
1.1.1. Юзер ведь не сразу видит вложенные пункты, он сначала должен нажать на основной и тогда парент передастся как == 0
В этом случае нам и необходимо вторым запросом вытянуть истинный ID
 

Фанат

oncle terrible
Команда форума
все рано не понимаю. почему ты делаешь ДВА ОДИНАКОВЫХ ЗАПРОСА?
 

igortik

Новичок
*****
Ты действительно прав, спасибо!

PHP:
if(@$_GET['page'])
	{
	$page = mysql_real_escape_string($_GET['page']);
	$result = mysql_query("SELECT * FROM `content` WHERE `page`='$page'") or die();
	$selected_id = mysql_result($result,0,'parent_id');
	//Если нажали на основной раздел
	if($selected_id == '0')
		{
		$selected_id = mysql_result($result,0,'id');
		}	
	}
 
Сверху