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

Вывод тем подфорума в родительском форуме

У вас есть идея для расширения функциональности phpBB 3.0.x? Расскажите о ней здесь!
Правила форума
Местная Конституция | Шаблон запроса | Документация (phpBB3) | Переход на 3.0.6 и выше | FAQ-3 (phpbb3) | Как задавать вопросы | Как устанавливать моды

Ваш вопрос может быть удален без объяснения причин, если на него есть ответы по приведённым ссылкам (а вы рискуете получить предупреждение ;) ).
kefiijrw
phpBB 1.0.0
Сообщения: 5
Стаж: 15 лет 10 месяцев

Вывод тем подфорума в родительском форуме

Сообщение kefiijrw »

Хочу использовать подфорумы в качестве фильтров.
То есть, например, если есть форум «авто», а в нем подфорумы «ауди», «бмв», «мерседес» и т.д., то чтобы в родительском форуме «авто» отображались все темы из этого форума + все темы из подфорумов. Таким образом подфорумы нужны будут для уточнения марки, а в родительском форуме отображаются темы про все марки автомобилей.

В общем, заходом в лоб я этого смог добиться: во viewforum.php во время формирования SQL-запроса я подмешал к id форума все его подфорумы

FIND

Код: Выделить всё

$sql_where = 't.forum_id = ' . $forum_id;
REPLACE WITH

Код: Выделить всё

if(sizeof($active_forum_ary['forum_id']) ){
	$sql_where = 't.forum_id IN (' . $forum_id.', '.implode(", ", $active_forum_ary['forum_id']).')';
} else{
	$sql_where = 't.forum_id = ' . $forum_id;
}
Темы отображает более-менее правильно, даже права доступа вроде не поломались — темы из скрытого подфорума в общей ленте не отображаются.

Но не всё работает гладко — некоторые темы из подфорума в общей ленте ошибочно отображаются как непрочитанные, хотя в подфоруме отображаются нормально. Покопавшись, я понял, что дело в массиве $topic_tracking_info, в котором хранятся таймстампы. Массив наполняется функциями get_topic_tracking и get_complete_topic_tracking, и вот тут я завис.

Чем отличаются эти функции и каким образом движок определяет, какие темы прочтенные, а какие нет? Функции, я так понял, скорее относятся к форумам, чем к темам, т.к. возвращают различающиеся значения для одной и той же темы в зависимости от форума, где эта тема отображается (в своем подфоруме или в общем форуме). Подозрения падают на кнопку «отметить форум прочитанным», но тему можно сделать прочитанной и другими способами.

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

Ну и какие еще проблемы несет подобный хак? Я пока еще только увидел необходимость объединения функционала кнопок «отметить темы прочтенными» и «отметить форумы прочтенными» в одну, ну и всякие мелочи с правами.
Последний раз редактировалось kefiijrw 24.05.2014 21:33, всего редактировалось 1 раз.
kefiijrw
phpBB 1.0.0
Сообщения: 5
Стаж: 15 лет 10 месяцев

Re: Вывод тем подфорума в родительском форуме — непрочитанны

Сообщение kefiijrw »

Ну ладно, тогда я сам попробую.

Я, конечно, был наивен, надеясь одним изменением в SQL-запросе всё разрулить. Итак, что пришлось проделать с viewforum.php:

Для начала полезная ссылка для понимания принципов работы отметок о прочитанных сообщениях: http://ilantipov.livejournal.com/2012.html
Так как при просмотре форума предполагается, что отображаемые темы из topicrow относятся к этому форуму (спасибо КО, хотя еще есть shadow-топики и глобальные объявления), то все проверки на «прочитанность» топика делаются из контекста текущего forum_id. Это и предстояло изменить.

Когда я размышлял над тем, как обойти это ограничение, я вспомнил про страницу с активными темами — там тоже собраны топики из разных форумов, но отметки о непрочитанных сообщениях работают корректно. Я немного покопался в search.php и криворукими костылями перенес некоторые решения оттуда. Главная идея очевидна — передавать в функции get_topic_tracking и get_complete_topic_tracking (они отвечают за отметки о непрочитанных сообщениях) вместе со списком сообщений правильный forum_id, который теперь не общий и неизменный для всех тем, а меняющийся в зависимости от топиков.

Итак, где-нибудь в начале файла устанавливаем триггер-включалку и объявляем список форумов, где подфорумы будут работать как метки.

