Календарь событий PHP + Javascript

в 7:38, , рубрики: javascript, php, Веб-разработка, Календарь, простой, события, метки: , , , ,

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

Задача вроде бы не сложная, но среди немногочисленных решений в интернете я не нашел подходящего по следующим причинам: слишком сложный и непонятный код, медленные запросы к БД (это особенно ощущается, если в базе много записей), использование библиотеки jQuery, к которой я отношусь не очень хорошо.

Итак, к плюсам моего календаря можно отнесли следующее:

  1. Весь код помещается в 200 строчек и состоит из одного файла, который подключается через include
  2. Скрипт состоит из чистого php + javascript без использования библиотеки jQuery
  3. Используются простые и оптимизированные запросы к БД
  4. Подгрузка следующего (предыдущего) месяца происходит через AJAX

Теперь обо всем по-порядку.

Логика

Календарь генерируется средствами php для текущего месяца. Для каждого дня проверяем нет ли записей в БД, если есть, — формируем ссылку на событие. Дописываем javascript код для перелистывание месяцев, который обращается к скрипту через ajax. Задача усложняется тем, что события растянуты во времени, то есть, начинаются в один день, а заканчиваются через несколько дней или даже месяцев. На всем временном промежутке существование события нужно его подсветить ссылкой для каждого дня.

Генерируем календарь на PHP

<?php
//Проверяем, пришел ли запрос на конкретную дату. Если нет, берем текущую дату.
if (isset($_REQUEST['date']))
{	
	//Проверяем, не пришло ли чего лишнего...
	$pattern = "/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/";
	if (preg_match($pattern, $_REQUEST['date'])) {
		$date = $_REQUEST['date'];
	} else {
		die('Неправильный параметр');
	}
}
else
{
	$date=date("Y-m-d");
}
$sd = explode("-", $date);
	$year 	= $sd[0];
	$month = $sd[1];
	$day 	= $sd[2];

// Вычисляем число дней в текущем месяце
$dayofmonth = date('t',
                      mktime(0, 0, 0, $month, 1, $year));
//Готовим запрос к БД
$todate = "$year-$month-$dayofmonth";
$fromdate = "$year-$month-01";
$query = "SELECT date,enddate from sobytia WHERE startdate<='$todate' AND enddate>=$fromdate";
$res_db = $db->sql($query);

Таким образом, мы выбрали все записи, которые есть в текущем месяце.

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

$d = array();$k=array();
for($i = 1; $i<=$dayofmonth; $i++){
	$k[$i] = $i;
}
$i=0;
while ($a = mysqli_fetch_row($res_db))
{
	//for($i = 1; $i<=$dayofmonth; $i++){
	foreach ($k	as $i)
	{	//Добавление 0 к дате
		if($i<10) $cd = "$year-$month-0".$i; else $cd = "$year-$month-$i";
		if ($cd >= $a[0] && $cd <= $a[1])
		{
			$d[$i] = $cd;
			unset($k[$i]);
		}
	}
}

Собственно, сам календарь:

// Счётчик для дней месяца
  $day_count = 1;

  // 1. Первая неделя
  $num = 0;
  for($i = 0; $i < 7; $i++)
  {
    // Вычисляем номер дня недели для числа
    $dayofweek = date('w',
                      mktime(0, 0, 0, $month, $day_count, $year));
    // Приводим к числа к формату 1 - понедельник, ..., 6 - суббота
    $dayofweek = $dayofweek - 1;
    if($dayofweek == -1) $dayofweek = 6;

    if($dayofweek == $i)
    {
      // Если дни недели совпадают,
      // заполняем массив $week
      // числами месяца
      $week[$num][$i] = $day_count;
      $day_count++;
    }
    else
    {
      $week[$num][$i] = "";
    }
  }

  // 2. Последующие недели месяца
  while(true)
  {
    $num++;
    for($i = 0; $i < 7; $i++)
    {
      $week[$num][$i] = $day_count;
      $day_count++;
      // Если достигли конца месяца - выходим
      // из цикла
      if($day_count > $dayofmonth) break;
    }
    // Если достигли конца месяца - выходим
    // из цикла
    if($day_count > $dayofmonth) break;
  }

  // 3. Выводим содержимое массива $week
  // в виде календаря
  // Выводим таблицу
  echo '<table id="calendar">';
  //заголовок
  $rusdays = array('ПН','ВТ','СР','ЧТ','ПТ','СБ','ВС');
  $rusmonth = array('Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь');
  echo '<thead>
			<tr>
				<td onclick="monthf('prev');"><</td>
				<td colspan="5">'.$rusmonth[$month-1].', '.$year.'</td>
				<td onclick="monthf('next');">></td>
			</tr>';
  echo '<tr>';
  foreach ($rusdays as $rusday){
	echo '<td>'.$rusday.'</td>';
  }
  echo '</tr>';
  echo '</thead>';
  //тело календаря
  for($i = 0; $i < count($week); $i++)
  {
    echo "<tr>";
    for($j = 0; $j < 7; $j++)
    {
      if(!empty($week[$i][$j]))
      {
		
		// Если имеем дело с выбраной датой подсвечиваем ee
		if($week[$i][$j]==$day)
		{
			echo '<td class="today">';
		}
		else
		{
			echo '<td>';
		}
		
		// Если запись в базе за текущую дату есть, делаем ссылку
        if($d[$week[$i][$j]])
		{
			echo '<a href="/afisha/'.$d[$week[$i][$j]].'/">'.$week[$i][$j].'</a>';
		}
		else
		{
			echo $week[$i][$j];
		}
		
        echo '</td>';
      }
      else echo "<td> </td>";
    }
    echo "</tr>";
  }
?>

Javascript код для перематывание месяцев

Он немного упрощен для наглядности (отсутствуют эффекты скольжения):

<script>
	var mon = parseInt("<?php echo $month; ?>");
	var year = parseInt(<?php echo $year; ?>);
	function monthf(pn){
		if (pn == 'next'){
			mon++;
		}else if (pn == 'prev'){
			mon--;
		}else{
			alert('Неправильный параметр');
			return false;
		}
		if (mon > 12){
			year ++;
			mon = 1;
		}
		if (mon < 1){
			year --;
			mon = 12;
		}
		if ((mon < 10) && (mon >= 1)){
			mon = '0'+mon;
		}
		var nextDate = year+'-'+mon+'-00';
		
		var ajaxaddr = "путь_к_текущему_скрипту?date='+nextDate;
		var http = new XMLHttpRequest();
		if (http) {
			http.open('get', ajaxaddr);  
			http.onreadystatechange = function () {
				if(http.readyState == 4){
					if (http.status == 200) {
						document.getElementById('calendar').innerHTML = http.responseText;
					}
				}
			}  
			http.send(null);
		}
	}
</script>

Закрываем тег таблицы:

<?php
echo "</table>";
?>

Выводы

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

Литература

  1. Календарь на PHP
  2. Календари на javascript
  3. Выборка из базы — ответы на Тостере

Автор: bohdaniel

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js