Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
<?php
namespace JET_ABAF;

/**
 * ICal management class
 */
class iCal {

	/**
	 * Trigger to get iCal file
	 * @var string
	 */
	private $trigger   = '_get_ical';
	private $hash      = null;
	private $domain    = null;
	private $ical_meta = '_import_ical';

	/**
	 * Setup class
	 */
	public function __construct() {

		$this->hash = md5( $this->get_domain() );

		if ( ! empty( $_GET[ $this->trigger ] ) && $this->hash === $_GET[ $this->trigger ] && ! empty( $_GET['_id'] ) ) {
			$this->get_calendar_file();
		}

		add_action( 'jet-booking/settings/on-ajax-save', array( $this, 'maybe_schedule_synch' ) );
		add_action( 'jet-booking/cron/synch-calendars', array( $this, 'cron_synch_calendars' ) );

	}

	/**
	 * [maybe_schedule_synch description]
	 * @return [type] [description]
	 */
	public function maybe_schedule_synch() {

		if ( Plugin::instance()->settings->get( 'ical_synch' ) ) {
			$this->reschedule_synch();
		} else {
			$this->unschedule_synch();
		}

	}

	/**
	 * Schedule calendar synchronizing for given post ID and unit ID
	 *
	 * @param  [type] $post_id [description]
	 * @param  [type] $unit_id [description]
	 * @return [type]          [description]
	 */
	public function schedule_synch() {

		if ( ! wp_next_scheduled( 'jet-booking/cron/synch-calendars' ) ) {

			$interval = Plugin::instance()->settings->get( 'synch_interval' );

			if ( ! $interval ) {
				$interval = 'daily';
			}

			$from_h = Plugin::instance()->settings->get( 'synch_interval_hours' );
			$from_m = Plugin::instance()->settings->get( 'synch_interval_mins' );

			if ( ! $from_h || ! $from_m ) {
				$time = time();
			} else {
				$time = strtotime( 'today ' . $from_h . ':' . $from_m );
			}

			wp_schedule_event( $time, $interval, 'jet-booking/cron/synch-calendars' );

		}

	}

	/**
	 * Unschedule calendars synchronizing
	 *
	 * @return [type] [description]
	 */
	public function unschedule_synch() {

		$timestamp = wp_next_scheduled( 'jet-booking/cron/synch-calendars' );

		if ( $timestamp ) {
			wp_unschedule_event( $timestamp, 'jet-booking/cron/synch-calendars' );
		}

	}

	/**
	 * Reshedule calendars synch
	 *
	 * @return [type] [description]
	 */
	public function reschedule_synch() {
		$this->unschedule_synch();
		$this->schedule_synch();
	}

	/**
	 * Synhronize calendars on cron hook
	 *
	 * @return [type] [description]
	 */
	public function cron_synch_calendars() {
		$calendars = $this->get_calendars();
		foreach ( $calendars as $calendar ) {
			$log = $this->synch( $calendar['post_id'], $calendar['unit_id'] );
		}
	}

	/**
	 * Returns current domain
	 *
	 * @return [type] [description]
	 */
	public function get_domain() {

		if ( $this->domain ) {
			return $this->domain;
		}

		$find         = array( 'http://', 'https://' );
		$replace      = '';
		$this->domain = str_replace( $find, $replace, home_url() );

		return $this->domain;

	}

	/**
	 * Synchronize calendars
	 * @return [type] [description]
	 */
	public function synch( $post_id = 0, $unit_id = false ) {

		$log = array();

		if ( ! $post_id ) {
			$log[] = __( 'Post ID not found', 'jet-engine' );
			return $log;
		}

		if ( ! $unit_id ) {
			$unit_id = 'default';
		}

		$import = get_post_meta( $post_id, $this->ical_meta, true );

		if ( ! $import ) {
			$import = array();
		}

		if ( empty( $import[ $unit_id ] ) ) {
			$log[] = __( 'External calendars is not found for this item', 'jet-engine' );
			return $log;
		}

		foreach ( $import[ $unit_id ] as $url ) {

			$response = wp_remote_get( $url );
			$label = '<b>' . $url . ':</b><br> ';

			if ( is_wp_error( $response ) ) {
				$log[] = $label . __( 'Can`t access caledar', 'jet-booking' ) . ', ' . $response->get_error_message();
				continue;
			}

			$body = wp_remote_retrieve_body( $response );

			if ( ! $body ) {
				$log[] = $label . __( 'Empty response from calendar', 'jet-booking' );
				continue;
			}

			$log[] = $label . $this->import_calendar( $body, $post_id, $unit_id );

		}

		return $log;

	}

