diff options
Diffstat (limited to 'kohana/libraries/Calendar.php')
-rw-r--r-- | kohana/libraries/Calendar.php | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/kohana/libraries/Calendar.php b/kohana/libraries/Calendar.php new file mode 100644 index 00000000..61b57366 --- /dev/null +++ b/kohana/libraries/Calendar.php @@ -0,0 +1,361 @@ +<?php defined('SYSPATH') or die('No direct script access.'); +/** + * Calendar creation library. + * + * $Id$ + * + * @package Calendar + * @author Kohana Team + * @copyright (c) 2007-2008 Kohana Team + * @license http://kohanaphp.com/license.html + */ +class Calendar_Core extends Event_Subject { + + // Start the calendar on Sunday by default + public static $start_monday = FALSE; + + // Month and year to use for calendaring + protected $month; + protected $year; + + // Week starts on Sunday + protected $week_start = 0; + + // Observed data + protected $observed_data; + + /** + * Returns an array of the names of the days, using the current locale. + * + * @param boolean return short names + * @return array + */ + public static function days($short = FALSE) + { + // strftime day format + $format = ($short == TRUE) ? '%a' : '%A'; + + // Days of the week + $days = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'); + + if (Calendar::$start_monday === TRUE) + { + // Push Sunday to the end of the days + array_push($days, array_shift($days)); + } + + if (strpos(Kohana::config('locale.language.0'), 'en') !== 0) + { + // This is a bit awkward, but it works properly and is reliable + foreach ($days as $i => $day) + { + // Convert the English names to i18n names + $days[$i] = strftime($format, strtotime($day)); + } + } + elseif ($short == TRUE) + { + foreach ($days as $i => $day) + { + // Shorten the day names to 3 letters + $days[$i] = substr($day, 0, 3); + } + } + + return $days; + } + + /** + * Create a new Calendar instance. A month and year can be specified. + * By default, the current month and year are used. + * + * @param integer month number + * @param integer year number + * @return object + */ + public static function factory($month = NULL, $year = NULL) + { + return new Calendar($month, $year); + } + + /** + * Create a new Calendar instance. A month and year can be specified. + * By default, the current month and year are used. + * + * @param integer month number + * @param integer year number + * @return void + */ + public function __construct($month = NULL, $year = NULL) + { + empty($month) and $month = date('n'); // Current month + empty($year) and $year = date('Y'); // Current year + + // Set the month and year + $this->month = (int) $month; + $this->year = (int) $year; + + if (Calendar::$start_monday === TRUE) + { + // Week starts on Monday + $this->week_start = 1; + } + } + + /** + * Allows fetching the current month and year. + * + * @param string key to get + * @return mixed + */ + public function __get($key) + { + if ($key === 'month' OR $key === 'year') + { + return $this->$key; + } + } + + /** + * Calendar_Event factory method. + * + * @param string unique name for the event + * @return object Calendar_Event + */ + public function event($name = NULL) + { + return new Calendar_Event($this); + } + + /** + * Calendar_Event factory method. + * + * @chainable + * @param string standard event type + * @return object + */ + public function standard($name) + { + switch ($name) + { + case 'today': + // Add an event for the current day + $this->attach($this->event()->condition('timestamp', strtotime('today'))->add_class('today')); + break; + case 'prev-next': + // Add an event for padding days + $this->attach($this->event()->condition('current', FALSE)->add_class('prev-next')); + break; + case 'holidays': + // Base event + $event = $this->event()->condition('current', TRUE)->add_class('holiday'); + + // Attach New Years + $holiday = clone $event; + $this->attach($holiday->condition('month', 1)->condition('day', 1)); + + // Attach Valentine's Day + $holiday = clone $event; + $this->attach($holiday->condition('month', 2)->condition('day', 14)); + + // Attach St. Patrick's Day + $holiday = clone $event; + $this->attach($holiday->condition('month', 3)->condition('day', 17)); + + // Attach Easter + $holiday = clone $event; + $this->attach($holiday->condition('easter', TRUE)); + + // Attach Memorial Day + $holiday = clone $event; + $this->attach($holiday->condition('month', 5)->condition('day_of_week', 1)->condition('last_occurrence', TRUE)); + + // Attach Independance Day + $holiday = clone $event; + $this->attach($holiday->condition('month', 7)->condition('day', 4)); + + // Attach Labor Day + $holiday = clone $event; + $this->attach($holiday->condition('month', 9)->condition('day_of_week', 1)->condition('occurrence', 1)); + + // Attach Halloween + $holiday = clone $event; + $this->attach($holiday->condition('month', 10)->condition('day', 31)); + + // Attach Thanksgiving + $holiday = clone $event; + $this->attach($holiday->condition('month', 11)->condition('day_of_week', 4)->condition('occurrence', 4)); + + // Attach Christmas + $holiday = clone $event; + $this->attach($holiday->condition('month', 12)->condition('day', 25)); + break; + case 'weekends': + // Weekend events + $this->attach($this->event()->condition('weekend', TRUE)->add_class('weekend')); + break; + } + + return $this; + } + + /** + * Returns an array for use with a view. The array contains an array for + * each week. Each week contains 7 arrays, with a day number and status: + * TRUE if the day is in the month, FALSE if it is padding. + * + * @return array + */ + public function weeks() + { + // First day of the month as a timestamp + $first = mktime(1, 0, 0, $this->month, 1, $this->year); + + // Total number of days in this month + $total = (int) date('t', $first); + + // Last day of the month as a timestamp + $last = mktime(1, 0, 0, $this->month, $total, $this->year); + + // Make the month and week empty arrays + $month = $week = array(); + + // Number of days added. When this reaches 7, start a new week + $days = 0; + $week_number = 1; + + if (($w = (int) date('w', $first) - $this->week_start) < 0) + { + $w = 6; + } + + if ($w > 0) + { + // Number of days in the previous month + $n = (int) date('t', mktime(1, 0, 0, $this->month - 1, 1, $this->year)); + + // i = number of day, t = number of days to pad + for ($i = $n - $w + 1, $t = $w; $t > 0; $t--, $i++) + { + // Notify the listeners + $this->notify(array($this->month - 1, $i, $this->year, $week_number, FALSE)); + + // Add previous month padding days + $week[] = array($i, FALSE, $this->observed_data); + $days++; + } + } + + // i = number of day + for ($i = 1; $i <= $total; $i++) + { + if ($days % 7 === 0) + { + // Start a new week + $month[] = $week; + $week = array(); + + $week_number++; + } + + // Notify the listeners + $this->notify(array($this->month, $i, $this->year, $week_number, TRUE)); + + // Add days to this month + $week[] = array($i, TRUE, $this->observed_data); + $days++; + } + + if (($w = (int) date('w', $last) - $this->week_start) < 0) + { + $w = 6; + } + + if ($w >= 0) + { + // i = number of day, t = number of days to pad + for ($i = 1, $t = 6 - $w; $t > 0; $t--, $i++) + { + // Notify the listeners + $this->notify(array($this->month + 1, $i, $this->year, $week_number, FALSE)); + + // Add next month padding days + $week[] = array($i, FALSE, $this->observed_data); + } + } + + if ( ! empty($week)) + { + // Append the remaining days + $month[] = $week; + } + + return $month; + } + + /** + * Adds new data from an observer. All event data contains and array of CSS + * classes and an array of output messages. + * + * @param array observer data. + * @return void + */ + public function add_data(array $data) + { + // Add new classes + $this->observed_data['classes'] += $data['classes']; + + if ( ! empty($data['output'])) + { + // Only add output if it's not empty + $this->observed_data['output'][] = $data['output']; + } + } + + /** + * Resets the observed data and sends a notify to all attached events. + * + * @param array UNIX timestamp + * @return void + */ + public function notify($data) + { + // Reset observed data + $this->observed_data = array + ( + 'classes' => array(), + 'output' => array(), + ); + + // Send a notify + parent::notify($data); + } + + /** + * Convert the calendar to HTML using the kohana_calendar view. + * + * @return string + */ + public function render() + { + $view = new View('kohana_calendar', array + ( + 'month' => $this->month, + 'year' => $this->year, + 'weeks' => $this->weeks(), + )); + + return $view->render(); + } + + /** + * Magically convert this object to a string, the rendered calendar. + * + * @return string + */ + public function __toString() + { + return $this->render(); + } + +} // End Calendar
\ No newline at end of file |