I’m trying to make this class more Object-Oriented. I need to do this so it’ll be easier to add events to the calendar. Check out the createMonth function.
If you just copy and paste the following code you’ll be able to see the class in action.
Thanks:D
<?php
/**
* A class for creating calendars
*
*
* @author Leonel Santos
* @copyright Leonel Santos 2009
* @version 1
------- to-do ----------
change styles and id's names, something more specific like
.LeoCalendar-daysOfWeek
.LeoCalendar-notThisMonth
#LeoCalendar-today
or
#LeoCalendar .daysOfWeek
#LeoCalendar .notThisMonth
#LeoCalendar #today
$_GET
CalendarType
workDate
Styles
on the month
.notThisMonth
.today
on the week
col#time
col#Sunday
col#Monday
col#Tuesday
col#Wednesday
col#Thursday
col#Friday
col#Saturday
th#today_col
on the day
tr#now
validation: accept only integers and two dashes xxxx-xx-xx
error handling
fix, next month or previous month, it just goes to the next month
on same day careful with Oct 31 because next month jumps to Dec
because November only has 30 days
*/
class LeoCalendar
{
protected $_workDate;
protected $_workDateYMD;
protected $_calendarType;
protected $_events;
protected $_year;
protected $_month;
protected $_day;
// boolean
// 0 = is not in this month
// 1 = it is in this month
protected $_inThisMonth;
public function __construct($events=array())
{
if(isset($_GET))
{
}
if(!is_null($events) && !is_array($events))
{
throw new Exception('Must be array');
}
$this->_events = $events;
if(!isset($_GET['workDate']))
{
$this->_workDate = date("Y-m-d");
$this->_workDateYMD = date('Y-m-d');
}
else
{
$this->_workDate = $_GET['workDate'];
$this->_workDateYMD = date('Y-m-d', strtotime($_GET['workDate']));
}
// assign the values to the class properties
$this->_year = ( int ) date( 'Y', strtotime($this->_workDate));
$this->_month = ( int ) date( 'n', strtotime($this->_workDate));
$this->_day = ( int ) date( 'j', strtotime($this->_workDate));
if(!isset($_GET['CalendarType']))
{
$this->_calendarType = 'month';
}
else
{
$isItAllowed = 0;
$allowedCalendarTypes = array('month', 'week', 'day');
foreach($allowedCalendarTypes as $key => $value)
{
if($value==$_GET['CalendarType'])
{
$isItAllowed = 1;
}
}
if($isItAllowed==1)
{
$this->_calendarType = $_GET['CalendarType'];
}
else
{
exit('Error! Calendar Type not allowed');
}
}
}
################################################
# PUBLIC METHODS FOR blah blah blah bl #
################################################
public function createWeek($enterDate)
{
$today = date('Y-m-d');
$today_timestamp = strtotime($today);
$timestamp = strtotime($enterDate);
$timestamp_legible = date('Y-m-d', $timestamp);
if(date('l', $timestamp)=='Sunday')
{
$sunday_timestamp = $timestamp;
$sunday_legible = date('F j, Y', $sunday_timestamp);
}
else
{
$sunday_timestamp = strtotime(date('r',strtotime('last Sunday '.$timestamp_legible)));
$sunday_legible = date('F j, Y', $sunday_timestamp);
}
$year = date('Y', $sunday_timestamp);
$output = '<p>
<a href="'.$_SERVER['PHP_SELF'].'?CalendarType=week&workDate='.date('Y-m-d', strtotime('-1 day '.$sunday_legible)).'">Previous Week</a>
|
<a href="'.$_SERVER['PHP_SELF'].'?CalendarType=week&workDate='.date('Y-m-d', strtotime('+7 days '.$sunday_legible)).'">Next Week</a>
</p>
<table>
<caption>'.date('F j', $sunday_timestamp).' - '.date('F j, Y', strtotime('+6 days '.$sunday_legible)).'</caption>
<colgroup>
<col id="time" />
<col id="Sunday" />
<col id="Monday" />
<col id="Tuesday" />
<col id="Wednesday" />
<col id="Thursday" />
<col id="Friday" />
<col id="Saturday" />
</colgroup>
<thead><tr><th scope="col">'.$year.'</th>
';
for($i=0;$i<7;$i++)
{
$date = date('l, M j', strtotime('+'.$i.' day '.$sunday_legible));
$today_col = '';
if(strtotime($date) === $today_timestamp)
{
$today_col = 'id="today_col"';
}
else
{
$today_col = '';
}
$output .= '<th scope="col" '.$today_col.'>'.$date.'</th>';
}
$output .= '</tr></thead><tbody>';
for($i=6; $i <= 22; $i++)
{
$time = strtotime('+'.$i.' hour 12AM');
$hour = date('H', $time);
$time = ($hour != '12') ? date('g A', $time) : 'Noon';
$output .= '<tr><th scope="row">'.$time.'</th>';
for($j=1; $j<=7;$j++)
{
$output .= '<td></td>';
}
$output .= '</tr>';
}
$output .= '</tbody></table>';
return $output;
}
public function createDay($enterDate)
{
$timestamp = strtotime($enterDate);
$timestamp_legible = date('Y-m-d', $timestamp);
$output = '<p>
<a href="'.$_SERVER['PHP_SELF'].'?CalendarType=day&workDate='.date('Y-m-d', strtotime('-1 day '.$timestamp_legible)).'">Previous Day</a>
|
<a href="'.$_SERVER['PHP_SELF'].'?CalendarType=day&workDate='.date('Y-m-d', strtotime('+1 days '.$timestamp_legible)).'">Next Day</a>
</p>';
$output .= '<table>
<caption>'.date('F j', $timestamp).'</caption>
<thead><tr><th>'.date('Y', $timestamp).'</th><th>'.date('F j', $timestamp).'</th></tr></thead>
</tbody>
';
for($i=6; $i <= 22; $i++)
{
$time = strtotime('+'.$i.' hour 12AM');
$hour = date('H', $time);
$time = ($hour != '12') ? date('g A', $time) : 'Noon';
$now = '';
if($i==date('G') && $timestamp_legible==date('Y-m-d'))
{
$now = 'id="now"';
}
$output .= '<tr '.$now.'><th scope="row">'.$time.'</th><td></td>';
$output .= '</tr>';
}
$output .= '</tbody></table>';
return $output;
}
protected function GetStartingPoint($DLM)
{
$today = getdate(strtotime($this->_workDate));
$mday = $today['mday'];
$mday-=1;
$FirstOfMonth = date("Y-m-d",strtotime($this->_workDate . "-" . $mday . " days"));
switch(date("l",strtotime($FirstOfMonth)))
{
case "Sunday":
$CD = 1;
$this->_inThisMonth=1;
break;
case "Monday":
$CD = $DLM;
break;
case "Tuesday":
$CD = $DLM-1;
break;
case "Wednesday":
$CD = $DLM-2;
break;
case "Thursday":
$CD = $DLM-3;
break;
case "Friday":
$CD = $DLM-4;
break;
case "Saturday":
$CD = $DLM-5;
}
return $CD;
}
/**
* Add specified number of months to date.
*
* This method adjusts the result to the final day of the month if
* the resulting date is invalid, e.g., September 31 is converted
* to September 30. Results in February also take account of leap
* year. This contrasts with DateTime::modify() and strtotime, which
* produce unexpected results by adding the day(s).
*
* @param int $numMonths Number of months to be added.
*/
public function addMonths($numMonths) {
if (! is_numeric ( $numMonths ) || $numMonths < 1) {
throw new Exception ( 'addMonths() expects a positive integer.' );
}
$numMonths = ( int ) $numMonths;
// Add the months to the current month number.
$newValue = $this->_month + $numMonths;
// If the new value is less than or equal to 12, the year
// doesn't change, so just assign the new value to the month.
if ($newValue <= 12) {
$this->_month = $newValue;
} else {
// A new value greater than 12 means calculating both
// the month and the year. Calculating the year is
// different for December, so do modulo division
// by 12 on the new value. If the remainder is not 0,
// the new month is not December.
$notDecember = $newValue % 12;
if ($notDecember) {
// The remainder of the modulo division is the new month.
$this->_month = $notDecember;
// Divide the new value by 12 and round down to get the
// number of years to add.
$this->_year += floor ( $newValue / 12 );
} else {
// The new month must be December
$this->_month = 12;
$this->_year += ($newValue / 12) - 1;
}
}
$this->checkLastDayOfMonth ();
parent::setDate ( $this->_year, $this->_month, $this->_day );
}
/**
* Subtract specified number of months from date.
*
* This method adjusts the result to the final day of the month if
* the resulting date is invalid, e.g., September 31 is converted
* to September 30. Results in February also take account of leap
* year. This contrasts with DateTime::modify() and strtotime, which
* produce unexpected results by subtracting the day(s).
*
* @param int $numMonths Number of months to be subtracted.
*/
public function subMonths($numMonths) {
if (! is_numeric ( $numMonths )) {
throw new Exception ( 'addMonths() expects an integer.' );
}
$numMonths = abs ( intval ( $numMonths ) );
// Subtract the months from the current month number.
$newValue = $this->_month - $numMonths;
// If the result is greater than 0, it's still the same year,
// and you can assign the new value to the month.
if ($newValue > 0) {
$this->_month = $newValue;
} else {
// Create an array of the months in reverse.
$months = range (12, 1);
// Get the absolute value of $newValue.
$newValue = abs ( $newValue );
// Get the array position of the resulting month.
$monthPosition = $newValue % 12;
$this->_month = $months [$monthPosition];
// Arrays begin at 0, so if $monthPosition is 0,
// it must be December.
if ($monthPosition) {
$this->_year -= ceil ( $newValue / 12 );
} else {
$this->_year -= ceil ( $newValue / 12 ) + 1;
}
}
$this->checkLastDayOfMonth ();
parent::setDate ( $this->_year, $this->_month, $this->_day );
}
/**
* Create a month calendar.
*
* This method returns a month grid calendar according to the
* workDate parameter
*
* @param array $events Array with events to be added to calendar.
*/
protected function createMonth($events=array())
{
// $previousMonth = date("Y-m-d", strtotime($this->_workDate . "-1 month"));
// $nextMonth = date("Y-m-d", strtotime($this->_workDate . "+1 month"));
// $this->_year = ( int ) date( 'Y', $this->_workDate);
// $this->_month = ( int ) date( 'n', $this->_workDate);
// $this->_day = ( int ) date( 'j', $this->_workDate);
// echo '<h1>'.$this->_year.'-'.$this->_month.'-01</h1>';
// echo 'New next month: '.date('Y-m-d', strtotime($this->_year.'-'.$this->_month.'-01 +1 month'));
$nextMonth = date('Y-m-d', strtotime($this->_year.'-'.$this->_month.'-01 +1 month'));
$previousMonth = date('Y-m-d', strtotime($this->_year.'-'.$this->_month.'-01 -1 month'));
$daysThisMonth = date("t",strtotime(date("Y-m-d",strtotime($this->_workDate))));
$daysLastMonth = date("t",strtotime(date("Y-m-d", strtotime($previousMonth))));
$this->_inThisMonth = 0;
$currentDate = $this->GetStartingPoint($daysLastMonth);
// echo '<h3>previous month: '.$previousMonth.'</h3>';
// echo '<h3>next month: '.$nextMonth.'</h3>';
echo '<h3>days this month: '.$daysThisMonth.'</h3>';
echo '<h3>days last month: '.$daysLastMonth.'</h3>';
echo '<h3>current date: '.$currentDate.'</h3>';
if(isset($events)&&!is_array($events))
{
exit('<p>Is not array inside createMonth function!</p>');
}
// $output = '<p><a href="'.$_SERVER['PHP_SELF'].'?workDate='.$previousMonth.'">Previous Month</a> | <a href="'.$_SERVER['PHP_SELF'].'?workDate='.$nextMonth.'">Next Month</a></p>';
$output = '<p><a href="'.$_SERVER['PHP_SELF'].'?workDate='.$previousMonth.'">Previous Month</a> | <a href="'.$_SERVER['PHP_SELF'].'?workDate='.$nextMonth.'">Next Month</a></p>';
$output .= '<table><caption>'.date('F Y',strtotime($this->_workDate)).'</caption>
<tr>
<th>Sunday</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>';
// what if you find a start date, the beginning of the calendar,
// then you set the end date. you would just have to +1 day until
// you hit the end date. that way, you always have the day you are
// printing, instead of just looping a for loop
for($x=1;$x<7;$x++)
{
$tdDay = '<tr>';
$tdContent = '<tr>';
for($i=0;$i<7;$i++)
{
// place something inside the tdContent td
// $tdContent .= date('m',strtotime($this->_workDate));
// $tdInside = date('Y',strtotime($this->_workDate)).'-'.date('m',strtotime($this->_workDate)).'-'.$currentDate;
// $tdInside = $currentDate;
$tdContent .= '<td ';
// not from this month
if($this->_inThisMonth==0)
{
$tdDay .= '<td class="notThisMonth">'.$currentDate++.'</td>';
$tdContent .= 'class="notThisMonth">';
// add stuff inside day
// $tdContent .= ($currentDate-1).' | '.date('Y',strtotime($this->_workDate)).'-'.date("n",strtotime($this->_workDate)).'-'.($currentDate-1);
}
else
{
// today
if( $currentDate == date("j") && date("n",strtotime($this->_workDate)) == date("n") && date("y",strtotime($this->_workDate)) == date("y") )
{
$tdDay .= '<td class="today">'.$currentDate++.'</td>';
$tdContent .= 'class="today">';
// add stuff inside day
// $tdContent .= date('Y',strtotime($this->_workDate)).'-'.date("n",strtotime($this->_workDate)).'-'.($currentDate-1);
}
// this month
else
{
$tdDay .= '<td>'.$currentDate++.'</td>';
$tdContent .= '>';
// add stuff inside day
// $tdContent .= date('Y',strtotime($this->_workDate)).'-'.date("n",strtotime($this->_workDate)).'-'.($currentDate-1);
}
}
// close tdContent td
$tdContent .= '</td>';
// this month
if( $this->_inThisMonth == 0 && $currentDate > $daysLastMonth )
{
$currentDate = 1;
$this->_inThisMonth = 1;
}
// not this month
elseif($this->_inThisMonth == 1 && $currentDate > $daysThisMonth )
{
$currentDate = 1;
$this->_inThisMonth = 0;
}
}
$tdDay .= '</tr>';
$tdContent .= '</tr>';
$output .= $tdDay.$tdContent;
}
$output .= '</table>';
return $output;
}
public function displayCalendar()
{
$calendarHeader = '<p><a href="'.$_SERVER['PHP_SELF'].'?CalendarType=day&workDate='.$this->_workDate.'">day</a> | <a href="'.$_SERVER['PHP_SELF'].'?CalendarType=week&workDate='.$this->_workDate.'">week</a> | <a href="'.$_SERVER['PHP_SELF'].'?CalendarType=month&workDate='.$this->_workDate.'">month</a></p><p><a href="'.$_SERVER['PHP_SELF'].'?CalendarType='.$this->_calendarType.'&workDate='.date("Y-m-d").'">Today</a></p>';
// change to a swich/case instead of ifelse
if($this->_calendarType=='month')
{
return $calendarHeader.$this->createMonth($this->_events);
}
elseif($this->_calendarType=='week')
{
return $calendarHeader.$this->createWeek($this->_workDateYMD);
}
elseif($this->_calendarType=='day')
{
return $calendarHeader.$this->createDay($this->_workDateYMD);
}
}
/**
* Determines whether the year is a leap year.
*
* @return bool True if it is a leap year, otherwise false.
*/
public function isLeap() {
if ($this->_year % 400 == 0 || ($this->_year % 4 == 0 && $this->_year % 100 != 0)) {
return true;
} else {
return false;
}
}
###########################################################
# PROTECTED METHOD #
###########################################################
/**
* Adjusts the day to the last day of the month when necessary.
*
* This internal method is called by addMonths(), subMonths(),
* addYears(), and subYears(). It checks whether the date calculation
* results in an invalid date, such as February 31. If the date is
* invalid, it readjusts the $_day property to the last day of
* the month.
*/
final protected function checkLastDayOfMonth() {
if (! checkdate ( $this->_month, $this->_day, $this->_year )) {
$use30 = array (4, 6, 9, 11 );
if (in_array ( $this->_month, $use30 )) {
$this->_day = 30;
} else {
$this->_day = $this->isLeap () ? 29 : 28;
}
}
}
}
?>
<style>
body { font-family:Arial, Helvetica, sans-serif; }
table { width:100%; }
th { background-color:#999999; }
td { border:1px solid #999999; }
td.notThisMonth { background-color:#CCCCCC; }
.today { background-color:#FFFF99; }
</style>
<?php
$events = array('2009-11-25', '2009-11-10');
$calendar = new LeoCalendar();
echo $calendar->displayCalendar($events);
?>