Вложенные циклы - PullRequest
       1

Вложенные циклы

1 голос
/ 11 августа 2011

У меня есть система комментариев. Каждый комментарий может получать ответы, и каждый ответ может получать ответы ad nauseam.

Таким образом, моя база данных содержит таблицу с именем «comments» со следующими важными полями:

id
text
reply_to

... в поле reply_to, конечно, указывается идентификатор комментария, на который он является ответом.

Итак, теперь проблема проста: как отобразить все комментарии, но зная, что после каждого комментария должны приходить ответы на него, а после каждого ответа должны приходить ответы на ответ и т. Д.?

То, что я пробовал больше всего и к чему я все время возвращаюсь, выглядит примерно так:

$query = mysql_query("SELECT * FROM comments WHERE reply_to=0");
while ($comment = mysql_fetch_array($query))
    include("comment.php");

И в comment.php у меня есть:

foreach ($comment as $key = $value) $$key = $value;
echo $text;
echo "<div style='margin-left:30px;'>"; //A margin for a little indent
$subquery = mysql_query("SELECT * FROM comments WHERE reply_to=$id");
while ($comment = mysql_fetch_array($subquery))
    include("comment.php");
echo "</div>";

Но если я правильно воспроизвел суть моего кода, проблема заключается в следующем: после первого ответа он переходит к первому ответу первого ответа, а затем к первому ответу первого ответа первый ответ, но цикл никогда не доходит до второго ответа. Так, например, предположим, что в таблице было 3 комментария, в каждом из которых было 3 ответа, и в каждом из них было 3 ответа и т. Д., Приведенный выше код выдает:

Comment
  First reply
    First second-order reply
      First third-order reply
        ...

Надеюсь, я объяснил это достаточно ясно. inb4: я не могу добавить новые столбцы в таблицу.

Ответы [ 5 ]

2 голосов
/ 11 августа 2011

в псевдокоде:

function display_comment(comm)
  echo comm's info and text
  children = get children of the comment: SELECT from comments WHERE parent = (comm's id)
  echo <div class="comment-thread">
  foreach children as child
    display_comment(comm) // notice this line
  echo </div>

Вы должны создать функцию, чтобы рекурсивно ссылаться на нее.

0 голосов
/ 11 августа 2011

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

http://www.devx.com/tips/Tip/22127

0 голосов
/ 11 августа 2011

Хм, интересные вещи. Итак, вот мои мысли (это своего рода вопрос дизайна, поэтому я предполагаю, что есть много подходов). Лично я бы использовал словарь для представления родительских комментариев. Вот некоторый псевдокод для того, как я подхожу к этому:

Первая БД:

+--------------------------+
| comments                 |
+--------------------------+
| id (INT)                 | <-- a unique id for the comment
| post_id (INT)            | <-- the original post / article being replied to
| parent_id (INT)          | <-- the comment this is in response to
| commenter_email (VARCHAR)| <-- just some way to identify the commenter
| comment_text (TEXT)      | <-- the actual comment
+--------------------------+

Второй псевдокод:

function print_comment($comment_id, $replies_children, $comments)
{
    // For every comment at this level...
    foreach($reply_id in $replies_children[$comment_id])
    {
        // Create a div container to contain both this comment AND
        // all child comments. We let CSS take care of indenting.
        echo '<div style="padding-left: 10px;">';

        // Print this comment first...
        echo $comments[$reply_id]['comment_text'];

        // And beneath it print all of the replies to this comment
        print_comment($reply_id, $replies_children, $comments);

        // Finally end this level of comment indentation
        echo '</div>';
    }
}

// Fetch all of the comments at once for post id 10
$sql = "SELECT * FROM comments WHERE post_id = 10;";

// Get the results back (associative array, please)
$results = execute_sql($sql);

// Holds a list of replies (comment ids) for each comment
$replies_children = array();

// Lets us map an ID to the actual full sql result
$comments = array();

foreach($result in $results)
{
    // Make sure there's a list for the parent
    if($replies_children doesnt have key $result['parent_id']))
        $replies_children[$results['parent_id']] = array();

    // Append this item to the parent's list
    $replies_children[$result['parent_id']][] = $result['id'];

    // Allows us to get to this result by id directly
    $comments[$result['id']] = $result;
}

// Assume that id = 0 is the root level
print_comment(0, $replies_children, $comments);

Таким образом, вы вызываете базу данных только один раз.

0 голосов
/ 11 августа 2011
$subquery = mysql_query(SELECT * FROM comments WHERE reply_to=$comment_id);

Может быть какая-то ошибка.Когда вы описали определение таблицы, поле с идентификатором комментария было названо id, но здесь вы используете comment_id.Кроме того, вы не заключили свой оператор SQL в кавычки (' ').Это ошибки копирования-вставки?

0 голосов
/ 11 августа 2011

Я обычно так делаю

  function get_comments($text_id, $parent_id,$depth){
         $sql="SELECT * FROM spam WHERE parent_id='".(int)$parent_id."' AND text_id='".(int)$text_id."' ";
         //..query 
         while ($row=mysql_fetch_assoc($query)){
             //some comment output use $depth*pixels to indent
             $depth++; 
             get_comments($text_id,$row['parent_id'],$depth);
             $depth--;

         }

  }

и при первом звонке

  get_comments($text_id,0,0); //
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...