public function testModifyDatePHP52()
 {
     $modify = 'first Monday of +1 Month';
     $date = new DateTime('2014-01-30');
     $date2 = new DateTime('2014-01-30');
     $date3 = _eventorganiser_php52_modify($date2, $modify);
     $expected = new DateTime('2014-02-03');
     $this->assertEquals($expected, $date3);
 }
Esempio n. 2
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 testModifyDatePHP52()
 {
     $modify = 'first Monday of +1 Month';
     $expected = new DateTime('2014-02-03');
     $date = new DateTime('2014-01-30');
     $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify));
     //Check multiple months
     $modify = 'LaSt FrIdAY oF +5 MoNtH';
     $expected = new DateTime('2014-06-27');
     $date = new DateTime('2014-01-30');
     $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify));
     //Check without a +
     $modify = 'LaSt FrIdAY oF 2 MoNtH';
     $expected = new DateTime('2014-03-28');
     $date = new DateTime('2014-01-30');
     $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify));
     //Check wit a -
     $modify = 'third wednesday of -1 month';
     $expected = new DateTime('2013-12-18');
     $date = new DateTime('2014-01-30');
     $this->assertEquals($expected, _eventorganiser_php52_modify($date, $modify));
 }