	/**
	 * Import calendar data
	 *
	 * @param  [type] $data [description]
	 * @param  [type] $url  [description]
	 * @return [type]       [description]
	 */
	public function import_calendar( $data = null, $post_id, $unit_id ) {

		$this->load_deps();
		$calendar_object = new \ZCiCal( $data );

		if ( ! $calendar_object->countEvents() || ! $calendar_object->tree->child ) {
			return __( 'Bookings not found', 'jet-booking' );
		}

		$inserted = array();
		$skipped  = array();

		foreach ( $calendar_object->tree->child as $node ) {

			if ( 'VEVENT' !== $node->getName() ) {
				continue;
			}

			$import_node = array(
				'apartment_id' => $post_id,
				'status'       => 'pending',
			);

			if ( 'default' !== $unit_id ) {
				$import_node['apartment_unit'] = $unit_id;
			}

			$import_id = false;

			foreach ( $node->data as $key => $value ) {

				switch ( $key ) {
					case 'DTSTART':
						$date = $value->getValues();
						$import_node['check_in_date'] = \ZDateHelper::fromiCaltoUnixDateTime( $date );
						break;

					case 'DTEND':
						$date = $value->getValues();
						$import_node['check_out_date'] = \ZDateHelper::fromiCaltoUnixDateTime( $date );
						break;

					case 'UID':
						$import_node['import_id'] = $import_id = untrailingslashit( $value->getValues() );
						break;

				}

			}

			$import_node = apply_filters( 'jet-booking/ical/import/node', $import_node, $node, $calendar_object );

			if ( ! Plugin::instance()->db->booking_exists( 'import_id', $import_id ) ) {
				$inserted[] = Plugin::instance()->db->insert_booking( $import_node );
			} else {
				$skipped[] = $import_id;
			}

		}

		return '<i>' . __( 'Inserted bookings: ', 'jet-booking' ) . '</i>' . implode( ', ', $inserted ) . ';<br><i>' . __( 'Skipped bookings: ', 'jet-booking' ) . '</i>' . implode( ', ', $skipped );

	}

	/**
	 * Get calendar export file
	 *
	 * @return [type] [description]
	 */
	public function get_calendar_file() {

		$post_id = ! empty( $_GET['_id'] ) ? absint( $_GET['_id'] ) : null;
		$uid     = ! empty( $_GET['_uid'] ) ? absint( $_GET['_uid'] ) : null;

		if ( ! $post_id ) {
			_e( 'Invalid request data', 'jet-booking' );
			die();
		}

		$post = get_post( $post_id );

		if ( ! $post ) {
			_e( 'Invalid request data', 'jet-booking' );
			die();
		}

		$this->load_deps();

		$datestamp = \ZCiCal::fromUnixDateTime() . 'Z';
		$calendar  = new \ZCiCal();

		$filename = 'calendar-export--' . $post->post_name;

		if ( $uid ) {
			$filename .= '-' . $uid;
		}

		$filename .= '.ics';

		$bookings = $this->get_bookings( $post_id, $uid );

		if ( ! empty( $bookings ) ) {
			foreach ( $bookings as $booking ) {
				$this->add_booking( $booking, $calendar, $datestamp );
			}
		}

		header( 'Content-type: text/calendar; charset=utf-8' );
		header( 'Content-Disposition: inline; filename=' . $filename );

		echo $calendar->export();

		die();

	}

	/**
	 * Add new booking into existing calendar
	 *
	 * @param [type] $booking  [description]
	 * @param [type] $calendar [description]
	 */
	public function add_booking( $booking, $calendar, $datestamp ) {

		$summary     = $description = $this->get_booking_summary( $booking );
		$hash_string = $booking['check_in_date'] . $booking['check_out_date'] . $booking['booking_id'];
		$uid         = md5( $hash_string ) . '@' . $this->get_domain();

		$event = new \ZCiCalNode( 'VEVENT', $calendar->curnode );

		$check_out_ts = $booking['check_out_date'];
		$period       = Plugin::instance()->settings->get( 'booking_period' );

		if ( ! $period || 'per_nights' === $period ) {
			$per_nights = true;
		} else {
			$per_nights = false;
		}

		if ( ! $per_nights ) {
			$check_out_ts = $check_out_ts + DAY_IN_SECONDS;
		}

		$check_in_date  = date( 'Y-m-d', $booking['check_in_date'] );
		$check_out_date = date( 'Y-m-d', $check_out_ts );

		$event->addNode( new \ZCiCalDataNode( 'UID:' . $uid ) );
		$event->addNode( new \ZCiCalDataNode( 'DTSTART;VALUE=DATE:' . \ZCiCal::fromSqlDateTime( $check_in_date ) ) );
		$event->addNode( new \ZCiCalDataNode( 'DTEND;VALUE=DATE:' . \ZCiCal::fromSqlDateTime( $check_out_date ) ) );
		$event->addNode( new \ZCiCalDataNode( 'DTSTAMP:' . $datestamp ) );
		$event->addNode( new \ZCiCalDataNode( 'SUMMARY:' . $summary ) );
		$event->addNode( new \ZCiCalDataNode( 'DESCRIPTION:' . $description ) );

		do_action_ref_array( 'jet-abaf/ical/export-booking', array( &$booking, &$calendar ) );

	}

