First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
180
sites/all/modules/civicrm/packages/When/README.md
Normal file
180
sites/all/modules/civicrm/packages/When/README.md
Normal file
|
@ -0,0 +1,180 @@
|
|||
##When
|
||||
|
||||
**If you are considering using When, please use the [develop branch](https://github.com/tplaner/When/tree/develop) it will replace this branch when the documentation is complete, functionally it offers everything this version does, it supports PHP 5.3+.**
|
||||
|
||||
Date/Calendar recursion library for PHP 5.2+
|
||||
|
||||
Author: Thomas Planer
|
||||
|
||||
---
|
||||
###About
|
||||
After a comprehensive search I couldn't find a PHP library which could handle recursive dates.
|
||||
There is: [http://phpicalendar.org/][6] however it would have been extremely difficult to extract the recursion
|
||||
portion of the script from the application.
|
||||
|
||||
Oddly, there are extremely good date recursion libraries for both Ruby and Python:
|
||||
|
||||
Ruby: [http://github.com/seejohnrun/ice_cube][1]
|
||||
|
||||
Python: [http://labix.org/python-dateutil][2]
|
||||
|
||||
Since I couldn't find an equivalent for PHP I created [When][3].
|
||||
|
||||
---
|
||||
###Unit Tests
|
||||
|
||||
Tests were written in PHPUnit ([http://www.phpunit.de/][4])
|
||||
|
||||
Initial set of tests were created from the examples found within RFC5545 ([http://tools.ietf.org/html/rfc5545][5]).
|
||||
|
||||
-----------------------------------
|
||||
###Documentation
|
||||
|
||||
Initializing the class
|
||||
|
||||
$when = new When();
|
||||
|
||||
Once you have initialized the class you can create a recurring event by calling on the recur method
|
||||
|
||||
$when->recur(<DateTime object|valid Date string>, <yearly|monthly|weekly|daily>);
|
||||
|
||||
You can limit the number of dates to find by specifying a limit():
|
||||
|
||||
$when->limit(<int>);
|
||||
|
||||
Alternatively you can specify an end date:
|
||||
|
||||
$when->until(<DateTime object|valid Date String>);
|
||||
|
||||
Note: the end date does not have to match the recurring pattern.
|
||||
|
||||
Note: the script will stop returning results when either the limit or the end date is met.
|
||||
|
||||
More documentation to come, please take a look at the unit tests for an understanding of what the class is capable of.
|
||||
|
||||
---
|
||||
###Examples (take a look at the unit tests for more examples)
|
||||
|
||||
The next 5 occurrences of Friday the 13th:
|
||||
|
||||
$r = new When();
|
||||
$r->recur(new DateTime(), 'monthly')
|
||||
->count(5)
|
||||
->byday(array('FR'))
|
||||
->bymonthday(array(13));
|
||||
|
||||
while($result = $r->next())
|
||||
{
|
||||
echo $result->format('c') . '<br />';
|
||||
}
|
||||
|
||||
Every four years, the first Tuesday after a Monday in November, for the next 20 years (U.S. Presidential Election day):
|
||||
|
||||
// this is the next election date
|
||||
$start = new DateTime('2012-09-06');
|
||||
|
||||
$r = new When();
|
||||
$r->recur($start, 'yearly')
|
||||
->until($start->modify('+20 years'))
|
||||
->interval(4)
|
||||
->bymonth(array(11))
|
||||
->byday(array('TU'))
|
||||
->bymonthday(array(2,3,4,5,6,7,8));
|
||||
|
||||
while($result = $r->next())
|
||||
{
|
||||
echo $result->format('c') . '<br />';
|
||||
}
|
||||
|
||||
You can now pass raw RRULE's to the class:
|
||||
|
||||
$r = new When();
|
||||
$r->recur('19970922T090000')->rrule('FREQ=MONTHLY;COUNT=6;BYDAY=-2MO');
|
||||
|
||||
while($result = $r->next())
|
||||
{
|
||||
echo $result->format('c') . '<br />';
|
||||
}
|
||||
|
||||
**Warnings:**
|
||||
|
||||
* If you submit a pattern which has no results the script will loop infinitely.
|
||||
* If you do not specify an end date (until) or a count for your pattern you must limit the number of results within your script to avoid an infinite loop.
|
||||
|
||||
---
|
||||
###Contributing
|
||||
|
||||
If you would like to contribute please create a fork and upon making changes submit a pull request.
|
||||
|
||||
Please ensure 100% pass of unit tests before submitting a pull request.
|
||||
|
||||
There are 78 tests, 1410 assertions currently.
|
||||
|
||||
>>>phpunit --verbose tests
|
||||
PHPUnit 3.4.15 by Sebastian Bergmann.
|
||||
|
||||
tests
|
||||
When_Core_Tests
|
||||
..
|
||||
|
||||
When_Daily_Rrule_Test
|
||||
.....
|
||||
|
||||
When_Daily_Test
|
||||
.....
|
||||
|
||||
When_Iterator_Tests
|
||||
..
|
||||
|
||||
When_Monthly_Rrule_Test
|
||||
..............
|
||||
|
||||
When_Monthly_Test
|
||||
..............
|
||||
|
||||
When_Weekly_Rrule_Test
|
||||
........
|
||||
|
||||
When_Weekly_Test
|
||||
........
|
||||
|
||||
When_Rrule_Test
|
||||
..........
|
||||
|
||||
When_Yearly_Test
|
||||
..........
|
||||
|
||||
Time: 2 seconds, Memory: 6.00Mb
|
||||
|
||||
OK (78 tests, 1410 assertions)
|
||||
|
||||
---
|
||||
###License
|
||||
|
||||
Copyright (c) 2010 Thomas Planer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
[1]: http://github.com/seejohnrun/ice_cube
|
||||
[2]: http://labix.org/python-dateutil
|
||||
[3]: http://github.com/tplaner/When
|
||||
[4]: http://www.phpunit.de/
|
||||
[5]: http://tools.ietf.org/html/rfc5545
|
||||
[6]: http://phpicalendar.org/
|
755
sites/all/modules/civicrm/packages/When/When.php
Normal file
755
sites/all/modules/civicrm/packages/When/When.php
Normal file
|
@ -0,0 +1,755 @@
|
|||
<?php
|
||||
/**
|
||||
* Name: When
|
||||
* Author: Thomas Planer <tplaner@gmail.com>
|
||||
* Location: http://github.com/tplaner/When
|
||||
* Created: September 2010
|
||||
* Description: Determines the next date of recursion given an iCalendar "rrule" like pattern.
|
||||
* Requirements: PHP 5.3+ - makes extensive use of the Date and Time library (http://us2.php.net/manual/en/book.datetime.php)
|
||||
*/
|
||||
class When
|
||||
{
|
||||
protected $frequency;
|
||||
|
||||
protected $start_date;
|
||||
protected $try_date;
|
||||
|
||||
protected $end_date;
|
||||
|
||||
protected $gobymonth;
|
||||
protected $bymonth;
|
||||
|
||||
protected $gobyweekno;
|
||||
protected $byweekno;
|
||||
|
||||
protected $gobyyearday;
|
||||
protected $byyearday;
|
||||
|
||||
protected $gobymonthday;
|
||||
protected $bymonthday;
|
||||
|
||||
protected $gobyday;
|
||||
protected $byday;
|
||||
|
||||
protected $gobysetpos;
|
||||
protected $bysetpos;
|
||||
|
||||
protected $suggestions;
|
||||
|
||||
protected $count;
|
||||
protected $counter;
|
||||
|
||||
protected $goenddate;
|
||||
|
||||
protected $interval;
|
||||
|
||||
protected $wkst;
|
||||
|
||||
protected $valid_week_days;
|
||||
protected $valid_frequency;
|
||||
|
||||
protected $keep_first_month_day;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->frequency = null;
|
||||
|
||||
$this->gobymonth = false;
|
||||
$this->bymonth = range(1,12);
|
||||
|
||||
$this->gobymonthday = false;
|
||||
$this->bymonthday = range(1,31);
|
||||
|
||||
$this->gobyday = false;
|
||||
// setup the valid week days (0 = sunday)
|
||||
$this->byday = range(0,6);
|
||||
|
||||
$this->gobyyearday = false;
|
||||
$this->byyearday = range(0,366);
|
||||
|
||||
$this->gobysetpos = false;
|
||||
$this->bysetpos = range(1,366);
|
||||
|
||||
$this->gobyweekno = false;
|
||||
// setup the range for valid weeks
|
||||
$this->byweekno = range(0,54);
|
||||
|
||||
$this->suggestions = array();
|
||||
|
||||
// this will be set if a count() is specified
|
||||
$this->count = 0;
|
||||
// how many *valid* results we returned
|
||||
$this->counter = 0;
|
||||
|
||||
// max date we'll return
|
||||
$this->end_date = new DateTime('9999-12-31');
|
||||
|
||||
// the interval to increase the pattern by
|
||||
$this->interval = 1;
|
||||
|
||||
// what day does the week start on? (0 = sunday)
|
||||
$this->wkst = 0;
|
||||
|
||||
$this->valid_week_days = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
|
||||
|
||||
$this->valid_frequency = array('SECONDLY', 'MINUTELY', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime|string $start_date of the recursion - also is the first return value.
|
||||
* @param string $frequency of the recrusion, valid frequencies: secondly, minutely, hourly, daily, weekly, monthly, yearly
|
||||
*/
|
||||
public function recur($start_date, $frequency = "daily")
|
||||
{
|
||||
try
|
||||
{
|
||||
if(is_object($start_date))
|
||||
{
|
||||
$this->start_date = clone $start_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timestamps within the RFC have a 'Z' at the end of them, remove this.
|
||||
$start_date = trim($start_date, 'Z');
|
||||
$this->start_date = new DateTime($start_date);
|
||||
}
|
||||
|
||||
$this->try_date = clone $this->start_date;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid start date DateTime: ' . $e);
|
||||
}
|
||||
|
||||
$this->freq($frequency);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function freq($frequency)
|
||||
{
|
||||
if(in_array(strtoupper($frequency), $this->valid_frequency))
|
||||
{
|
||||
$this->frequency = strtoupper($frequency);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid frequency type.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// accepts an rrule directly
|
||||
public function rrule($rrule)
|
||||
{
|
||||
// strip off a trailing semi-colon
|
||||
$rrule = trim($rrule, ";");
|
||||
|
||||
$parts = explode(";", $rrule);
|
||||
|
||||
foreach($parts as $part)
|
||||
{
|
||||
list($rule, $param) = explode("=", $part);
|
||||
|
||||
$rule = strtoupper($rule);
|
||||
$param = strtoupper($param);
|
||||
|
||||
switch($rule)
|
||||
{
|
||||
case "FREQ":
|
||||
$this->frequency = $param;
|
||||
break;
|
||||
case "UNTIL":
|
||||
$this->until($param);
|
||||
break;
|
||||
case "COUNT":
|
||||
$this->count($param);
|
||||
$this->counter = 0;
|
||||
break;
|
||||
case "INTERVAL":
|
||||
$this->interval($param);
|
||||
break;
|
||||
case "BYDAY":
|
||||
$params = explode(",", $param);
|
||||
$this->byday($params);
|
||||
break;
|
||||
case "BYMONTHDAY":
|
||||
$params = explode(",", $param);
|
||||
$this->bymonthday($params);
|
||||
break;
|
||||
case "BYYEARDAY":
|
||||
$params = explode(",", $param);
|
||||
$this->byyearday($params);
|
||||
break;
|
||||
case "BYWEEKNO":
|
||||
$params = explode(",", $param);
|
||||
$this->byweekno($params);
|
||||
break;
|
||||
case "BYMONTH":
|
||||
$params = explode(",", $param);
|
||||
$this->bymonth($params);
|
||||
break;
|
||||
case "BYSETPOS":
|
||||
$params = explode(",", $param);
|
||||
$this->bysetpos($params);
|
||||
break;
|
||||
case "WKST":
|
||||
$this->wkst($param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//max number of items to return based on the pattern
|
||||
public function count($count)
|
||||
{
|
||||
$this->count = (int)$count;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// how often the recurrence rule repeats
|
||||
public function interval($interval)
|
||||
{
|
||||
$this->interval = (int)$interval;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// starting day of the week
|
||||
public function wkst($day)
|
||||
{
|
||||
switch($day)
|
||||
{
|
||||
case 'SU':
|
||||
$this->wkst = 0;
|
||||
break;
|
||||
case 'MO':
|
||||
$this->wkst = 1;
|
||||
break;
|
||||
case 'TU':
|
||||
$this->wkst = 2;
|
||||
break;
|
||||
case 'WE':
|
||||
$this->wkst = 3;
|
||||
break;
|
||||
case 'TH':
|
||||
$this->wkst = 4;
|
||||
break;
|
||||
case 'FR':
|
||||
$this->wkst = 5;
|
||||
break;
|
||||
case 'SA':
|
||||
$this->wkst = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// max date
|
||||
public function until($end_date)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(is_object($end_date))
|
||||
{
|
||||
$this->end_date = clone $end_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timestamps within the RFC have a 'Z' at the end of them, remove this.
|
||||
$end_date = trim($end_date, 'Z');
|
||||
$this->end_date = new DateTime($end_date);
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid end date DateTime: ' . $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function bymonth($months)
|
||||
{
|
||||
if(is_array($months))
|
||||
{
|
||||
$this->gobymonth = true;
|
||||
$this->bymonth = $months;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function bymonthday($days)
|
||||
{
|
||||
if(is_array($days))
|
||||
{
|
||||
$this->gobymonthday = true;
|
||||
$this->bymonthday = $days;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function byweekno($weeks)
|
||||
{
|
||||
$this->gobyweekno = true;
|
||||
|
||||
if(is_array($weeks))
|
||||
{
|
||||
$this->byweekno = $weeks;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function bysetpos($days)
|
||||
{
|
||||
$this->gobysetpos = true;
|
||||
|
||||
if(is_array($days))
|
||||
{
|
||||
$this->bysetpos = $days;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function byday($days)
|
||||
{
|
||||
$this->gobyday = true;
|
||||
|
||||
if(is_array($days))
|
||||
{
|
||||
$this->byday = array();
|
||||
foreach($days as $day)
|
||||
{
|
||||
$len = strlen($day);
|
||||
|
||||
$as = '+';
|
||||
|
||||
// 0 mean no occurence is set
|
||||
$occ = 0;
|
||||
|
||||
if($len == 3)
|
||||
{
|
||||
$occ = substr($day, 0, 1);
|
||||
}
|
||||
if($len == 4)
|
||||
{
|
||||
$as = substr($day, 0, 1);
|
||||
$occ = substr($day, 1, 1);
|
||||
}
|
||||
|
||||
if($as == '-')
|
||||
{
|
||||
$occ = '-' . $occ;
|
||||
}
|
||||
else
|
||||
{
|
||||
$occ = '+' . $occ;
|
||||
}
|
||||
|
||||
$day = substr($day, -2, 2);
|
||||
switch($day)
|
||||
{
|
||||
case 'SU':
|
||||
$this->byday[] = $occ . 'SU';
|
||||
break;
|
||||
case 'MO':
|
||||
$this->byday[] = $occ . 'MO';
|
||||
break;
|
||||
case 'TU':
|
||||
$this->byday[] = $occ . 'TU';
|
||||
break;
|
||||
case 'WE':
|
||||
$this->byday[] = $occ . 'WE';
|
||||
break;
|
||||
case 'TH':
|
||||
$this->byday[] = $occ . 'TH';
|
||||
break;
|
||||
case 'FR':
|
||||
$this->byday[] = $occ . 'FR';
|
||||
break;
|
||||
case 'SA':
|
||||
$this->byday[] = $occ . 'SA';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function byyearday($days)
|
||||
{
|
||||
$this->gobyyearday = true;
|
||||
|
||||
if(is_array($days))
|
||||
{
|
||||
$this->byyearday = $days;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// this creates a basic list of dates to "try"
|
||||
protected function create_suggestions()
|
||||
{
|
||||
switch($this->frequency)
|
||||
{
|
||||
case "YEARLY":
|
||||
$interval = 'year';
|
||||
break;
|
||||
case "MONTHLY":
|
||||
$interval = 'month';
|
||||
break;
|
||||
case "WEEKLY":
|
||||
$interval = 'week';
|
||||
break;
|
||||
case "DAILY":
|
||||
$interval = 'day';
|
||||
break;
|
||||
case "HOURLY":
|
||||
$interval = 'hour';
|
||||
break;
|
||||
case "MINUTELY":
|
||||
$interval = 'minute';
|
||||
break;
|
||||
case "SECONDLY":
|
||||
$interval = 'second';
|
||||
break;
|
||||
}
|
||||
|
||||
$month_day = $this->try_date->format('j');
|
||||
$month = $this->try_date->format('n');
|
||||
$year = $this->try_date->format('Y');
|
||||
|
||||
|
||||
|
||||
$timestamp = $this->try_date->format('H:i:s');
|
||||
|
||||
if($this->gobysetpos)
|
||||
{
|
||||
if($this->try_date == $this->start_date)
|
||||
{
|
||||
$this->suggestions[] = clone $this->try_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($this->gobyday)
|
||||
{
|
||||
foreach($this->bysetpos as $_pos)
|
||||
{
|
||||
$tmp_array = array();
|
||||
$_mdays = range(1, date('t',mktime(0,0,0,$month,1,$year)));
|
||||
foreach($_mdays as $_mday)
|
||||
{
|
||||
$date_time = new DateTime($year . '-' . $month . '-' . $_mday . ' ' . $timestamp);
|
||||
|
||||
$occur = ceil($_mday / 7);
|
||||
|
||||
$day_of_week = $date_time->format('l');
|
||||
$dow_abr = strtoupper(substr($day_of_week, 0, 2));
|
||||
|
||||
// set the day of the month + (positive)
|
||||
$occur = '+' . $occur . $dow_abr;
|
||||
$occur_zero = '+0' . $dow_abr;
|
||||
|
||||
// set the day of the month - (negative)
|
||||
$total_days = $date_time->format('t') - $date_time->format('j');
|
||||
$occur_neg = '-' . ceil(($total_days + 1)/7) . $dow_abr;
|
||||
|
||||
$day_from_end_of_month = $date_time->format('t') + 1 - $_mday;
|
||||
|
||||
if(in_array($occur, $this->byday) || in_array($occur_zero, $this->byday) || in_array($occur_neg, $this->byday))
|
||||
{
|
||||
$tmp_array[] = clone $date_time;
|
||||
}
|
||||
}
|
||||
|
||||
if($_pos > 0)
|
||||
{
|
||||
$this->suggestions[] = clone $tmp_array[$_pos - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->suggestions[] = clone $tmp_array[count($tmp_array) + $_pos];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($this->gobyyearday)
|
||||
{
|
||||
foreach($this->byyearday as $_day)
|
||||
{
|
||||
if($_day >= 0)
|
||||
{
|
||||
$_day--;
|
||||
|
||||
$_time = strtotime('+' . $_day . ' days', mktime(0, 0, 0, 1, 1, $year));
|
||||
$this->suggestions[] = new Datetime(date('Y-m-d', $_time) . ' ' . $timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
$year_day_neg = 365 + $_day;
|
||||
$leap_year = $this->try_date->format('L');
|
||||
if($leap_year == 1)
|
||||
{
|
||||
$year_day_neg = 366 + $_day;
|
||||
}
|
||||
|
||||
$_time = strtotime('+' . $year_day_neg . ' days', mktime(0, 0, 0, 1, 1, $year));
|
||||
$this->suggestions[] = new Datetime(date('Y-m-d', $_time) . ' ' . $timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
// special case because for years you need to loop through the months too
|
||||
elseif($this->gobyday && $interval == "year")
|
||||
{
|
||||
foreach($this->bymonth as $_month)
|
||||
{
|
||||
// this creates an array of days of the month
|
||||
$_mdays = range(1, date('t',mktime(0,0,0,$_month,1,$year)));
|
||||
foreach($_mdays as $_mday)
|
||||
{
|
||||
$date_time = new DateTime($year . '-' . $_month . '-' . $_mday . ' ' . $timestamp);
|
||||
|
||||
// get the week of the month (1, 2, 3, 4, 5, etc)
|
||||
$week = $date_time->format('W');
|
||||
|
||||
if($date_time >= $this->start_date && in_array($week, $this->byweekno))
|
||||
{
|
||||
$this->suggestions[] = clone $date_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($interval == "day")
|
||||
{
|
||||
$this->suggestions[] = clone $this->try_date;
|
||||
}
|
||||
elseif($interval == "week")
|
||||
{
|
||||
$this->suggestions[] = clone $this->try_date;
|
||||
|
||||
if($this->gobyday)
|
||||
{
|
||||
$week_day = $this->try_date->format('w');
|
||||
|
||||
$days_in_month = $this->try_date->format('t');
|
||||
|
||||
$overflow_count = 1;
|
||||
$_day = $month_day;
|
||||
|
||||
$run = true;
|
||||
while($run)
|
||||
{
|
||||
$_day++;
|
||||
if($_day <= $days_in_month)
|
||||
{
|
||||
$tmp_date = new DateTime($year . '-' . $month . '-' . $_day . ' ' . $timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//$tmp_month = $month+1;
|
||||
$tmp_date = new DateTime($year . '-' . $month . '-' . $overflow_count . ' ' . $timestamp);
|
||||
$tmp_date->modify('+1 month');
|
||||
$overflow_count++;
|
||||
}
|
||||
|
||||
$week_day = $tmp_date->format('w');
|
||||
|
||||
if($this->try_date == $this->start_date)
|
||||
{
|
||||
if($week_day == $this->wkst)
|
||||
{
|
||||
$this->try_date = clone $tmp_date;
|
||||
$this->try_date->modify('-7 days');
|
||||
$run = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($week_day != $this->wkst)
|
||||
{
|
||||
$this->suggestions[] = clone $tmp_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
$run = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($this->gobyday || ($this->gobymonthday && $interval == "month"))
|
||||
{
|
||||
$_mdays = range(1, date('t',mktime(0,0,0,$month,1,$year)));
|
||||
foreach($_mdays as $_mday)
|
||||
{
|
||||
$date_time = new DateTime($year . '-' . $month . '-' . $_mday . ' ' . $timestamp);
|
||||
// get the week of the month (1, 2, 3, 4, 5, etc)
|
||||
$week = $date_time->format('W');
|
||||
|
||||
if($date_time >= $this->start_date && in_array($week, $this->byweekno))
|
||||
{
|
||||
$this->suggestions[] = clone $date_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($this->gobymonth)
|
||||
{
|
||||
foreach($this->bymonth as $_month)
|
||||
{
|
||||
$date_time = new DateTime($year . '-' . $_month . '-' . $month_day . ' ' . $timestamp);
|
||||
|
||||
if($date_time >= $this->start_date)
|
||||
{
|
||||
$this->suggestions[] = clone $date_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($interval == "month")
|
||||
{
|
||||
// Keep track of the original day of the month that was used
|
||||
if ($this->keep_first_month_day === null) {
|
||||
$this->keep_first_month_day = $month_day;
|
||||
}
|
||||
|
||||
$month_count = 1;
|
||||
foreach($this->bymonth as $_month)
|
||||
{
|
||||
$date_time = new DateTime($year . '-' . $_month . '-' . $this->keep_first_month_day . ' ' . $timestamp);
|
||||
if ($month_count == count($this->bymonth)) {
|
||||
$this->try_date->modify('+1 year');
|
||||
}
|
||||
|
||||
if($date_time >= $this->start_date)
|
||||
{
|
||||
$this->suggestions[] = clone $date_time;
|
||||
}
|
||||
$month_count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->suggestions[] = clone $this->try_date;
|
||||
}
|
||||
|
||||
if($interval == "month")
|
||||
{
|
||||
for ($i=0; $i< $this->interval; $i++)
|
||||
{
|
||||
$this->try_date->modify('+ 28 days');
|
||||
$this->try_date->setDate($this->try_date->format('Y'), $this->try_date->format('m'), $this->try_date->format('t'));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->try_date->modify($this->interval . ' ' . $interval);
|
||||
}
|
||||
}
|
||||
|
||||
public function valid_date($date)
|
||||
{
|
||||
$year = $date->format('Y');
|
||||
$month = $date->format('n');
|
||||
$day = $date->format('j');
|
||||
|
||||
$year_day = $date->format('z') + 1;
|
||||
|
||||
$year_day_neg = -366 + $year_day;
|
||||
$leap_year = $date->format('L');
|
||||
if($leap_year == 1)
|
||||
{
|
||||
$year_day_neg = -367 + $year_day;
|
||||
}
|
||||
|
||||
// this is the nth occurence of the date
|
||||
$occur = ceil($day / 7);
|
||||
|
||||
$week = $date->format('W');
|
||||
|
||||
$day_of_week = $date->format('l');
|
||||
$dow_abr = strtoupper(substr($day_of_week, 0, 2));
|
||||
|
||||
// set the day of the month + (positive)
|
||||
$occur = '+' . $occur . $dow_abr;
|
||||
$occur_zero = '+0' . $dow_abr;
|
||||
|
||||
// set the day of the month - (negative)
|
||||
$total_days = $date->format('t') - $date->format('j');
|
||||
$occur_neg = '-' . ceil(($total_days + 1)/7) . $dow_abr;
|
||||
|
||||
$day_from_end_of_month = $date->format('t') + 1 - $day;
|
||||
|
||||
if(in_array($month, $this->bymonth) &&
|
||||
(in_array($occur, $this->byday) || in_array($occur_zero, $this->byday) || in_array($occur_neg, $this->byday)) &&
|
||||
in_array($week, $this->byweekno) &&
|
||||
(in_array($day, $this->bymonthday) || in_array(-$day_from_end_of_month, $this->bymonthday)) &&
|
||||
(in_array($year_day, $this->byyearday) || in_array($year_day_neg, $this->byyearday)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// return the next valid DateTime object which matches the pattern and follows the rules
|
||||
public function next()
|
||||
{
|
||||
// check the counter is set
|
||||
if($this->count !== 0)
|
||||
{
|
||||
if($this->counter >= $this->count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// create initial set of suggested dates
|
||||
if(count($this->suggestions) === 0)
|
||||
{
|
||||
$this->create_suggestions();
|
||||
}
|
||||
|
||||
// loop through the suggested dates
|
||||
while(count($this->suggestions) > 0)
|
||||
{
|
||||
// get the first one on the array
|
||||
$try_date = array_shift($this->suggestions);
|
||||
|
||||
// make sure the date doesn't exceed the max date
|
||||
if($try_date > $this->end_date)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure it falls within the allowed days
|
||||
if($this->valid_date($try_date) === true)
|
||||
{
|
||||
$this->counter++;
|
||||
return $try_date;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we might be out of suggested days, so load some more
|
||||
if(count($this->suggestions) === 0)
|
||||
{
|
||||
$this->create_suggestions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
112
sites/all/modules/civicrm/packages/When/When_Iterator.php
Normal file
112
sites/all/modules/civicrm/packages/When/When_Iterator.php
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
/**
|
||||
* Name: When_Iterator
|
||||
* Author: Thomas Planer <tplaner@gmail.com>
|
||||
* Location: http://github.com/tplaner/When
|
||||
* Created: November 2010
|
||||
* Description: Implements PHP's Object Iteration Interface (http://us.php.net/Iterator & http://php.net/manual/en/class.iterator.php) so you can use the object within a foreach loop.
|
||||
*
|
||||
* Thanks to Andrew Collington for suggesting the implementation of an Iterator and supplying the base code for it.
|
||||
*/
|
||||
|
||||
require_once('When.php');
|
||||
|
||||
class When_Iterator extends When implements Iterator
|
||||
{
|
||||
// store the current position in the array
|
||||
protected $position = 0;
|
||||
|
||||
// store an individual result if caching is disabled
|
||||
protected $result;
|
||||
|
||||
// store all of the results
|
||||
protected $results = array();
|
||||
|
||||
protected $cache = false;
|
||||
|
||||
// caching the results will cause the script to
|
||||
// use more memory but less cpu (should also perform quicker)
|
||||
//
|
||||
// results should always be the same regardless of cache
|
||||
public function __construct($cache = false)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->position = 0;
|
||||
$this->results = array();
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
if($this->cache)
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset the counter and try_date in the parent class
|
||||
$this->counter = 0;
|
||||
$this->try_date = clone $this->start_date;
|
||||
}
|
||||
}
|
||||
|
||||
public function current()
|
||||
{
|
||||
if($this->cache === true)
|
||||
{
|
||||
return $this->results[$this->position];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
}
|
||||
|
||||
// only used if caching is enabled
|
||||
public function key()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
// only used of caching is enabled
|
||||
public function next()
|
||||
{
|
||||
++$this->position;
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
if($this->cache === true)
|
||||
{
|
||||
// check to see if the current position has already been stored
|
||||
if(!empty($this->results[$this->position]))
|
||||
{
|
||||
return isset($this->results[$this->position]);
|
||||
}
|
||||
// if it hasn't been found, check to see if there are more dates
|
||||
elseif($next_date = parent::next())
|
||||
{
|
||||
$this->results[] = $next_date;
|
||||
return isset($next_date);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check to see if there is another result and set that as the result
|
||||
if($next_date = parent::next())
|
||||
{
|
||||
$this->result = $next_date;
|
||||
return isset($this->result);
|
||||
}
|
||||
}
|
||||
|
||||
// end the foreach loop when all options are exhausted
|
||||
return false;
|
||||
}
|
||||
|
||||
public function enable_cache($cache)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue