File: //home/globfdxw/www/wp-content/plugins/wpforms-google-calendar/src/Provider/FieldMapper.php
<?php
namespace WPFormsGoogleCalendar\Provider;
use RuntimeException;
/**
* Class Mapper
* Maps form data to Google Calendar event data.
*
* @since 1.0.0
*/
class FieldMapper {
/**
* Connection data.
*
* @since 1.0.0
*
* @var array
*/
private $connection;
/**
* Form data.
*
* @since 1.0.0
*
* @var array
*/
private $form_data;
/**
* Fields data.
*
* @since 1.0.0
*
* @var array
*/
private $fields;
/**
* Entry ID.
*
* @since 1.0.0
*
* @var int|string
*/
private $entry_id;
/**
* Account calendars.
*
* @since 1.0.0
*
* @var array
*/
private $calendars;
/**
* Constructor.
*
* @since 1.0.0
*
* @param array $connection Connection data.
* @param array $form_data Form data.
* @param array $fields Fields data.
* @param int|string $entry_id Entry ID.
* @param array $calendars Calendars.
*/
public function __construct( array $connection, array $form_data, array $fields, $entry_id, array $calendars ) {
$this->connection = $connection;
$this->form_data = $form_data;
$this->fields = $fields;
$this->entry_id = $entry_id;
$this->calendars = $calendars;
}
/**
* Prepare event data for Google Calendar.
*
* @since 1.0.0
*
* @return array Event data.
*
* @throws RuntimeException When required data is missing.
*/
public function prepare_event(): array {
$calendar_id = $this->get_option( 'calendar_id', true );
$timezone = $this->get_timezone( $calendar_id );
$event = [
'calendar_id' => $calendar_id,
'summary' => $this->get_event_title(),
'attendees' => $this->get_guests(),
'start' => [
'dateTime' => $this->get_start_datetime(),
'timeZone' => $timezone,
],
'end' => [
'dateTime' => $this->get_end_datetime(),
'timeZone' => $timezone,
],
'source' => [
'title' => $this->process_smart_tags(
sprintf( /* translators: %1$s is entry ID, %2$s - form name, %3$s - form ID. */
__( 'Submission #%1$s – %2$s(#%3$s)' ),
'{entry_id}',
'{form_name}',
'{form_id}'
)
),
'url' => $this->process_smart_tags( '{page_url}' ),
],
];
$this->add_optional_event_data( $event );
$this->add_guest_permissions( $event );
return $event;
}
/**
* Get event title.
*
* @since 1.0.0
*
* @return string Event title.
*
* @throws RuntimeException When the event title is empty.
*/
private function get_event_title(): string {
$event_title = $this->process_smart_tags( $this->get_option( 'event_title', true ) );
if ( wpforms_is_empty_string( $event_title ) ) {
throw new RuntimeException( 'Event title is required but is empty.' );
}
return $event_title;
}
/**
* Get timezone from calendar settings.
*
* @since 1.0.0
*
* @param string $calendar_id Calendar ID.
*
* @return string
*
* @throws RuntimeException Calendar details not found.
*/
private function get_timezone( string $calendar_id ): string {
if ( empty( $this->calendars[ $calendar_id ]['timezone'] ) ) {
throw new RuntimeException( sprintf( 'Calendar %s not found.', esc_html( $calendar_id ) ) );
}
return (string) $this->calendars[ $calendar_id ]['timezone'];
}
/**
* Get start datetime.
*
* @since 1.0.0
*
* @return string Start datetime data.
*
* @throws RuntimeException When the start datetime field is empty.
*/
private function get_start_datetime(): string {
$field_id = $this->get_option( 'start_datetime', true );
if ( empty( $this->fields[ $field_id ]['unix'] ) ) {
throw new RuntimeException( sprintf( 'Date Time field with ID %d has wrong format.', (int) $field_id ) );
}
return $this->get_formatted_datetime( (int) $this->fields[ $field_id ]['unix'] );
}
/**
* Get formatted end datetime.
*
* @since 1.0.0
*
* @return string End datetime data.
*
* @throws RuntimeException When the start datetime field is empty.
*/
private function get_end_datetime(): string {
$start_field_id = $this->get_option( 'start_datetime', true );
if ( empty( $this->fields[ $start_field_id ]['unix'] ) ) {
throw new RuntimeException( sprintf( 'Date Time field with ID %d has wrong format.', (int) $start_field_id ) );
}
$duration = $this->get_option( 'duration', true );
$start_timestamp = (int) $this->fields[ $start_field_id ]['unix'];
if ( $duration !== 'user_defined' ) {
$duration = (int) $duration;
if ( $duration <= 0 ) {
throw new RuntimeException( 'Event duration must be greater than 0.' );
}
$end_timestamp = $start_timestamp + ( $duration * MINUTE_IN_SECONDS );
return $this->get_formatted_datetime( $end_timestamp );
}
$end_field_id = $this->get_option( 'end_datetime', true );
if ( empty( $this->fields[ $end_field_id ]['unix'] ) ) {
throw new RuntimeException( 'Invalid end time field.' );
}
if ( $start_timestamp >= (int) $this->fields[ $end_field_id ]['unix'] ) {
throw new RuntimeException( 'End time can not be less than start time.' );
}
return $this->get_formatted_datetime( (int) $this->fields[ $end_field_id ]['unix'] );
}
/**
* Convert the date to a specific format.
*
* @since 1.0.0
*
* @param int $unix_timestamp Timestamp.
*
* @return false|string
*/
private function get_formatted_datetime( int $unix_timestamp ) {
return gmdate( 'Y-m-d\TH:i:s', $unix_timestamp );
}
/**
* Add optional event data.
*
* @since 1.0.0
*
* @param array $event Event data.
*/
private function add_optional_event_data( array &$event ): void {
$event_description = $this->process_smart_tags( $this->get_option( 'event_description' ) );
if ( $event_description ) {
$event['description'] = $event_description;
}
$event_location = $this->process_smart_tags( $this->get_option( 'event_location' ) );
if ( $event_location ) {
$event['location'] = $event_location;
}
$recurrence = $this->get_recurrence();
if ( $recurrence ) {
$event['recurrence'][] = $recurrence;
}
}
/**
* Add guest permissions.
*
* @since 1.0.0
*
* @param array $event Event.
*
* @return void
*/
private function add_guest_permissions( array &$event ): void {
$permissions = [
'invite_others' => [
'name' => 'guestsCanInviteOthers',
'default' => true,
],
'modify_event' => [
'name' => 'guestsCanModify',
'default' => false,
],
'see_guest_list' => [
'name' => 'guestsCanSeeOtherGuests',
'default' => true,
],
];
foreach ( $permissions as $option => $permission ) {
$value = $this->get_option( $option );
if ( $value !== null && $value !== $permission['default'] ) {
$event[ $permission['name'] ] = (bool) $value;
}
}
}
/**
* Get option from connection data.
*
* @since 1.0.0
*
* @param string $key Option key.
* @param bool $is_required Whether the option is required.
*
* @return mixed Option value.
*
* @throws RuntimeException When a required option is missing.
*/
public function get_option( string $key, bool $is_required = false ) {
if ( isset( $this->connection[ $key ] ) && ! wpforms_is_empty_string( $this->connection[ $key ] ) ) {
return $this->connection[ $key ];
}
if ( $is_required ) {
throw new RuntimeException( sprintf( 'Required option "%s" is missing.', esc_html( $key ) ) );
}
return null;
}
/**
* Process smart tags in a value.
*
* @since 1.0.0
*
* @param string|null $value Value to process.
*
* @return string Processed value.
*/
private function process_smart_tags( ?string $value ): string {
if ( $value === null || wpforms_is_empty_string( $value ) ) {
return '';
}
return wpforms_process_smart_tags( $value, $this->form_data, $this->fields, $this->entry_id, 'google-calendar-field-value' );
}
/**
* Get guests for the event.
*
* @since 1.0.0
*
* @return array Guests data.
*
* @throws RuntimeException When guests are not configured correctly or are empty.
*/
private function get_guests(): array {
if ( empty( $this->connection['guests'] ) || ! is_array( $this->connection['guests'] ) ) {
throw new RuntimeException( 'Guests are not configured correctly. Please check your form settings.' );
}
$emails = [];
foreach ( $this->connection['guests'] as $field_id ) {
$email_value = $this->get_field_value( $field_id );
if ( ! is_array( $email_value ) ) {
$emails[] = [ $email_value ];
continue;
}
$emails[] = $email_value;
}
$emails = array_filter( array_unique( array_merge( [], ...$emails ) ) );
return $this->convert_emails_to_guests( $emails );
}
/**
* Convert emails to guests objects.
*
* @since 1.0.0
*
* @param array $emails Submitted values.
*
* @return array
*
* @throws RuntimeException No valid emails were submitted.
*/
private function convert_emails_to_guests( array $emails ): array {
$guests = [];
foreach ( $emails as $email ) {
if ( wpforms_is_email( $email ) ) {
$guests[] = [
'email' => $email,
];
}
}
if ( empty( $guests ) ) {
throw new RuntimeException( 'No valid attendee emails were found. Please check your form submission.' );
}
return $guests;
}
/**
* Get recurrence rule for the event.
*
* @since 1.0.0
*
* @return string Recurrence rule in RFC5545 format.
*/
private function get_recurrence(): string {
$recurrence = $this->get_option( 'recurrence' );
if ( ! $recurrence ) {
return '';
}
$recurrence_rules = [
'daily' => 'RRULE:FREQ=DAILY',
'weekday' => 'RRULE:FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR',
'weekly' => 'RRULE:FREQ=WEEKLY',
'monthly' => 'RRULE:FREQ=MONTHLY',
'quarterly' => 'RRULE:FREQ=MONTHLY;INTERVAL=3',
'yearly' => 'RRULE:FREQ=YEARLY',
];
/**
* Filter recurrence rules.
*
* @since 1.0.0
*
* @param array $recurrence_rules Recurrence rules in RFC5545 format.
* @param string $recurrence Recurrence type.
* @param array $connection Connection data.
* @param array $form_data Form data and settings.
* @param array $fields Form fields data.
* @param int|string $entry_id Entry ID.
*/
$recurrence_rules = (array) apply_filters(
'wpforms_google_calendar_provider_field_mapper_recurrence_rules',
$recurrence_rules,
$recurrence,
$this->connection,
$this->form_data,
$this->fields,
$this->entry_id
);
return $recurrence_rules[ $recurrence ] ?? '';
}
/**
* Get field value by field ID.
*
* @since 1.0.0
*
* @param string $field_id Field ID.
*
* @return string|array Field value or array of values for repeater fields.
*/
private function get_field_value( string $field_id ) {
if ( wpforms_is_repeated_field( $field_id, $this->fields ) ) {
return $this->get_repeater_field_values( $field_id );
}
return $this->fields[ $field_id ]['value'] ?? '';
}
/**
* Get a list of repeated field values by field ID.
*
* @since 1.0.0
*
* @param string $repeated_field_id Repeated field ID.
*
* @return array
*/
private function get_repeater_field_values( string $repeated_field_id ): array {
$values = [
$this->fields[ $repeated_field_id ]['value'] ?? '',
];
$repeater_ids = wpforms_get_repeater_field_ids( $repeated_field_id );
$repeater_prefix = $repeater_ids['original_id'] . '_';
foreach ( $this->fields as $field_id => $field ) {
if ( strpos( $field_id, $repeater_prefix ) === 0 ) {
$values[] = $this->fields[ $field_id ]['value'] ?? '';
}
}
return array_filter( $values );
}
}