Конфигуратор, помогите разобраться в foreach

Serenity

Новичок
Конфигуратор, помогите разобраться в foreach

Прошу о помощи, и как не могу разобраться с этой проблемой. Help!
Пишу конфигуратор, он берет категории из базы и вставляет названия в html-код. Обходит он таблицу foreach, а дальше скрипт должен брать модели для этой категории и писать их после каждого названия категории, что-то типа этого:
Категория 1
модель1.1
модель1.2
Категория 2
модель 2.1
модель2.2 и так далее..
С категориями все отлично, берет их из базы и вставляет в код, но функция по обработке foreach моделей в функция категорий вставлять не дает. А если писать после нее, получается что сначала все категории и в последнюю категорию все модели. Как сделать, чтобы он после каждой написаной категории, писал модели относящиеся к нему?
PHP:
function display_categories($cat_array)
{
  foreach ($cat_array as $row)  // print name and id categories
  {
		echo "<td>".($row["catname"]),"</td>";
		echo "<td>".($row["catid"]),"</td>;
  }
}
function display_gelezo($gel_array) //display model gelezo
    {
  	foreach ($gel_array as $row)
  	{
  		echo "<option  value=\"".($row["gelid"]), "\">".($row["gelmodel"]),"</option>"; 					    	 	 	
  	}
    }
Функции совершенно однотиптые, но я записала обе.
Функции, которые берут данные из базы работают, но вот и они, чтобы легче было разобраться, как это исправить.
PHP:
function get_categories()
{
   // query database for a list of categories
   $conn = db_connect();
   $query = "select catid, catname
             from categories"; 
   $result = @mysql_query($query);
   if (!$result)
     return false;
   $num_cats = @mysql_num_rows($result);
   if ($num_cats ==0)
      return false;  
   $result = db_result_to_array($result);
   return $result; 
}

function get_category_name($catid)
{
   // query database for the name for a category id
   $conn = db_connect();
   $query = "select catname
             from categories 
             where catid = $catid"; 
   $result = @mysql_query($query);
   if (!$result)
     return false;
   $num_cats = @mysql_num_rows($result);
   if ($num_cats ==0)
      return false;  
   $result = mysql_result($result, 0, "catname");
   return $result; 
}
Вот как это выглядит в html
http://dll.1gb.ru/Configurator/nrd_config.html
 

Фанат

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

и со второй попытки - тоже

-~{}~ 07.01.08 00:24:

кавычку в коде ты забыла случайно, или в коде так и есть?
и где тот самый foreach, который тебе не даёт?
 

Serenity

Новичок
Большое спасибо, за столь быстрый отклик.
foreach, который меня так мучает первый, именно он пишет названия и id категории. А второй цикл, пишет информацию по модели. Они оба работаю, но вот только мне нужно чтобы второй цикл начинал работу как только, как только первый написал оба echo по одной из категорий.
Наверно, их стоит совместить в один и я пробовалата так поступить. (то есть, перед закрывающей скобкой первого цикла вставить второй) Но тут тогда надо изменить функции которые берут информацию из таблиц, чтобы они брали информацию сразу из двух таблиц. get_categories
get_categories, get_category_name берут информацию по категориям из одноименной таблицы. А функции get_gelezo, get_gelezo_details берут иинформацию по моделии из таблицы gelezo.
Вот эти две функциии:
PHP:
function get_gelezo($catid)
{
   // query database for the gelezo in a category
  // if (!$catid || $catid=="")
    //return false;
   
   $conn = db_connect();
   $query = "select * from gelezo";
   $result = @mysql_query($query);
   if (!$result)
     return false;
   $num_gel = @mysql_num_rows($result);
   if ($num_gel ==0)
      return false;
   $result = db_result_to_array($result);
   return $result;
}
function get_gelezo_details($gelid)
{
  // берет название и цену из таблицы
  if (!$gelid || $gelid=="")
     return false;

   $conn = db_connect();
   $query = "select gelid, gelprice from gelezo where gelid='$gelid'";
   $result = @mysql_query($query);
   if (!$result)
     return false;
   $result = @mysql_fetch_array($result);
   return $result;
}
Может нужно, чтобы они в общей функции брали информацию из двух таблиц?

-~{}~ 07.01.08 00:56:

Да, а где та ковычка о которой вы говорите?
 

Фанат

oncle terrible
Команда форума
кАвычка, о которой я говорю, в 7 строке твоего кода, после </td>
 

Serenity

Новичок
А поняла, но она получилась при убирании лишних html тегов, для форума, так что ничего страшного в коде верно.
 

dimagolov

Новичок
а где вызовы ф-й display_*** ? по идее из display_categories должна вызываться display_gelezo если я правильно все понял и gelezo это и есть модель.
кроме того, зачем в get_gelezo получаем парвметром $catid но запрашиваем все равно всю таблицу, а не то, что нам конкретно нужно?
 

