A simple calendar script


#1

Merry Christmas Everyone!!!

In the spirit of Christmas I thought it would be nice to share a simple calendar script written in PHP Object-Oriented Programming style. It also uses namespaces in PHP meaning if you have other classes with the same methods or variables there will be no conflict with them.

SPECIAL NOTE
[php]require_once ‘lib/classes/calendar/DisplayCalendar.php’;[/php]
You have to have the correct folder structure and file name (obviously) in order for this to work, if you use your own file structure make sure to make the appropriate changes.

The script is actually pretty short and can be modified pretty easily (Well, at least I think so. ;D)

Here is the index.php page:
[php]<?php
date_default_timezone_set(‘America/Detroit’); // Set the Default Time Zone:
require_once ‘lib/classes/calendar/DisplayCalendar.php’;

/* Uses namespaces */
use jrpepp_production\DisplayCalendar as Calendar;

$mydate = new Calendar(“NOW”);

?>
<!doctype html>

Calendar 3.0 <?php echo $mydate->output; ?> [/php]

The DisplayCalendar.php file:
[php]<?php

namespace jrpepp_production;

use DateTime;

class DisplayCalendar {

private $date;
public $output = \NULL;
protected $prev = \NULL;
protected $current = \NULL;
protected $next = \NULL;
protected $month = \NULL;
protected $day = \NULL;
protected $year = \NULL;
protected $days = \NULL;
protected $prevMonth = \NULL;
protected $nextMonth = \NULL;
protected $calendar = array();
protected $dispCalendar = array();
protected $theForm = \NULL;
protected $alphaDay = array(0 => “Sun”, 1 => “Mon”, 2 => “Tue”, 3 => “Wed”, 4 => “Thu”, 5 => “Fri”, 6 => “Sat”);

/* Constructor to create the calendar */
public function __construct($date) {
$this->output = $this->generateCalendar($date);
}

/* Last month filler days (if needed) */
protected function lastMonth($date) {
$this->prev = new DateTime($date . “-1 Month”);
$this->prev->modify(“last day of this month”);
$this->prevMonth = $this->prev->format(‘w’); // Numeric day of the week the last month’s day falls on:
for ($x = $this->prevMonth; $x >= 0; $x–) {
$this->calendar[] = ‘

  • ’ . ($this->prev->format(‘t’) - $x) . ‘
  • ’ . “\n”;
    }
    }

    /* Calendar days */
    protected function currentMonth($date) {
    $this->current = new DateTime($date);
    $this->days = $this->current->format(‘t’); // Days in the current month:
    for ($x = 1; $x <= $this->days; $x++) {
    $this->calendar[] = ‘

  • ’ . $x . ‘
  • ’ . “\n”;
    }
    }

    /* Next month filler days (if needed) */
    protected function nextMonth($date) {
    $this->next = new DateTime($date . ‘+1 Month’);
    $this->next->modify(‘first day of this Month’);
    $this->nextMonth = $this->next->format(‘w’);
    if ($this->nextMonth === 0) {
    return \NULL;
    }
    for ($x = 1; $x <= (7 - $this->nextMonth); $x++) {
    $this->calendar[] = ‘

  • ’ . $x . ‘
  • ’ . “\n”;
    }
    }

    protected function twoDimensional() {

    /* Initialize all the variables to zero */
    $num = 0;
    $b = 0;
    $c = 0;
    
    /* Create a while loop in order to create the two-dimensional array */
    while ($num < sizeof($this->calendar)) {
    
      /* Values being put into the two-dimensional array */
      $this->dispCalendar[$b][$c] = $this->calendar[$num];
    
      $num += 1; // Increment this variable by one to avoid infinite loop:
      $c += 1;  // Inside portion of the two dimension array: 
    
      /* Check to see if number can be divided by 7 (seven days in a week) */
      if (($num % 7) == 0) {
        $b += 1; // Increment the outer portion of the array by one to get the rows of weeks:
        $c = 0; // Reset back to zero (Remember Arrays are zero based!):
      }
    }
    

    }

