PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Calendar_Event.php

https://github.com/robertleeplummerjr/bluebox
PHP | 297 lines | 153 code | 38 blank | 106 comment | 15 complexity | 4ef81fe10e860d4d583d7edcc6fa1355 MD5 | raw file
  1. <?php defined('SYSPATH') OR die('No direct access allowed.');
  2. /**
  3. * Calendar event observer class.
  4. *
  5. * $Id: Calendar_Event.php 3769 2008-12-15 00:48:56Z zombor $
  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. // Boolean conditions
  14. protected $booleans = array
  15. (
  16. 'current',
  17. 'weekend',
  18. 'first_day',
  19. 'last_day',
  20. 'last_occurrence',
  21. 'easter',
  22. );
  23. // Rendering conditions
  24. protected $conditions = array();
  25. // Cell classes
  26. protected $classes = array();
  27. // Cell output
  28. protected $output = '';
  29. /**
  30. * Adds a condition to the event. The condition can be one of the following:
  31. *
  32. * timestamp - UNIX timestamp
  33. * day - day number (1-31)
  34. * week - week number (1-5)
  35. * month - month number (1-12)
  36. * year - year number (4 digits)
  37. * day_of_week - day of week (1-7)
  38. * current - active month (boolean) (only show data for the month being rendered)
  39. * weekend - weekend day (boolean)
  40. * first_day - first day of month (boolean)
  41. * last_day - last day of month (boolean)
  42. * occurrence - occurrence of the week day (1-5) (use with "day_of_week")
  43. * last_occurrence - last occurrence of week day (boolean) (use with "day_of_week")
  44. * easter - Easter day (boolean)
  45. * callback - callback test (boolean)
  46. *
  47. * To unset a condition, call condition with a value of NULL.
  48. *
  49. * @chainable
  50. * @param string condition key
  51. * @param mixed condition value
  52. * @return object
  53. */
  54. public function condition($key, $value)
  55. {
  56. if ($value === NULL)
  57. {
  58. unset($this->conditions[$key]);
  59. }
  60. else
  61. {
  62. if ($key === 'callback')
  63. {
  64. // Do nothing
  65. }
  66. elseif (in_array($key, $this->booleans))
  67. {
  68. // Make the value boolean
  69. $value = (bool) $value;
  70. }
  71. else
  72. {
  73. // Make the value an int
  74. $value = (int) $value;
  75. }
  76. $this->conditions[$key] = $value;
  77. }
  78. return $this;
  79. }
  80. /**
  81. * Add a CSS class for this event. This can be called multiple times.
  82. *
  83. * @chainable
  84. * @param string CSS class name
  85. * @return object
  86. */
  87. public function add_class($class)
  88. {
  89. $this->classes[$class] = $class;
  90. return $this;
  91. }
  92. /**
  93. * Remove a CSS class for this event. This can be called multiple times.
  94. *
  95. * @chainable
  96. * @param string CSS class name
  97. * @return object
  98. */
  99. public function remove_class($class)
  100. {
  101. unset($this->classes[$class]);
  102. return $this;
  103. }
  104. /**
  105. * Set HTML output for this event.
  106. *
  107. * @chainable
  108. * @param string HTML output
  109. * @return object
  110. */
  111. public function output($str)
  112. {
  113. $this->output = $str;
  114. return $this;
  115. }
  116. /**
  117. * Add a CSS class for this event. This can be called multiple times.
  118. *
  119. * @chainable
  120. * @param string CSS class name
  121. * @return object
  122. */
  123. public function notify($data)
  124. {
  125. // Split the date and current status
  126. list ($month, $day, $year, $week, $current) = $data;
  127. // Get a timestamp for the day
  128. $timestamp = mktime(0, 0, 0, $month, $day, $year);
  129. // Date conditionals
  130. $condition = array
  131. (
  132. 'timestamp' => (int) $timestamp,
  133. 'day' => (int) date('j', $timestamp),
  134. 'week' => (int) $week,
  135. 'month' => (int) date('n', $timestamp),
  136. 'year' => (int) date('Y', $timestamp),
  137. 'day_of_week' => (int) date('w', $timestamp),
  138. 'current' => (bool) $current,
  139. );
  140. // Tested conditions
  141. $tested = array();
  142. foreach ($condition as $key => $value)
  143. {
  144. // Test basic conditions first
  145. if (isset($this->conditions[$key]) AND $this->conditions[$key] !== $value)
  146. return FALSE;
  147. // Condition has been tested
  148. $tested[$key] = TRUE;
  149. }
  150. if (isset($this->conditions['weekend']))
  151. {
  152. // Weekday vs Weekend
  153. $condition['weekend'] = ($condition['day_of_week'] === 0 OR $condition['day_of_week'] === 6);
  154. }
  155. if (isset($this->conditions['first_day']))
  156. {
  157. // First day of month
  158. $condition['first_day'] = ($condition['day'] === 1);
  159. }
  160. if (isset($this->conditions['last_day']))
  161. {
  162. // Last day of month
  163. $condition['last_day'] = ($condition['day'] === (int) date('t', $timestamp));
  164. }
  165. if (isset($this->conditions['occurrence']))
  166. {
  167. // Get the occurance of the current day
  168. $condition['occurrence'] = $this->day_occurrence($timestamp);
  169. }
  170. if (isset($this->conditions['last_occurrence']))
  171. {
  172. // Test if the next occurance of this date is next month
  173. $condition['last_occurrence'] = ((int) date('n', $timestamp + 604800) !== $condition['month']);
  174. }
  175. if (isset($this->conditions['easter']))
  176. {
  177. if ($condition['month'] === 3 OR $condition['month'] === 4)
  178. {
  179. // This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
  180. // Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
  181. // 1876. This algorithm has also been published in the 1922 book General Astronomy by
  182. // Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
  183. // 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus.
  184. $a = $condition['year'] % 19;
  185. $b = (int) ($condition['year'] / 100);
  186. $c = $condition['year'] % 100;
  187. $d = (int) ($b / 4);
  188. $e = $b % 4;
  189. $f = (int) (($b + 8) / 25);
  190. $g = (int) (($b - $f + 1) / 3);
  191. $h = (19 * $a + $b - $d - $g + 15) % 30;
  192. $i = (int) ($c / 4);
  193. $k = $c % 4;
  194. $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7;
  195. $m = (int) (($a + 11 * $h + 22 * $l) / 451);
  196. $p = ($h + $l - 7 * $m + 114) % 31;
  197. $month = (int) (($h + $l - 7 * $m + 114) / 31);
  198. $day = $p + 1;
  199. $condition['easter'] = ($condition['month'] === $month AND $condition['day'] === $day);
  200. }
  201. else
  202. {
  203. // Easter can only happen in March or April
  204. $condition['easter'] = FALSE;
  205. }
  206. }
  207. if (isset($this->conditions['callback']))
  208. {
  209. // Use a callback to determine validity
  210. $condition['callback'] = call_user_func($this->conditions['callback'], $condition, $this);
  211. }
  212. $conditions = array_diff_key($this->conditions, $tested);
  213. foreach ($conditions as $key => $value)
  214. {
  215. if ($key === 'callback')
  216. {
  217. // Callbacks are tested on a TRUE/FALSE basis
  218. $value = TRUE;
  219. }
  220. // Test advanced conditions
  221. if ($condition[$key] !== $value)
  222. return FALSE;
  223. }
  224. $this->caller->add_data(array
  225. (
  226. 'classes' => $this->classes,
  227. 'output' => $this->output,
  228. ));
  229. }
  230. /**
  231. * Find the week day occurrence for a specific timestamp. The occurrence is
  232. * relative to the current month. For example, the second Saturday of any
  233. * given month will return "2" as the occurrence. This is used in combination
  234. * with the "occurrence" condition.
  235. *
  236. * @param integer UNIX timestamp
  237. * @return integer
  238. */
  239. protected function day_occurrence($timestamp)
  240. {
  241. // Get the current month for the timestamp
  242. $month = date('m', $timestamp);
  243. // Default occurrence is one
  244. $occurrence = 1;
  245. // Reduce the timestamp by one week for each loop. This has the added
  246. // benefit of preventing an infinite loop.
  247. while ($timestamp -= 604800)
  248. {
  249. if (date('m', $timestamp) !== $month)
  250. {
  251. // Once the timestamp has gone into the previous month, the
  252. // proper occurrence has been found.
  253. return $occurrence;
  254. }
  255. // Increment the occurrence
  256. $occurrence++;
  257. }
  258. }
  259. } // End Calendar Event