PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/core/calendar.php

https://github.com/smgladkovskiy/kohana_calendar
PHP | 361 lines | 178 code | 55 blank | 128 comment | 17 complexity | 328c3cbfc74a4e89879a198ee700a709 MD5 | raw file
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * Calendar creation library.
  4. *
  5. * $Id: Calendar.php 3769 2008-12-15 00:48:56Z zombor $
  6. *
  7. * @package Calendar
  8. * @author Kohana Team, Anton Pawlik
  9. * @author Sergei Gladkovskiy <smgladkovskiy@gmail.com>
  10. * @copyright (c) 2007-2008 Kohana Team
  11. * @license http://kohanaphp.com/license.html
  12. */
  13. abstract class Core_Calendar extends Event_Subject {
  14. // Start the calendar on Sunday by default
  15. public static $start_monday = TRUE;
  16. // Month and year to use for calendaring
  17. protected $month;
  18. protected $year;
  19. // Week starts on Sunday
  20. protected $week_start = 0;
  21. // Observed data
  22. protected $observed_data;
  23. /**
  24. * Returns an array of the names of the days, using the current locale.
  25. *
  26. * @static
  27. * @param int|bool $length length of days names
  28. * @return array
  29. */
  30. public static function days($length = TRUE)
  31. {
  32. $days = array();
  33. // strftime day format
  34. $format = ($length > 3) ? '%A' : '%a';
  35. // Days of the week
  36. for ($i = 0; $i < 7; $i++)
  37. {
  38. $days[] = strftime($format, ($i * 86400 + 300000));
  39. }
  40. if (Calendar::$start_monday === TRUE)
  41. {
  42. // Push Sunday to the end of the days
  43. array_push($days, array_shift($days));
  44. }
  45. if (is_int($length) OR ctype_digit($length))
  46. {
  47. foreach ($days as $i => $day)
  48. {
  49. // Shorten the days to the expected length
  50. $days[$i] = utf8::substr($day, 0, $length);
  51. }
  52. }
  53. return $days;
  54. }
  55. /**
  56. * Create a new Calendar instance. A month and year can be specified.
  57. * By default, the current month and year are used.
  58. *
  59. * @static
  60. * @param int|null $month number
  61. * @param int|null $year number
  62. * @return Calendar
  63. */
  64. public static function factory($month = NULL, $year = NULL)
  65. {
  66. return new Calendar($month, $year);
  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 int|null $month number
  73. * @param int|null $year number
  74. */
  75. public function __construct($month = NULL, $year = NULL)
  76. {
  77. empty($month) and $month = date('n'); // Current month
  78. empty($year) and $year = date('Y'); // Current year
  79. // Set the month and year
  80. $this->month = (int) $month;
  81. $this->year = (int) $year;
  82. if (Calendar::$start_monday === TRUE)
  83. {
  84. // Week starts on Monday
  85. $this->week_start = 1;
  86. }
  87. }
  88. /**
  89. * Allows fetching the current month and year.
  90. *
  91. * @param string $key
  92. * @return mixed
  93. */
  94. public function __get($key)
  95. {
  96. if ($key === 'month' OR $key === 'year')
  97. {
  98. return $this->$key;
  99. }
  100. return NULL;
  101. }
  102. /**
  103. * Event factory method.
  104. *
  105. * @param string|null $name unique name of the event
  106. * @return Event
  107. */
  108. public function event($name = NULL)
  109. {
  110. return new Event($this);
  111. }
  112. /**
  113. * Event factory method.
  114. *
  115. * @chainable
  116. * @param string $name
  117. * @return Calendar
  118. */
  119. public function standard($name)
  120. {
  121. switch ($name)
  122. {
  123. case 'today':
  124. // Add an event for the current day
  125. $this->attach($this->event()->condition('timestamp', strtotime('today'))->add_class('today'));
  126. break;
  127. case 'prev-next':
  128. // Add an event for padding days
  129. $this->attach($this->event()->condition('current', FALSE)->add_class('prev-next'));
  130. break;
  131. case 'holidays':
  132. // Base event
  133. $event = $this->event()->condition('current', TRUE)->add_class('holiday');
  134. // Attach New Years
  135. $holiday = clone $event;
  136. $this->attach($holiday->condition('month', 1)->condition('day', 1));
  137. // Attach Valentine's Day
  138. $holiday = clone $event;
  139. $this->attach($holiday->condition('month', 2)->condition('day', 14));
  140. // Attach St. Patrick's Day
  141. $holiday = clone $event;
  142. $this->attach($holiday->condition('month', 3)->condition('day', 17));
  143. // Attach Easter
  144. $holiday = clone $event;
  145. $this->attach($holiday->condition('easter', TRUE));
  146. // Attach Memorial Day
  147. $holiday = clone $event;
  148. $this->attach($holiday->condition('month', 5)->condition('day_of_week', 1)->condition('last_occurrence', TRUE));
  149. // Attach Independance Day
  150. $holiday = clone $event;
  151. $this->attach($holiday->condition('month', 7)->condition('day', 4));
  152. // Attach Labor Day
  153. $holiday = clone $event;
  154. $this->attach($holiday->condition('month', 9)->condition('day_of_week', 1)->condition('occurrence', 1));
  155. // Attach Halloween
  156. $holiday = clone $event;
  157. $this->attach($holiday->condition('month', 10)->condition('day', 31));
  158. // Attach Thanksgiving
  159. $holiday = clone $event;
  160. $this->attach($holiday->condition('month', 11)->condition('day_of_week', 4)->condition('occurrence', 4));
  161. // Attach Christmas
  162. $holiday = clone $event;
  163. $this->attach($holiday->condition('month', 12)->condition('day', 25));
  164. break;
  165. case 'weekends':
  166. // Weekend events
  167. $this->attach($this->event()->condition('weekend', TRUE)->add_class('weekend'));
  168. break;
  169. }
  170. return $this;
  171. }
  172. /**
  173. * Returns an array for use with a view. The array contains an array for
  174. * each week. Each week contains 7 arrays, with a day number and status:
  175. * TRUE if the day is in the month, FALSE if it is padding.
  176. *
  177. * @return array
  178. */
  179. public function weeks()
  180. {
  181. // First day of the month as a timestamp
  182. $first = mktime(1, 0, 0, $this->month, 1, $this->year);
  183. // Total number of days in this month
  184. $total = (int) date('t', $first);
  185. // Last day of the month as a timestamp
  186. $last = mktime(1, 0, 0, $this->month, $total, $this->year);
  187. // Make the month and week empty arrays
  188. $month = $week = array();
  189. // Number of days added. When this reaches 7, start a new week
  190. $days = 0;
  191. $week_number = 1;
  192. if (($w = (int) date('w', $first) - $this->week_start) < 0)
  193. {
  194. $w = 6;
  195. }
  196. if ($w > 0)
  197. {
  198. // Number of days in the previous month
  199. $n = (int) date('t', mktime(1, 0, 0, $this->month - 1, 1, $this->year));
  200. // i = number of day, t = number of days to pad
  201. for ($i = $n - $w + 1, $t = $w; $t > 0; $t--, $i++)
  202. {
  203. // Notify the listeners
  204. $this->notify(array($this->month - 1, $i, $this->year, $week_number, FALSE));
  205. // Add previous month padding days
  206. $week[] = array($i, FALSE, $this->observed_data);
  207. $days++;
  208. }
  209. }
  210. // i = number of day
  211. for ($i = 1; $i <= $total; $i++)
  212. {
  213. if ($days % 7 === 0 && $days !== 0)
  214. {
  215. // Start a new week
  216. $month[] = $week;
  217. $week = array();
  218. $week_number++;
  219. }
  220. // Notify the listeners
  221. $this->notify(array($this->month, $i, $this->year, $week_number, TRUE));
  222. // Add days to this month
  223. $week[] = array($i, TRUE, $this->observed_data);
  224. $days++;
  225. }
  226. if (($w = (int) date('w', $last) - $this->week_start) < 0)
  227. {
  228. $w = 6;
  229. }
  230. if ($w >= 0)
  231. {
  232. // i = number of day, t = number of days to pad
  233. for ($i = 1, $t = 6 - $w; $t > 0; $t--, $i++)
  234. {
  235. // Notify the listeners
  236. $this->notify(array($this->month + 1, $i, $this->year, $week_number, FALSE));
  237. // Add next month padding days
  238. $week[] = array($i, FALSE, $this->observed_data);
  239. }
  240. }
  241. if ( ! empty($week))
  242. {
  243. // Append the remaining days
  244. $month[] = $week;
  245. }
  246. return $month;
  247. }
  248. /**
  249. * Adds new data from an observer. All event data contains and array of CSS
  250. * classes and an array of output messages.
  251. *
  252. * @param array $data
  253. * @return void
  254. */
  255. public function add_data(array $data)
  256. {
  257. // Add new classes
  258. $this->observed_data['classes'] += $data['classes'];
  259. if ( ! empty($data['output']))
  260. {
  261. // Only add output if it's not empty
  262. $this->observed_data['output'][] = $data['output'];
  263. }
  264. }
  265. /**
  266. * Resets the observed data and sends a notify to all attached events.
  267. *
  268. * @param array $data
  269. * @return void
  270. */
  271. public function notify($data)
  272. {
  273. // Reset observed data
  274. $this->observed_data = array
  275. (
  276. 'classes' => array(),
  277. 'output' => array(),
  278. );
  279. // Send a notify
  280. parent::notify($data);
  281. }
  282. /**
  283. * Convert the calendar to HTML using the kohana_calendar view.
  284. * @param string $tmpl
  285. * @return string
  286. */
  287. public function render($tmpl = 'calendar')
  288. {
  289. $view = new View($tmpl, array
  290. (
  291. 'month' => $this->month,
  292. 'year' => $this->year,
  293. 'weeks' => $this->weeks(),
  294. ));
  295. return $view->render();
  296. }
  297. /**
  298. * Magically convert this object to a string, the rendered calendar.
  299. *
  300. * @return string
  301. */
  302. public function __toString()
  303. {
  304. return $this->render();
  305. }
  306. } // End Core_Calendar