/wp-content/plugins/google-calendar-events/includes/events/events.php

https://github.com/livinglab/openlab · PHP · 608 lines · 245 code · 43 blank · 320 comment · 27 complexity · ac2aebcb1dc3e55292a2fbc9c1fc6038 MD5 · raw file

  1. <?php
  2. /**
  3. * Events Collection
  4. *
  5. * @package SimpleCalendar/Events
  6. */
  7. namespace SimpleCalendar\Events;
  8. use SimpleCalendar\plugin_deps\Carbon\Carbon;
  9. use SimpleCalendar\plugin_deps\DateTime;
  10. use SimpleCalendar\plugin_deps\DateTimeZone;
  11. if ( ! defined( 'ABSPATH' ) ) {
  12. exit;
  13. }
  14. /**
  15. * The Events.
  16. *
  17. * A collection of Event objects.
  18. *
  19. * @since 3.0.0
  20. */
  21. class Events {
  22. /**
  23. * Events.
  24. *
  25. * @access public
  26. * @var array
  27. */
  28. protected $events = array();
  29. /**
  30. * Timezone.
  31. *
  32. * @access public
  33. * @var string
  34. */
  35. protected $timezone = 'UTC';
  36. /**
  37. * Constructor.
  38. *
  39. * @since 3.0.0
  40. *
  41. * @param array $e Events.
  42. * @param string|\DateTimeZone $tz Timezone.
  43. */
  44. public function __construct( $e = array(), $tz = 'UTC' ) {
  45. $this->set_events( $e );
  46. $this->set_timezone( $tz );
  47. }
  48. /**
  49. * Get events.
  50. *
  51. * @since 3.0.0
  52. *
  53. * @param string|int $n Amount of events (optional).
  54. *
  55. * @return array
  56. */
  57. public function get_events( $n = '' ) {
  58. if ( ! empty( $n ) && ! empty( $this->events ) ) {
  59. $length = absint( $n );
  60. return array_slice( $this->events, 0, $length, true );
  61. }
  62. return $this->events;
  63. }
  64. /**
  65. * Set events.
  66. *
  67. * @since 3.0.0
  68. *
  69. * @param array $ev Events.
  70. */
  71. public function set_events( array $ev ) {
  72. $this->events = $ev;
  73. }
  74. /**
  75. * Set timezone.
  76. *
  77. * @since 3.0.0
  78. *
  79. * @param string|\DateTimeZone $tz Timezone.
  80. *
  81. * @return Events
  82. */
  83. public function set_timezone( $tz ) {
  84. if ( $tz instanceof DateTimeZone ) {
  85. $tz = $tz->getName();
  86. }
  87. $this->timezone = simcal_esc_timezone( $tz, $this->timezone );
  88. return $this;
  89. }
  90. /**
  91. * Shift events.
  92. *
  93. * @since 3.0.0
  94. *
  95. * @param int $n
  96. *
  97. * @return Events
  98. */
  99. public function shift( $n ) {
  100. if ( ! empty( $this->events ) ) {
  101. $offset = intval( $n );
  102. $length = count( $this->events );
  103. $this->set_events( array_slice( $this->events, $offset, $length, true ) );
  104. }
  105. return $this;
  106. }
  107. /**
  108. * Filter private events.
  109. *
  110. * @since 3.0.0
  111. *
  112. * @return Events
  113. */
  114. public function private_only() {
  115. $this->set_events( $this->filter_property( 'public', 'hide' ) );
  116. return $this;
  117. }
  118. /**
  119. * Filter public events.
  120. *
  121. * @since 3.0.0
  122. *
  123. * @return Events
  124. */
  125. public function public_only() {
  126. $this->set_events( $this->filter_property( 'public', 'show' ) );
  127. return $this;
  128. }
  129. /**
  130. * Filter recurring events in the current block.
  131. *
  132. * @since 3.0.0
  133. *
  134. * @return Events
  135. */
  136. public function recurring() {
  137. $this->set_events( $this->filter_property( 'recurrence', 'show' ) );
  138. return $this;
  139. }
  140. /**
  141. * Filter non recurring events in the current block.
  142. *
  143. * @since 3.0.0
  144. *
  145. * @return Events
  146. */
  147. public function not_recurring() {
  148. $this->set_events( $this->filter_property( 'recurrence', 'hide' ) );
  149. return $this;
  150. }
  151. /**
  152. * Filter whole day events in the current block.
  153. *
  154. * @since 3.0.0
  155. *
  156. * @return Events
  157. */
  158. public function whole_day() {
  159. $this->set_events( $this->filter_property( 'whole_day', 'show' ) );
  160. return $this;
  161. }
  162. /**
  163. * Filter non whole day in the current block.
  164. *
  165. * @since 3.0.0
  166. *
  167. * @return Events
  168. */
  169. public function not_whole_day() {
  170. $this->set_events( $this->filter_property( 'whole_day', 'hide' ) );
  171. return $this;
  172. }
  173. /**
  174. * Filter events spanning multiple days in the current block.
  175. *
  176. * @since 3.0.0
  177. *
  178. * @return Events
  179. */
  180. public function multi_day() {
  181. $this->set_events( $this->filter_property( 'multiple_days', 'show' ) );
  182. return $this;
  183. }
  184. /**
  185. * Filter events that do not span multiple days in the current block.
  186. *
  187. * @since 3.0.0
  188. *
  189. * @return Events
  190. */
  191. public function single_day() {
  192. $this->set_events( $this->filter_property( 'multiple_days', 'hide' ) );
  193. return $this;
  194. }
  195. /**
  196. * Filter events in the current block that have a location.
  197. *
  198. * @since 3.0.0
  199. *
  200. * @return Events
  201. */
  202. public function with_location() {
  203. $this->set_events( $this->filter_property( 'venue', 'show' ) );
  204. return $this;
  205. }
  206. /**
  207. * Filter events in the current block that do not have a location.
  208. *
  209. * @since 3.0.0
  210. *
  211. * @return Events
  212. */
  213. public function without_location() {
  214. $this->set_events( $this->filter_property( 'venue', 'hide' ) );
  215. return $this;
  216. }
  217. /**
  218. * Filter whole day events.
  219. *
  220. * @since 3.0.0
  221. * @access private
  222. *
  223. * @param string $property
  224. * @param string $toggle
  225. *
  226. * @return array
  227. */
  228. private function filter_property( $property, $toggle ) {
  229. $filtered = array();
  230. if ( ! empty( $this->events ) ) {
  231. foreach ( $this->events as $ts => $events ) {
  232. foreach ( $events as $event ) {
  233. if ( 'hide' == $toggle ) {
  234. if ( ! $event->$property ) {
  235. $filtered[ $ts ][] = $event;
  236. }
  237. } elseif ( 'show' == $toggle ) {
  238. if ( $event->$property ) {
  239. $filtered[ $ts ][] = $event;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. return $filtered;
  246. }
  247. /**
  248. * Filter events in the past.
  249. *
  250. * @since 3.0.0
  251. *
  252. * @param int|string $present
  253. *
  254. * @return Events
  255. */
  256. public function future( $present = '' ) {
  257. $last = $this->get_last();
  258. $to = $last instanceof Event ? $last->start_utc : false;
  259. if ( $to ) {
  260. if ( empty( $present ) ) {
  261. $present = Carbon::now( $this->timezone )->getTimestamp();
  262. }
  263. $this->set_events( $this->filter_events( intval( $present ), $to ) );
  264. }
  265. return $this;
  266. }
  267. /**
  268. * Filter events in the future.
  269. *
  270. * @since 3.0.0
  271. *
  272. * @param int|string $present
  273. *
  274. * @return Events
  275. */
  276. public function past( $present = '' ) {
  277. $first = $this->get_last();
  278. $from = $first instanceof Event ? $first->start_utc : false;
  279. if ( $from ) {
  280. if ( empty( $present ) ) {
  281. $present = Carbon::now( $this->timezone )->getTimestamp();
  282. }
  283. $this->set_events( $this->filter_events( $from, intval( $present ) ) );
  284. }
  285. return $this;
  286. }
  287. /**
  288. * Filter events after time.
  289. *
  290. * @since 3.0.0
  291. *
  292. * @param int|string|\DateTime|Carbon $time
  293. *
  294. * @return Events
  295. */
  296. public function after( $time ) {
  297. $dt = $this->parse( $time );
  298. return ! is_null( $dt ) ? $this->future( $dt->getTimestamp() ) : $this;
  299. }
  300. /**
  301. * Filter events before time.
  302. *
  303. * @since 3.0.0
  304. *
  305. * @param int|string|\DateTime|Carbon $time
  306. *
  307. * @return Events
  308. */
  309. public function before( $time ) {
  310. $dt = $this->parse( $time );
  311. return ! is_null( $dt ) ? $this->past( $dt->getTimestamp() ) : $this;
  312. }
  313. /**
  314. * Filter events from a certain time onwards.
  315. *
  316. * @since 3.0.0
  317. *
  318. * @param int|string|\DateTime|Carbon $time
  319. *
  320. * @return Events
  321. */
  322. public function from( $time ) {
  323. $last = $this->parse( $time );
  324. if ( ! is_null( $last ) ) {
  325. $this->set_events( $this->filter_events( $time, $last->getTimestamp() ) );
  326. }
  327. return $this;
  328. }
  329. /**
  330. * Filter events up to to a certain time.
  331. *
  332. * @since 3.0.0
  333. *
  334. * @param int|string|\DateTime|Carbon $time
  335. *
  336. * @return Events
  337. */
  338. public function to( $time ) {
  339. $first = $this->parse( $time );
  340. if ( ! is_null( $first ) ) {
  341. $this->set_events( $this->filter_events( $first->getTimestamp(), $time ) );
  342. }
  343. return $this;
  344. }
  345. /**
  346. * Parse time.
  347. *
  348. * @since 3.0.0
  349. *
  350. * @param int|string|\DateTime|Carbon $time
  351. *
  352. * @return null|Carbon
  353. */
  354. private function parse( $time ) {
  355. if ( is_int( $time ) ) {
  356. return Carbon::createFromTimestamp( $time, $this->timezone );
  357. } elseif ( is_string( $time ) && ! empty( $time ) ) {
  358. return Carbon::parse( $time, $this->timezone );
  359. } elseif ( $time instanceof Carbon ) {
  360. return $time->setTimezone( $this->timezone );
  361. } elseif ( $time instanceof DateTime ) {
  362. return Carbon::instance( $time )->setTimezone( $this->timezone );
  363. }
  364. return null;
  365. }
  366. /**
  367. * Get first event of the current block.
  368. *
  369. * @since 3.0.0
  370. *
  371. * @return null|Event
  372. */
  373. public function get_first() {
  374. return array_shift( $this->events );
  375. }
  376. /**
  377. * Get last event of the current block.
  378. *
  379. * @since 3.0.0
  380. *
  381. * @return null|Event
  382. */
  383. public function get_last() {
  384. return array_pop( $this->events );
  385. }
  386. /**
  387. * Get the closest event in the future.
  388. *
  389. * @since 3.0.0
  390. *
  391. * @return null|Event
  392. */
  393. public function get_upcoming() {
  394. return $this->get_closest( 'future' );
  395. }
  396. /**
  397. * Get the closest event in the past.
  398. *
  399. * @since 3.0.0
  400. *
  401. * @return null|Event
  402. */
  403. public function get_latest() {
  404. return $this->get_closest( 'past' );
  405. }
  406. /**
  407. * Get the closest event compared to now.
  408. *
  409. * @since 3.0.0
  410. * @access private
  411. *
  412. * @param string $dir Direction: 'future' or 'past'.
  413. *
  414. * @return null|Event
  415. */
  416. private function get_closest( $dir ) {
  417. if ( 'future' == $dir ) {
  418. return array_shift( $this->future()->get_events() );
  419. } elseif ( 'past' == $dir ) {
  420. return array_shift( $this->past()->get_events() );
  421. }
  422. return null;
  423. }
  424. /**
  425. * Get events for the given year.
  426. *
  427. * @since 3.0.0
  428. *
  429. * @param int $year Year.
  430. *
  431. * @return array Multidimensional array with month number, week number and Event objects for each weekday.
  432. */
  433. public function get_year( $year ) {
  434. $y = intval( $year );
  435. $months = array();
  436. for ( $m = 1; $m <= 12; $m++ ) {
  437. $months[ strval( $m ) ] = $this->get_month( $y, $m );
  438. }
  439. return $months;
  440. }
  441. /**
  442. * Get events for the given month in the given year.
  443. *
  444. * @since 3.0.0
  445. *
  446. * @param int $year Year.
  447. * @param int $month Month number.
  448. *
  449. * @return array Multidimensional array with week number, day of the week and array of Event objects for each week day.
  450. */
  451. public function get_month( $year, $month ) {
  452. $y = intval( $year );
  453. $m = min( max( 1, absint( $month ) ), 12 );
  454. $days = Carbon::createFromDate( $y, $m, 2, $this->timezone )->startOfMonth()->daysInMonth;
  455. $weeks = array();
  456. for ( $d = 1; $d < $days; $d++ ) {
  457. $current = Carbon::createFromDate( $y, $m, $d );
  458. $week = $current->weekOfYear;
  459. $day = $current->dayOfWeek;
  460. $weeks[ strval( $week ) ][ strval( $day ) ] = $this->get_day( $y, $m, $d );
  461. }
  462. return $weeks;
  463. }
  464. /**
  465. * Get events for the given week in the given year.
  466. *
  467. * @since 3.0.0
  468. *
  469. * @param int $year Year.
  470. * @param int $week Week number.
  471. *
  472. * @return array Associative array with day of the week for key and array of Event objects for value.
  473. */
  474. public function get_week( $year, $week ) {
  475. $y = intval( $year );
  476. $w = absint( $week );
  477. $m = date( 'n', strtotime( strval( $y ) . '-W' . strval( $w ) ) );
  478. $month_dt = Carbon::createFromDate( $y, $m, 2, $this->timezone );
  479. $days = array();
  480. for ( $d = 1; $d < $month_dt->daysInMonth; $d++ ) {
  481. $current = Carbon::createFromDate( $y, $m, $d );
  482. if ( $w == $current->weekOfYear ) {
  483. $days[ strval( $current->dayOfWeek ) ] = $this->get_day( $y, $m, $d );
  484. }
  485. }
  486. return $days;
  487. }
  488. /**
  489. * Get events for the given day of the given month in the given year.
  490. *
  491. * @since 3.0.0
  492. *
  493. * @param int $year Year.
  494. * @param int $month Month number.
  495. * @param int $day Day of the month number.
  496. *
  497. * @return array Event objects for the day.
  498. */
  499. public function get_day( $year, $month, $day ) {
  500. $y = intval( $year );
  501. $m = min( max( 1, absint( $month ) ), 12 );
  502. $d = min( absint( $day ), 31 );
  503. $from = Carbon::createFromDate( $y, $m, $d, $this->timezone )->startOfDay()->getTimestamp();
  504. $to = Carbon::createFromDate( $y, $m, $d, $this->timezone )->endOfDay()->getTimestamp();
  505. return $this->filter_events( $from, $to );
  506. }
  507. /**
  508. * Get events for today.
  509. *
  510. * @since 3.0.0
  511. *
  512. * @return array Event objects for today.
  513. */
  514. public function get_today() {
  515. $start = Carbon::today( $this->timezone )->startOfDay()->getTimestamp();
  516. $end = Carbon::today( $this->timezone )->endOfDay()->getTimestamp();
  517. return $this->filter_events( $start, $end );
  518. }
  519. /**
  520. * Get events for tomorrow.
  521. *
  522. * @since 3.0.0
  523. *
  524. * @return array Event objects for tomorrow.
  525. */
  526. public function get_tomorrow() {
  527. $start = Carbon::tomorrow( $this->timezone )->startOfDay()->getTimestamp();
  528. $end = Carbon::tomorrow( $this->timezone )->endOfDay()->getTimestamp();
  529. return $this->filter_events( $start, $end );
  530. }
  531. /**
  532. * Get events for yesterday.
  533. *
  534. * @since 3.0.0
  535. *
  536. * @return array Event objects for yesterday.
  537. */
  538. public function get_yesterday() {
  539. $start = Carbon::yesterday( $this->timezone )->startOfDay()->getTimestamp();
  540. $end = Carbon::yesterday( $this->timezone )->endOfDay()->getTimestamp();
  541. return $this->filter_events( $start, $end );
  542. }
  543. /**
  544. * Filter events by timestamps.
  545. *
  546. * @since 3.0.0
  547. * @access private
  548. *
  549. * @param int $from Lower bound timestamp.
  550. * @param int $to Upper bound timestamp.
  551. *
  552. * @return array Filtered array of Event objects.
  553. */
  554. private function filter_events( $from, $to ) {
  555. $timestamps = array_keys( $this->events );
  556. $lower_bound = array_filter( $timestamps, function( $ts ) use( $from ) {
  557. return intval( $ts ) > intval( $from );
  558. } );
  559. $higher_bound = array_filter( $lower_bound, function( $ts ) use( $to ) {
  560. return intval( $ts ) > intval( $to );
  561. } );
  562. $filtered = array_combine( $higher_bound, $higher_bound );
  563. return array_intersect_key( $this->events, $filtered );
  564. }
  565. }