Beispiel #1
0
/**
* This is a private function - handles the generation of occurrence dates from the schedule data
* @access private
* @ignore
*
* @param array $event_data - Array containing the event's schedule data
* @return array $event_data - Array containing the event's schedule data including 'occurrences', an array of DateTimes
*/
function _eventorganiser_generate_occurrences($event_data = array())
{
    $event_defaults = array('start' => '', 'end' => '', 'all_day' => 0, 'schedule' => 'once', 'schedule_meta' => '', 'frequency' => 1, 'schedule_last' => '', 'number_occurrences' => 0, 'exclude' => array(), 'include' => array());
    extract(wp_parse_args($event_data, $event_defaults));
    $occurrences = array();
    //occurrences array
    $exclude = array_filter((array) $exclude);
    $include = array_filter((array) $include);
    $exclude = array_udiff($exclude, $include, '_eventorganiser_compare_datetime');
    $include = array_udiff($include, $exclude, '_eventorganiser_compare_datetime');
    //White list schedule
    if (!in_array($schedule, array('once', 'daily', 'weekly', 'monthly', 'yearly', 'custom'))) {
        return new WP_Error('eo_error', __('Schedule not recognised.', 'eventorganiser'));
    }
    //Ensure event frequency is a positive integer. Else set to 1.
    $frequency = max(absint($frequency), 1);
    $all_day = (int) $all_day;
    $number_occurrences = absint($number_occurrences);
    //Check dates are supplied and are valid
    if (!$start instanceof DateTime) {
        return new WP_Error('eo_error', __('Start date not provided.', 'eventorganiser'));
    }
    if (!$end instanceof DateTime) {
        $end = clone $start;
    }
    //If use 'number_occurrences' to limit recurring event, set dummy 'schedule_last' date.
    if (!$schedule_last instanceof DateTime && $number_occurrences && in_array($schedule, array('daily', 'weekly', 'monthly', 'yearly'))) {
        //Set dummy "last occurrance" date.
        $schedule_last = clone $start;
    } else {
        $number_occurrences = 0;
    }
    if ('once' == $schedule || !$schedule_last instanceof DateTime) {
        $schedule_last = clone $start;
    }
    //Check dates are in chronological order
    if ($end < $start) {
        return new WP_Error('eo_error', __('Start date occurs after end date.', 'eventorganiser'));
    }
    if ($schedule_last < $start) {
        return new WP_Error('eo_error', __('Schedule end date is before is before the start date.', 'eventorganiser'));
    }
    //Now set timezones
    $timezone = eo_get_blog_timezone();
    $start->setTimezone($timezone);
    $end->setTimezone($timezone);
    $schedule_last->setTimezone($timezone);
    $H = intval($start->format('H'));
    $i = intval($start->format('i'));
    $start_days = array();
    $workaround = '';
    $icaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
    $weekdays = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
    $ical2day = array('SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday');
    //Set up schedule
    switch ($schedule) {
        case 'once':
        case 'custom':
            $frequency = 1;
            $schedule_meta = '';
            $schedule_start = clone $start;
            $schedule_last = clone $start;
            $start_days[] = clone $start;
            $workaround = 'once';
            //Not strictly a workaround.
            break;
        case 'daily':
            $interval = "+" . $frequency . "day";
            $start_days[] = clone $start;
            break;
        case 'weekly':
            $schedule_meta = $schedule_meta ? array_filter($schedule_meta) : array();
            if (!empty($schedule_meta) && is_array($schedule_meta)) {
                foreach ($schedule_meta as $day) {
                    $start_day = clone $start;
                    $start_day->modify($ical2day[$day]);
                    $start_days[] = $start_day;
                }
            } else {
                $schedule_meta = array($icaldays[$start->format('w')]);
                $start_days[] = clone $start;
            }
            $interval = "+" . $frequency . "week";
            break;
        case 'monthly':
            $start_days[] = clone $start;
            $rule_value = explode('=', $schedule_meta, 2);
            $rule = $rule_value[0];
            $values = !empty($rule_value[1]) ? explode(',', $rule_value[1]) : array();
            //Should only be one value, but may support more in future
            $values = array_filter($values);
            if ($rule == 'BYMONTHDAY') {
                $date = (int) $start_days[0]->format('d');
                $interval = "+" . $frequency . "month";
                if ($date >= 29) {
                    $workaround = 'short months';
                }
                //This case deals with 29/30/31 of month
                $schedule_meta = 'BYMONTHDAY=' . $date;
            } else {
                if (empty($values)) {
                    $date = (int) $start_days[0]->format('d');
                    $n = ceil($date / 7);
                    // nth weekday of month.
                    $day_num = intval($start_days[0]->format('w'));
                    //0 (Sun) - 6(Sat)
                } else {
                    //expect e.g. array( 2MO )
                    preg_match('/^(-?\\d{1,2})([a-zA-Z]{2})/', $values[0], $matches);
                    $n = (int) $matches[1];
                    $day_num = array_search($matches[2], $icaldays);
                    //(Sun) - 6(Sat)
                }
                if ($n == 5) {
                    $n = -1;
                }
                //If 5th, interpret it as last.
                $ordinal = array('1' => "first", '2' => "second", '3' => "third", '4' => "fourth", '-1' => "last");
                if (!isset($ordinal[$n])) {
                    return new WP_Error('eo_error', __('Invalid monthly schedule (invalid ordinal)', 'eventorganiser'));
                }
                $ical_day = $icaldays[$day_num];
                //ical day from day_num (SU - SA)
                $day = $weekdays[$day_num];
                //Full day name from day_num (Sunday -Monday)
                $schedule_meta = 'BYDAY=' . $n . $ical_day;
                //E.g. BYDAY=2MO
                $interval = $ordinal[$n] . ' ' . $day . ' of +' . $frequency . ' month';
                //E.g. second monday of +1 month
                //Work around for PHP <5.3
                if (!function_exists('date_diff')) {
                    $workaround = 'php5.2';
                }
            }
            break;
        case 'yearly':
            $start_days[] = clone $start;
            if ('29-02' == $start_days[0]->format('d-m')) {
                $workaround = 'leap year';
            }
            $interval = "+" . $frequency . "year";
            break;
    }
    //End $schedule switch
    //Now we have setup and validated the schedules - loop through and generate occurrences
    foreach ($start_days as $index => $start_day) {
        $current = clone $start_day;
        $occurrence_n = 0;
        switch ($workaround) {
            //Not really a workaround. Just add the occurrence and finish.
            case 'once':
                $current->setTime($H, $i);
                $occurrences[] = clone $current;
                break;
                //Loops for monthly events that require php5.3 functionality
            //Loops for monthly events that require php5.3 functionality
            case 'php5.2':
                while ($current <= $schedule_last || $occurrence_n < $number_occurrences) {
                    $current->setTime($H, $i);
                    $occurrences[] = clone $current;
                    $current = _eventorganiser_php52_modify($current, $interval);
                    $occurrence_n++;
                }
                break;
                //Loops for monthly events on the 29th/30th/31st
            //Loops for monthly events on the 29th/30th/31st
            case 'short months':
                $day_int = intval($start_day->format('d'));
                //Set the first month
                $current_month = clone $start_day;
                $current_month = date_create($current_month->format('Y-m-1'));
                while ($current_month <= $schedule_last || $occurrence_n < $number_occurrences) {
                    $month_int = intval($current_month->format('m'));
                    $year_int = intval($current_month->format('Y'));
                    if (checkdate($month_int, $day_int, $year_int)) {
                        $current = new DateTime($day_int . '-' . $month_int . '-' . $year_int, $timezone);
                        $current->setTime($H, $i);
                        $occurrences[] = clone $current;
                        $occurrence_n++;
                    }
                    $current_month->modify($interval);
                }
                break;
                //To be used for yearly events occuring on Feb 29
            //To be used for yearly events occuring on Feb 29
            case 'leap year':
                $current_year = clone $current;
                $current_year->modify('-1 day');
                while ($current_year <= $schedule_last || $occurrence_n < $number_occurrences) {
                    $is_leap_year = (int) $current_year->format('L');
                    if ($is_leap_year) {
                        $current = clone $current_year;
                        $current->modify('+1 day');
                        $current->setTime($H, $i);
                        $occurrences[] = clone $current;
                        $occurrence_n++;
                    }
                    $current_year->modify($interval);
                }
                break;
            default:
                while ($current <= $schedule_last || $occurrence_n < $number_occurrences) {
                    $current->setTime($H, $i);
                    $occurrences[] = clone $current;
                    $current->modify($interval);
                    $occurrence_n++;
                }
                break;
        }
        //End 'workaround' switch;
    }
    //Now schedule meta is set up and occurrences are generated.
    if ($number_occurrences > 0) {
        //If recurrence is limited by #occurrences. Do that here.
        sort($occurrences);
        $occurrences = array_slice($occurrences, 0, $number_occurrences);
    }
    //Add inclusions, removes exceptions and duplicates
    if (defined('WP_DEBUG') && WP_DEBUG) {
        //Make sure 'included' dates doesn't appear in generate date
        $include = array_udiff($include, $occurrences, '_eventorganiser_compare_datetime');
    }
    $occurrences = array_merge($occurrences, $include);
    $occurrences = array_udiff($occurrences, $exclude, '_eventorganiser_compare_datetime');
    $occurrences = _eventorganiser_remove_duplicates($occurrences);
    //Sort occurrences
    sort($occurrences);
    if (empty($occurrences) || !$occurrences[0] || !$occurrences[0] instanceof DateTime) {
        return new WP_Error('eo_error', __('Event does not contain any dates.', 'eventorganiser'));
    }
    $schedule_start = clone $occurrences[0];
    $schedule_last = clone end($occurrences);
    $_event_data = array('start' => $start, 'end' => $end, 'all_day' => $all_day, 'schedule' => $schedule, 'schedule_meta' => $schedule_meta, 'frequency' => $frequency, 'schedule_start' => $schedule_start, 'schedule_last' => $schedule_last, 'exclude' => $exclude, 'include' => $include, 'occurrences' => $occurrences);
    /**
     * Filters the event schedule after its dates has been generated by a given schedule.
     * 
     * The filtered array is an array of occurrences generated from a 
     * schedule which may include:
     * 
     * * **start** (DateTime) -  when the event starts
     * * **end** (DateTime) - when the event ends
     * * **all_day** (Bool) - If the event is all day or no
     * * **all_day** (Bool) - If the event is all day or not
     * * **schedule** (String) - One of once|weekl|daily|monthly|yearly|custom
     * * **schedule_meta** (Array|String) - See documentation for `eo_insert_event()`
     * * **frequency** (int) - The frequency of which the event repeats
     * * **schedule_last** (DateTime) - date of last occurrence of event
     * * **number_occurrences** (int) - number of times the event should repeat (if `schedule_last` is not specified).
     * * **exclude** (array) - Array of DateTime objects  to exclude from the schedule
     * * **include** (array) - Array of DateTime objects to include in the schedule
     * * **occurrences** (array) - Array of DateTime objects generated from the above schedule.
     * 
     * @param array The event schedule with generated occurrences.
     * @param array The original event schedule (without occurrences).  
     */
    $_event_data = apply_filters('eventorganiser_generate_occurrences', $_event_data, $event_data);
    return $_event_data;
}
 public function testRemoveDuplicatesAssociative()
 {
     $array = array('hello' => new DateTime('2013-01-01 15:00'), 'foo' => new DateTime('2013-01-02 15:00'), 'bar' => new DateTime('2013-01-01 15:00'));
     $array_without_duplicates = array('hello' => new DateTime('2013-01-01 15:00'), 'foo' => new DateTime('2013-01-02 15:00'));
     $this->assertEquals($array_without_duplicates, _eventorganiser_remove_duplicates($array));
 }
