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

jsarnowski / jsarnowski/jet-booking   php

Repository URL to install this package:

Version: 2.2.1 

/ ical.php

<?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;

	}

}