Файловый менеджер - Редактировать - /home/harasnat/www/labour/wp-content/plugins/events-manager/classes/recurrences/recurrence-sets.php
Назад
<?php namespace EM\Recurrences; use EM_DateTime; use EM_DateTimeZone; use EM_Event; use EM_Ticket; /** * @property int $length The number of recurrence sets in this object. */ class Recurrence_Sets extends \EM_Object implements \Iterator, \ArrayAccess, \Countable { /** * Associative array of times where events occur, used for avoiding collisions created by a preceding set in this recurring event. * * Each recurrence is stored in $this->recurrences as: * [ * 'start' => start_timestamp, * 'end' => end_timestamp, * 'event_id' => 123 // present for inclusions, omitted for exclusions * ] * * @var array */ public $recurrences; /** * Array of Recurrence_Set objects, keyed by recurrence_set_id if not already saved. * @var Recurrence_Set[] */ public $include = []; /** * Array of Recurrence_Set objects representing blackout date/time patterns, keyed by recurrence_set_id if not already saved. * @var Recurrence_Set[] */ public $exclude = []; /** * The primary/default recurrence set, which other recurrences can take settings from if not defined (for example, the starT/end dates of the recurrence pattern, timezone, etc.) * @var Recurrence_Set */ public $default; /** * @var int Event ID of the recurring event */ public $event_id; /** * @var EM_Event $event The recurring Event object */ public $event; // Rescheduling - flags to help identify when rescheduing is to take place upon save /** * If 'cancel' or 'delete', all recurrence sets will be rescheduled and recurrences will be handled accordingly, if true the recurrences will be cancelled if possible otherwise deleted. * @var boolean|string */ public $reschedule = false; /** * Action to be taken to currently created events if rescheduling this set is authorized. This would be 'cancel' or 'delete' depending if cancellations are allowed. * @var string */ public $reschedule_exclude; // Booking flags - detect when to modify bookings in recurrences /** * @var array{ * tickets: array{ * added: array<string, EM_Ticket>, // Keyed by EM_Ticket::ticket_uuid * modified: array<int, EM_Ticket>, // Keyed by EM_Ticket::ticket_id * deleted: array<int, EM_Ticket>, // Keyed by EM_Ticket::ticket_id * unchanged: array<int, EM_Ticket> // Keyed by EM_Ticket::ticket_id * } * } Map of things to be updated/deleted in bookings when recurrences are saved. */ public $booking_updates = [ 'tickets' => [ 'added' => [], 'modified' => [], 'deleted' => [], 'unchanged' => [] ] ]; /** * Flag used for when saving a recurring event that previously had bookings enabled and then subsequently disabled. * If set to true, and $this->recreate_bookings is false, bookings and tickets of recurrences will be deleted. * @var boolean */ public $update_bookings = false; /** * Constructor to initialize the Recurrence_Sets object. * Accepts an EM_Event object and loads its recurrence sets. * * @param EM_Event $event */ public function __construct ( $event ) { // add event data to this object if ( $event instanceof EM_Event ) { $this->event_id = $event->event_id; $this->event = $event; } else { $this->event_id = $event; } if ( $this->event_id ) { // load recurrence sets global $wpdb; $results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM " . EM_EVENT_RECURRENCES_TABLE . " WHERE event_id = %d ORDER BY recurrence_order, recurrence_set_id ASC", $this->event_id ), ARRAY_A ); foreach ( $results as $row ) { $Recurrence_Set = new Recurrence_Set( $row ); if ( $Recurrence_Set->type == 'include' ) { $this->include[ $Recurrence_Set->id ] = $Recurrence_Set; if ( !$this->default ) { $this->default = $Recurrence_Set; } } elseif ( $Recurrence_Set->type == 'exclude' ) { $this->exclude[ $Recurrence_Set->id ] = $Recurrence_Set; } if ( $event instanceof EM_Event ) { $Recurrence_Set->event = $event; } } } } public function __get ( $prop ) { if ( $prop === 'length' ) { return count( $this->include ); } return parent::__get( $prop ); } public function add_empty_set () { if ( count( $this->include ) == 0 ) { $this->include[] = new Recurrence_Set(); } } /** * Returns a multi-dimensional array of recurrences, indexed by UTC start date then start_time, which can be used for collision detection. * * Within a start time record, it can be an array containg an event array, or an array of events in case there are multiple events on the same time. * * @return array */ /** * @var bool Flag to track if recurrences have been modified and need resorting */ public $recurrences_modified = true; /** * @var int Last count of recurrences array, used to detect modifications */ protected $recurrences_count = 0; /** * Returns a multi-dimensional array of recurrences, indexed by UTC start date then start_time, which can be used for collision detection. * * Within a start time record, it can be an array containg an event array, or an array of events in case there are multiple events on the same time. * * @return array */ public function get_recurrences() { if ($this->recurrences === null) { $this->recurrences = []; // excludes take priority since we don't want events on that day foreach ($this->exclude as $Recurrence_Set) { $this->recurrences += $Recurrence_Set->get_recurrences(); } foreach ($this->include as $Recurrence_Set) { $this->recurrences += $Recurrence_Set->get_recurrences(); } $this->recurrences_modified = true; $this->recurrences_count = count($this->recurrences); } else { // Check if the array size changed, which indicates modification $current_count = count($this->recurrences); if ($current_count !== $this->recurrences_count) { $this->recurrences_modified = true; $this->recurrences_count = $current_count; } } // Only sort if modifications have been made if ($this->recurrences_modified) { ksort($this->recurrences); reset($this->recurrences); $this->recurrences_modified = false; } return $this->recurrences; } /** * Check if a given interval overlaps any recurrence rule. A collision can be from an exclusion or an overlapping event. * * @param int $start Unix timestamp for the start of the query interval. * @param int $end Unix timestamp for the end of the query interval. * @param int $type If supplied, only checks for the specific type of collision is checked, values can be 'exclude' or 'include' * * @return false|string Recurrence type (include|exclude) of an overlapping recurrence if found, false otherwise. */ public function has_collision ( $start, $end, $type = null ) { // Assume $this->recurrences is sorted by start timestamp. $this->get_recurrences(); if ( defined('EM_DEBUG') && EM_DEBUG ) { $start_dt = new EM_DateTime( $start, 'UTC' ); $end_dt = new EM_DateTime( $end, 'UTC' ); } foreach ( $this->recurrences as $recurrence ) { // If this recurrence starts after the query interval ends, // no subsequent recurrences can overlap. if ( $recurrence['start'] > $end ) { break; } // Check if there is an overlap. if ( $start < $recurrence['end'] && $end > $recurrence['start'] ) { $type_found = !empty($recurrence['event_id']) ? 'include' : 'exclude'; // overlap found, return if it matches type needed or if none specified if ( !$type || $type_found === $type ) { return $type; } } } return false; } /** * Returns a string representation of this recurrence. Will return false if not a recurrence * @return string */ function get_recurrence_description ( $include_dates = true ) { $EM_Event = $this->get_event(); $descriptions = []; if ( $EM_Event ) { if ( !empty($this->default) ) { if ( $include_dates ) { $descriptions[] = sprintf( __( 'From %1$s to %2$s', 'events-manager' ), $EM_Event->start()->i18n( em_get_date_format() ), $EM_Event->end()->i18n( em_get_date_format() ) ); } $pattern = ucfirst( $this->default->get_recurrence_description() ); $count = count( $this->include ); if ( $count > 1 ) { $pattern .= ' + ' . sprintf( _n( '%d Pattern', '%d Patterns', $count - 1, 'events-manager' ), $count - 1 ); } $descriptions[] = $pattern; } } return implode( ', ', $descriptions ); } /** * Smart event locator, saves a database read if possible. Note that if an event doesn't exist, a blank object will be created to prevent duplicates. */ function get_event () { global $EM_Event; if ( $this->event && $this->event->event_id == $this->event_id ) { return $this->event; } if ( is_object( $EM_Event ) && $EM_Event->event_id == $this->event_id ) { $this->event = $EM_Event; } else { $this->event = em_get_event( $this->event_id ); } return $this->event; } /** * Gets the first and last date/time that this recurring event spans from/to, * accounting for potentially different timezones between recurrence sets. * * @return array An associative array with start_date, end_date, start_time, end_time */ public function get_datetime_range () { // Initialize with null values $DateTime['start'] = null; $DateTime['end'] = null; // get all recurrences, and loop from the start until we find first event_id foreach ( $this->get_recurrences() as $recurrence ) { if ( !empty( $recurrence['event_id'] ) ) { // it's an event, grab the date and break $DateTime['start'] = new EM_DateTime( $recurrence['start'], 'UTC' ); break; } } // get keys of recurrences and loop backwards to find the last event_id $keys = array_keys( $this->recurrences ); for ($i = count($keys) - 1; $i >= 0; $i--) { $ts = $keys[$i]; if ( !empty( $this->recurrences[$ts]['event_id'] ) ) { $DateTime['end'] = new EM_DateTime( $this->recurrences[$ts]['end'], 'UTC' ); break; } } // build result array $result = []; // Before returning, standardize timezone to the default recurrence set timezone $default_timezone = !empty( $this->default->timezone ) ? $this->default->timezone : EM_DateTimeZone::create(); foreach ( $DateTime as $when => $EM_DateTime ) { if ( $EM_DateTime instanceof EM_DateTime ) { $EM_DateTime->setTimezone( $default_timezone ); } $result[ $when . '_date' ] = $EM_DateTime ? $EM_DateTime->getDate() : null; $result[ $when . '_time' ] = $EM_DateTime ? $EM_DateTime->getTime() : null; } // Determine if this is an all-day event, which must correspond to the current timezone, otherwise even if all-day it's starting/ending at a specific local time and not midnight $result['all_day'] = ( $result['start_time'] === '00:00:00' && $result['end_time'] === '23:59:59' ); return $result; } public function get_post () { if ( !$this->get_event() ) { return false; } //Get original recurring event so we can tell whether event recurrences or bookings will be recreated or just modified $EM_Event = $this->get_event(); // first go through all requested values and mark those for deletion if ( !empty( $_REQUEST['recurrences'] ) && is_array( $_REQUEST['recurrences'] ) ) { // we go through all the recurrences that are set to delete, we must have a nonce to set this to delete, as a fail-safe foreach ( $_REQUEST['recurrences'] as $type => $type_sets ) { if ( !in_array( $type, [ 'include', 'exclude' ] ) ) { continue; } foreach ( $type_sets as $data ) { $set_id = !empty( $data['recurrence_set_id'] ) ? absint( $data['recurrence_set_id'] ) : false; if ( !empty( $data['delete'] ) && $set_id ) { // check we have a valid set ID present, and that the nonce checks out if ( !empty( $this->{$type}[ $set_id ] ) ) { if ( wp_verify_nonce( $data['delete'], 'delete_recurrence_' . $set_id . '_' . get_current_user_id() ) ) { $this->{$type}[ $set_id ]->delete = $data['delete']; } else { $this->add_error( sprintf( 'Cannot delete set ID %d, invalid nonce provided.', $set_id ) ); } } else { $this->add_error( sprintf( 'Cannot find set ID to delete - %d', $set_id ) ); } } else { if ( !$set_id || empty( $this->{$type}[ $set_id ] ) ) { // if this is a new exclude type to a previously-created event, and we're adding an exclusion, we need to double-check that we have confirmed the rescheduling and what action would be taken if ( $type == 'exclude' && $EM_Event->event_id ) { // we need to potentially reschedule, check nonce is good and set flags $nonce = $_REQUEST['recurrences']['exclude_reschedule']['nonce'] ?? false; if ( !$nonce || !wp_verify_nonce( $nonce, 'reschedule_exclude_' . get_current_user_id() ) ) { // not adding the new exclusion as nonce not met continue; } } // add a recurrence pattern $Recurrence_Set = new Recurrence_Set( $this->get_event(), $type ); $this->{$type}[] = $Recurrence_Set; } else { $Recurrence_Set = $this->{$type}[ $set_id ]; } if ( !$Recurrence_Set->get_post( $data ) ) { $this->add_error( $Recurrence_Set->get_errors() ); } if ( $type == 'include' ) { // Use the initial recurrence_order as a string key $orderKey = (string) $Recurrence_Set->order ?: 99999; // If this key already exists, append a suffix to differentiate it if ( isset( $order[ $orderKey ] ) ) { $suffix = 1; // Increment the suffix until we find a unique key (e.g., "1.1", "1.2", etc.) while ( isset( $order[ $orderKey . '.' . $suffix ] ) ) { $suffix ++; } $orderKey .= '.' . $suffix; } $order[ $orderKey ] = $Recurrence_Set; } } } } // make sure we have a numerical ordering system, 1 onwwards, and designate the default recurrence set uksort( $order, function ( $a, $b ) { return floatval( $a ) <=> floatval( $b ); } ); $i = 1; foreach ( $order as $Recurrence_Set ) { $Recurrence_Set->order = $i; if ( $i === 1 ) { $this->default = $Recurrence_Set; } $i ++; } // now we know the recurrences we're dealing with, we can check for set-wide rescheduling if ( $this->reschedule ) { // reschedule everything $reschedule_action = static::get_reschedule_action( $this->reschedule ); foreach ( $this->include as $Recurrence_Set ) { $Recurrence_Set->set_reschedule( true ); $Recurrence_Set->reschedule_action = $reschedule_action; } $this->reschedule_exclude = $reschedule_action; } elseif ( $this->default->has_reschedule('dates') ) { // check the primary recurrence for changes to dates and make sure any subsequent recurrences depending on the primary are set for reschedule too if applicable foreach ( $this->include as $Recurrence_Set ) { if ( $Recurrence_Set !== $this->default ) { // if the recurrence has either of the start/end dates unset then we mark it for rescheduling if ( empty( $Recurrence_Set->recurrence_start_date ) || empty( $Recurrence_Set->recurrence_end_date ) ) { if ( !$Recurrence_Set->has_reschedule() ) { // copy the rescheduling action if the set isn't already set to be rescheduled $Recurrence_Set->reschedule_action = $this->default->reschedule_action; } $Recurrence_Set->reschedule['dates'] = true; // set to be rescheduled } } } } // check for exclusion rescheduling if ( !empty( $_REQUEST['recurrences']['exclude_reschedule']['nonce'] ) ) { if ( wp_verify_nonce( $_REQUEST['recurrences']['exclude_reschedule']['nonce'], 'reschedule_exclude_' . get_current_user_id() ) ) { // assign the flags to allow recurrences to be rescheduled $this->reschedule_exclude = static::get_reschedule_action( $_REQUEST['recurrences']['exclude_reschedule']['action'] ?? null ); } } } return apply_filters( 'em_recurrence_sets_get_post', count( $this->errors ) === 0, $this ); } /** * Handle saving booking-related information such as RSVP-by cutt-offs and checking ticket changes, this is triggered after EM_Event::get_post() has fully processed booking information. * @return void */ public function get_post_bookings() { $EM_Event = $this->get_event(); // Create timestamps and set rsvp date/time rules for recurrences. // We will save this for now on the primary recurrence for all recurrences, we can address overriding this on per-set basis if ( $this->get_event()->can_manage('manage_bookings','manage_others_bookings') ) { if ( $EM_Event->event_rsvp ) { if ( !empty($_REQUEST['modify_recurring_tickets']) && wp_verify_nonce( $_REQUEST['modify_recurring_tickets'], 'modify_recurring_tickets' ) ) { /* WIP for a later date, overridable per-set cut-off dates could be done if a requested feature //recurring events may have a cut-off date x days before or after the recurrence start dates $this->default->recurrence_rsvp_days = null; $this->default->recurrence_rsvp_time = null; if ( em_get_option( 'dbem_bookings_tickets_single' ) && count( $EM_Event->get_tickets()->tickets ) == 1 ) { //if in single ticket mode then ticket cut-off date determines event cut-off date $EM_Ticket = $EM_Event->get_tickets()->get_first(); if ( !empty( $EM_Ticket->ticket_meta['recurrences'] ) ) { $this->default->recurrence_rsvp_days = $EM_Ticket->ticket_meta['recurrences']['end_days']; $this->default->recurrence_rsvp_time = $EM_Ticket->ticket_meta['recurrences']['end_time']; } } else { if ( isset( $_POST['recurrence_rsvp_days'] ) ) { if ( !empty( $_POST['recurrence_rsvp_days_when'] ) && $_POST['recurrence_rsvp_days_when'] == 'after' ) { $this->default->recurrence_rsvp_days = absint( $_POST['recurrence_rsvp_days'] ); } else { //by default the start date is the point of reference $this->default->recurrence_rsvp_days = absint( $_POST['recurrence_rsvp_days'] ) * - 1; } } } */ // check for added or modified tickets $EM_Tickets = $EM_Event->get_tickets(); foreach ( $EM_Tickets->tickets as $EM_Ticket ) { if ( $EM_Ticket->ticket_id ) { // check if ticket has been modified in any way $ticket = new EM_Ticket( $EM_Ticket->ticket_id ); $original = $ticket->to_array(); $modified = $EM_Ticket->to_array(); $key_changes = []; foreach (['ticket_name', 'ticket_order', 'ticket_meta'] as $key) { if ( $original[$key] !== $modified[$key]) { $key_changes[$key] = true; } } if ( !empty($key_changes) ) { $this->booking_updates['tickets']['modified'][$EM_Ticket->ticket_id] = $EM_Ticket; } else { $this->booking_updates['tickets']['unchanged'][$EM_Ticket->ticket_id] = $EM_Ticket; } } else { // added $this->booking_updates['tickets']['added'][$EM_Ticket->ticket_uuid] = $EM_Ticket; } } $this->booking_updates['tickets']['deleted'] = $EM_Tickets->deleted_tickets; } else { foreach ( $EM_Event->get_tickets()->tickets as $EM_Ticket ) { $this->booking_updates['tickets']['unchanged'][$EM_Ticket->ticket_id] = $EM_Ticket; } } } } } /** * Saves events and replaces old ones. Returns true if sucecssful or false if not. * @return boolean */ public function validate () { foreach ( $this->include as $Recurrence_Set ) { if ( !$Recurrence_Set->validate() ) { $this->add_error( $Recurrence_Set->get_errors() ); } } return apply_filters( 'em_recurrence_sets_validate', empty( $this->errors ), $this ); } public function save () { if ( $this->get_event() ) { $this->event_id = $this->get_event()->event_id; foreach ( [ 'include', 'exclude' ] as $type ) { foreach ( $this->{$type} as $Recurrence_Set ) { /* @var Recurrence_Set $Recurrence_Set */ $Recurrence_Set->event_id = $this->event_id; // in case of a new save if ( $this->reschedule && !$Recurrence_Set->has_reschedule() ) { $Recurrence_Set->set_reschedule(true); } if ( !$Recurrence_Set->save() ) { $this->add_error( $Recurrence_Set->get_errors() ); } } } } else { $this->add_error( 'Recurrence sets do not have a linked Event to save from.' ); // this'd be a bug, therefore no translation } return apply_filters( 'em_recurrence_sets_save', empty( $this->errors ), $this ); } /** * Saves events and replaces old ones. Returns true if sucecssful or false if not. * @return boolean */ public function save_recurrences () { // TODO - If a recurrence with higher priority is rescheduled and results in a deleted event that preivously collided/overrode with a lower prio recurrence set, that lower prio event recurrence isn't created unless the lower prio is also rescheduled in some way. $result = true; $this->recurrences = []; // remove all recurrence records, since we're loading or recreating in both cases // add negative recurrence sets foreach ( $this->exclude as $Recurrence_Set ) { $this->recurrences += $Recurrence_Set->get_recurrences(); } // save each recurrence set, highest priority first, and keep adding them to recurrences array to build collision detection as we go foreach ( $this->include as $Recurrence_Set ) { if ( $Recurrence_Set->save_recurrences() === false ) { $this->add_error( $Recurrence_Set->get_errors() ); $result = false; } else { $this->recurrences += $Recurrence_Set->recurrences; } } // get the range of dates from all events, times, default timezone, etc. and apply it to the event now that we've saved everything $EM_Event = $this->get_event(); $dates = $this->get_datetime_range(); $EM_Event->event_start_date = $dates['start_date']; $EM_Event->event_start_time = $dates['start_time']; $EM_Event->event_end_date = $dates['end_date']; $EM_Event->event_end_time = $dates['end_time']; $EM_Event->event_all_day = $dates['all_day']; // we need to update the event object RSVP cut-off date as well if( $EM_Event->get_option('dbem_bookings_tickets_single') && count($EM_Event->get_tickets()->tickets) == 1 ){ //single ticket mode will use the ticket end date/time as cut-off date/time $EM_Ticket = $EM_Event->get_tickets()->get_first(); $EM_Event->event_rsvp_date = null; if ( !empty( $EM_Ticket->meta['recurrences']['end_date'] ) ) { $ticket_end_days = $EM_Ticket->meta['recurrences']['end_days'] >= 0 ? '+' . $EM_Ticket->meta['recurrences']['end_days'] : $EM_Ticket->meta['recurrences']['end_days']; $EM_DateTime = $EM_Event->end()->copy(); $EM_Event->event_rsvp_date = $EM_DateTime->modify( $ticket_end_days . ' days' )->getDate(); $EM_Event->event_rsvp_time = $EM_Ticket->meta['recurrences']['end_time']; } else { //no default ticket end time, so make it default to event end date/time which is roughly the last event $EM_Event->event_rsvp_date = $EM_Event->event_end_date; $EM_Event->event_rsvp_time = $EM_Event->event_end_time; } }else{ //if no rsvp cut-off date supplied, make it the event end date/time which is roughly the last event $EM_Event->event_rsvp_date = $EM_Event->event_end_date; $EM_Event->event_rsvp_time = $EM_Event->event_end_time; } //reset EM_DateTime object $EM_Event->rsvp_end = null; // Save the event data we just modified here $event = $EM_Event->to_array( true ); // update the database row directly, and the post meta (if there's a post_id) global $wpdb; $keys = [ 'event_start', 'event_end', 'event_start_date', 'event_start_time', 'event_end_date', 'event_end_time', 'event_all_day', 'event_rsvp_date', 'event_rsvp_time' ]; $event_data = array_intersect_key( $event, array_flip( $keys)); $wpdb->update( EM_EVENTS_TABLE, $event_data, ['event_id' => $this->event_id] ); if ( $EM_Event->post_id ) { $event_data['event_start_local'] = $EM_Event->start()->getDateTime(); $event_data['event_end_local'] = $EM_Event->end()->getDateTime(); // update post meta foreach ( $event_data as $key => $value ) { update_post_meta( $EM_Event->post_id, '_' . $key, $value ); } } // return final result return apply_filters( 'em_recurrence_sets_save_recurrences', $result, $this ); } /** * Saves events and replaces old ones. Returns true if sucecssful or false if not. * @return boolean */ public function delete_events () { $result = true; foreach ( $this->include as $Recurrence_Set ) { if ( !$Recurrence_Set->delete_events() ) { $this->add_error( $Recurrence_Set->get_errors() ); $result = false; } } return apply_filters( 'em_recurrence_sets_delete_events', $result, $this ); } // create a booking deletion function for all recurrences /** * Deletes events and replaces old ones. Returns true if sucecssful or false if not. * @return boolean */ public function delete_bookings () { $result = true; foreach ( $this->include as $Recurrence_Set ) { if ( !$Recurrence_Set->delete_bookings() ) { $this->add_error( $Recurrence_Set->get_errors() ); $result = false; } } return apply_filters( 'em_recurrence_sets_delete_bookings', $result, $this ); } /** * Saves events and replaces old ones. Returns true if sucecssful or false if not. * @return boolean */ public function set_status_events ( $status ) { $result = true; foreach ( $this->include as $Recurrence_Set ) { if ( !$Recurrence_Set->set_status_recurrences( $status ) ) { $this->add_error( $Recurrence_Set->get_errors() ); $result = false; } } return apply_filters( 'em_recurrence_sets_delete_events', $result, $this ); } /** * Validates and returns the currently supplied reschedule action, if null or invalid the default action is returned. * @param $action * * @return string */ public static function get_reschedule_action ( $action = null ) { $can_cancel = em_get_option( 'dbem_event_status_enabled' ) && array_key_exists( 0, EM_Event::get_active_statuses() ); $reschedule_possibilities = $can_cancel ? [ 'delete', 'cancel' ] : [ 'delete' ]; // cancel if not defined, delete if cancellations not possible return in_array( $action, $reschedule_possibilities ) ? $action : ( $can_cancel ? 'cancel' : 'delete' ); } public static function add_js_vars() { $notices = [ 'deleteSet' => sprintf( __( 'When you save this %s, all recurrences of this set will be deleted. Would you like to proceed?', 'events-manager' ), __( 'event', 'events-manager' ) ), 'rescheduleDatesPrimary' => __( 'By editing your primary recurrence set, you will change all subsequent default values of your other recurrences.', 'events-manager' ), 'reschedule' => __( 'You have chosen to edit your recurrence date ranges. If you shorten the date range, any recurrences falling outside the new date range will be cancelled or deleted.', 'events-manager' ), ]; \EM\Scripts_and_Styles::add_js_var('recurrenceNotices', $notices); } /** * Returns an API-friendly representation * @return array */ public function to_api () { $api = [ 'sets' => [], 'event_id' => $this->event_id, ]; foreach ( $this->include as $Recurrence_Set ) { $api['sets'][] = $Recurrence_Set->to_api(); } return $api; } /** * Gets first recurrence set in the array of sets, without resetting internal pointer. * @return Recurrence_Set|false */ public function get_first () { return $this->default; } //Iterator Implementation #[\ReturnTypeWillChange] public function rewind () { reset( $this->include ); } #[\ReturnTypeWillChange] /** * @return Recurrence_Set */ public function current () { return current( $this->include ); } #[\ReturnTypeWillChange] public function key () { return key( $this->include ); } #[\ReturnTypeWillChange] /** * @return Recurrence_Set|false */ public function next () { return next( $this->include ); } #[\ReturnTypeWillChange] public function valid () { $key = key( $this->include ); return ( $key !== null && $key !== false ); } // ArrayAccess Implementation #[\ReturnTypeWillChange] /** * @param $offset * @param $value * * @return void */ public function offsetSet ( $offset, $value ) { if ( is_null( $offset ) ) { $this->include[] = $value; } else { $this->include[ $offset ] = $value; } } #[\ReturnTypeWillChange] public function offsetExists ( $offset ) { return isset( $this->include[ $offset ] ); } #[\ReturnTypeWillChange] public function offsetUnset ( $offset ) { unset( $this->include[ $offset ] ); } #[\ReturnTypeWillChange] /** * @param $offset * * @return Recurrence_Set|null */ public function offsetGet ( $offset ) { return isset( $this->include[ $offset ] ) ? $this->include[ $offset ] : null; } #[\ReturnTypeWillChange] public function count () { return count( $this->include ); } }
| ver. 1.4 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0 |
proxy
|
phpinfo
|
Настройка