	/**
	 * Returns booking summary
	 *
	 * @return [type] [description]
	 */
	public function get_booking_summary( $booking ) {

		$summary = null;
		$format  = __( 'Booking #%1$d', 'jet-booking' );

		if ( ! empty( $booking['order_id'] ) ) {
			$summary = sprintf( $format, $booking['order_id'] );
		} else {
			$db_col = Plugin::instance()->settings->get( 'related_post_type_column' );

			if ( $db_col && ! empty( $booking[ $db_col ] ) ) {
				$summary = sprintf( $format, $booking[ $db_col ] );
			} else {
				$summary = __( 'Booking Item', 'jet-booking' );
			}

		}

		return apply_filters( 'jet-abaf/ical/export-booking-summary', $summary, $booking );

	}

	/**
	 * Returns all valid bookings
	 *
	 * @return [type] [description]
	 */
	public function get_bookings( $post_id, $unit_id = false ) {

		$query = array(
			'apartment_id' => $post_id,
			'status'       => Plugin::instance()->statuses->valid_statuses(),
		);

		if ( $unit_id ) {
			$query['apartment_unit'] = $unit_id;
		}

		return Plugin::instance()->db->query( $query );

	}

	/**
	 * Load dependencies
	 *
	 * @return [type] [description]
	 */
	public function load_deps() {

		if ( defined( '_ZAPCAL' ) ) {
			return;
		}

		require_once JET_ABAF_PATH . 'includes/vendor/icalendar/zapcallib.php';

	}

	/**
	 * Returns export URL
	 *
	 * @param  [type] $post_id [description]
	 * @param  [type] $unit_id [description]
	 * @return [type]          [description]
	 */
	public function get_export_url( $post_id = 0, $unit_id = 0 ) {
		return add_query_arg(
			array(
				$this->trigger => $this->hash,
				'_id'          => $post_id,
				'_uid'         => $unit_id,
			),
			home_url( '/' )
		);
	}

	/**
	 * Strore external calendar URL to synch
	 *
	 * @param  array   $urls    [description]
	 * @param  integer $post_id [description]
	 * @param  boolean $unit_id [description]
	 * @return [type]           [description]
	 */
	public function update_import_urls( $urls = array(), $post_id = 0, $unit_id = false ) {

		if ( ! $post_id ) {
			return;
		}

		$existing = get_post_meta( $post_id, $this->ical_meta, true );

		if ( ! $existing ) {
			$existing = array();
		}

		if ( ! $unit_id ) {
			$unit_id = 'default';
		}

		$existing[ $unit_id ] = $urls;

		update_post_meta( $post_id, $this->ical_meta, $existing );

	}

	/**
	 * Returns all URLs for calendars
	 *
	 * @return [type] [description]
	 */
	public function get_calendars() {

		$post_type = Plugin::instance()->settings->get( 'apartment_post_type' );

		if ( ! $post_type ) {
			return array();
		}

		$posts = get_posts( array(
			'post_type' => $post_type,
			'numberposts' => -1,
		) );

		if ( ! $posts ) {
			return array();
		}

		$result = array();

		foreach ( $posts as $post ) {

			$import = get_post_meta( $post->ID, $this->ical_meta, true );

			if ( ! $import ) {
				$import = array();
			}

			$item = array(
				'post_id'    => $post->ID,
				'title'      => $post->post_title,
				'unit_id'    => false,
				'unit_title' => '',
				'import_url' => isset( $import['default'] ) ? $import['default'] : false,
				'export_url' => $this->get_export_url( $post->ID, false ),
			);

			$units = Plugin::instance()->db->get_apartment_units( $post->ID );

			if ( empty( $units ) ) {
				$result[] = $item;
			} else {
				foreach ( $units as $unit ) {

					$unit_item               = $item;
					$uid                     = $unit['unit_id'];
					$unit_item['unit_id']    = $uid;
					$unit_item['unit_title'] = $unit['unit_title'];
					$unit_item['import_url'] = isset( $import[ $uid ] ) ? $import[ $uid ] : false;
					$unit_item['export_url'] = $this->get_export_url( $post->ID, $uid );

					$result[] = $unit_item;
				}
			}

		}

		return $result;

	}

}