/**
 * Saves the event data posted from the event metabox.
 * Hooked to the 'save_post' action
 * 
 * @since 1.0.0
 *
 * @param int $post_id the event post ID
 * @return int $post_id the event post ID
 */
function eventorganiser_details_save($post_id)
{
    //make sure data came from our meta box
    if (!isset($_POST['_eononce']) || !wp_verify_nonce($_POST['_eononce'], 'eventorganiser_event_update_' . $post_id . '_' . get_current_blog_id())) {
        return;
    }
    //verify this is not an auto save routine.
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return;
    }
    //authentication checks
    if (!current_user_can('edit_event', $post_id)) {
        return;
    }
    //Collect raw data
    $raw_data = isset($_POST['eo_input']) ? $_POST['eo_input'] : array();
    $raw_data = wp_parse_args($raw_data, array('StartDate' => '', 'EndDate' => '', 'StartTime' => '00:00', 'FinishTime' => '23:59', 'schedule' => 'once', 'event_frequency' => 1, 'schedule_end' => '', 'allday' => 0, 'schedule_meta' => '', 'days' => array(), 'include' => '', 'exclude' => ''));
    //Update venue
    $venue_id = !empty($raw_data['event-venue']) ? intval($raw_data['event-venue']) : null;
    //Maybe create a new venue
    if (empty($venue_id) && !empty($_POST['eo_venue']) && current_user_can('manage_venues')) {
        $venue = $_POST['eo_venue'];
        if (!empty($venue['name'])) {
            $new_venue = eo_insert_venue($venue['name'], $venue);
            if (!is_wp_error($new_venue)) {
                $venue_id = $new_venue['term_id'];
            } else {
                if ($new_venue->get_error_code() == 'term_exists') {
                    $venue_id = eo_get_venue($event_id);
                }
            }
        }
    }
    //Set venue
    $r = wp_set_post_terms($post_id, array($venue_id), 'event-venue', false);
    //If reocurring, but not editing occurrences, can abort here, but trigger hook.
    if (eo_reoccurs($post_id) && (!isset($raw_data['AlterRe']) || 'yes' != $raw_data['AlterRe'])) {
        /**
         * Triggered after an event has been updated.
         *
         * @param int $post_id The ID of the event
         */
        do_action('eventorganiser_save_event', $post_id);
        //Need this to update cache
        return;
    }
    //Check dates
    $date_format = eventorganiser_get_option('dateformat');
    $is24 = eventorganiser_blog_is_24();
    $time_format = $is24 ? 'H:i' : 'g:ia';
    $datetime_format = $date_format . ' ' . $time_format;
    //Set times for all day events
    $all_day = intval($raw_data['allday']);
    if ($all_day) {
        $raw_data['StartTime'] = $is24 ? '00:00' : '12:00am';
        $raw_data['FinishTime'] = $is24 ? '23:59' : '11:59pm';
    }
    $start = eo_check_datetime($datetime_format, trim($raw_data['StartDate']) . ' ' . trim($raw_data['StartTime']));
    $end = eo_check_datetime($datetime_format, trim($raw_data['EndDate']) . ' ' . trim($raw_data['FinishTime']));
    $schedule_last = eo_check_datetime($datetime_format, trim($raw_data['schedule_end']) . ' ' . trim($raw_data['StartTime']));
    //Collect schedule meta
    $schedule = $raw_data['schedule'];
    if ('weekly' == $schedule) {
        $schedule_meta = $raw_data['days'];
        $occurs_by = '';
    } elseif ('monthly' == $schedule) {
        $schedule_meta = $raw_data['schedule_meta'];
        $occurs_by = trim($schedule_meta, '=');
    } else {
        $schedule_meta = '';
        $occurs_by = '';
    }
    //Collect include/exclude
    $in_ex = array();
    $orig_schedule = eo_get_event_schedule($post_id);
    foreach (array('include', 'exclude') as $key) {
        $in_ex[$key] = array();
        $arr = explode(',', sanitize_text_field($raw_data[$key]));
        if (!empty($arr)) {
            foreach ($arr as $date) {
                if ($date_obj = eo_check_datetime('Y-m-d', trim($date))) {
                    $date_obj->setTime($start->format('H'), $start->format('i'));
                    $in_ex[$key][] = $date_obj;
                }
            }
            if ($orig = array_uintersect($orig_schedule[$key], $in_ex[$key], '_eventorganiser_compare_dates')) {
                $in_ex[$key] = array_merge($orig, $in_ex[$key]);
                $in_ex[$key] = _eventorganiser_remove_duplicates($in_ex[$key]);
            }
        }
    }
    $event_data = array('start' => $start, 'end' => $end, 'all_day' => $all_day, 'schedule' => $schedule, 'frequency' => (int) $raw_data['event_frequency'], 'schedule_last' => $schedule_last, 'schedule_meta' => $schedule_meta, 'occurs_by' => $occurs_by, 'include' => $in_ex['include'], 'exclude' => $in_ex['exclude']);
    $response = eo_update_event($post_id, $event_data);
    if (is_wp_error($response)) {
        global $EO_Errors;
        $code = $response->get_error_code();
        $message = $response->get_error_message($code);
        $errors[$post_id][] = __('Event dates were not saved.', 'eventorganiser');
        $errors[$post_id][] = $message;
        $EO_Errors->add('eo_error', $message);
        update_option('eo_notice', $errors);
    }
    return;
}