Многопоточные комментарии PHP? - PullRequest
7 голосов
/ 06 декабря 2011

У меня есть сценарий, который я написал, пока возвращался для комментариев, но он только однопоточный. Я хотел бы, чтобы он был многопоточным, но только так, чтобы пользователь мог ответить на комментарий, а не чтобы пользователь мог ответить на комментарий к комментарию. Так что темы будут только две глубокие.

В настоящее время я храню comment_id против user_id в моей базе данных.

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

Должен быть лучший способ. Есть идеи по этому поводу? Или учебники?

Ответы [ 4 ]

16 голосов
/ 06 декабря 2011

Есть три (четыре) альтернативных варианта:

  1. A рекурсивный запрос , чтобы выбрать все комментарии на основе их родительских идентификаторов. Это поддерживается многими продуктами баз данных, и синтаксис зависит от типа базы данных. Проверьте документы для получения дополнительной информации (поиск «рекурсивный»).

  2. Если вы сохраняете идентификатор статьи в каждом (под) комментарии, вы можете просто выбрать все комментарии с идентификатором статьи в одном обычном запросе выбора. Вы можете использовать родительские идентификаторы для правильного отображения комментариев на странице под правильным родительским комментарием:

    SELECT * FROM comments WHERE article_id = :article_id
    
  3. Если вам нужны только два уровня комментариев, вы можете использовать расширенный , где , чтобы включить комментарии как первого уровня, так и второго уровня:

    SELECT * FROM comments 
    WHERE parent_id = :article_id
    OR    parent_id IN (SELECT id FROM comments WHERE parent_id = :article_id)
    
  4. Можно также использовать union all для объединения двух запросов, имеющих одинаковые столбцы, но, поскольку я предполагаю, что все данные взяты из одной таблицы, вероятно, в этом нет необходимости. (см. расширенный пункт where выше):

    SELECT * FROM comments WHERE parent_id = :article_id
    UNION ALL
    SELECT * FROM comments WHERE parent_id IN 
        (SELECT id FROM comments WHERE parent_id = :article_id)
    

Лично я бы выбрал вариант 2, потому что он прост (не требуется экзотическая конструкция SQL), эффективен (1 запрос) и гибок (поддерживает столько уровней комментариев, сколько вам нужно).

2 голосов
/ 06 декабря 2011

Это обычное использование для иерархических данных или данных древовидной структуры.Я написал популярный ответ на этот вопрос переполнения стека: Какой самый эффективный / элегантный способ разбить плоский стол на дерево?

Я также написал презентацию, описывающую альтернативы для дерева.структурированные данные: Модели для иерархических данных с SQL и PHP .

Еще одно решение, которое не включено в мою презентацию, - это способ, которым Slashdot выполняет потоковые комментарии.Они используют столбец parent, как и вы, поэтому каждый комментарий ссылается на комментарий, на который он отвечает.Но тогда они также включают столбец root, поэтому каждый комментарий знает, к какой записи он относится.К данному сообщению редко добавляется более нескольких сотен комментариев, и обычно вы хотите получить все дерево комментариев к данному сообщению, начиная с верхней части цепочки комментариев:

SELECT * FROM comments WHERE root = 1234;

Тогда, когда выизвлекая комментарии, вы можете написать код PHP для обработки их в массивы массивов в соответствии со столбцами parent (это то, на что ссылается ответ @ JanL).Я написал код для этого в своем ответе на другой вопрос переполнения стека, Преобразование плоского массива в многомерный .

2 голосов
/ 06 декабря 2011

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

1 голос
/ 06 декабря 2011

Этот запрос может работать для вас (я не знал вашей структуры, поэтому я догадался об этом):

SELECT * FROM comments a
LEFT JOIN comments b ON a.comment_id = b.parent_coment_id
LEFT JOIN comments c ON b.comment_id = c.parent_coment_id
WHERE a.comment_id <> b.comment_id
      AND a.comment_id <> c.comment_id
      AND b.comment_id <> c.comment_id;
...