PHP. Генератор календаря с подсветкой событий.
PHP

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

Постановка задачи:
1. Сгенерировать матрицу для календаря. Разработать механизм подсветки ячеек.
2. Передать числа дней рождения массивом в качестве первого параметра;
месяц в качестве второго и год в качестве третьего.
3. Второй и третий параметр не обязательные. Если они не переданы, считать месяц и год текущими.
4. Предусмотреть возможность подсветки «сегодня» (например, рамочка), если календарь строится на текущий месяц.

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

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

Код:

function calendar($days, $month=0, $year=0)
{
   $nowdate = getdate(); 
   $arraytorender=array();
   if($month >= 1 && $month <=12)
      $nowdate['mon']=$month;
      
   if($year > 0)
      $nowdate['year']=$year;
        
   $m_start = mktime(0,0,0,$nowdate['mon'],1,$nowdate['year']);
   $first_day = getdate($m_start);
        
   $previousvalue=0;
        
   foreach($days as $row)
   {
      if($row - $previousvalue > 1)
      {
         for($i=$previousvalue; $i<$row-1; $i++)
            $arraytorender[$i]='ffffff';
      }
      $arraytorender[$row-1]='00ff00';
      $previousvalue = $row;
   }
        
   /*Count of the days in current month*/
   $sumofday = date('t', $m_start);
   $countofarray=count($arraytorender);
        
   if($countofarray < $sumofday)
   {
      for($i=$countofarray; $i<$sumofday; $i++)
         $arraytorender[]='ffffff';
   }
       
   /*For change american style to european*/
   if($first_day['wday']==0)
      $first_day['wday']=7;
        
   if($month == 0 && $year == 0)
      $arraytorender[$nowdate['mday']-1] = implode("", substr_replace(str_split($arraytorender[$nowdate['mday']-1],2),"",-1));
        
        
   /*----------------LETS CREATE CALENDAR-----------------*/
   $dayofweek = 0;    //Global for fill first week of the month 0-th
   $numberofweek = 0; //Global for fill last week of the month trailing 0-th

   /*Filling first week with 0, if first day is not monday*/
   for($i=0; $i<$first_day['wday']-1; $i++)
   {
      $calendar[0][$i]=0;
      $dayofweek++;
   }

   /*Filling current month with colors*/
   foreach($arraytorender AS $value)
   {
      if($dayofweek>6)
      {
         $numberofweek++;
         $dayofweek=0;
      }
    
      $calendar[$numberofweek][$dayofweek]=$value;
      $dayofweek++;
   }

   /*Filling last week of the month trailing 0-th*/
   for($i = $dayofweek; $i<7; $i++)
      $calendar[$numberofweek][$i]=0;
   /*--------------------END OF CREATE CALENDAR----------------------*/
   return $calendar;
}

Используем следующим образом:

 $daysofbday = array(10, 15, 16, 22);
 $bcalendar = calendar($daysofbday);

В переменной $bcalendar получаем массив.

print_r($bcalendar);

Array
(
    [0] => Array
        (
            [0] => 0
            [1] => 0
            [2] => 0
            [3] => 0
            [4] => ffffff
            [5] => ffffff
            [6] => ffffff
        )

    [1] => Array
        (
            [0] => ffffff
            [1] => ffffff
            [2] => ffffff
            [3] => ffffff
            [4] => ffffff
            [5] => ffffff
            [6] => 00ff00
        )

    [2] => Array
        (
            [0] => ffffff
            [1] => ffffff
            [2] => ffffff
            [3] => ffffff
            [4] => 00ff00
            [5] => 00ff00
            [6] => ffffff
        )

    [3] => Array
        (
            [0] => ffffff
            [1] => ffffff
            [2] => ffffff
            [3] => ffffff
            [4] => 00ff00
            [5] => ffffff
            [6] => ffffff
        )

    [4] => Array
        (
            [0] => ffffff
            [1] => ffffff
            [2] => fff
            [3] => ffffff
            [4] => 0
            [5] => 0
            [6] => 0
        )

)

Нетрудно догадаться, что внешний массив являет собой недели, тогда как внутренний — дни.
Значения 0 означают пустые дни недели. Своего рода маячки, по которым рисовать пустые клеточки.
Остальные элементы содержат цвет ячейки. Если существует хоть одно событие (день рождения),
присваивается зеленый цвет.

Обратите внимание на цвет из 3-х символов! Это текущий день, проще говоря «сегодня». При выводе на экран можно легко определить его с помощью простого условия strlen и добавить соответствующий стиль. Например, рамочку или выделить число жирным шрифтом.

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

 <table border="1">
    <th>пн.</th>
    <th>вт.</th>
    <th>ср.</th>
    <th>чт.</th>
    <th>пт.</th>
    <th style="color:#ff0000;">сб.</th>
    <th style="color:#ff0000;">вс.</th>
    
<?php 
$i=1;
foreach($bcalendar as $weeks)
{
    echo "<tr>";
    foreach ($weeks as $key=>$day)
    {
        if($day) //Если значение не 0.
        {
            echo "<td style=\"background: #$day; width: 20px; height: 20px; text-align: center;";
            if(strlen($day)==3) //Рисуем красную рамочку для "сегодня"
                echo " border: 2px solid RED;\">";
            else 
                echo "\">";
            
            if($key == 5 || $key == 6) //Подсвечиваем выходные красным шрифтом.
                echo "<span style=\"color: RED;\">$i</span>";
            else
                echo "<span>$i</span>";
            echo "</td>";
            $i++; //Счетчик чисел.
        }         
        else
            echo "<td></td>";
    }
    echo "</tr>";
}
?>
    
</table>

Результат:
calendar

F.A.Q.
Q: Почему сразу не отрисовать календарь в функции, и возвращать готовй HTML?
A: Чтобы функцию можно было использовать с шаблонизаторами.

  • Evg:

    Подскажите, как присвоить значение переменной —
    $month=2;
    function calendar($days, $month, $year=0)
    не работает

    • root4root aka admin:

      В каком смысле не работает? Присвоить очень просто — передать значение при вызове. Например, $bcalendar = calendar($daysofbday, 2);
      Если не нужно подсвечивать дни, а нужен просто календарь, то вызвать можно так: $bcalendar = calendar(array(), 2);

      Остальное, как в примере. Больше ничего менять не нужно.

  • Василий:

    А можно ли как то сюда допилить смену месяца?

Добавить комментарий