-
Notifications
You must be signed in to change notification settings - Fork 0
OOCalendar
An object oriented approach to building a monthly calendar.
This code assumes a database table with event dates specified in a datetime field. It also helps to have a CSS file that defines a few table classes. you can see my example below.
The controller: [CODE] function cal($y,$m) { $this->load->helper('url'); $this->load->model('Month_model'); $this->Month_model->set_event_table('Events'); $this->Month_model->set_event_field('datetime_start');
$p_arr = array('year','month','month_name_long','month_prev','month_next','year_in_month_prev','year_in_month_next');
$data['month_array'] = $this->Month_model->db_month_box($m,$y);
foreach ($p_arr as $p)
{
$data[$p] = $this->Month_model->$p;
}
$this->load->view('month_table',$data);
}
[/CODE]
The model: [CODE]<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Month_model extends Model {
var $month;
var $month_prev;
var $month_next;
var $month_name_long;
var $month_name_short;
var $year;
var $year_in_month_prev;
var $year_in_month_next;
var $month_arr;
var $db_table_with_dates;
var $db_field_with_date;
function Month_model()
{
parent::Model();
}
// set the db and field
// where events are
function set_event_table($tbl_name)
{
$this->db_table_with_dates = $tbl_name;
}
function set_event_field($fld_name)
{
$this->db_field_with_date = $fld_name;
}
// send month and year
// build month box
// and then hang the events
// fetched from the specified db
function db_month_box($m,$y)
{
// get the raw month structure
$arr = $this->month_box($m,$y);
// hang some objects onto the month
$arr = $this->hang_events();
// chunk out weekly arrays, keep keys
$ca = array_chunk($arr,7,TRUE);
return $ca;
}
// return an array with Ymd format
// dates as keys, calendar month with
// padded entries to make a fully
// rectangular month calendar
function month_box($m,$y)
{
if ($m > 12) $m = 12;
if ($m < 1) $m = 1;
$this->month = $m;
$this->year = $y;
$this->month_arr = array();
// get timestamp of the first
// day of requested month and year
$ts_start = mktime(12, 0, 0, $this->month, 1, $this->year);
$days_in_month = date('t',$ts_start);
// use noon so we don't get messed up
$ts_end = mktime(12, 0, 0, $this->month, $days_in_month, $this->year);
$pms = strtotime('-1 month',$ts_start);
$pme = strtotime('-1 day',$ts_start);
$nms = strtotime('+1 day',$ts_end);
// have to do extra to get prev/next month params
$this->month_next = date('m',$nms);
$this->year_in_month_next = date('Y',$nms);
$this->month_prev = date('m',$pms);
$this->year_in_month_prev = date('Y',$pms);
$days_in_month_nm = date('t',$nms);
$nme = mktime(12, 0, 0, $this->month_next, $days_in_month_nm, $this->year_in_month_next);
$prev_month_start = date('Ymd', $pms);
$prev_month_end = date('Ymd', $pme);
$next_month_start = date('Ymd', $nms);
$next_month_end = date('Ymd', $nme);
$start_day = date('Ymd',$ts_start);
$end_day = date('Ymd',$ts_end);
// generate array from the
// number of days in month
$arr_tm = range($start_day,$end_day);
$arr_pm = range($prev_month_start,$prev_month_end);
$arr_nm = range($next_month_start,$next_month_end);
// get the day num of the
// first/last day of the month
$day_of_week_first = date('w', $ts_start);
$day_of_week_last = date('w', $ts_end);
// pad the beginning of the array
// based on day_of_week, negative keys
$pad_in = ($day_of_week_first) ? array_slice($arr_pm,-$day_of_week_first) : array();
// now the lead-out days
$day_mod = 6-$day_of_week_last;
$pad_out = ($day_mod)?array_slice($arr_nm,0,$day_mod):array();
// put the lead-in/lead-out days on
$arr = array_merge($pad_in,$arr_tm,$pad_out);
$arr = array_flip($arr);
// normalize every value
// do this to avoid making
// a day class right now
// just use stdClass
$today_Ymd = date('Ymd');
$this->month_name_long = date('F',$ts_start);
$this->month_name_short = date('M',$ts_start);
foreach($arr as $k => $v)
{
$o = new stdClass;
// remove the spaces in the sscanf() format string
list($year,$month,$day) = sscanf($k, "% 4d% 2d% 2d");
// store the timestamp to enable
// access to any date formatting
// via date() function in view
$o->ts = strtotime($month.'/'.$day.'/'.$year);
$o->day_of_month = $day;
$o->day_of_year = date('z',$o->ts);
$o->day_ordinal = date('jS',$o->ts);
$o->day_name_long = date('D',$o->ts);
$o->day_name_short = substr($o->day_name_long,0,3);
$o->day_name_initial = substr($o->day_name_short,0,1);
$o->not_in_month = ($month!=$this->month);
$o->today = ($today_Ymd==$k);
// start with event FALSE,
// add events in other function
$o->has_event = FALSE;
$o->data = array();
$this->month_arr[$k] = $o;
}
return $this->month_arr;
}
function hang_events()
{
$f = $this->db_field_with_date;
// define some calculated fields in SQL
$this->db->select("*, DATE_FORMAT($f, '%m') as month, DATE_FORMAT($f, '%d') as day, DATE_FORMAT($f, '%Y%m%d') AS Ymd", FALSE);
// get everything in the month (any year)
$this->db->where("MONTH($f)",$this->month);
$this->db->order_by($f);
$q = $this->db->get($this->db_table_with_dates);
$ev = $q->result();
foreach ($ev as $e)
{
$month_date = $this->year.$e->month.$e->day;
// check for exact match first then annual
// these should be separated to handle single and
// repeating dates differently
if ( array_key_exists($e->Ymd, $this->month_arr) OR array_key_exists($month_date, $this->month_arr) )
{
$this->month_arr[$month_date]->has_event = TRUE;
$this->month_arr[$month_date]->data[] = $e;
}
}
return $this->month_arr;
}
} // EOF [/CODE]
and the view: [CODE]
<?php foreach($month_array[0] as $head): ?> <?php endforeach; ?> <?php foreach($month_array as $week): ?> <?php foreach($week as $day): ?><?php echo $head->day_name_initial; ?> |
---|
today){echo '"today"';}
elseif($day->not_in_month){echo '"not_in_month"';}
else{echo '"day"';} ?>
>
|
The CSS for the table (needs a gif file): [CODE]body { font: normal 12px/20px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; color: #616B76; }
a { color: #DF9496; }
#calendar { width: 141px; padding: 0; margin: 0; border-left: 1px solid #A2ADBC; font: normal 12px/20px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; color: #616B76; text-align: center; background-color: #fff; }
.nav, .nav a {
font: bold 18px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
color: #fff;
text-align: center;
text-decoration: none;
}
caption {
margin: 0;
padding: 0;
width: 141px;
background: #A2ADBC;
color: #fff;
font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
text-align: center;
}
th { font: bold 11px/20px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; color: #616B76; background: #D9E2E1; border-right: 1px solid #A2ADBC; border-bottom: 1px solid #A2ADBC; border-top: 1px solid #A2ADBC; }
.today, td.today a, td.today a:link, td.today a:visited { color: #F6F4DA; font-weight: bold; background: #DF9496; }
.not_in_month, td.not_in_month a, td.not_in_month a:link, td.not_in_month a:visited { color: #CCCCCC; font-weight: normal; background: #EEEEEE; }
td.day { border-right: 1px solid #A2ADBC; border-bottom: 1px solid #A2ADBC; width: 20px; height: 20px; text-align: center; background: url(../img/bg_calendar.gif) no-repeat right bottom; }
td.day a { text-decoration: none; font-weight: bold; display: block; }
td.day a:link, td.day a:visited {
color: #B88546;
background: url(../img/bg_calendar.gif) no-repeat;
}
td.day a:hover, td.day a:active { color: #6aa3ae; background: url(../img/bg_calendar.gif) no-repeat right top; }[/CODE]