Serenity

Новичок
Огромное спасибо, я так благодарна, что вы мне помогаете.
С Рождеством! А вот и ответы:
Нужно все из таблицы gelezo, но я не стала перегружать на форуме код лишними функциями.
Запрашиваю параметром $catid, так как важно к какой категории относится конкретная модель.
PHP:
  $cat_array = get_categories();
  $gel_array = get_gelezo($catid);

  display_categories($cat_array);
  display_gelezo($gel_array);
Это код вызывающий все эти функции, он находится в отдельном файле.
 

Фанат

oncle terrible
Команда форума
Слушай, подруга.
нафига городить функцию из двух десятков строчек, если достаточно двух?
$query = "select * from gelezo";
$result = mysql_query($query);
db_result_to_array($result);

почему все эти многочисленные одинаковые проверки нельзя сделать в функции db_result_to_array?
почему нельзя передавать ей сразу строку запроса?

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

и в любом случае - учись отлаживать свой код сама.

-~{}~ 07.01.08 02:49:

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

Serenity

Новичок
почему нельзя просто написать два вложенных друг в друга цикла*?
Ты прав, именно это меня и интересует и я это описала раньше.
только мне нужно чтобы второй цикл начинал работу как только, как только первый написал оба echo по одной из категорий.
Наверно, их стоит совместить в один и я пробовалата так поступить. (то есть, перед закрывающей скобкой первого цикла вставить второй) Но тут тогда надо изменить функции которые берут информацию из таблиц, чтобы они брали информацию сразу из двух таблиц.
Вот как их совместить я и не понимаю.
Можешь подсказать конкретным кодом?
Я подумаю над твоим предложением убрать лишние строчки, но в данный момент работать коду правильно мешает не это.
Сейчас они вызываются последовательно, но нужно чтобы вызывалась одна внутри которой другая. По отдельности они потому, что я код проверяла на работоспособность. Совместить мне их пока не удалось, чтобы они работали верно именно из-за этого я и здесь.
без единой функции
Без единой функции не получится, так как там еще и магазин заодно.
Спасибо, за столь стремительную отзывчивость.

-~{}~ 07.01.08 05:20:

Я изменила код, теперь он выдает модели, сразу за одной любой категорией. Но появилась другая проблема, он выбирает все модели, а не только относящиеся к определенной категории. Подскажите, как правильно написать условие.
Теперь код выглядит так:
PHP:
function display_configurator($config_array) 
{

  foreach ($config_array as $row)  // print name and id categories
  {
		echo "<td>".($row["catname"]),"</td>";
		echo "<td>".($row["catid"]),"</td>";
        
	foreach ($config_array as $row)
  	{
  	if (($row["gelezo.catid"])== ($row["categories.catid"]))
  	{	
  	echo "<option  value=\"".($row["gelid"]), "\">".($row["gelmodel"]),"</option>";
  	}
  	}
  }
надо изменить функции которые берут информацию из таблиц, чтобы они брали информацию сразу из двух таблиц.
Я реализовала мою проблему, через join так:
PHP:
function get_configurator($catid, $gelid)
{
	$conn = db_connect();
   $query = "select categories.catid, categories.catname, gelezo.gelid, gelezo.gelmodel 
from categories join gelezo where categories.catid = gelezo.catid";	
   $result = @mysql_query($query);
   if (!$result)
     return false;
   $num_config = @mysql_num_rows($result);
   if ($num_config ==0)
      return false;
   $result = db_result_to_array($result);
   return $result;
}
А тот код, который все это вызывает выглядит так:
PHP:
  $config_array = get_configurator($catid, $gelid);
  display_configurator($config_array);
 

Фанат

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

Подскажите, как правильно написать условие.
ты представляешь себе, какие данные находятся в массиве, который вернул get_configurator?
там именно то, что нужно?
 

Serenity

Новичок
Да, он вернул все модели из таблицы gelezo и прописал их к каждой категории, а не конкрето к той к которой относится.
Вот схематично, что он вернул:
Категория 1
модель1.1
модель1.2
модель 2.1
модель2.2
Категория 2
модель1.1
модель1.2
модель 2.1
модель2.2 и так далее..
А требуется:
Категория 1
модель1.1
модель1.2
Категория 2
модель 2.1
модель2.2 и так далее..
 

Фанат

oncle terrible
Команда форума
запрос не может вернуть данные в таком виде.
он может вернуть только строки.
вида
Категория 1 модель1.1
Категория 1 модель1.2
и так далее.

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

Serenity

Новичок
Еще немного измениний и теперь он правильно выдает модели относящиеся к категориям, то есть к каждой категории соответствующие модели, а не все из таблицы gelezo:
PHP:
  foreach ($config_array as $row)  // print name and id categories
  {
		echo "<tr>";
		echo "<td>".($row["catname"]),"</td>";
		echo "<td>".($row["catid"]),"</td>";
        $i = $row["catid"];
        	foreach ($config_array as $row)
        	{
        	if($i == $row["catid"])
        	{
        		echo "<option  value=\"".($row["gelid"]), "\">".($row["gelmodel"]),"</option>";
        	}
        	else 
        	{
        		echo "";
        	}	
           }
}
И все было бы ничего, но проблема появилась. Скрипт отображает категорию столько раз сколько в ней моделей к ней относящихся.
То есть если в категории 3 модели, он три раза пишет категорию и каждый раз правильно прописывает туда модели, если 2 модели то 2 раза и т.д.
Попробую описать схематично:
Категория 1
модель1.1
модель1.2
модель1.3
Категория 1
модель1.1
модель1.2
модель1.3
Категория 1
модель1.1
модель1.2
модель1.3
Категория 2
модель 2.1
модель2.2
Категория 2
модель 2.1
модель2.2
Категория 3
модель3.1 и так далее..
Надеюсь описала понятно, если у кого есть идея от чего у первого цикла появилась обратная зависимоть от второго подскажите, пожалуйста
 

Фанат

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

dimagolov

Новичок
Serenity, опуская то, что в обоих вложенных циклах as $row скажу, что результат ожидаемый. так как join, то категории вывелись вместе с моделями, то есть нужно во-первых сортировать выборку в запросе order by categories.catid, gelezo.gelid, а во вторых запоминать последнюю выведенную категорию и выводить ее только тогда, когда она отличается от выведенной.

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

WP

^_^
Девушка, Вы слышали о классах работы с БД? О шаблонизаторах?
> if (!$catid || $catid=="")
Эти условия сколь равнозначны, столь и нецелесообразны в данном случае.
Зачем $conn брать каждый раз из connect? Не лучше ли взять из переменной?
Зачем @ ?
Читали синтаксис SELECT ... JOIN?
Слышали о преобразовании спец. символов в мнемонические последовательности с помощью [m]htmlspecialchars[/m]?
В контексте написания магазина.... Попробуйте написать Гостевую книгу.
И про ORM (то что Вы пытаетесь сделать), пожалуйста, прочтите :)
 

