Вывод пользователю обновлений на сайте

Angelight

Новичок
Доброго времени суток!

Пытаюсь решить следующую задачу:

Пользователь входит на сайт. Дабы быть ему в курсе произошедших на сайте событий, на специально отведенной для них странице, пользователю выводятся все события, произошедшие на сайте за 8 дней (к примеру).

Действия, которые предпринял для решения поставленной задачи:

PHP:
// на сколько дней выводим обновления
$config['news_days'] = 8;

// текущая дата в unix
$nowtime = time() + ( 360 * 60 );

$month = array( '1' => 'января', '2' => 'февраля', '3' => 'марта',
'4' => 'апреля', '5' => 'мая', '6' => 'июня', '7' => 'июля',
'8' => 'августа', '9' => 'сентября', '10' => 'октября', '11' => 'ноября', '12' => 'декабря' );

$start_time = strtotime( date( 'd.m.Y' ) );
$end_time = $start_time - ( 86400 * $config['news_days'] );

// в массив помещаем события
$new = array();

// извлекаем записи с пользователями в промежутке между заданными датами (`reg_date` - дата регистрации в unix)
$sel_members = "SELECT * FROM `members` WHERE `reg_date` BETWEEN '" . $end_time . "' AND '" . $nowtime . "' ORDER BY `reg_date` DESC";
$res_sel_members = mysql_query( $sel_members, $dbcnx );
		
if( mysql_num_rows( $res_sel_members ) > 0 )
	{
		while( $arr = mysql_fetch_array( $res_sel_members ) )
			{
				$tnews = 'Зарегистрировался новый участник <a href="member.php?id=' . $arr['member_id'] . '">' . $arr['nickname'] . '</a>';
				$new[$arr['reg_date']] = $tnews;
			}
	}

// извлекаем записи с публикациями в промежутке между заданными датами (`add_time` - дата добавления публикации)
$sel_articles = "SELECT * FROM `articles` WHERE `add_time` BETWEEN '" . $end_time . "' AND '" . $nowtime . "' ORDER BY `add_time` DESC";
$res_sel_articles = mysql_query( $sel_articles, $dbcnx );
		
if( mysql_num_rows( $res_sel_articles ) > 0 )
	{
		while( $rows = mysql_fetch_array( $res_sel_articles ) )
			{
				$art_new = 'Добавлена новая статья <a href="article.php?id=' . $rows['id'] . '">' . $rows['title'] . '</a>';
				$new[$rows['add_time']] = $art_new;
			}
	}

// сортируем массив по ключам в порядке убывания
krsort( $new );

Получился массив примерно следующего содержания:


HTML:
Array
(
    [1290683260] => Добавлена новая статья ***
    [1290630243] => Зарегистрировался новый участник ***
    [1290554760] => Добавлена новая статья  ***
    [1290541269] => Зарегистрировался новый участник  ***
    [1290532438] => Добавлена новая статья  ***
)
Идем дальше:

PHP:
// выводим все имеющиеся обновления по дням
for( $i = 1; $i <= $config['news_days']; $i++ )
	{
		$dt = date( 'd.m.Y', $start_time );
		$exp = explode( '.', $dt );
		$dat = $exp[0] . ' ' . $month[$exp[1]] . ' ' . $exp[2];
		
		if( $i == 1 )
			{
				$where = 'Сегодня, ' . $dat;
			}
		elseif( $i == 2 )
			{
				$where = 'Вчера, ' . $dat;
			}
		elseif( $i == 3 )
			{
				$where = 'Позавчера, ' . $dat;
			}
		else
			{
				$where = $dat;
			}
		
		echo '<strong>' . $where . '</strong>' . "<br /><br />";
				
		// получаем дату (день, месяц, год, 00:00:00) на день вперед
		$ntime = $start_time + 86400;
		
		foreach( $new as $key => $value )
			{
				if( ( $key > $start_time ) && ( $key < $ntime ) )
					{
						echo date( 'H:i', $key ) . ' - ' . $value . "<br />";
					}
			}
		

		echo "<br /><br />";
		
		$start_time = $start_time - 86400;
	}
Результат выполнения приблизительно следующий:

Сегодня, 25 ноября 2010

Вчера, 24 ноября 2010

20:24 - Зарегистрировался новый участник ***

Позавчера, 23 ноября 2010

23:26 - Добавлена статья ***
19:41 - Зарегистрировался участник ***
17:13 - Добавлена статья ***
13:01 - Зарегистрировался участник ***
02:16 - Зарегистрировался участник ***

22 ноября 2010

00:50 - Зарегистрировался участник ***
00:39 - Зарегистрировался участник ***

21 ноября 2010

20 ноября 2010

19 ноября 2010