Код: Выделить всё

define('SUBFORUMS_AS_TAGS', true);
$subforums_as_tags_forums_id = array(4, 6, 14);

В $forum_data хранятся данные о форуме. Большинством свойств родительского форума (стиль, имя, тип форума, пароль и т.д.) пользуемся без изменений, эти свойства у подфорумов значение не имеют, поэтому этот массив переопределять не будем. Но одно свойство надо разузнать у подфорумов — mark_time, оно отвечает за правильное отображение непрочитанных топиков. Сохраняем заготовку формирующего $forum_data SQL-запроса на будущее:

SEARCH

Код: Выделить всё

$sql = "SELECT f.* $lastread_select
	FROM $sql_from
	WHERE f.forum_id = $forum_id";
ADD AFTER

Код: Выделить всё

$sql_for_subforums = "SELECT f.* $lastread_select
	FROM $sql_from";

После того, как список подфорумов определен, пользуемся заготовленным куском запроса и сохраняем значения mark_time форума и подфорумов.

SEARCH

Код: Выделить всё

// Dump out the page header and load viewforum template
page_header($forum_data['forum_name']);
ADD BEFORE

Код: Выделить всё

if(SUBFORUMS_AS_TAGS && in_array($forum_id, $subforums_as_tags_forums_id) && sizeof($active_forum_ary['forum_id']) ){

	if ($user->data['is_registered'] && $config['load_db_lastread'])
	{
		$sql_for_subforums .= ' WHERE f.forum_id IN ('.$forum_id.', '.implode(", ", $active_forum_ary['forum_id']).')';

		$result_subforums = $db->sql_query($sql_for_subforums);

		while ($row = $db->sql_fetchrow($result_subforums)){
			$forum_data_subforums[$row['forum_id']] = $row;
		}

		$db->sql_freeresult($result_subforums);	
	}
}

Заводим массив для распределения сведения о топиках по форумам.

SEARCH

Код: Выделить всё

$rowset = $announcement_list = $topic_list = $global_announce_list = array();
REPLACE WITH

Код: Выделить всё

$forums = $rowset = $announcement_list = $topic_list = $global_announce_list = array();

Вмешиваемся в первый SQL-запрос на список тем

SEARCH

Код: Выделить всё

if ($forum_data['forum_type'] == FORUM_POST)
{
	// Obtain announcements ... removed sort ordering, sort by time in all cases
ADD AFTER

Код: Выделить всё

	if(SUBFORUMS_AS_TAGS && in_array($forum_id, $subforums_as_tags_forums_id) && sizeof($active_forum_ary['forum_id']) ){
		$subforo_list = $forum_id.', '.implode(", ", $active_forum_ary['forum_id']);
	} else{
		$subforo_list = $forum_id;
	}

SEARCH

Код: Выделить всё

		'WHERE'		=> 't.forum_id IN (' . $forum_id . ', 0)
REPLACE WITH

Код: Выделить всё

		'WHERE'		=> 't.forum_id IN (' . $subforo_list . ', 0)


В цикле сбора результатов запроса раскладываем топики по форумам

SEARCH

Код: Выделить всё

		$announcement_list[] = $row['topic_id'];
ADD BEFORE

Код: Выделить всё

		$forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']];

То же самое с другими запросами

SEARCH

Код: Выделить всё

	$sql_where = 't.forum_id = ' . $forum_id;
REPLACE WITH

Код: Выделить всё

	//здесь айди не только отцовского форума, но и подфорумов
	if(SUBFORUMS_AS_TAGS && in_array($forum_id, $subforums_as_tags_forums_id) && sizeof($active_forum_ary['forum_id']) ){
		$sql_where = 't.forum_id IN (' . $forum_id.', '.implode(", ", $active_forum_ary['forum_id']).')';
	} else{
		$sql_where = 't.forum_id = ' . $forum_id;
	}

SEARCH

Код: Выделить всё

$sql = 'SELECT t.topic_id
REPLACE WITH

Код: Выделить всё

$sql = 'SELECT t.topic_id, t.forum_id


SEARCH

Код: Выделить всё

	$topic_list[] = (int) $row['topic_id'];
ADD AFTER

Код: Выделить всё

	$forums[(int) $row['forum_id']]['topic_list'][] = (int) $row['topic_id'];

SEARCH

Код: Выделить всё

		if ($row['topic_status'] == ITEM_MOVED)
		{
			$shadow_topic_list[$row['topic_moved_id']] = $row['topic_id'];
		}

		$rowset[$row['topic_id']] = $row;
ADD AFTER

Код: Выделить всё

		$forums[$row['forum_id']]['rowset'][$row['topic_id']] = &$rowset[$row['topic_id']];

Ну и финальный блок, где всё разруливается. Проверяется триггер и в зависимости от его значения запускается новый или старый вариант обработки. В новом варианте всё просто — блок оборачивается в цикл по форумам, ну и аргументы при вызове функций подмениваются на сохраненные ранее в массивы $forums и $forum_data_subforums.

SEARCH

Код: Выделить всё

		if ($config['load_db_lastread'] && $user->data['is_registered'])
		{
			$topic_tracking_info = get_topic_tracking($forum_id, $topic_list, $rowset, array($forum_id => $forum_data['mark_time']), $global_announce_list);
			$mark_time_forum = (!empty($forum_data['mark_time'])) ? $forum_data['mark_time'] : $user->data['user_lastmark'];
		}
		else if ($config['load_anon_lastread'] || $user->data['is_registered'])
		{
			$topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_list, $global_announce_list);

			if (!$user->data['is_registered'])
			{
				$user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
			}
			$mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark'];
		}