    protected function form() {

    /* Create a div box and an unordered list */
    $this->theForm .= '<div class="row calDays clearfix"><ul>' . "\n";
    
    /* Create heading for the calendar */
    $this->theForm .= '<li class="calHeading"><a class="calHeaderText" href="#" onclick="return false">' . $this->current->format('F j, Y') . '</a></li>' . "\n";
    /* Create days of the week heading */
    for ($x = 0; $x <= 6; $x++) {
      $this->theForm .= '<li class="day"><a href="#" onclick="return false">' . $this->alphaDay[$x] . '</a></li>' . "\n";
    }
    
    /* Create the days of the calendar using foreach loops */
    foreach ($this->dispCalendar as $innerCalendar) {
      foreach ($innerCalendar as $value) {
        $this->theForm .= $value . "\n";
      }
    }
    
    $this->theForm .= "</ul></div>\n";
    

    }

    protected function generateCalendar($date) {

    $this->lastMonth($date); // put previous month days in array as filler (if needed):
    $this->currentMonth($date); // put current momth days in same array:
    $this->nextMonth($date); // put next month days in same array as filler (if neeeded):
    
    $this->twoDimensional(); // create two-dimensional array:
    $this->form(); // create calendar form:
    
    return $this->theForm; // return finished calendar for to be output as HTML:
    

    }

    }
    [/php]

    and since this is Christmas the style.css file:

    body { background-color: #ffa; padding: 0; margin: 0; } .clearfix:before, .clearfix:after { content: " "; display: table; } .clearfix:after { clear: both; } .clearfix { *zoom: 1; } .calDays { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; width: 100%; max-width: 418px; padding: 0; margin: 0; } ol, ul { list-style: none; } .calHeading { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; background-color: #267e9f; width: 100%; max-width: 418px; padding: 1.250rem; text-align: center; } .calHeaderText { cursor: default; text-decoration: none; font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; font-size: 1.2rem; color: #fff; } .day { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; float: left; display: block; background-color: #f3f3f3; text-align: center; width: 100%; max-width: 54px; height: 54px; line-height: 54px; } .day a { cursor: default; text-decoration: none; color: #000; } .calday { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; float: left; display: block; background-color: #e7d1a2; text-align: center; width: 100%; max-width: 54px; height: 54px; } .calday a { pointer-events: none; cursor: default; font-family: Arial, Helvetica, sans-serif; text-decoration: none; color: black; font-size: 1.0rem; line-height: 54px; } li.calday:nth-child(even), li.calday:nth-child(odd) { border-right: 1px solid black; border-top: 1px solid black; } li.calday:nth-child(7n+8) { border-right: none; } li.highlightHoliday { background-color: #cccdc8; font-weight: bolder; font-size: 1.0rem; } li.highlightHoliday a { color: white; } a.highlightToday { color: #12c712; font-weight: bolder; font-size: 1.2rem; } a.fade { color: #aaa; font-size: 1.0rem; }

    It’s free to use and modify, I hope this helps out someone. If you don’t use the calendar at least you can see how neat and compact OOP can be. I even plan to add abstract methods to this in the near future for even easier modifications and also put this on Github someday.


    #2

    Is that the same calendar script on your site?


    #3

    For the most part it is, but I have added a little jQuery & Ajax (Though it will even work with JavaScript Disabled ) and added a few modifications (minor logic bug fixes). I’ve also added a control feature to it, so a person can scroll back & forth through the months. I also plan on adding a blogging feature to the calendar in the near future.


    #4

    OK I have made a few changes to the Calendar, added a feature, fix a few logic bugs and so I thought I would post an update of the code. However, this will probably be the last time I do this, for the modifications that I’ll be doing next will branch off to a calendar blog that will involve a database table(s).

    Anyways here it is the classe(s) - I’ve added a controller and the reason I’ve used two classes is the calendar can run without the use of the controller. However, adding a controller adds a nice touch in my opinion.
    [php]<?php

    namespace jrpepp_production;

    use DateTime;

    class CalendarControls {

    public $returnDate;
    public $displayControls;
    public $returnControls;
    protected static $todaysDate;
    protected static $page;
    protected static $varPage;
    protected static $next;
    protected static $previous;
    protected $currentMonthPositon;

    public function __Construct($page) {
    $this->returnDate = $this->todaysDate($page);
    $this->returnControls = $this->calButtons();
    }

    public function currentMonthPosition($calendarDate, $numOfMonths) {
    return $this->currentMonthPositon = date(‘F j, Y’, strtotime($calendarDate . ’ +’ . $numOfMonths . ’ months’));
    }

    protected function todaysDate($page) {

    self::$todaysDate = date('F Y'); // Today's Month && Year:
    self::$page = isset($page) ? $page : NULL;
    
    self::$varPage = isset(self::$page) ? self::$page : 0;
    
    self::$previous = isset(self::$page) ? self::$page - 1 : -1;
    self::$next = isset(self::$page) ? self::$page + 1 : 1;
    
    return $this->currentMonthPosition(self::$todaysDate, self::$varPage);
    

    }

    protected function calButtons() {
    $this->displayControls = ‘

    ’ . PHP_EOL;
    $this->displayControls .= ’ ’ . PHP_EOL;
    $this->displayControls .= ’ ’ . PHP_EOL;
    $this->displayControls .= ‘
    ’ . PHP_EOL;
    return $this->displayControls;
    }

    }

    class DisplayCalendar {

    private $date;
    private $dayPos;
    public $output = \NULL;
    protected $prev = \NULL;
    protected $current = \NULL;
    protected $next = \NULL;
    protected $month = \NULL;
    protected $day = \NULL;
    protected $year = \NULL;
    protected $days = \NULL;
    protected $highlightToday = \NULL;
    protected $prevMonth = \NULL;
    protected $nextMonth = \NULL;
    protected $today = \NULL;
    protected $calendar = array();
    protected $theForm = \NULL;
    protected $alphaDay = array(0 => “Sun”, 1 => “Mon”, 2 => “Tue”, 3 => “Wed”, 4 => “Thu”, 5 => “Fri”, 6 => “Sat”);

    /* Constructor to create the calendar */
    public function __construct($date) {
    $this->output = $this->generateCalendar($date);
    }

    /* Last month filler days (if needed) */
    protected function lastMonth($date) {
    $this->prev = new DateTime($date . “-1 Month”);
    $this->prev->modify(“last day of this month”);
    $this->prevMonth = $this->prev->format(‘w’); // Numeric day of the week the last month’s day falls on:
    if ($this->prevMonth != 6) {
    for ($x = $this->prevMonth; $x >= 0; $x–) {
    $this->calendar[] = ‘

  • ’ . ($this->prev->format(‘t’) - $x) . ‘
  • ’ . “\n”;
    }
    } else {
    for ($x = 6; $x >= 0; $x–) {
    $this->calendar[] = ‘
  • ’ . ($this->prev->format(‘t’) - $x) . ‘
  • ’ . “\n”;
    }
    }
    }

    /* Current Month’s Calendar days /
    protected function currentMonth($date) {
    /
    Grab the current month DateTime /
    $this->current = new DateTime($date);
    /
    Grab the month & year of the current month */
    $this->month = $this->current->format(‘F’);
    $this->year = $this->current->format(‘Y’);

    $this->days = $this->current->format('t'); // Days in the current month:		
    /* Generate each day of the week's date */
    for ($x = 1; $x <= $this->days; $x++) {
      /* Figure out if the month's day is today and highlight if it is */
      if ( $this->today->format('F j, Y') === ($this->month . ' ' . $x . ', ' . $this->year)) {
        $this->highlightToday = 'highlightToday';
      } else {
        $this->highlightToday = \NULL;
      }
      /* The Actual Link of the day of the week for the current month */
      $this->calendar[] = '<li class="calday"><a class="' . $this->highlightToday . '" href="#">' . $x . '</a></li>' . "\n";
    }
    

    }
    /* Filler Day Function */
    protected function addRow($dayPos = 1, $totalDays = 0) {
    for ($x = $dayPos; $x <= (7 + $totalDays); $x++) {
    $this->calendar[] = ‘

  • ’ . $x . ‘
  • ’ . “\n”;
    }
    }

    /* Next month filler days /
    protected function nextMonth($date) {
    /
    Advance to the next month by adding +1 month to current date /
    $this->next = new DateTime($date . ‘+1 Month’);
    /
    Need to set the month to the first day of the month /
    $this->next->modify(‘first day of this Month’);
    /
    Grab how many day’s position in the week /
    $this->nextMonth = $this->next->format(‘w’);
    /
    Fill the week with days of next month if month ends on Saturday /
    if ($this->nextMonth != 0) {
    /
    Subtract 7 form days to get the correct day position */
    for ($x = 1; $x <= (7 - $this->nextMonth); $x++) {
    $this->calendar[] = ‘

  • ’ . $x . ‘
  • ’ . “\n”;
    }
    } else {
    $this->addRow(); // Tack on an extra week if the month ends on a Saturday:
    }
    /* If calendar month only has 5 weeks (35 days) tack on an extra week */
    if ( sizeof($this->calendar) === 35) {
      /* $dayPos is really next month's day position on Current Caleandar */
      $dayPos = 8 - $this->nextMonth; 
      /* Total days that need to be filled to make it a week */
      $totalDays = 7 - $this->nextMonth; 
      $this->addRow($dayPos, $totalDays);
    }
    

    }

    protected function form() {
    /* Create a div box and an unordered list /
    $this->theForm .= ‘

      ’ . “\n”;
      / Create heading for the calendar /
      $this->theForm .= ‘
    • ’ . $this->current->format(‘F Y’) . ‘
    • ’ . “\n”;
      /
      Create days of the week heading /
      for ($x = 0; $x <= 6; $x++) {
      $this->theForm .= ‘
    • ’ . $this->alphaDay[$x] . ‘
    • ’ . “\n”;
      }
      foreach($this->calendar as $value) {
      $this->theForm .= $value . “\n”;
      }
      /
      Close the HTML tags */
      return $this->theForm .= “
    \n”;
    }

    protected function generateCalendar($date) {
    $this->today = new DateTime(“NOW”); // Set today’s date in a variable/argument:
    $this->lastMonth($date); // put previous month days in array as filler (if needed):
    $this->currentMonth($date); // put current momth days in same array:
    $this->nextMonth($date); // put next month days in calendar array as filler days:
    return $this->form(); // create calendar form and return it to the constructor:
    }

    }
    [/php]
    I’m officially an airhead, for the calendar works perfectly fine without a two-dimensional array, plus I also tighten the code a little. (I’m sure it can still be tighten. ;))

    I use font-awesome for the arrow keys, do a Google search an you will find the website and they are FREE to use. I’ll let you figure out the CSS for the control keys, it shouldn’t be a problem for people who know CSS.

    Here’s a example page incorporating the Calendar:
    [php]<?php
    session_start();
    date_default_timezone_set(‘America/Detroit’); // Set the Default Time Zone:
    require_once ‘lib/classes/calendar/DisplayCalendar.php’;
    /* Uses namespaces */
    use jrpepp_production\DisplayCalendar as Calendar;
    use jrpepp_production\CalendarControls as Control;

    /* This makes sures that the input is a number */
    $page = filter_input(INPUT_GET, ‘page’, FILTER_VALIDATE_INT);
    if (!$page) {
    $page = 0;
    }
    $setMonth = new Control($page);
    $currentMonth = $setMonth->returnDate;

    /* Generate the Calendar */
    $mydate = new Calendar($currentMonth);

    ?>
    <!doctype html>

    Calendar 3.0
    <?php echo $setMonth->returnControls; ?>
    <?php echo $mydate->output; ?>
    [/php]

    Yes I know there’s Google Calendar and other calendars out there on the internet, the purpose of me making this calendar is to be able to go onto the next step (the calendar blog). I personally don’t like using frameworks or libraries if I can do it myself, for I feel I learn the material faster and I also don’t get as confused trying to figure out code that isn’t written by me in order to modify it to fit what I want to do - if I use a framework or library. If I have a chance I will I post the CSS, but I have to hunt it down controller css for I use Sass (A CSS preprocessor) which puts it in a big CSS file for me.
    HTH someone John