17:13 - Зарегистрировался участник ***
14:26 - Добавлена статья ***

18 ноября 2010

----------------------

Из примера видно, что на некоторые даты (21.11.2010, 20.11.2010 и 18.11.2010) нет никаких событий. Несмотря на их отсутствие, даты успешно выводятся. Из чего выходит, что пользователь видит события за 4 дня, вместо положенных восьми. Вот здесь я зашел в тупик...

Задача подразумевает вывод обновлений на 8 дней. Восемь дней не обязательно должны быть последовательными. Иначе говоря, если вчера и позавчера на сайте ничего не произошло - эти дни не засчитываем. Выводит только те даты, на которые есть какие-либо события.

Перед циклом foreach я вывожу дату. К примеру, Сегодня, 25 ноября 2010. НО: на этот день может и не быть никаких событий. А могут и быть, но после того, как пользователь вошел на сайт. К примеру, пользователь вошел сегодня, в 2 часа ночи. Между 25.11.2010, 00:00:00 и 25.11.2010, 02:00:00 нет событий. Первое событие может произойти позже - скажем, в 16:20 зарегистрируется новый пользователь. Это событие в 16:20 успешно выйдет на соответствующей странице с выводом событий на сайте.

У меня же, после 25.11.2010, 00:00:00 надпись "Сегодня, 25 ноября 2010" успешно выводится, несмотря на то, что на сегодня никаких событий...

Никак не могу решить задачу с выводом дат:

Необходимо в самом начале проверять, есть ли на текущую дату какие-либо события (в массиве $new)? Если есть - выводим текущую дату и имеющиеся на текущую дату события. Затем проверяем предыдущий день - если нет событий, пропускаем дату. Проверяем очередную - по убыванию и т.д. Выводим только те даты, на которые произошли какие-либо события на сайте. В итоге, получится 8 дней...

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

PS. Сразу оговорюсь, что вывод событий выводятся НЕ в промежутке "текущая дата - время последнего посещения сайта пользователем". Пользователь может отсутствовать 2 недели и вошел, к примеру, сегодня. Ему все равно выводятся обновления на 8 дат (которые могут идти последовательно, начиная с сегодняшнего дня и далее, по убыванию)...

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

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

Вурдалак

Продвинутый новичок
Надо в цикле перебирать события, а не даты. Наверное, несложно сообразить как сделать вывод даты один раз.
 

iceman

говнокодер
Angelight
и не нужно формировать никакой массив, нужно делать все в цикле while($row = mysql_fetch_array($result))
 

Mamont

Новичок
1. Найти дни, за которые были события для каждой таблицы. Поскольку нам нужно отсечь время, используем mysql функцию TO_DAYS() (или аналогичную):
PHP:
$sql = "SELECT DISTINCT TO_DAYS(`reg_date`) FROM `members` ORDER BY `reg_date` DESC LIMIT ".$config['news_days'];
2. Все полученные дни сливаем в 1 массив ($days), сортируем по убыванию и оставляем первые 8 - получаем список дат, за которые произошли хоть какие-то события.

3. из таблиц извлекаем записи, даты которых входят в полученное множество:
PHP:
$sql = "SELECT * FROM `members` WHERE TO_DAYS(`reg_date`) IN (".implode(',',$days).")";
и т.д.
 

Вурдалак

Продвинутый новичок
Если автора вдруг интересует правильное решение, то надо заводить новую таблицу events. При каждом новом событии нужно добавлять туда запись с соответствующим идентификатором события. Тут допустимо выделить поля для объекта события: идентификатор объекта, его тип (пользователь, статья, etc.) и даже имя (имя пользователя, название статьи, etc.). Выводить таким запросом:
Код:
SELECT * FROM events WHERE occurred_at >= NOW() - INTERVAL 8 DAY ORDER BY occurred_at DESC
 

Mamont

Новичок
2 Вурдалак
Согласен, задачу, в принципе, необходимо свести к ведению логов: когда, кем и что делалось (не только создавалось, но и изменялось, удалялось и тд).

Но не забывай также:
Задача подразумевает вывод обновлений на 8 дней. Восемь дней не обязательно должны быть последовательными. Иначе говоря, если вчера и позавчера на сайте ничего не произошло - эти дни не засчитываем. Выводит только те даты, на которые есть какие-либо события.
 

Вурдалак

Продвинутый новичок
Mamont, это да, решается дополнительным запросом. Причём TO_DAYS(occurred_at) я бы хранил доп. полем, чтобы индекс работал (правда в некоторых СУБД можно делать функциональный индекс).
 

Angelight

Новичок
Вурдалак, Mamont, большое спасибо за предложение идей! Мои начальные знания php (изучаю около года) дали о себе знать. Несколько раз зашел в тупик:

1. Найти дни, за которые были события для каждой таблицы. Поскольку нам нужно отсечь время, используем mysql функцию TO_DAYS() (или аналогичную):
PHP:
$sql = "SELECT DISTINCT TO_DAYS(`reg_date`) FROM `members` ORDER BY `reg_date` DESC LIMIT ".$config['news_days'];
2. Все полученные дни сливаем в 1 массив ($days), сортируем по убыванию и оставляем первые 8 - получаем список дат, за которые произошли хоть какие-то события.
Сделал такой же запрос. Затем полученные даты попытался внести в новый массив:

PHP:
$sql = "SELECT DISTINCT TO_DAYS(`reg_date`) FROM `members` ORDER BY `reg_date` DESC LIMIT ".$config['news_days'];
$result = mysql_query( $sql, $dbcnx );

$days = array();

while( $arr = mysql_fetch_array( $result ) )
	{
		$days[] = $arr['reg_date'];
	}
	
echo '<pre>';
print_r( $days );
echo '</pre>';
print_r( $days ); - вывел на экран пустой массив:

HTML:
Array
(
    [0] => 
)
Также понравилась идея с созданием дополнительной таблички "events". Вот, что я сделал:

Создал 2 таблицы (articles, events) для практики:

articles:

id ( INT(30) )
title ( VARCHAR(255) )
add_time ( VARCHAR(150) )

Тут допустимо выделить поля для объекта события: идентификатор объекта, его тип (пользователь, статья, etc.) и даже имя (имя пользователя, название статьи, etc.)
Если я правильно понял, то тип объекта я сделал как VARCHAR:

events:

id ( INT(30) )
type ( VARCHAR(150) )
title ( VARCHAR(255) )
occurred_at ( VARCHAR(150 )

С этой же целью (для практики) уменьшил количество дней (4 дня вместо восьми), выводящих обновления. И внес в таблички следующие данные:

PHP:
// текущее время
$nowtime = time() + ( 360 * 60 );

// вношу первую статью
$ins_article1 = "INSERT INTO `articles` (`id`, `title`, `add_time`) VALUES ('', 'Статья №1', '" . $nowtime . "')";
$result_articles1 = mysql_query( $ins_article1, $dbcnx );

// тут же, вношу данные в таблицу "events"
$ins_events1 = "INSERT INTO `events` (`id`, `type`, `title`, `occurred_at`) VALUES ('', 'article', 'Статья №1', '" . $nowtime . "')";
$result_events1 = mysql_query( $ins_events1, $dbcnx );

$last_time = $nowtime - 86400;

// вношу вторую статью
$ins_article2 = "INSERT INTO `articles` (`id`, `title`, `add_time`) VALUES ('', 'Статья №2', '" . $last_time . "')";
$result_articles2 = mysql_query( $ins_article2, $dbcnx );

// тут же, вношу данные в таблицу "events"
$ins_events2 = "INSERT INTO `events` (`id`, `type`, `title`, `occurred_at`) VALUES ('', 'article', 'Статья №2', '" . $last_time . "')";
$result_events2 = mysql_query( $ins_events2, $dbcnx );

$last_time = $last_time - 86400;
Таким же образом внес еще 6 записей. Последнюю, 6-ю запись в обе таблички внес со следующей датой (дата публикации 5-й статьи минус 3 дня):

$last_time = $last_time - 259200;

В результате, в табличке "articles" 8 статей на следующие даты:

27.11.2010
26.11.2010
25.11.2010
24.11.2010
23.11.2010
22.11.2010
21.11.2010
18.11.2010

В `events` также 8 записей.

Затем произвожу запрос:

PHP:
$sql = "SELECT * FROM `events` WHERE `occurred_at` >= NOW() - INTERVAL 4 DAY ORDER BY `occurred_at` DESC";
$res_sql = mysql_query( $sql, $dbcnx );

if( mysql_num_rows( $res_sql ) > 0 )
	{
		while( $row = mysql_fetch_array( $res_sql ) )
			{
				//
			}
	}
Результат: mysql_num_rows( $res_sql ) показывает 0...

Mamont, это да, решается дополнительным запросом. Причём TO_DAYS(occurred_at) я бы хранил доп. полем, чтобы индекс работал (правда в некоторых СУБД можно делать функциональный индекс).
Если можно, с этого места поподробнее? Можно увидеть это на примере? Вчера все обдумывал, сегодня тоже. Но ни к чему не могу прийти. С запросами ничего не получается сделать...
 

Mamont

Новичок
Хочешь обрабатывать дату средствами БД - храни дату в понятном БД формате:
`add_time` timestamp NOT NULL default CURRENT_TIMESTAMP
 
Сверху