Фанат

oncle terrible
Команда форума
WP
нет, ничего этого она не слышала и не читала.
и с удовольствием почитает, если ты напишешь
 

WP

^_^
Serenity
1. Советую выбрать один из паттернов, например Singleton. Например, Я храню основной указатель базы данных в классе xE (название системы).
Т.е.
PHP:
class system
{
 static $db;
 //...
}
system::$db = mysql_connect(...);
// или создание объекта от класса работы с СУБД.
system::$db доступно из любого контекста (любой области видимости переменных).
2. Советую прочесть мануал, в том числе что касается сравнения данных. Поймете почему те условия равнозначны. Достаточно проверить с помощью [m]ctype_digit[/m], либо провести к типу int модификатором (у этих двух способов разница в обработке).
3. @ писать не нужно, об этом популярно написано в http://phpfaq.ru/debug .
4. Прочти http://dev.mysql.com/doc/refman/4.1/en/join.html .
5. Все литеральные значения которые могут содержать спец. символы HTML (например "<" и ">"), следует экранировать через [m]htmlspecialchars[/m].
6. При генерации запросов к СУБД MySQL следует использовать [m]mysql_real_escape_string[/m].
7. Группы функций следует объединять в классы.

Фaнат
Польщен, но Google даст больше букв чем Я :)

-~{}~ 07.01.08 21:56:

Serenity
8. Не стоит мешать логику приложения и логику представления (вывод HTML). Следует генерировать совокупность переменных, и передавать их шаблону.
9. Не советую для записи строк использовать двойные кавычки если не планируется использовать экранированные последовательности.

-~{}~ 07.01.08 22:17:

10. Прочти про Деревья в БД, для вывода категорий и моделей.
 

Serenity

Новичок
Огромное спасибо за советы и информацию, я их учла и использую в реализации данного проекта.
Правда, стыдно признаваться, но у меня не получается реализовать условие проверки изменения выводимого элемента в цикле. О чем писал dimagolov
запоминать последнюю выведенную категорию и выводить ее только тогда, когда она отличается от выведенной
Пожалуйста, покажите его реализацию на примере кода. Я отлично поняла теоретически, что требуется делать, но реализовать так и не получилось. Именно поэтому прошу показать, как это написать практически на любом примере.
 

dimagolov

Новичок
Я отлично поняла теоретически, что требуется делать, но реализовать так и не получилось.
(с) Не верю. Данная фраза имеет внутреннее противоречие.

Serenity, Вам в школе что такое алгоритм расказывали? если нет или не поняли - срочно в гугл.
PHP:
$lastCat= -1;
foreach () {
   if ($curCat != $lastCat) {
      printCat();
      $lastCat= $curCat;
   }
   printModel();
}
 
Сверху