Creating a calendar in PHP

To create our calendar we will create a class to hold all the information that will be associated with a calendar.

function Calendar($date)
{
   if(empty($date)) $date = time();
   define('NUM_OF_DAYS', date('t',$date));
   define('CURRENT_DAY', date('j',$date));
   define('CURRENT_MONTH_A', date('F',$date));
   define('CURRENT_MONTH_N', date('n',$date));
   define('CURRENT_YEAR', date('Y',$date));
   define('START_DAY', (int) date('N', mktime(0,0,0,CURRENT_MONTH_N,1, CURRENT_YEAR)) - 1);
   define('COLUMNS', 7);
   define('PREV_MONTH', $this->prev_month());
   define('NEXT_MONTH', $this->next_month());
   $this->events = array();
}

This constructor takes a single argument (a UNIX timestamp) and from that defines several constants that we will use in our code. If the argument is empty then the current date is used. An events array is also set up to hold the events for our calendar.

function prev_month()
{
   return mktime(0,0,0,
         (CURRENT_MONTH_N == 1 ? 12 : CURRENT_MONTH_N - 1),
         (checkdate((CURRENT_MONTH_N == 1 ? 12 : CURRENT_MONTH_N - 1),
                                 CURRENT_DAY,
                                 (CURRENT_MONTH_N == 1 ? CURRENT_YEAR - 1 : CURRENT_YEAR)) ? CURRENT_DAY : 1),
         (CURRENT_MONTH_N == 1 ? CURRENT_YEAR - 1 : CURRENT_YEAR));
}

This function will return the timestamp for the same day in the next month (or the 1st day of the next month if the current day is not correct). A similar function returns the timestamp for the same day in the previous month (again will return the 1st day if the current day does not exist in the previous month). This is achieved by using ternary statements to return the arguments for the mktime function.

function getEvent($timestamp)
{
   $event = NULL;
   if(array_key_exists($timestamp, $this->events))
      $event = $this->events[$timestamp];
   return $event;
}

We need a function to return the entry in the event array for a given timestamp and this done by making the event array a map with the key being the timestamp and the value being an array of strings that hold the events.

function addEvent($event, $day = CURRENT_DAY, $month = CURRENT_MONTH_N, $year = CURRENT_YEAR)
{
   $timestamp = mktime(0, 0, 0, $month, $day, $year);
   if(array_key_exists($timestamp, $this->events))
      array_push($this->events[$timestamp], $event);
   else
      $this->events[$timestamp] = array($event);
}

To add a value to the events array the key is checked to see if it exists and if it does then the event is put onto the map and otherwise an array is created with the single element that is the event. Only the event is needed in this function, the other parameters are optional and if not used will default to the current day, meaning that you can specify that an event to occur once, at the same day and month every year, at the same day every month and year or occur every day.

function makeEvents()
{
   if($events = $this->getEvent(mktime(0, 0, 0, CURRENT_MONTH_N, CURRENT_DAY, CURRENT_YEAR)))
      foreach($events as $event) echo $event.'<br />';
}

Here we simply output all the events for the current day.

function makeCalendar()
{
   echo '<table border="1" cellspacing="4"><tr>';
   echo '<td width="30"><a href="?date='.PREV_MONTH.'">&lt;&lt;</a></td>';
   echo '<td colspan="5" style="text-align:center">'.CURRENT_MONTH_A .' - '. CURRENT_YEAR.'</td>';
   echo '<td width="30"><a href="?date='.NEXT_MONTH.'">&gt;&gt;</a></td>';
   echo '</tr><tr>';
   echo '<td width="30">Mon</td>';
   echo '<td width="30">Tue</td>';
   echo '<td width="30">Wed</td>';
   echo '<td width="30">Thu</td>';
   echo '<td width="30">Fri</td>';
   echo '<td width="30">Sat</td>';
   echo '<td width="30">Sun</td>';
   echo '</tr><tr>';
   echo str_repeat('<td>&nbsp;</td>', START_DAY);

We finally make a function that will output our calendar. We start by making the static part of the table, which will contain the days of the week and links to the previous month and year.

$rows = 1;
for($i = 1; $i <= NUM_OF_DAYS; $i++)
{

This loop will iterate over all the days in the current month. We now need to output the days, if the current day is selected it will be bold, if the day has an event associated with it then it will have a blue background otherwise it will simply be a link to that day.

if($i == CURRENT_DAY)
   echo '<td style="background-color: #C0C0C0"><strong>'.$i.'</strong></td>';
else if($event = $this->getEvent(mktime(0, 0, 0, CURRENT_MONTH_N, $i, CURRENT_YEAR)))
   echo '<td style="background-color: #99CCFF">
         <a href="?date='.mktime(0,0,0,CURRENT_MONTH_N,$i,CURRENT_YEAR).'">'.$i.'</a></td>';
else
   echo '<td><a href="?date='.mktime(0 ,0 ,0, CURRENT_MONTH_N, $i, CURRENT_YEAR).'">'.$i.'</a></td>';

This code splits the day into three cases defined earlier. The data is passed as a query string to the document and this will be used to decide which date is currently selected.

      if((($i + START_DAY) % COLUMNS) == 0 && $i != NUM_OF_DAYS)
      {
         echo '</tr><tr>';
         $rows++;
      }
   }
   echo str_repeat('<td>&nbsp;</td>', (COLUMNS * $rows) - (NUM_OF_DAYS + START_DAY)).'</tr></table>';
}

The calendar is output as a table so we need to end the row when we have output seven days. The end of the table is padded to fill in any gaps that are left.

Instantiating the calendar

We now need to make a new calendar object and add events. The date input is taken from the query string and given as an argument to the calendar.

$cal = new Calendar($_GET['date']);
$cal->addEvent('event 1');
$cal->addEvent('event 2', 10);
$cal->addEvent('event 3', 10, 10);
$cal->addEvent('event 4', 10, 10, 10);
$cal->makeCalendar();
$cal->makeEvents();

Four events are added with a varying number of arguments. Finally the calendar is output and the corresponding events are also output.

Downloads

Categories

Tags

No tags

Social