Avail feature updated
[ninja.git] / system / libraries / Calendar_Event.php
blob12dbb23e0794124c01316b6cb583774ca0e8810a
1 <?php defined('SYSPATH') OR die('No direct access allowed.');
2 /**
3 * Calendar event observer class.
5 * $Id: Calendar_Event.php 3917 2009-01-21 03:06:22Z zombor $
7 * @package Calendar
8 * @author Kohana Team
9 * @copyright (c) 2007-2008 Kohana Team
10 * @license http://kohanaphp.com/license.html
12 class Calendar_Event extends Event_Observer {
14 // Boolean conditions
15 protected $booleans = array
17 'current',
18 'weekend',
19 'first_day',
20 'last_day',
21 'last_occurrence',
22 'easter',
25 // Rendering conditions
26 protected $conditions = array();
28 // Cell classes
29 protected $classes = array();
31 // Cell output
32 protected $output = '';
34 /**
35 * Adds a condition to the event. The condition can be one of the following:
37 * timestamp - UNIX timestamp
38 * day - day number (1-31)
39 * week - week number (1-5)
40 * month - month number (1-12)
41 * year - year number (4 digits)
42 * day_of_week - day of week (1-7)
43 * current - active month (boolean) (only show data for the month being rendered)
44 * weekend - weekend day (boolean)
45 * first_day - first day of month (boolean)
46 * last_day - last day of month (boolean)
47 * occurrence - occurrence of the week day (1-5) (use with "day_of_week")
48 * last_occurrence - last occurrence of week day (boolean) (use with "day_of_week")
49 * easter - Easter day (boolean)
50 * callback - callback test (boolean)
52 * To unset a condition, call condition with a value of NULL.
54 * @chainable
55 * @param string condition key
56 * @param mixed condition value
57 * @return object
59 public function condition($key, $value)
61 if ($value === NULL)
63 unset($this->conditions[$key]);
65 else
67 if ($key === 'callback')
69 // Do nothing
71 elseif (in_array($key, $this->booleans))
73 // Make the value boolean
74 $value = (bool) $value;
76 else
78 // Make the value an int
79 $value = (int) $value;
82 $this->conditions[$key] = $value;
85 return $this;
88 /**
89 * Add a CSS class for this event. This can be called multiple times.
91 * @chainable
92 * @param string CSS class name
93 * @return object
95 public function add_class($class)
97 $this->classes[$class] = $class;
99 return $this;
103 * Remove a CSS class for this event. This can be called multiple times.
105 * @chainable
106 * @param string CSS class name
107 * @return object
109 public function remove_class($class)
111 unset($this->classes[$class]);
113 return $this;
117 * Set HTML output for this event.
119 * @chainable
120 * @param string HTML output
121 * @return object
123 public function output($str)
125 $this->output = $str;
127 return $this;
131 * Add a CSS class for this event. This can be called multiple times.
133 * @chainable
134 * @param string CSS class name
135 * @return object
137 public function notify($data)
139 // Split the date and current status
140 list ($month, $day, $year, $week, $current) = $data;
142 // Get a timestamp for the day
143 $timestamp = mktime(0, 0, 0, $month, $day, $year);
145 // Date conditionals
146 $condition = array
148 'timestamp' => (int) $timestamp,
149 'day' => (int) date('j', $timestamp),
150 'week' => (int) $week,
151 'month' => (int) date('n', $timestamp),
152 'year' => (int) date('Y', $timestamp),
153 'day_of_week' => (int) date('w', $timestamp),
154 'current' => (bool) $current,
157 // Tested conditions
158 $tested = array();
160 foreach ($condition as $key => $value)
162 // Test basic conditions first
163 if (isset($this->conditions[$key]) AND $this->conditions[$key] !== $value)
164 return FALSE;
166 // Condition has been tested
167 $tested[$key] = TRUE;
170 if (isset($this->conditions['weekend']))
172 // Weekday vs Weekend
173 $condition['weekend'] = ($condition['day_of_week'] === 0 OR $condition['day_of_week'] === 6);
176 if (isset($this->conditions['first_day']))
178 // First day of month
179 $condition['first_day'] = ($condition['day'] === 1);
182 if (isset($this->conditions['last_day']))
184 // Last day of month
185 $condition['last_day'] = ($condition['day'] === (int) date('t', $timestamp));
188 if (isset($this->conditions['occurrence']))
190 // Get the occurance of the current day
191 $condition['occurrence'] = $this->day_occurrence($timestamp);
194 if (isset($this->conditions['last_occurrence']))
196 // Test if the next occurance of this date is next month
197 $condition['last_occurrence'] = ((int) date('n', $timestamp + 604800) !== $condition['month']);
200 if (isset($this->conditions['easter']))
202 if ($condition['month'] === 3 OR $condition['month'] === 4)
204 // This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
205 // Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
206 // 1876. This algorithm has also been published in the 1922 book General Astronomy by
207 // Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
208 // 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus.
210 $a = $condition['year'] % 19;
211 $b = (int) ($condition['year'] / 100);
212 $c = $condition['year'] % 100;
213 $d = (int) ($b / 4);
214 $e = $b % 4;
215 $f = (int) (($b + 8) / 25);
216 $g = (int) (($b - $f + 1) / 3);
217 $h = (19 * $a + $b - $d - $g + 15) % 30;
218 $i = (int) ($c / 4);
219 $k = $c % 4;
220 $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7;
221 $m = (int) (($a + 11 * $h + 22 * $l) / 451);
222 $p = ($h + $l - 7 * $m + 114) % 31;
224 $month = (int) (($h + $l - 7 * $m + 114) / 31);
225 $day = $p + 1;
227 $condition['easter'] = ($condition['month'] === $month AND $condition['day'] === $day);
229 else
231 // Easter can only happen in March or April
232 $condition['easter'] = FALSE;
236 if (isset($this->conditions['callback']))
238 // Use a callback to determine validity
239 $condition['callback'] = call_user_func($this->conditions['callback'], $condition, $this);
242 $conditions = array_diff_key($this->conditions, $tested);
244 foreach ($conditions as $key => $value)
246 if ($key === 'callback')
248 // Callbacks are tested on a TRUE/FALSE basis
249 $value = TRUE;
252 // Test advanced conditions
253 if ($condition[$key] !== $value)
254 return FALSE;
257 $this->caller->add_data(array
259 'classes' => $this->classes,
260 'output' => $this->output,
265 * Find the week day occurrence for a specific timestamp. The occurrence is
266 * relative to the current month. For example, the second Saturday of any
267 * given month will return "2" as the occurrence. This is used in combination
268 * with the "occurrence" condition.
270 * @param integer UNIX timestamp
271 * @return integer
273 protected function day_occurrence($timestamp)
275 // Get the current month for the timestamp
276 $month = date('m', $timestamp);
278 // Default occurrence is one
279 $occurrence = 1;
281 // Reduce the timestamp by one week for each loop. This has the added
282 // benefit of preventing an infinite loop.
283 while ($timestamp -= 604800)
285 if (date('m', $timestamp) !== $month)
287 // Once the timestamp has gone into the previous month, the
288 // proper occurrence has been found.
289 return $occurrence;
292 // Increment the occurrence
293 $occurrence++;
297 } // End Calendar Event