REPLACE WITH

Код: Выделить всё

		if( SUBFORUMS_AS_TAGS && in_array($forum_id, $subforums_as_tags_forums_id) && sizeof($active_forum_ary['forum_id']) ){//новый вариант

			foreach ($forums as $forum_id => $forum){
				if ($config['load_db_lastread'] && $user->data['is_registered'])
				{
					$topic_tracking_info += get_topic_tracking($forum_id, $forum['topic_list'], $forum['rowset'], array($forum_id => $forum_data_subforums[$forum_id]['mark_time']), $global_announce_list);
					$mark_time_forum = (!empty($forum_data_subforums[$forum_id]['mark_time'])) ? $forum_data_subforums[$forum_id]['mark_time'] : $user->data['user_lastmark'];


				}
				else if ($config['load_anon_lastread'] || $user->data['is_registered'])
				{
					$topic_tracking_info += get_complete_topic_tracking($forum_id, $forum['topic_list'], $global_announce_list);
					if (!$user->data['is_registered'])
					{
						$user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
					}
					$mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark'];
				}
			}
			unset($forums);

		} else{//старый вариант
		
			if ($config['load_db_lastread'] && $user->data['is_registered'])
			{
				$topic_tracking_info = get_topic_tracking($forum_id, $topic_list, $rowset, array($forum_id => $forum_data['mark_time']), $global_announce_list);
				$mark_time_forum = (!empty($forum_data['mark_time'])) ? $forum_data['mark_time'] : $user->data['user_lastmark'];
			}
			else if ($config['load_anon_lastread'] || $user->data['is_registered'])
			{
				$topic_tracking_info = get_complete_topic_tracking($forum_id, $topic_list, $global_announce_list);
				if (!$user->data['is_registered'])
				{
					$user->data['user_lastmark'] = (isset($tracking_topics['l'])) ? (int) (base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate']) : 0;
				}
				$mark_time_forum = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark'];
			}

		}

Работает на боевом форуме, пока баги не замечены. Хотя наверняка есть какие-то нестыковки в особых случаях, которые я не тестировал. Оптимизировать там тоже дофига чего, но я пока добивался только функциональности. Ну и, конечно, можно оформить цивилизованно как МОД, чтобы включалось-выключалось для форумов в админке.
sweetah
phpBB 2.0.6
Сообщения: 506
Стаж: 16 лет 8 месяцев
Благодарил (а): 108 раз
Поблагодарили: 26 раз

Re: Вывод тем подфорума в родительском форуме

Сообщение sweetah »

Может стоило придумать что-то с активными темами и разделами? Сделать по-умолчанию большой период для активных тем, а так всё стандартно выводится в раздел.
kefiijrw
phpBB 1.0.0
Сообщения: 5
Стаж: 15 лет 10 месяцев

Re: Вывод тем подфорума в родительском форуме

Сообщение kefiijrw »

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

Вернуться в «Запросы модов для phpBB 3.0.x»