PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/all-in-one-event-calendar/app/helper/class-ai1ec-importer-helper.php

https://github.com/jdickie/mithpressbeta
PHP | 238 lines | 120 code | 30 blank | 88 comment | 15 complexity | 1b5e7d325d2a91b7983ebdc421eb7887 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, AGPL-1.0
  1. <?php
  2. //
  3. // class-ai1ec-importer-helper.php
  4. // all-in-one-event-calendar
  5. //
  6. // Created by The Seed Studio on 2011-07-13.
  7. //
  8. /**
  9. * Ai1ec_Importer_Helper class
  10. *
  11. * @package Helpers
  12. * @author The Seed Studio
  13. **/
  14. class Ai1ec_Importer_Helper {
  15. /**
  16. * _instance class variable
  17. *
  18. * Class instance
  19. *
  20. * @var null | object
  21. **/
  22. private static $_instance = NULL;
  23. /**
  24. * Constructor
  25. *
  26. * Default constructor
  27. **/
  28. private function __construct() { }
  29. /**
  30. * get_instance function
  31. *
  32. * Return singleton instance
  33. *
  34. * @return object
  35. **/
  36. static function get_instance() {
  37. if( self::$_instance === NULL ) {
  38. self::$_instance = new self();
  39. }
  40. return self::$_instance;
  41. }
  42. /**
  43. * time_array_to_timestamp function
  44. *
  45. * Converts time array to time string.
  46. * Passed array: Array( 'year', 'month', 'day', ['hour', 'min', 'sec', ['tz']] )
  47. * Return int: UNIX timestamp in GMT
  48. *
  49. * @param array $t iCalcreator's time property array (*full* format expected)
  50. * @param string $def_timezone Default time zone in case not defined in $t
  51. *
  52. * @return int UNIX timestamp
  53. **/
  54. function time_array_to_timestamp( $t, $def_timezone ) {
  55. $ret = $t['value']['year'] .
  56. '-' . $t['value']['month'] .
  57. '-' . $t['value']['day'];
  58. if( isset( $t['value']['hour'] ) )
  59. $ret .= ' ' . $t['value']['hour'] .
  60. ':' . $t['value']['min'] .
  61. ':' . $t['value']['sec'];
  62. $timezone = ( isset( $t['value']['tz'] ) && $t['value']['tz'] == 'Z' ) ? 'Z' : $t['params']['TZID'];
  63. if( ! $timezone ) $timezone = $def_timezone;
  64. if( $timezone )
  65. $ret .= ' ' . $timezone;
  66. return strtotime( $ret );
  67. }
  68. /**
  69. * Gets and parses an iCalendar feed into an array of Ai1ec_Event objects
  70. *
  71. * @param object $feed Row from the ai1ec_event_feeds table
  72. *
  73. * @return int Number of events imported
  74. */
  75. function parse_ics_feed( &$feed )
  76. {
  77. global $ai1ec_events_helper;
  78. $count = 0;
  79. // include ical parser
  80. require_once( AI1EC_LIB_PATH . '/iCalcreator.class.php' );
  81. // set unique id, required if any component UID is missing
  82. $config = array( 'unique_id' => 'ai1ec' );
  83. // create new instance
  84. $v = new vcalendar( array(
  85. 'unique_id' => $feed->feed_url,
  86. 'url' => $feed->feed_url,
  87. ) );
  88. // actual parse of the feed
  89. if( $v->parse() )
  90. {
  91. $v->sort();
  92. // Reverse the sort order, so that RECURRENCE-IDs are listed before the
  93. // defining recurrence events, and therefore take precedence during
  94. // caching.
  95. $v->components = array_reverse( $v->components );
  96. // TODO: select only VEVENT components that occur after, say, 1 month ago.
  97. // Maybe use $v->selectComponents(), which takes into account recurrence
  98. // Fetch default timezone in case individual properties don't define it
  99. $timezone = $v->getProperty( 'X-WR-TIMEZONE' );
  100. $timezone = $timezone[1];
  101. // go over each event
  102. while( $e = $v->getComponent( 'vevent' ) )
  103. {
  104. $start = $e->getProperty( 'dtstart', 1, true );
  105. $end = $e->getProperty( 'dtend', 1, true );
  106. // Event is all-day if no time components are defined
  107. $allday = ! isset( $start['value']['hour'] );
  108. // convert times to GMT UNIX timestamps
  109. $start = $this->time_array_to_timestamp( $start, $timezone );
  110. $end = $this->time_array_to_timestamp( $end, $timezone );
  111. // If all-day, and start and end times are equal, then this event has
  112. // invalid end time (happens sometimes with poorly implemented iCalendar
  113. // exports, such as in The Event Calendar), so set end time to 1 day
  114. // after start time.
  115. if( $allday && $start === $end )
  116. $end += 24 * 60 * 60;
  117. // Due to potential time zone differences (WP time zone vs. feed time
  118. // zone), must convert all-day event start/end dates to date only (the
  119. // *intended* local date, non-GMT-ified)
  120. if( $allday ) {
  121. $start = $ai1ec_events_helper->gmt_to_local( $start );
  122. $start = $ai1ec_events_helper->gmgetdate( $start );
  123. $start = gmmktime( 0, 0, 0, $start['mon'], $start['mday'], $start['year'] );
  124. $start = $ai1ec_events_helper->local_to_gmt( $start );
  125. $end = $ai1ec_events_helper->gmt_to_local( $end );
  126. $end = $ai1ec_events_helper->gmgetdate( $end );
  127. $end = gmmktime( 0, 0, 0, $end['mon'], $end['mday'], $end['year'] );
  128. $end = $ai1ec_events_helper->local_to_gmt( $end );
  129. }
  130. if( $rrule = $e->createRrule() )
  131. $rrule = trim( end( explode( ':', $rrule ) ) );
  132. if( $exrule = $e->createExrule() )
  133. $exrule = trim( end( explode( ':', $exrule ) ) );
  134. if( $rdate = $e->createRdate() )
  135. $rdate = trim( end( explode( ':', $rdate ) ) );
  136. if( $exdate = $e->createExdate() )
  137. $exdate = trim( end( explode( ':', $exdate ) ) );
  138. $data = array(
  139. 'start' => $start,
  140. 'end' => $end,
  141. 'allday' => $allday,
  142. 'recurrence_rules' => $rrule,
  143. 'exception_rules' => $exrule,
  144. 'recurrence_dates' => $rdate,
  145. 'exception_dates' => $exdate,
  146. 'venue' => $e->getProperty( 'location' ),
  147. 'ical_feed_url' => $feed->feed_url,
  148. 'ical_source_url' => $e->getProperty( 'url' ),
  149. 'ical_organizer' => $e->getProperty( 'organizer' ),
  150. 'ical_contact' => $e->getProperty( 'contact' ),
  151. 'ical_uid' => $e->getProperty( 'uid' ),
  152. 'categories' => $feed->feed_category,
  153. 'tags' => $feed->feed_tags,
  154. 'post' => array(
  155. 'post_status' => 'publish',
  156. 'post_type' => AI1EC_POST_TYPE,
  157. 'post_author' => 1,
  158. 'post_title' => $e->getProperty( 'summary' ),
  159. 'post_content' => stripslashes( str_replace( '\n', "\n", $e->getProperty( 'description' ) ) ),
  160. ),
  161. );
  162. $event = new Ai1ec_Event( $data );
  163. // TODO: when singular events change their times in an ICS feed from one
  164. // import to another, the matching_event_id is null, which is wrong. We
  165. // want to match that event that previously had a different time.
  166. // However, we also want the function to NOT return a matching event in
  167. // the case of recurring events, and different events with different
  168. // RECURRENCE-IDs... ponder how to solve this.. may require saving the
  169. // RECURRENCE-ID as another field in the database.
  170. $matching_event_id = $ai1ec_events_helper->get_matching_event_id(
  171. $event->ical_uid,
  172. $event->ical_feed_url,
  173. $event->start,
  174. ! empty( $event->recurrence_rules )
  175. );
  176. if( is_null( $matching_event_id ) )
  177. {
  178. // =================================================
  179. // = Event was not found, so store it and the post =
  180. // =================================================
  181. $event->save();
  182. }
  183. else
  184. {
  185. // ======================================================
  186. // = Event was found, let's store the new event details =
  187. // ======================================================
  188. // Update the post
  189. $post = get_post( $matching_event_id );
  190. $post->post_title = $event->post->post_title;
  191. $post->post_content = $event->post->post_content;
  192. wp_update_post( $post );
  193. // Update the event
  194. $event->post_id = $matching_event_id;
  195. $event->post = $post;
  196. $event->save( true );
  197. // Delete event's cache
  198. $ai1ec_events_helper->delete_event_cache( $matching_event_id );
  199. }
  200. // Regenerate event's cache
  201. $ai1ec_events_helper->cache_event( $event );
  202. $count++;
  203. }
  204. }
  205. return $count;
  206. }
  207. }
  208. // END class