За последние 24 часа нас посетили 20829 программистов и 1132 робота. Сейчас ищут 359 программистов ...

Реализация "новых" тем в форуме

Тема в разделе "Решения, алгоритмы", создана пользователем antonn, 21 июн 2007.

  1. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    Для удаления/переноса потребуется пересчет для всех юзеров.
    Можно поднимать флаг (дату), чтобы каждый юзер после удаления постов в разделе однократно пересчитывал себе t_unread_count
    тогда активные модерские правки не будут так тормозить. Но us2f растет в ширину )))
     
  2. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    armadillo
    На тебя напало прозрение, однако идея хорошая. Кажись займусь реализацией :)
     
  3. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    Кстати заметно раздражает во всех пхпбб непометка прочтенной темы, если в нее влез с главной.
     
  4. Alehandr

    Alehandr Активный пользователь

    С нами с:
    16 апр 2009
    Сообщения:
    20
    Симпатии:
    0
    Адрес:
    Селенгинск + Иркутск
    А если на каждого юзера заводить отдельный файл в формате Json в виде массива:
    [{"регистрация":"дата","топы":{"id":"время просмотра",...}}]

    Для того, чтобы определить является ли тема новой сначала сравниваем дату последнего сообщения с датой регистрации, если больше, то с датой последнего посещения темы.

    При просмотре темы, обновляем значение массива["топы"][id топика] на now().

    Нагрузка на сервак будет куда меньше, а утечки данных не будет, т.к. перезапись файла будет только с 1 сессии.
    + если массив будет численным (не ассоциативным) JSON_en(de)code будут работать быстро.
     
  5. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    что есть "топы"?
     
  6. Alehandr

    Alehandr Активный пользователь

    С нами с:
    16 апр 2009
    Сообщения:
    20
    Симпатии:
    0
    Адрес:
    Селенгинск + Иркутск
  7. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    Alehandr
    представь, 1000 юзеров (это даже очень мало, в принципе), 10К тем (почти много, да ладно) и 100к постов, если каждый будет этот файл обрабатывать (а это серилизованный массив, значит он грузится весь в память) при каждом просмотре (ты ведь не знаешь, смотрел эту тему юзер, пока не откроешь файл)... ну как бы долго и памятижрущще получается :)
     
  8. Alehandr

    Alehandr Активный пользователь

    С нами с:
    16 апр 2009
    Сообщения:
    20
    Симпатии:
    0
    Адрес:
    Селенгинск + Иркутск
    antonn
    Ну да, про память не подумал...
    Но я бы всеравно реализовал на файлах, только надо придумать как получше будет...
     
  9. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Файлы, файлы... Всёравно в базе хранить надо. Самый приемлимый вариант это следить за выбранными пользователем темами в режиме live в базу и остальное по схеме PHPBB с куками и последним временем входа. Для кеширования выборок с базы юзаю memcached или xcache
     
  10. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    куки - это привязка к машине, а так я на работе и дома вижу привычное положение дел - где я был и где небыл
     
  11. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    antonn
    Честно я не сильно смотрел как в PHPBB там сделано толком. Вобщем то записывается время последнего посещения и показывает новое после этого момента. А конкретно 100% правильное слежение можно сделать только за активными темами.
     
  12. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    100% работающее я описывал уже, а "правильно" понятие растяжимое :) а "вход" клиента из той же серии, что и "юзеры онлайн".
    я браузер могу раз в час обновлять, по дефолту на куче сайтов сессия будет пересоздаваться, на втором часе у меня исчезнут маркеры?
     
  13. kas1e

    kas1e Активный пользователь

    С нами с:
    6 апр 2009
    Сообщения:
    280
    Симпатии:
    0
    не реализовывал такого. но вообще в голову первое пришло - пишем юзеру в два поля ид максимальной темы, и ид макимальной мессаги(если форум написан с одной таблицей для мессаг и тем - то еще лучше).

    Потом смотрим - если в теме присутствует комменты с ид выше нашего - значит новое =)

    но тут идет другое. глядим последнюю тему - и все предыдущие кагбе прочитано.

    "на середине поста появилось странное ощущение, что что-то неверно. так и вышло" :)
     
  14. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    kas1e
    да, юзеров много и для каждого свое :)
     
  15. vital

    vital Активный пользователь

    С нами с:
    18 дек 2006
    Сообщения:
    162
    Симпатии:
    0
    Адрес:
    Минск
    всю тему не читал поэтому могу повторить предложенный ранее вариант.. и всё же
    1. в начало каждого скрипта добавляем код, который записывает в куку или в БД время (время последнего посещения)
    2. проверяем есть ли сессия в которой записано время последнего посещения. если нет создаём сессию, и все темы где есть посты добавленные позднее времени последнего посещения помечаем как непрочитанные
    если тема пользователю интересна он её прочтёт, если нет то при следующем посещении она не будет и мазолить ему глаза своей подсветкой
     
  16. antonn

    antonn Активный пользователь

    С нами с:
    10 июн 2007
    Сообщения:
    2.996
    Симпатии:
    0
    Фигня в том, что нет такого понятия как "последнее посещение". Браузер запрашивает страничку, получает в ответ, никаких "вы сечаст на сайте" и "последний раз вы заходили". Я могу случайно обновить страницу браузера и через час увижу, что "новых" тем совсем мало осталось :)
    Так же лично я считаю, что у юзера нету куков :)
     
  17. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    пришел в голову похожий функционал, глядя на форумы, включая этот.
    внести тему в черный список. в двух вариантах - не как новые темы/форумы и скрыть вообще
     
  18. Koc

    Koc Активный пользователь

    С нами с:
    3 мар 2008
    Сообщения:
    2.253
    Симпатии:
    0
    Адрес:
    \Ukraine\Dnepropetrovsk
    здесь этот функционал плохо сделан. На pyha.ru/forum стоит SMF, там реально круто непрочитанные отмечаются. Может кто-то поставит-поковыряет его?
     
  19. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Сделал форум. Форумы и темы помечаются на ура. Задачка плёвая, как 2 пальца. Не буду полностью расписывать решение, нудная хрень, всё равно потом выложу в открытый доступ. Правда не спрашивайте когда, делал под заказ, нужно время, чтобы открыть код. Могу таблички шпиона показать и куски кода:
    [sql]CREATE TABLE IF NOT EXISTS `forums_spy` (
    `user_id` int(11) default NULL,
    `forum_id` int(11) default NULL,
    `time` int(11) default NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=UTF8;[/sql]
    [sql]CREATE TABLE IF NOT EXISTS `forum_topics_spy` (
    `user_id` int(11) default NULL,
    `forum_id` int(11) default NULL,
    `topic_id` int(11) default NULL,
    `time` int(11) default NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=UTF8;[/sql]
    При выводе форумов:
    Выбираем статистику шпиона по форумам:
    PHP:
    1. <?php
    2. if($USER_ID != 1) // для гостя не мониторим
    3. {
    4.     $result = $DB->query("SELECT `forum_id`, `time` FROM `{prefix}forums_spy` WHERE `user_id` = ".$USER_ID);
    5.     while($row = $DB->fetch_assoc($result))
    6.     {
    7.         $forums_spy[$row['forum_id']] = $row['time'];
    8.     }
    9. }
    Дальше при обходе форумов делаем такую фишку:
    PHP:
    1. <?php
    2. if(isset($forums_spy[$forum['id']])) // У шпиона есть запись на текущий форум
    3. {
    4.     if($forums_spy[$forum['id']] >= $forum['last_post_time']) // Форум прочитан
    5.     {
    6.         $forum_read = ($category['open'] and $forum['open'])? /*форум прочитан | открыт*/ : /*форум прочитан | закрыт*/ ;
    7.     }
    8.     else
    9.     {
    10.         $forum_read = ($category['open'] and $forum['open'])? /*форум не прочитан | открыт*/ : /*форум не прочитан | закрыт*/ ;
    11.     }
    12. }
    13. else // Запись отсутствует
    14. {
    15.     if($forum['topics_num'] and $USER_ID != 1) // Форум не прочитан
    16.     {
    17.         $forum_read = ($category['open'] and $forum['open'])? /*форум не прочитан | открыт*/ : /*форум не прочитан | закрыт*/ ;
    18.  
    19.         $forum_spy_insert[] = '('.$USER_ID.', '.$forum['id'].', 0)'; // Собираем данные для шпиона
    20.     }
    21.     else
    22.     {
    23.         $forum_read = ($category['open'] and $forum['open'])? /*форум прочитан | открыт*/ : /*форум прочитан | закрыт*/ ; ;
    24.     }
    25. }
    После обхода форумов надо сделать записи шпиону на те форумы про которые он не знает:
    PHP:
    1. <?php
    2. if(isset($forum_spy_insert)) $DB->query("INSERT INTO `{prefix}forums_spy` VALUES ".implode(', ', $forum_spy_insert));
    При выводе топиков:
    Вычищаем статистику по устаревшим топикам:
    PHP:
    1. <?php
    2. $DB->query("DELETE FROM `{prefix}forum_topics_spy` WHERE `forum_id` = ".get('id')." AND `time` <= ".(time() - $forums[$forum_category_id][get('id')]['topics_outdated_time']));
    Выбираем статистику:
    PHP:
    1. <?php
    2. if($USER_ID != 1)
    3. {
    4.     $result = $DB->query("SELECT `topic_id`, `time` FROM `{prefix}forum_topics_spy` WHERE `user_id` = ".$USER_ID." AND `forum_id` = ".get('id'));
    5.     while($row = $DB->fetch_assoc($result))
    6.     {
    7.         $forum_topics_spy[$row['topic_id']] = $row['time'];
    8.     }
    9. }
    При обходе топиков проверяем так:
    PHP:
    1. <?php
    2. if(isset($forum_topics_spy[$row['id']])) // У шпиона есть запись на текущую тему
    3. {
    4.     $forum_topic_read = ($forum_topics_spy[$row['id']] >= $row['last_post_time'])? true : false ;
    5. }
    6. else // Запись отсутствует
    7. {
    8.     $forum_topic_read = ($USER_ID != 1 and $row['last_post_time'] > time() - $forums[$forum_category_id][get('id')]['topics_outdated_time'])? false : true ;
    9. }
    При выводе постов начинается самое веселье:
    PHP:
    1. <?php
    2. if($USER_ID != 1)
    3. {
    4.     // Провереям наличие записи у шпиона на текущую тему
    5.     $result = $DB->query("SELECT `time` FROM `{prefix}forum_topics_spy` WHERE `user_id` = ".$USER_ID." AND `topic_id` = ".$forum_topic['id']);
    6.  
    7.     $forum_topic_spy = $DB->fetch_row($result);
    8.  
    9.     if(!$DB->num_rows($result) or $forum_topic_spy[0] < $forum_topic['last_post_time']) // Тема не прочитана
    10.     {
    11.         // Правим статистику шпиона
    12.         if(!$DB->num_rows($result))
    13.         {
    14.             $DB->query("INSERT INTO `{prefix}forum_topics_spy` VALUES (".$USER_ID.", ".$forum_topic['forum_id'].", ".$forum_topic['id'].", ".$forum_topic['last_post_time'].")");
    15.         }
    16.         else
    17.         {
    18.             $DB->query("UPDATE `{prefix}forum_topics_spy` SET `time` = ".$forum_topic['last_post_time']." WHERE `user_id` = ".$USER_ID." AND `topic_id` = ".$forum_topic['id']);
    19.         }
    20.  
    21.         // Кол-во не устаревших прочитанных тем в форуме
    22.         $result_spy_read = $DB->fetch_row($DB->query("SELECT COUNT(*) FROM `{prefix}forum_topics_spy`, `{prefix}forum_topics` WHERE
    23.         `user_id` = ".$USER_ID." AND
    24.         `{prefix}forum_topics_spy`.`forum_id` = `{prefix}forum_topics`.`forum_id` AND
    25.         `{prefix}forum_topics`.`forum_id` = ".$forum_topic['forum_id']." AND
    26.         `topic_id` = `id` AND
    27.         `time` >= `last_post_time` AND
    28.         `time` > ".(($forum_spy_time = time()) - $forums[$forum_category_id][$forum_topic['forum_id']]['topics_outdated_time'])));
    29.  
    30.         // Кол-во устаревших тем в форуме
    31.         $result_spy_outdated = $DB->fetch_row($DB->query("SELECT COUNT(*) FROM `{prefix}forum_topics` WHERE
    32.         `forum_id` = ".$forum_topic['forum_id']." AND
    33.         `last_post_time` <= ".($forum_spy_time - $forums[$forum_category_id][$forum_topic['forum_id']]['topics_outdated_time'])));
    34.  
    35.         // Кол-во прочитанных тем + кол-во устаревших тем = кол-ву тем в форуме -> форум прочитан
    36.         if($result_spy_read[0] + $result_spy_outdated[0] == $forums[$forum_category_id][$forum_topic['forum_id']]['topics_num'])
    37.         {
    38.             $DB->query("UPDATE `{prefix}forums_spy` SET `time` = ".$forums[$forum_category_id][$forum_topic['forum_id']]['last_post_time']." WHERE
    39.             `user_id` = ".$USER_ID." AND `forum_id` = ".$forum_topic['forum_id']);
    40.         }
    41.     }
    42. }
    Вот такая ацкая хрень. Алгоритм, насколько я понимаю, очень похож на алгоритм из IPB. Такой вывод делаю на основе изучения базы. Вот такие пироги.
     
  20. Апельсин

    Апельсин Активный пользователь

    С нами с:
    20 мар 2010
    Сообщения:
    3.645
    Симпатии:
    2
    пля. много кода. придется самому придумывать запоминалку сообщений :(
    походу, куками тут не отделаться.
     
  21. Апельсин

    Апельсин Активный пользователь

    С нами с:
    20 мар 2010
    Сообщения:
    3.645
    Симпатии:
    2
    сделал свой вариант. Помечает темы с непрочит. мессагами. Всего нужна 1 таблица с ид юзера и текстовым полем для пар ид_топика+mktime. Еще чуток допилю, чтоб самоочищалось поле и чтоб можно было просмотреть новые сообщения отдельно. А так ничё вроде.