root/trunk/system/libraries/Calendar.php

Revision 3186, 8.3 kB (checked in by Shadowhand, 3 days ago)

Follow up to r3185, week_start fixes

  • Property svn:eol-style set to LF
  • Property copyright set to Copyright (c) 2007 Kohana Team
  • Property svn:keywords set to Id
Line 
1 <?php defined('SYSPATH') or die('No direct script access.');
2 /**
3  * Calendar creation library.
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_Core extends Event_Subject {
13
14     // Start the calendar on Sunday by default
15     public static $start_monday = FALSE;
16
17     // Month and year to use for calendaring
18     protected $month;
19     protected $year;
20
21     // Week starts on Sunday
22     protected $week_start = 0;
23
24     // Observed data
25     protected $observed_data;
26
27     /**
28      * Returns an array of the names of the days, using the current locale.
29      *
30      * @param   boolean  return short names
31      * @return  array
32      */
33     public static function days($short = FALSE)
34     {
35         // strftime day format
36         $format = ($short == TRUE) ? '%a' : '%A';
37
38         // Days of the week
39         $days = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
40
41         if (Calendar::$start_monday === TRUE)
42         {
43             // Push Sunday to the end of the days
44             array_push($days, array_shift($days));
45         }
46
47         if (strpos(Kohana::config('locale.language.0'), 'en') !== 0)
48         {
49             // This is a bit awkward, but it works properly and is reliable
50             foreach ($days as $i => $day)
51             {
52                 // Convert the English names to i18n names
53                 $days[$i] = strftime($format, strtotime($day));
54             }
55         }
56         elseif ($short == TRUE)
57         {
58             foreach ($days as $i => $day)
59             {
60                 // Shorten the day names to 3 letters
61                 $days[$i] = substr($day, 0, 3);
62             }
63         }
64
65         return $days;
66     }
67
68     /**
69      * Create a new Calendar instance. A month and year can be specified.
70      * By default, the current month and year are used.
71      *
72      * @param   integer  month number
73      * @param   integer  year number
74      * @return  object
75      */
76     public static function factory($month = NULL, $year = NULL)
77     {
78         return new Calendar($month, $year);
79     }
80
81     /**
82      * Create a new Calendar instance. A month and year can be specified.
83      * By default, the current month and year are used.
84      *
85      * @param   integer  month number
86      * @param   integer  year number
87      * @return  void
88      */
89     public function __construct($month = NULL, $year = NULL)
90     {
91         empty($month) and $month = date('n'); // Current month
92         empty($year)  and $year  = date('Y'); // Current year
93
94         // Set the month and year
95         $this->month = (int) $month;
96         $this->year  = (int) $year;
97
98         if (Calendar::$start_monday === TRUE)
99         {
100             // Week starts on Monday
101             $this->week_start = 1;
102         }
103     }
104
105     /**
106      * Allows fetching the current month and year.
107      *
108      * @param   string  key to get
109      * @return  mixed
110      */
111     public function __get($key)
112     {
113         if ($key === 'month' OR $key === 'year')
114         {
115             return $this->$key;
116         }
117     }
118
119     /**
120      * Calendar_Event factory method.
121      *
122      * @param   string  unique name for the event
123      * @return  object  Calendar_Event
124      */
125     public function event($name = NULL)
126     {
127         return new Calendar_Event($this);
128     }
129
130     /**
131      * Calendar_Event factory method.
132      *
133      * @chainable
134      * @param   string  standard event type
135      * @return  object
136      */
137     public function standard($name)
138     {
139         switch ($name)
140         {
141             case 'today':
142                 // Add an event for the current day
143                 $this->attach($this->event()->condition('timestamp', strtotime('today'))->add_class('today'));
144             break;
145             case 'prev-next':
146                 // Add an event for padding days
147                 $this->attach($this->event()->condition('current', FALSE)->add_class('prev-next'));
148             break;
149             case 'holidays':
150                 // Base event
151                 $event = $this->event()->condition('current', TRUE)->add_class('holiday');
152
153                 // Attach New Years
154                 $holiday = clone $event;
155                 $this->attach($holiday->condition('month', 1)->condition('day', 1));
156
157                 // Attach Valentine's Day
158                 $holiday = clone $event;
159                 $this->attach($holiday->condition('month', 2)->condition('day', 14));
160
161                 // Attach St. Patrick's Day
162                 $holiday = clone $event;
163                 $this->attach($holiday->condition('month', 3)->condition('day', 17));
164
165                 // Attach Easter
166                 $holiday = clone $event;
167                 $this->attach($holiday->condition('easter', TRUE));
168
169                 // Attach Memorial Day
170                 $holiday = clone $event;
171                 $this->attach($holiday->condition('month', 5)->condition('day_of_week', 1)->condition('last_occurrence', TRUE));
172
173                 // Attach Independance Day
174                 $holiday = clone $event;
175                 $this->attach($holiday->condition('month', 7)->condition('day', 4));
176
177                 // Attach Labor Day
178                 $holiday = clone $event;
179                 $this->attach($holiday->condition('month', 9)->condition('day_of_week', 1)->condition('occurrence', 1));
180
181                 // Attach Halloween
182                 $holiday = clone $event;
183                 $this->attach($holiday->condition('month', 10)->condition('day', 31));
184
185                 // Attach Thanksgiving
186                 $holiday = clone $event;
187                 $this->attach($holiday->condition('month', 11)->condition('day_of_week', 4)->condition('occurrence', 4));
188
189                 // Attach Christmas
190                 $holiday = clone $event;
191                 $this->attach($holiday->condition('month', 12)->condition('day', 25));
192             break;
193             case 'weekends':
194                 // Weekend events
195                 $this->attach($this->event()->condition('weekend', TRUE)->add_class('weekend'));
196             break;
197         }
198
199         return $this;
200     }
201
202     /**
203      * Returns an array for use with a view. The array contains an array for
204      * each week. Each week contains 7 arrays, with a day number and status:
205      * TRUE if the day is in the month, FALSE if it is padding.
206      *
207      * @return  array
208      */
209     public function weeks()
210     {
211         // First day of the month as a timestamp
212         $first = mktime(1, 0, 0, $this->month, 1, $this->year);
213
214         // Total number of days in this month
215         $total = (int) date('t', $first);
216
217         // Last day of the month as a timestamp
218         $last  = mktime(1, 0, 0, $this->month, $total, $this->year);
219
220         // Make the month and week empty arrays
221         $month = $week = array();
222
223         // Number of days added. When this reaches 7, start a new month
224         $days = 0;
225         $week_number = 1;
226
227         if (($w = (int) date('w', $first)) > $this->week_start)
228         {
229             // Number of days in the previous month
230             $n = (int) date('t', mktime(1, 0, 0, $this->month - 1, 1, $this->year));
231
232             // i = number of day, t = number of days to pad
233             for ($i = $n - $w + $this->week_start + 1, $t = $w - $this->week_start; $t > 0; $t--, $i++)
234             {
235                 // Notify the listeners
236                 $this->notify(array($this->month - 1, $i, $this->year, $week_number, FALSE));
237
238                 // Add previous month padding days
239                 $week[] = array($i, FALSE, $this->observed_data);
240                 $days++;
241             }
242         }
243
244         // i = number of day
245         for ($i = 1; $i <= $total; $i++)
246         {
247             if ($days % 7 === 0)
248             {
249                 // Start a new week
250                 $month[] = $week;
251                 $week = array();
252
253                 $week_number++;
254             }
255
256             // Notify the listeners
257             $this->notify(array($this->month, $i, $this->year, $week_number, TRUE));
258
259             // Add days to this month
260             $week[] = array($i, TRUE, $this->observed_data);
261             $days++;
262         }
263
264         if (($w = (int) date('w', $last) - $this->week_start) < 6 AND $w > -1)
265         {
266             // i = number of day, t = number of days to pad
267             for ($i = 1, $t = 6 - $w; $t > 0; $t--, $i++)
268             {
269                 // Notify the listeners
270                 $this->notify(array($this->month + 1, $i, $this->year, $week_number, FALSE));
271
272                 // Add next month padding days
273                 $week[] = array($i, FALSE, $this->observed_data);
274             }
275         }
276
277         if ( ! empty($week))
278         {
279             // Append the remaining days
280             $month[] = $week;
281         }
282
283         return $month;
284     }
285
286     /**
287      * Adds new data from an observer. All event data contains and array of CSS
288      * classes and an array of output messages.
289      *
290      * @param   array  observer data.
291      * @return  void
292      */
293     public function add_data(array $data)
294     {
295         // Add new classes
296         $this->observed_data['classes'] += $data['classes'];
297
298         if ( ! empty($data['output']))
299         {
300             // Only add output if it's not empty
301             $this->observed_data['output'][] = $data['output'];
302         }
303     }
304
305     /**
306      * Resets the observed data and sends a notify to all attached events.
307      *
308      * @param   array  UNIX timestamp
309      * @return  void
310      */
311     public function notify($data)
312     {
313         // Reset observed data
314         $this->observed_data = array
315         (
316             'classes' => array(),
317             'output' => array(),
318         );
319
320         // Send a notify
321         parent::notify($data);
322     }
323
324     /**
325      * Convert the calendar to HTML using the kohana_calendar view.
326      *
327      * @return  string
328      */
329     public function render()
330     {
331         $view =  new View('kohana_calendar', array
332         (
333             'month'  => $this->month,
334             'year'   => $this->year,
335             'weeks'  => $this->weeks(),
336         ));
337
338         return $view->render();
339     }
340
341     /**
342      * Magically convert this object to a string, the rendered calendar.
343      *
344      * @return  string
345      */
346     public function __toString()
347     {
348         return $this->render();
349     }
350
351 } // End Calendar
Note: See TracBrowser for help on using the browser.