| Server IP : 81.2.241.106 / Your IP : 216.73.216.165 Web Server : Apache/2.4.67 (Debian) System : Linux tranq-f.bakta.org 5.10.0-45-amd64 #1 SMP Debian 5.10.259-1 (2026-07-02) x86_64 User : lisky ( 1002) PHP Version : 7.4.33 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/lisky/wp-content/plugins/events-manager/classes/timeslots/ |
Upload File : |
<?php
namespace EM;
/**
* Collection class for managing multiple Timerange objects.
* Provides traversable, searchable functionality similar to Recurrence_Sets.
*
* @property int $length The number of timeranges in this collection.
*/
class Timeranges extends \EM_Object implements \Iterator, \ArrayAccess, \Countable {
/**
* @var Timerange[] Array of Timerange objects
*/
public $timeranges = [];
/**
* @var string The group ID these timeranges belong to
*/
public $group_id;
/**
* @var array Timeranges that have been marked for deletion
*/
public $deleted_timeranges = [];
/**
* @var bool Whether this collection allows more than one timerange.
*/
public $allow_timeranges = true;
/**
* @var string The action to take when deleting a timerange, which is usually connected to associated events, bookings, etc.
*/
public $allow_edit = true;
/**
* @var string The action to take when deleting a timerange, which is usually connected to associated events, bookings, etc.
*/
public $delete_action = 'cancel';
/**
* @var Timeslot[] Array of timeslots generated from this collection
*/
public $generated_timeslots = [];
/**
* Constructor to initialize the Timeranges collection.
*
* @param string|null $group_id The group ID to load timeranges for
*/
public function __construct( $group_id = null ) {
$this->group_id = $group_id;
}
/**
* Sets the group id of this set and recursively sets each group id in the timeranges
* @param $group_id
*
* @return void
*/
public function set_group_id( $group_id ) {
$this->group_id = $group_id;
foreach ( $this->timeranges as $Timerange ) {
$Timerange->timerange_group_id = $group_id;
}
}
/**
* @param $data
*
* @return Timerange
*/
public function get_timerange( $data = false ) {
return new Timerange( $data );
}
/**
* Load timeranges from database for given group ID
*/
protected function load_timeranges( $padding = false ) {
global $wpdb;
if ( !$this->timeranges && $this->group_id ) {
// Use the constant if available, otherwise construct table name
$sql = $wpdb->prepare("SELECT * FROM ". EM_TIMERANGES_TABLE ." WHERE timerange_group_id = %s ORDER BY timerange_start ASC", $this->group_id);
$timeranges_data = $wpdb->get_results($sql, ARRAY_A);
foreach ($timeranges_data as $timerange_data) {
$Timerange = $this->get_timerange($timerange_data);
$this->timeranges[ $Timerange->timerange_id ] = $Timerange;
}
}
if ( empty( $this->timeranges ) && $padding ) {
$this->timeranges = [ $this->get_timerange() ];
}
return $this->timeranges;
}
public function get_timeranges( $padding = false ) {
$this->load_timeranges( $padding );
return $this->timeranges;
}
/**
* Return array of timeslots, in seconds since midnight for a day based on timerange rules in this set.
* @return Timeslot[]
*/
public function get_timeslots() {
return $this->generate_timeslots();
}
/**
* Generates an array of timeslots, in minutes since midnight for a day based on timerange rules in this set.
* @param $reload
* @return Timeslot[]
*/
public function generate_timeslots( $reload = false ) {
if ( !$this->generated_timeslots || $reload ) {
$this->generated_timeslots = [];
foreach ( $this->get_timeranges() as $timerange ) {
$this->generated_timeslots = array_merge( $this->generated_timeslots, $timerange->generate_timeslots() );
}
// Remove duplicate start timeslots
foreach ($this->generated_timeslots as $key1 => $Timeslot) {
foreach ( $this->generated_timeslots as $key2 => $_Timeslot ) {
// We only compare items that are after the current item in the array, given this is a numerically key-ordered array
if ( $key1 < $key2 ) {
if ( $Timeslot->start === $_Timeslot->start ) {
unset( $this->generated_timeslots[ $key2 ] );
}
}
}
}
// Re-index the array after removing elements with unset().
$this->generated_timeslots = array_values($this->generated_timeslots);
}
return $this->generated_timeslots;
}
/**
* Gets the earliest time in the collection, in HH:MM:SS format or in WP localized format if $format is set to true
*
* @param bool $format
* @return string
*/
public function get_time_start( $format = false ) {
$earliest_time = null; // latest is 24h
foreach ( $this->get_timeranges() as $Timerange ) {
$hour_start = $Timerange->timerange_start;
$ts_start = strtotime('1970-01-01 ' . $hour_start);
if ( $earliest_time === null || $ts_start < $earliest_time ) {
$earliest_time = $ts_start;
}
}
$date_format = $format ?: 'H:i:s';
return date($date_format, $earliest_time ?? 0);
}
public function get_time_end( $format = false ) {
$latest = null; // latest is 24h
foreach ( $this->get_timeranges() as $timerange ) {
$hour_start = $timerange->timerange_end;
$ts_end = strtotime('1970-01-01 ' . $hour_start);
if ( $ts_end > $latest ) {
$latest = $ts_end;
}
}
$date_format = $format ?: 'H:i:s';
return date($date_format, $latest ?? 0);
}
public function is_all_day() {
if ( $this->count() == 1 ) {
foreach ( $this->get_timeranges() as $timerange ) {
if ( $timerange->timerange_all_day ) {
return true;
}
}
}
return false;
}
public function get_time_from_minutes( $minutes ) {
return date('H:i:s', $minutes * 60 );
}
/**
* Static method to get timeranges data from database
*
* @return array
*/
public function get() {
return $this->get_timeranges();
}
/**
* Add a new timerange to the collection
*
* @param Timerange|array $timerange
* @return bool
*/
public function add($timerange) {
if ( is_array($timerange) ) {
$timerange = new Timerange($timerange);
}
if ( $timerange instanceof Timerange ) {
$timerange->timerange_group_id = $this->group_id;
$this->timeranges[] = $timerange;
return true;
}
return false;
}
/**
* Remove a timerange from the collection
*
* @param int|Timerange $timerange_id_or_object
* @return boolean
*/
public function remove( $timerange_id_or_object ) {
$timerange_id = is_object($timerange_id_or_object) ? $timerange_id_or_object->timerange_id : $timerange_id_or_object;
foreach ($this->timeranges as $key => $timerange) {
if ($timerange->timerange_id == $timerange_id) {
$this->deleted_timeranges[] = $timerange;
unset($this->timeranges[$key]);
// Reindex array
$this->timeranges = array_values($this->timeranges);
return true;
}
}
return false;
}
/**
* Get POST data for all timeranges in the collection
*
* @param string|array $post_name
* @return boolean
*/
public function get_post( $post_name = 'timeranges' ) {
do_action('em_timeranges_get_post_pre', $this);
$result = true;
$post_array = is_array( $post_name ) ? $post_name : $_POST[ $post_name ] ?? [];
if ( !$this->group_id || $this->allow_edit || wp_verify_nonce( $post_array['edit_nonce'] ?? '', 'em_timeranges_edit_' . $this->group_id ) ) {
$this->allow_edit = true;
if ( is_array( $post_name ) || ( !empty( $_POST[ $post_name ] ) && is_array( $_POST[ $post_name ] ) ) ) {
$this->load_timeranges();
// remove default timerange
if ( !empty($this->timeranges[0]) ) {
unset( $this->timeranges[0] );
}
// add or update timeranges
foreach ( $post_array as $key => $timerange_data ) {
if ( $key !== 'edit_nonce' && $key !== 'delete' ) {
if ( isset( $timerange_data['timerange_id'] ) && array_key_exists( $timerange_data['timerange_id'], $this->timeranges ) ) {
$Timerange = $this->timeranges[ $timerange_data['timerange_id'] ];
// check for edit nonce or delete nonce
} else {
$Timerange = $this->get_timerange( ['timerange_group_id' => $this->group_id ]);
$this->timeranges[] = $Timerange;
}
$Timerange->get_post( $timerange_data );
}
}
// process deleted ones and mark for deletion
if ( !empty( $post_array['delete'] ) ) {
foreach ( $post_array['delete'] as $timerange_id => $delete_nonce ) {
if ( $delete_nonce && wp_verify_nonce( $delete_nonce, 'delete_timerange_' . $timerange_id ) ) {
$this->deleted_timeranges[ $timerange_id ] = $this->timeranges[ $timerange_id ];
unset( $this->timeranges[ $timerange_id ] );
}
}
}
}
}
return apply_filters('em_timeranges_get_post', $result, $this);
}
/**
* Validate all timeranges in the collection
*
* @return boolean
*/
public function validate() {
do_action('em_timeranges_validate_pre', $this);
$result = true;
foreach ($this->timeranges as $timerange) {
if (!$timerange->validate()) {
$this->add_error($timerange->get_errors());
$result = false;
}
}
// Check for overlapping timeranges (optional validation)
if ($result && $this->has_overlapping_timeranges()) {
$this->add_error(__('Timeranges cannot overlap with each other.', 'events-manager'));
$result = false;
}
return apply_filters('em_timeranges_validate', $result, $this);
}
/**
* Check if any timeranges overlap with each other
*
* @return boolean
*/
public function has_overlapping_timeranges() {
foreach ( $this->timeranges as $i => $Timerange ) {
foreach ( $this->timeranges as $j => $Timerange_2 ) {
if ( $i !== $j ) {
// If we detect an all day time range, return true as something is just wrong
if ( $Timerange->timerange_all_day || $Timerange_2->timerange_all_day) {
return true;
}
$start1 = strtotime('1970-01-01 ' . $Timerange->timerange_start);
$end1 = strtotime('1970-01-01 ' . $Timerange->timerange_end);
$start2 = strtotime('1970-01-01 ' . $Timerange_2->timerange_start);
$end2 = strtotime('1970-01-01 ' . $Timerange_2->timerange_end);
// Check for overlap, either same start time, or start/end time is within another start/end time
if ($start1 === $start2 || ( $start1 < $end2 && $start1 > $start2 ) || ( $end1 > $start2 && $end1 < $end2 )) {
return true;
}
}
}
}
return false;
}
/**
* Checks all timeranges in set and returns true if at least one has timeslots
* @return bool
*/
public function has_timeslots() {
if ( $this->count() > 1 ) {
return true;
} elseif ( $this->count() == 1 ) {
return $this->get_first()->has_timeslots();
}
return false;
}
/**
* Save all timeranges in the collection
*
* @return boolean
*/
public function save() {
if ( $this->allow_edit ) {
do_action( 'em_timeranges_save_pre', $this );
$result = true;
// Delete marked timeranges first
foreach ( $this->deleted_timeranges as $timerange ) {
if ( !$timerange->delete() ) {
$this->add_error( $timerange->get_errors() );
$result = false;
}
}
// Save all timeranges
foreach ( $this->timeranges as $timerange ) {
if ( !$timerange->save() ) {
$this->add_error( $timerange->get_errors() );
$result = false;
}
}
if ( $result ) {
$this->deleted_timeranges = []; // Clear deleted list after successful save
$this->feedback_message = sprintf( __( 'Successfully saved %d timeranges.', 'events-manager' ), count( $this->timeranges ) );
}
do_action( 'em_timeranges_save_post', $this, $result );
return apply_filters( 'em_timeranges_save', $result, $this );
}
}
/**
* Delete all timeranges in the collection
*
* @return boolean
*/
public function delete() {
do_action('em_timeranges_delete_pre', $this);
$result = true;
foreach ($this->timeranges as $timerange) {
if ( !$timerange->delete() ) {
$this->add_error($timerange->get_errors());
$result = false;
}
}
if ($result) {
$this->timeranges = [];
$this->feedback_message = __('Successfully deleted all timeranges.', 'events-manager');
}
do_action('em_timeranges_delete_post', $this, $result);
return apply_filters('em_timeranges_delete', $result, $this);
}
/**
* Get the first timerange in the collection
*
* @return Timerange|false
*/
public function get_first() {
$this->load_timeranges();
foreach ( $this->timeranges as $timerange ) {
return $timerange;
}
return false;
}
/**
* Get the last timerange in the collection
*
* @return Timerange|false
*/
public function get_last() {
return !empty($this->timeranges) ? end($this->timeranges) : false;
}
/**
* Convert collection to API format
*
* @return array
*/
public function to_api() {
$api_data = array(
'group_id' => $this->group_id,
'timeranges' => array()
);
foreach ( $this->load_timeranges() as $timerange ) {
$api_data['timeranges'][] = $timerange->to_api();
}
return apply_filters('em_timeranges_to_api', $api_data, $this);
}
// Iterator Implementation
#[\ReturnTypeWillChange]
public function rewind() {
$this->load_timeranges();
reset($this->timeranges);
}
#[\ReturnTypeWillChange]
/**
* @return Timerange
*/
public function current() {
$this->load_timeranges();
return current($this->timeranges);
}
#[\ReturnTypeWillChange]
public function key() {
$this->load_timeranges();
return key($this->timeranges);
}
#[\ReturnTypeWillChange]
/**
* @return Timerange|false
*/
public function next() {
$this->load_timeranges();
return next($this->timeranges);
}
#[\ReturnTypeWillChange]
public function valid() {
$this->load_timeranges();
$key = key($this->timeranges);
return ($key !== null && $key !== false);
}
// ArrayAccess Implementation
#[\ReturnTypeWillChange]
/**
* @param mixed $offset
* @param Timerange $value
* @return void
*/
public function offsetSet($offset, $value) {
$this->load_timeranges();
if (is_null($offset)) {
$this->timeranges[] = $value;
} else {
$this->timeranges[$offset] = $value;
}
}
#[\ReturnTypeWillChange]
public function offsetExists($offset) {
$this->load_timeranges();
return isset($this->timeranges[$offset]);
}
#[\ReturnTypeWillChange]
public function offsetUnset($offset) {
$this->load_timeranges();
unset($this->timeranges[$offset]);
// Reindex array to maintain sequential keys
$this->timeranges = array_values($this->timeranges);
}
#[\ReturnTypeWillChange]
/**
* @param mixed $offset
* @return Timerange|null
*/
public function offsetGet($offset) {
$this->load_timeranges();
return isset($this->timeranges[$offset]) ? $this->timeranges[$offset] : null;
}
// Countable Implementation
#[\ReturnTypeWillChange]
public function count() {
$this->load_timeranges();
return count($this->timeranges);
}
/*
* Possibly redundant methods
*/
/**
* Find a timerange by ID
*
* @param int $timerange_id
* @return Timerange|false
*/
public function find($timerange_id) {
foreach ($this->timeranges as $timerange) {
if ($timerange->timerange_id == $timerange_id) {
return $timerange;
}
}
return false;
}
/**
* Find timeranges by criteria
*
* @param array $criteria
* @return Timerange[]
*/
public function find_by($criteria) {
$found = [];
foreach ($this->timeranges as $timerange) {
$match = true;
foreach ($criteria as $field => $value) {
if ($timerange->$field != $value) {
$match = false;
break;
}
}
if ($match) {
$found[] = $timerange;
}
}
return $found;
}
/**
* Get timeranges that are all-day
*
* @return Timerange[]
*/
public function get_all_day() {
return $this->find_by(['timerange_all_day' => 1]);
}
/**
* Get timeranges within a time range
*
* @param string $start_time
* @param string $end_time
* @return Timerange[]
*/
public function get_by_time_range($start_time, $end_time) {
$found = [];
foreach ($this->timeranges as $timerange) {
if ($timerange->timerange_start >= $start_time && $timerange->timerange_end <= $end_time) {
$found[] = $timerange;
}
}
return $found;
}
/**
* Sort timeranges by specified field
*
* @param string $field
* @param string $order ASC or DESC
*/
public function sort_by($field = 'timerange_start', $order = 'ASC') {
usort($this->timeranges, function($a, $b) use ($field, $order) {
$result = strcmp($a->$field, $b->$field);
return ($order === 'DESC') ? -$result : $result;
});
}
}
include( __DIR__ . '/timeslot.php' );
include( __DIR__ . '/timerange.php' );