root/trunk/system/libraries/Calendar_Event.php

Revision 2899, 7.2 kB (checked in by armen, 2 weeks ago)

Removed extra called in foreaches.

  • Property svn:eol-style set to LF
  • Property copyright set to Copyright (c) 2007-2008 Kohana Team
  • Property svn:keywords set to Id
Line 
1 <?php defined('SYSPATH') or die('No direct script access.');
2 /**
3  * Calendar event observer class.
4  *
5  * $Id$
6  *
7  * @package    Calendar
8  * @author     Kohana Team
9  * @copyright  (c) 2007-2008 Kohana Team
10  * @license    http://kohanaphp.com/license.html
11  */
12 class Calendar_Event_Core extends Event_Observer {
13
14     // Boolean conditions
15     protected $booleans = array
16     (
17         'current',
18         'weekend',
19         'first_day',
20         'last_day',
21         'last_occurrence',
22         'easter',
23     );
24
25     // Rendering conditions
26     protected $conditions = array();
27
28     // Cell classes
29     protected $classes = array();
30
31     // Cell output
32     protected $output = '';
33
34     /**
35      * Adds a condition to the event. The condition can be one of the following:
36      *
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)
51      *
52      * To unset a condition, call condition with a value of NULL.
53      *
54      * @chainable
55      * @param   string  condition key
56      * @param   mixed   condition value
57      * @return  object
58      */
59     public function condition($key, $value)
60     {
61         if ($value === NULL)
62         {
63             unset($this->conditions[$key]);
64         }
65         else
66         {
67             if ($key === 'callback')
68             {
69                 // Do nothing
70             }
71             elseif (in_array($key, $this->booleans))
72             {
73                 // Make the value boolean
74                 $value = (bool) $value;
75             }
76             else
77             {
78                 // Make the value an int
79                 $value = (int) $value;
80             }
81
82             $this->conditions[$key] = $value;
83         }
84
85         return $this;
86     }
87
88     /**
89      * Add a CSS class for this event. This can be called multiple times.
90      *
91      * @chainable
92      * @param   string  CSS class name
93      * @return  object
94      */
95     public function add_class($class)
96     {
97         $this->classes[$class] = $class;
98
99         return $this;
100     }
101
102     /**
103      * Remove a CSS class for this event. This can be called multiple times.
104      *
105      * @chainable
106      * @param   string  CSS class name
107      * @return  object
108      */
109     public function remove_class($class)
110     {
111         unset($this->classes[$class]);
112
113         return $this;
114     }
115
116     /**
117      * Set HTML output for this event.
118      *
119      * @chainable
120      * @param   string  HTML output
121      * @return  object
122      */
123     public function output($str)
124     {
125         $this->output = $str;
126
127         return $this;
128     }
129
130     /**
131      * Add a CSS class for this event. This can be called multiple times.
132      *
133      * @chainable
134      * @param   string  CSS class name
135      * @return  object
136      */
137     public function notify($data)
138     {
139         // Split the date and current status
140         list ($month, $day, $year, $week, $current) = $data;
141
142         // Get a timestamp for the day
143         $timestamp = mktime(0, 0, 0, $month, $day, $year);
144
145         // Date conditionals
146         $condition = array
147         (
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,
155         );
156
157         // Tested conditions
158         $tested = array();
159
160         foreach ($condition as $key => $value)
161         {
162             // Test basic conditions first
163             if (isset($this->conditions[$key]) AND $this->conditions[$key] !== $value)
164                 return FALSE;
165
166             // Condition has been tested
167             $tested[$key] = TRUE;
168         }
169
170         if (isset($this->conditions['weekend']))
171         {
172             // Weekday vs Weekend
173             $condition['weekend'] = ($condition['day_of_week'] === 0 OR $condition['day_of_week'] === 6);
174         }
175
176         if (isset($this->conditions['first_day']))
177         {
178             // First day of month
179             $condition['first_day'] = ($condition['day'] === 1);
180         }
181
182         if (isset($this->conditions['last_day']))
183         {
184             // Last day of month
185             $condition['last_day'] = ($condition['day'] === (int) date('t', $timestamp));
186         }
187
188         if (isset($this->conditions['occurrence']))
189         {
190             // Get the occurance of the current day
191             $condition['occurrence'] = $this->day_occurrence($timestamp);
192         }
193
194         if (isset($this->conditions['last_occurrence']))
195         {
196             // Test if the next occurance of this date is next month
197             $condition['last_occurrence'] = ((int) date('n', $timestamp + 604800) !== $condition['month']);
198         }
199
200         if (isset($this->conditions['easter']))
201         {
202             if ($condition['month'] === 3 OR $condition['month'] === 4)
203             {
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.
209
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;
223
224                 $month = (int) (($h + $l - 7 * $m + 114) / 31);
225                 $day = $p + 1;
226
227                 $condition['easter'] = ($condition['month'] === $month AND $condition['day'] === $day);
228             }
229             else
230             {
231                 // Easter can only happen in March or April
232                 $condition['easter'] = FALSE;
233             }
234         }
235
236         if (isset($this->conditions['callback']))
237         {
238             // Use a callback to determine validity
239             $condition['callback'] = call_user_func($this->conditions['callback'], $condition, $this);
240         }
241
242         $conditions = array_diff_key($this->conditions, $tested);
243
244         foreach ($conditions as $key => $value)
245         {
246             if ($key === 'callback')
247             {
248                 // Callbacks are tested on a TRUE/FALSE basis
249                 $value = TRUE;
250             }
251
252             // Test advanced conditions
253             if ($condition[$key] !== $value)
254                 return FALSE;
255         }
256
257         $this->caller->add_data(array
258         (
259             'classes' => $this->classes,
260             'output'  => $this->output,
261         ));
262     }
263
264     /**
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.
269      *
270      * @param   integer  UNIX timestamp
271      * @return  integer
272      */
273     protected function day_occurrence($timestamp)
274     {
275         // Get the current month for the timestamp
276         $month = date('m', $timestamp);
277
278         // Default occurrence is one
279         $occurrence = 1;
280
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)
284         {
285             if (date('m', $timestamp) !== $month)
286             {
287                 // Once the timestamp has gone into the previous month, the
288                 // proper occurrence has been found.
289                 return $occurrence;
290             }
291
292             // Increment the occurrence
293             $occurrence++;
294         }
295     }
296
297 } // End Calendar Event
298
Note: See TracBrowser for help on using the browser.