Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F6066201
Horde_Date_Recurrence.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
53 KB
Referenced Files
None
Subscribers
None
Horde_Date_Recurrence.php
View Options
<?php
/**
* This is a modified copy of Horde/Date/Recurrence.php
* Pull the latest version of this file from the PEAR channel of the Horde
* project at http://pear.horde.org by installing the Horde_Date package.
*/
if
(!
class_exists
(
'Horde_Date'
))
require_once
(
dirname
(
__FILE__
)
.
'/Horde_Date.php'
);
// minimal required implementation of Horde_Date_Translation to avoid a huge dependency nightmare
class
Horde_Date_Translation
{
function
t
(
$arg
)
{
return
$arg
;
}
function
ngettext
(
$sing
,
$plur
,
$num
)
{
return
(
$num
>
1
?
$plur
:
$sing
);
}
}
/**
* This file contains the Horde_Date_Recurrence class and according constants.
*
* Copyright 2007-2012 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @category Horde
* @package Date
*/
/**
* The Horde_Date_Recurrence class implements algorithms for calculating
* recurrences of events, including several recurrence types, intervals,
* exceptions, and conversion from and to vCalendar and iCalendar recurrence
* rules.
*
* All methods expecting dates as parameters accept all values that the
* Horde_Date constructor accepts, i.e. a timestamp, another Horde_Date
* object, an ISO time string or a hash.
*
* @author Jan Schneider <jan@horde.org>
* @category Horde
* @package Date
*/
class
Horde_Date_Recurrence
{
/** No Recurrence **/
const
RECUR_NONE
=
0
;
/** Recurs daily. */
const
RECUR_DAILY
=
1
;
/** Recurs weekly. */
const
RECUR_WEEKLY
=
2
;
/** Recurs monthly on the same date. */
const
RECUR_MONTHLY_DATE
=
3
;
/** Recurs monthly on the same week day. */
const
RECUR_MONTHLY_WEEKDAY
=
4
;
/** Recurs yearly on the same date. */
const
RECUR_YEARLY_DATE
=
5
;
/** Recurs yearly on the same day of the year. */
const
RECUR_YEARLY_DAY
=
6
;
/** Recurs yearly on the same week day. */
const
RECUR_YEARLY_WEEKDAY
=
7
;
/**
* The start time of the event.
*
* @var Horde_Date
*/
public
$start
;
/**
* The end date of the recurrence interval.
*
* @var Horde_Date
*/
public
$recurEnd
=
null
;
/**
* The number of recurrences.
*
* @var integer
*/
public
$recurCount
=
null
;
/**
* The type of recurrence this event follows. RECUR_* constant.
*
* @var integer
*/
public
$recurType
=
self
::
RECUR_NONE
;
/**
* The length of time between recurrences. The time unit depends on the
* recurrence type.
*
* @var integer
*/
public
$recurInterval
=
1
;
/**
* Any additional recurrence data.
*
* @var integer
*/
public
$recurData
=
null
;
/**
* BYDAY recurrence number
*
* @var integer
*/
public
$recurNthDay
=
null
;
/**
* BYMONTH recurrence data
*
* @var array
*/
public
$recurMonths
=
array
();
/**
* All the exceptions from recurrence for this event.
*
* @var array
*/
public
$exceptions
=
array
();
/**
* All the dates this recurrence has been marked as completed.
*
* @var array
*/
public
$completions
=
array
();
/**
* Constructor.
*
* @param Horde_Date $start Start of the recurring event.
*/
public
function
__construct
(
$start
)
{
$this
->
start
=
new
Horde_Date
(
$start
);
}
/**
* Resets the class properties.
*/
public
function
reset
()
{
$this
->
recurEnd
=
null
;
$this
->
recurCount
=
null
;
$this
->
recurType
=
self
::
RECUR_NONE
;
$this
->
recurInterval
=
1
;
$this
->
recurData
=
null
;
$this
->
exceptions
=
array
();
$this
->
completions
=
array
();
}
/**
* Checks if this event recurs on a given day of the week.
*
* @param integer $dayMask A mask consisting of Horde_Date::MASK_*
* constants specifying the day(s) to check.
*
* @return boolean True if this event recurs on the given day(s).
*/
public
function
recurOnDay
(
$dayMask
)
{
return
(
$this
->
recurData
&
$dayMask
);
}
/**
* Specifies the days this event recurs on.
*
* @param integer $dayMask A mask consisting of Horde_Date::MASK_*
* constants specifying the day(s) to recur on.
*/
public
function
setRecurOnDay
(
$dayMask
)
{
$this
->
recurData
=
$dayMask
;
}
/**
*
* @param integer $nthDay The nth weekday of month to repeat events on
*/
public
function
setRecurNthWeekday
(
$nth
)
{
$this
->
recurNthDay
=
(
int
)
$nth
;
}
/**
*
* @return integer The nth weekday of month to repeat events.
*/
public
function
getRecurNthWeekday
()
{
return
isset
(
$this
->
recurNthDay
)
?
$this
->
recurNthDay
:
ceil
(
$this
->
start
->
mday
/
7
);
}
/**
* Specifies the months for yearly (weekday) recurrence
*
* @param array $months List of months (integers) this event recurs on.
*/
function
setRecurByMonth
(
$months
)
{
$this
->
recurMonths
=
(
array
)
$months
;
}
/**
* Returns a list of months this yearly event recurs on
*
* @return array List of months (integers) this event recurs on.
*/
function
getRecurByMonth
()
{
return
$this
->
recurMonths
;
}
/**
* Returns the days this event recurs on.
*
* @return integer A mask consisting of Horde_Date::MASK_* constants
* specifying the day(s) this event recurs on.
*/
public
function
getRecurOnDays
()
{
return
$this
->
recurData
;
}
/**
* Returns whether this event has a specific recurrence type.
*
* @param integer $recurrence RECUR_* constant of the
* recurrence type to check for.
*
* @return boolean True if the event has the specified recurrence type.
*/
public
function
hasRecurType
(
$recurrence
)
{
return
(
$recurrence
==
$this
->
recurType
);
}
/**
* Sets a recurrence type for this event.
*
* @param integer $recurrence A RECUR_* constant.
*/
public
function
setRecurType
(
$recurrence
)
{
$this
->
recurType
=
$recurrence
;
}
/**
* Returns recurrence type of this event.
*
* @return integer A RECUR_* constant.
*/
public
function
getRecurType
()
{
return
$this
->
recurType
;
}
/**
* Returns a description of this event's recurring type.
*
* @return string Human readable recurring type.
*/
public
function
getRecurName
()
{
switch
(
$this
->
getRecurType
())
{
case
self
::
RECUR_NONE
:
return
Horde_Date_Translation
::
t
(
"No recurrence"
);
case
self
::
RECUR_DAILY
:
return
Horde_Date_Translation
::
t
(
"Daily"
);
case
self
::
RECUR_WEEKLY
:
return
Horde_Date_Translation
::
t
(
"Weekly"
);
case
self
::
RECUR_MONTHLY_DATE
:
case
self
::
RECUR_MONTHLY_WEEKDAY
:
return
Horde_Date_Translation
::
t
(
"Monthly"
);
case
self
::
RECUR_YEARLY_DATE
:
case
self
::
RECUR_YEARLY_DAY
:
case
self
::
RECUR_YEARLY_WEEKDAY
:
return
Horde_Date_Translation
::
t
(
"Yearly"
);
}
}
/**
* Sets the length of time between recurrences of this event.
*
* @param integer $interval The time between recurrences.
*/
public
function
setRecurInterval
(
$interval
)
{
if
(
$interval
>
0
)
{
$this
->
recurInterval
=
$interval
;
}
}
/**
* Retrieves the length of time between recurrences of this event.
*
* @return integer The number of seconds between recurrences.
*/
public
function
getRecurInterval
()
{
return
$this
->
recurInterval
;
}
/**
* Sets the number of recurrences of this event.
*
* @param integer $count The number of recurrences.
*/
public
function
setRecurCount
(
$count
)
{
if
(
$count
>
0
)
{
$this
->
recurCount
=
(
int
)
$count
;
// Recurrence counts and end dates are mutually exclusive.
$this
->
recurEnd
=
null
;
}
else
{
$this
->
recurCount
=
null
;
}
}
/**
* Retrieves the number of recurrences of this event.
*
* @return integer The number recurrences.
*/
public
function
getRecurCount
()
{
return
$this
->
recurCount
;
}
/**
* Returns whether this event has a recurrence with a fixed count.
*
* @return boolean True if this recurrence has a fixed count.
*/
public
function
hasRecurCount
()
{
return
isset
(
$this
->
recurCount
);
}
/**
* Sets the start date of the recurrence interval.
*
* @param Horde_Date $start The recurrence start.
*/
public
function
setRecurStart
(
$start
)
{
$this
->
start
=
clone
$start
;
}
/**
* Retrieves the start date of the recurrence interval.
*
* @return Horde_Date The recurrence start.
*/
public
function
getRecurStart
()
{
return
$this
->
start
;
}
/**
* Sets the end date of the recurrence interval.
*
* @param Horde_Date $end The recurrence end.
*/
public
function
setRecurEnd
(
$end
)
{
if
(!
empty
(
$end
))
{
// Recurrence counts and end dates are mutually exclusive.
$this
->
recurCount
=
null
;
$this
->
recurEnd
=
clone
$end
;
}
else
{
$this
->
recurEnd
=
$end
;
}
}
/**
* Retrieves the end date of the recurrence interval.
*
* @return Horde_Date The recurrence end.
*/
public
function
getRecurEnd
()
{
return
$this
->
recurEnd
;
}
/**
* Returns whether this event has a recurrence end.
*
* @return boolean True if this recurrence ends.
*/
public
function
hasRecurEnd
()
{
return
isset
(
$this
->
recurEnd
)
&&
isset
(
$this
->
recurEnd
->
year
)
&&
$this
->
recurEnd
->
year
!=
9999
;
}
/**
* Finds the next recurrence of this event that's after $afterDate.
*
* @param Horde_Date|string $after Return events after this date.
*
* @return Horde_Date|boolean The date of the next recurrence or false
* if the event does not recur after
* $afterDate.
*/
public
function
nextRecurrence
(
$after
)
{
if
(!(
$after
instanceof
Horde_Date
))
{
$after
=
new
Horde_Date
(
$after
);
}
else
{
$after
=
clone
(
$after
);
}
// Make sure $after and $this->start are in the same TZ
$after
->
setTimezone
(
$this
->
start
->
timezone
);
if
(
$this
->
start
->
compareDateTime
(
$after
)
>=
0
)
{
return
clone
$this
->
start
;
}
if
(
$this
->
recurInterval
==
0
)
{
return
false
;
}
switch
(
$this
->
getRecurType
())
{
case
self
::
RECUR_DAILY
:
$diff
=
$this
->
start
->
diff
(
$after
);
$recur
=
ceil
(
$diff
/
$this
->
recurInterval
);
if
(
$this
->
recurCount
&&
$recur
>=
$this
->
recurCount
)
{
return
false
;
}
$recur
*=
$this
->
recurInterval
;
$next
=
$this
->
start
->
add
(
array
(
'day'
=>
$recur
));
if
((!
$this
->
hasRecurEnd
()
||
$next
->
compareDateTime
(
$this
->
recurEnd
)
<=
0
)
&&
$next
->
compareDateTime
(
$after
)
>=
0
)
{
return
$next
;
}
break
;
case
self
::
RECUR_WEEKLY
:
if
(
empty
(
$this
->
recurData
))
{
return
false
;
}
$start_week
=
Horde_Date_Utils
::
firstDayOfWeek
(
$this
->
start
->
format
(
'W'
),
$this
->
start
->
year
);
$start_week
->
timezone
=
$this
->
start
->
timezone
;
$start_week
->
hour
=
$this
->
start
->
hour
;
$start_week
->
min
=
$this
->
start
->
min
;
$start_week
->
sec
=
$this
->
start
->
sec
;
// Make sure we are not at the ISO-8601 first week of year while
// still in month 12...OR in the ISO-8601 last week of year while
// in month 1 and adjust the year accordingly.
$week
=
$after
->
format
(
'W'
);
if
(
$week
==
1
&&
$after
->
month
==
12
)
{
$theYear
=
$after
->
year
+
1
;
}
elseif
(
$week
>=
52
&&
$after
->
month
==
1
)
{
$theYear
=
$after
->
year
-
1
;
}
else
{
$theYear
=
$after
->
year
;
}
$after_week
=
Horde_Date_Utils
::
firstDayOfWeek
(
$week
,
$theYear
);
$after_week
->
timezone
=
$this
->
start
->
timezone
;
$after_week_end
=
clone
$after_week
;
$after_week_end
->
mday
+=
7
;
$diff
=
$start_week
->
diff
(
$after_week
);
$interval
=
$this
->
recurInterval
*
7
;
$repeats
=
floor
(
$diff
/
$interval
);
if
(
$diff
%
$interval
<
7
)
{
$recur
=
$diff
;
}
else
{
/**
* If the after_week is not in the first week interval the
* search needs to skip ahead a complete interval. The way it is
* calculated here means that an event that occurs every second
* week on Monday and Wednesday with the event actually starting
* on Tuesday or Wednesday will only have one incidence in the
* first week.
*/
$recur
=
$interval
*
(
$repeats
+
1
);
}
if
(
$this
->
hasRecurCount
())
{
$recurrences
=
0
;
/**
* Correct the number of recurrences by the number of events
* that lay between the start of the start week and the
* recurrence start.
*/
$next
=
clone
$start_week
;
while
(
$next
->
compareDateTime
(
$this
->
start
)
<
0
)
{
if
(
$this
->
recurOnDay
((
int
)
pow
(
2
,
$next
->
dayOfWeek
())))
{
$recurrences
--;
}
++
$next
->
mday
;
}
if
(
$repeats
>
0
)
{
$weekdays
=
$this
->
recurData
;
$total_recurrences_per_week
=
0
;
while
(
$weekdays
>
0
)
{
if
(
$weekdays
%
2
)
{
$total_recurrences_per_week
++;
}
$weekdays
=
(
$weekdays
-
(
$weekdays
%
2
))
/
2
;
}
$recurrences
+=
$total_recurrences_per_week
*
$repeats
;
}
}
$next
=
clone
$start_week
;
$next
->
mday
+=
$recur
;
while
(
$next
->
compareDateTime
(
$after
)
<
0
&&
$next
->
compareDateTime
(
$after_week_end
)
<
0
)
{
if
(
$this
->
hasRecurCount
()
&&
$next
->
compareDateTime
(
$after
)
<
0
&&
$this
->
recurOnDay
((
int
)
pow
(
2
,
$next
->
dayOfWeek
())))
{
$recurrences
++;
}
++
$next
->
mday
;
}
if
(
$this
->
hasRecurCount
()
&&
$recurrences
>=
$this
->
recurCount
)
{
return
false
;
}
if
(!
$this
->
hasRecurEnd
()
||
$next
->
compareDateTime
(
$this
->
recurEnd
)
<=
0
)
{
if
(
$next
->
compareDateTime
(
$after_week_end
)
>=
0
)
{
return
$this
->
nextRecurrence
(
$after_week_end
);
}
while
(!
$this
->
recurOnDay
((
int
)
pow
(
2
,
$next
->
dayOfWeek
()))
&&
$next
->
compareDateTime
(
$after_week_end
)
<
0
)
{
++
$next
->
mday
;
}
if
(!
$this
->
hasRecurEnd
()
||
$next
->
compareDateTime
(
$this
->
recurEnd
)
<=
0
)
{
if
(
$next
->
compareDateTime
(
$after_week_end
)
>=
0
)
{
return
$this
->
nextRecurrence
(
$after_week_end
);
}
else
{
return
$next
;
}
}
}
break
;
case
self
::
RECUR_MONTHLY_DATE
:
$start
=
clone
$this
->
start
;
if
(
$after
->
compareDateTime
(
$start
)
<
0
)
{
$after
=
clone
$start
;
}
else
{
$after
=
clone
$after
;
}
// If we're starting past this month's recurrence of the event,
// look in the next month on the day the event recurs.
if
(
$after
->
mday
>
$start
->
mday
)
{
++
$after
->
month
;
$after
->
mday
=
$start
->
mday
;
}
// Adjust $start to be the first match.
$offset
=
(
$after
->
month
-
$start
->
month
)
+
(
$after
->
year
-
$start
->
year
)
*
12
;
$offset
=
floor
((
$offset
+
$this
->
recurInterval
-
1
)
/
$this
->
recurInterval
)
*
$this
->
recurInterval
;
if
(
$this
->
recurCount
&&
(
$offset
/
$this
->
recurInterval
)
>=
$this
->
recurCount
)
{
return
false
;
}
$start
->
month
+=
$offset
;
$count
=
$offset
/
$this
->
recurInterval
;
do
{
if
(
$this
->
recurCount
&&
$count
++
>=
$this
->
recurCount
)
{
return
false
;
}
// Bail if we've gone past the end of recurrence.
if
(
$this
->
hasRecurEnd
()
&&
$this
->
recurEnd
->
compareDateTime
(
$start
)
<
0
)
{
return
false
;
}
if
(
$start
->
isValid
())
{
return
$start
;
}
// If the interval is 12, and the date isn't valid, then we
// need to see if February 29th is an option. If not, then the
// event will _never_ recur, and we need to stop checking to
// avoid an infinite loop.
if
(
$this
->
recurInterval
==
12
&&
(
$start
->
month
!=
2
||
$start
->
mday
>
29
))
{
return
false
;
}
// Add the recurrence interval.
$start
->
month
+=
$this
->
recurInterval
;
}
while
(
true
);
break
;
case
self
::
RECUR_MONTHLY_WEEKDAY
:
// Start with the start date of the event.
$estart
=
clone
$this
->
start
;
// What day of the week, and week of the month, do we recur on?
if
(
isset
(
$this
->
recurNthDay
))
{
$nth
=
$this
->
recurNthDay
;
$weekday
=
log
(
$this
->
recurData
,
2
);
}
else
{
$nth
=
ceil
(
$this
->
start
->
mday
/
7
);
$weekday
=
$estart
->
dayOfWeek
();
}
// Adjust $estart to be the first candidate.
$offset
=
(
$after
->
month
-
$estart
->
month
)
+
(
$after
->
year
-
$estart
->
year
)
*
12
;
$offset
=
floor
((
$offset
+
$this
->
recurInterval
-
1
)
/
$this
->
recurInterval
)
*
$this
->
recurInterval
;
// Adjust our working date until it's after $after.
$estart
->
month
+=
$offset
-
$this
->
recurInterval
;
$count
=
$offset
/
$this
->
recurInterval
;
do
{
if
(
$this
->
recurCount
&&
$count
++
>=
$this
->
recurCount
)
{
return
false
;
}
$estart
->
month
+=
$this
->
recurInterval
;
$next
=
clone
$estart
;
$next
->
setNthWeekday
(
$weekday
,
$nth
);
if
(
$next
->
compareDateTime
(
$after
)
<
0
)
{
// We haven't made it past $after yet, try again.
continue
;
}
if
(
$this
->
hasRecurEnd
()
&&
$next
->
compareDateTime
(
$this
->
recurEnd
)
>
0
)
{
// We've gone past the end of recurrence; we can give up
// now.
return
false
;
}
// We have a candidate to return.
break
;
}
while
(
true
);
return
$next
;
case
self
::
RECUR_YEARLY_DATE
:
// Start with the start date of the event.
$estart
=
clone
$this
->
start
;
$after
=
clone
$after
;
if
(
$after
->
month
>
$estart
->
month
||
(
$after
->
month
==
$estart
->
month
&&
$after
->
mday
>
$estart
->
mday
))
{
++
$after
->
year
;
$after
->
month
=
$estart
->
month
;
$after
->
mday
=
$estart
->
mday
;
}
// Seperate case here for February 29th
if
(
$estart
->
month
==
2
&&
$estart
->
mday
==
29
)
{
while
(!
Horde_Date_Utils
::
isLeapYear
(
$after
->
year
))
{
++
$after
->
year
;
}
}
// Adjust $estart to be the first candidate.
$offset
=
$after
->
year
-
$estart
->
year
;
if
(
$offset
>
0
)
{
$offset
=
floor
((
$offset
+
$this
->
recurInterval
-
1
)
/
$this
->
recurInterval
)
*
$this
->
recurInterval
;
$estart
->
year
+=
$offset
;
}
// We've gone past the end of recurrence; give up.
if
(
$this
->
recurCount
&&
$offset
>=
$this
->
recurCount
)
{
return
false
;
}
if
(
$this
->
hasRecurEnd
()
&&
$this
->
recurEnd
->
compareDateTime
(
$estart
)
<
0
)
{
return
false
;
}
return
$estart
;
case
self
::
RECUR_YEARLY_DAY
:
// Check count first.
$dayofyear
=
$this
->
start
->
dayOfYear
();
$count
=
(
$after
->
year
-
$this
->
start
->
year
)
/
$this
->
recurInterval
+
1
;
if
(
$this
->
recurCount
&&
(
$count
>
$this
->
recurCount
||
(
$count
==
$this
->
recurCount
&&
$after
->
dayOfYear
()
>
$dayofyear
)))
{
return
false
;
}
// Start with a rough interval.
$estart
=
clone
$this
->
start
;
$estart
->
year
+=
floor
(
$count
-
1
)
*
$this
->
recurInterval
;
// Now add the difference to the required day of year.
$estart
->
mday
+=
$dayofyear
-
$estart
->
dayOfYear
();
// Add an interval if the estimation was wrong.
if
(
$estart
->
compareDate
(
$after
)
<
0
)
{
$estart
->
year
+=
$this
->
recurInterval
;
$estart
->
mday
+=
$dayofyear
-
$estart
->
dayOfYear
();
}
// We've gone past the end of recurrence; give up.
if
(
$this
->
hasRecurEnd
()
&&
$this
->
recurEnd
->
compareDateTime
(
$estart
)
<
0
)
{
return
false
;
}
return
$estart
;
case
self
::
RECUR_YEARLY_WEEKDAY
:
// Start with the start date of the event.
$estart
=
clone
$this
->
start
;
// What day of the week, and week of the month, do we recur on?
if
(
isset
(
$this
->
recurNthDay
))
{
$nth
=
$this
->
recurNthDay
;
$weekday
=
log
(
$this
->
recurData
,
2
);
}
else
{
$nth
=
ceil
(
$this
->
start
->
mday
/
7
);
$weekday
=
$estart
->
dayOfWeek
();
}
// Adjust $estart to be the first candidate.
$offset
=
floor
((
$after
->
year
-
$estart
->
year
+
$this
->
recurInterval
-
1
)
/
$this
->
recurInterval
)
*
$this
->
recurInterval
;
// Adjust our working date until it's after $after.
$estart
->
year
+=
$offset
-
$this
->
recurInterval
;
$count
=
$offset
/
$this
->
recurInterval
;
do
{
if
(
$this
->
recurCount
&&
$count
++
>=
$this
->
recurCount
)
{
return
false
;
}
$estart
->
year
+=
$this
->
recurInterval
;
$next
=
clone
$estart
;
$next
->
setNthWeekday
(
$weekday
,
$nth
);
if
(
$next
->
compareDateTime
(
$after
)
<
0
)
{
// We haven't made it past $after yet, try again.
continue
;
}
if
(
$this
->
hasRecurEnd
()
&&
$next
->
compareDateTime
(
$this
->
recurEnd
)
>
0
)
{
// We've gone past the end of recurrence; we can give up
// now.
return
false
;
}
// We have a candidate to return.
break
;
}
while
(
true
);
return
$next
;
}
// We didn't find anything, the recurType was bad, or something else
// went wrong - return false.
return
false
;
}
/**
* Returns whether this event has any date that matches the recurrence
* rules and is not an exception.
*
* @return boolean True if an active recurrence exists.
*/
public
function
hasActiveRecurrence
()
{
if
(!
$this
->
hasRecurEnd
())
{
return
true
;
}
$next
=
$this
->
nextRecurrence
(
new
Horde_Date
(
$this
->
start
));
while
(
is_object
(
$next
))
{
if
(!
$this
->
hasException
(
$next
->
year
,
$next
->
month
,
$next
->
mday
)
&&
!
$this
->
hasCompletion
(
$next
->
year
,
$next
->
month
,
$next
->
mday
))
{
return
true
;
}
$next
=
$this
->
nextRecurrence
(
$next
->
add
(
array
(
'day'
=>
1
)));
}
return
false
;
}
/**
* Returns the next active recurrence.
*
* @param Horde_Date $afterDate Return events after this date.
*
* @return Horde_Date|boolean The date of the next active
* recurrence or false if the event
* has no active recurrence after
* $afterDate.
*/
public
function
nextActiveRecurrence
(
$afterDate
)
{
$next
=
$this
->
nextRecurrence
(
$afterDate
);
while
(
is_object
(
$next
))
{
if
(!
$this
->
hasException
(
$next
->
year
,
$next
->
month
,
$next
->
mday
)
&&
!
$this
->
hasCompletion
(
$next
->
year
,
$next
->
month
,
$next
->
mday
))
{
return
$next
;
}
$next
->
mday
++;
$next
=
$this
->
nextRecurrence
(
$next
);
}
return
false
;
}
/**
* Adds an exception to a recurring event.
*
* @param integer $year The year of the execption.
* @param integer $month The month of the execption.
* @param integer $mday The day of the month of the exception.
*/
public
function
addException
(
$year
,
$month
,
$mday
)
{
$this
->
exceptions
[]
=
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
);
}
/**
* Deletes an exception from a recurring event.
*
* @param integer $year The year of the execption.
* @param integer $month The month of the execption.
* @param integer $mday The day of the month of the exception.
*/
public
function
deleteException
(
$year
,
$month
,
$mday
)
{
$key
=
array_search
(
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
),
$this
->
exceptions
);
if
(
$key
!==
false
)
{
unset
(
$this
->
exceptions
[
$key
]);
}
}
/**
* Checks if an exception exists for a given reccurence of an event.
*
* @param integer $year The year of the reucrance.
* @param integer $month The month of the reucrance.
* @param integer $mday The day of the month of the reucrance.
*
* @return boolean True if an exception exists for the given date.
*/
public
function
hasException
(
$year
,
$month
,
$mday
)
{
return
in_array
(
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
),
$this
->
getExceptions
());
}
/**
* Retrieves all the exceptions for this event.
*
* @return array Array containing the dates of all the exceptions in
* YYYYMMDD form.
*/
public
function
getExceptions
()
{
return
$this
->
exceptions
;
}
/**
* Adds a completion to a recurring event.
*
* @param integer $year The year of the execption.
* @param integer $month The month of the execption.
* @param integer $mday The day of the month of the completion.
*/
public
function
addCompletion
(
$year
,
$month
,
$mday
)
{
$this
->
completions
[]
=
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
);
}
/**
* Deletes a completion from a recurring event.
*
* @param integer $year The year of the execption.
* @param integer $month The month of the execption.
* @param integer $mday The day of the month of the completion.
*/
public
function
deleteCompletion
(
$year
,
$month
,
$mday
)
{
$key
=
array_search
(
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
),
$this
->
completions
);
if
(
$key
!==
false
)
{
unset
(
$this
->
completions
[
$key
]);
}
}
/**
* Checks if a completion exists for a given reccurence of an event.
*
* @param integer $year The year of the reucrance.
* @param integer $month The month of the recurrance.
* @param integer $mday The day of the month of the recurrance.
*
* @return boolean True if a completion exists for the given date.
*/
public
function
hasCompletion
(
$year
,
$month
,
$mday
)
{
return
in_array
(
sprintf
(
'%04d%02d%02d'
,
$year
,
$month
,
$mday
),
$this
->
getCompletions
());
}
/**
* Retrieves all the completions for this event.
*
* @return array Array containing the dates of all the completions in
* YYYYMMDD form.
*/
public
function
getCompletions
()
{
return
$this
->
completions
;
}
/**
* Parses a vCalendar 1.0 recurrence rule.
*
* @link http://www.imc.org/pdi/vcal-10.txt
* @link http://www.shuchow.com/vCalAddendum.html
*
* @param string $rrule A vCalendar 1.0 conform RRULE value.
*/
public
function
fromRRule10
(
$rrule
)
{
$this
->
reset
();
if
(!
$rrule
)
{
return
;
}
if
(!
preg_match
(
'/([A-Z]+)(
\d
+)?(.*)/'
,
$rrule
,
$matches
))
{
// No recurrence data - event does not recur.
$this
->
setRecurType
(
self
::
RECUR_NONE
);
}
// Always default the recurInterval to 1.
$this
->
setRecurInterval
(!
empty
(
$matches
[
2
])
?
$matches
[
2
]
:
1
);
$remainder
=
trim
(
$matches
[
3
]);
switch
(
$matches
[
1
])
{
case
'D'
:
$this
->
setRecurType
(
self
::
RECUR_DAILY
);
break
;
case
'W'
:
$this
->
setRecurType
(
self
::
RECUR_WEEKLY
);
if
(!
empty
(
$remainder
))
{
$mask
=
0
;
while
(
preg_match
(
'/^ ?[A-Z]{2} ?/'
,
$remainder
,
$matches
))
{
$day
=
trim
(
$matches
[
0
]);
$remainder
=
substr
(
$remainder
,
strlen
(
$matches
[
0
]));
$mask
|=
$maskdays
[
$day
];
}
$this
->
setRecurOnDay
(
$mask
);
}
else
{
// Recur on the day of the week of the original recurrence.
$maskdays
=
array
(
Horde_Date
::
DATE_SUNDAY
=>
Horde_Date
::
MASK_SUNDAY
,
Horde_Date
::
DATE_MONDAY
=>
Horde_Date
::
MASK_MONDAY
,
Horde_Date
::
DATE_TUESDAY
=>
Horde_Date
::
MASK_TUESDAY
,
Horde_Date
::
DATE_WEDNESDAY
=>
Horde_Date
::
MASK_WEDNESDAY
,
Horde_Date
::
DATE_THURSDAY
=>
Horde_Date
::
MASK_THURSDAY
,
Horde_Date
::
DATE_FRIDAY
=>
Horde_Date
::
MASK_FRIDAY
,
Horde_Date
::
DATE_SATURDAY
=>
Horde_Date
::
MASK_SATURDAY
,
);
$this
->
setRecurOnDay
(
$maskdays
[
$this
->
start
->
dayOfWeek
()]);
}
break
;
case
'MP'
:
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_WEEKDAY
);
break
;
case
'MD'
:
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_DATE
);
break
;
case
'YM'
:
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DATE
);
break
;
case
'YD'
:
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DAY
);
break
;
}
// We don't support modifiers at the moment, strip them.
while
(
$remainder
&&
!
preg_match
(
'/^(#
\d
+|
\d
{8})($| |T
\d
{6})/'
,
$remainder
))
{
$remainder
=
substr
(
$remainder
,
1
);
}
if
(!
empty
(
$remainder
))
{
if
(
strpos
(
$remainder
,
'#'
)
===
0
)
{
$this
->
setRecurCount
(
substr
(
$remainder
,
1
));
}
else
{
list
(
$year
,
$month
,
$mday
)
=
sscanf
(
$remainder
,
'%04d%02d%02d'
);
$this
->
setRecurEnd
(
new
Horde_Date
(
array
(
'year'
=>
$year
,
'month'
=>
$month
,
'mday'
=>
$mday
,
'hour'
=>
23
,
'min'
=>
59
,
'sec'
=>
59
)));
}
}
}
/**
* Creates a vCalendar 1.0 recurrence rule.
*
* @link http://www.imc.org/pdi/vcal-10.txt
* @link http://www.shuchow.com/vCalAddendum.html
*
* @param Horde_Icalendar $calendar A Horde_Icalendar object instance.
*
* @return string A vCalendar 1.0 conform RRULE value.
*/
public
function
toRRule10
(
$calendar
)
{
switch
(
$this
->
recurType
)
{
case
self
::
RECUR_NONE
:
return
''
;
case
self
::
RECUR_DAILY
:
$rrule
=
'D'
.
$this
->
recurInterval
;
break
;
case
self
::
RECUR_WEEKLY
:
$rrule
=
'W'
.
$this
->
recurInterval
;
$vcaldays
=
array
(
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
);
for
(
$i
=
0
;
$i
<=
7
;
++
$i
)
{
if
(
$this
->
recurOnDay
(
pow
(
2
,
$i
)))
{
$rrule
.=
' '
.
$vcaldays
[
$i
];
}
}
break
;
case
self
::
RECUR_MONTHLY_DATE
:
$rrule
=
'MD'
.
$this
->
recurInterval
.
' '
.
trim
(
$this
->
start
->
mday
);
break
;
case
self
::
RECUR_MONTHLY_WEEKDAY
:
$nth_weekday
=
(
int
)(
$this
->
start
->
mday
/
7
);
if
((
$this
->
start
->
mday
%
7
)
>
0
)
{
$nth_weekday
++;
}
$vcaldays
=
array
(
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
);
$rrule
=
'MP'
.
$this
->
recurInterval
.
' '
.
$nth_weekday
.
'+ '
.
$vcaldays
[
$this
->
start
->
dayOfWeek
()];
break
;
case
self
::
RECUR_YEARLY_DATE
:
$rrule
=
'YM'
.
$this
->
recurInterval
.
' '
.
trim
(
$this
->
start
->
month
);
break
;
case
self
::
RECUR_YEARLY_DAY
:
$rrule
=
'YD'
.
$this
->
recurInterval
.
' '
.
$this
->
start
->
dayOfYear
();
break
;
default
:
return
''
;
}
if
(
$this
->
hasRecurEnd
())
{
$recurEnd
=
clone
$this
->
recurEnd
;
return
$rrule
.
' '
.
$calendar
->
_exportDateTime
(
$recurEnd
);
}
return
$rrule
.
' #'
.
(
int
)
$this
->
getRecurCount
();
}
/**
* Parses an iCalendar 2.0 recurrence rule.
*
* @link http://rfc.net/rfc2445.html#s4.3.10
* @link http://rfc.net/rfc2445.html#s4.8.5
* @link http://www.shuchow.com/vCalAddendum.html
*
* @param string $rrule An iCalendar 2.0 conform RRULE value.
*/
public
function
fromRRule20
(
$rrule
)
{
$this
->
reset
();
// Parse the recurrence rule into keys and values.
$rdata
=
array
();
$parts
=
explode
(
';'
,
$rrule
);
foreach
(
$parts
as
$part
)
{
list
(
$key
,
$value
)
=
explode
(
'='
,
$part
,
2
);
$rdata
[
strtoupper
(
$key
)]
=
$value
;
}
if
(
isset
(
$rdata
[
'FREQ'
]))
{
// Always default the recurInterval to 1.
$this
->
setRecurInterval
(
isset
(
$rdata
[
'INTERVAL'
])
?
$rdata
[
'INTERVAL'
]
:
1
);
$maskdays
=
array
(
'SU'
=>
Horde_Date
::
MASK_SUNDAY
,
'MO'
=>
Horde_Date
::
MASK_MONDAY
,
'TU'
=>
Horde_Date
::
MASK_TUESDAY
,
'WE'
=>
Horde_Date
::
MASK_WEDNESDAY
,
'TH'
=>
Horde_Date
::
MASK_THURSDAY
,
'FR'
=>
Horde_Date
::
MASK_FRIDAY
,
'SA'
=>
Horde_Date
::
MASK_SATURDAY
,
);
switch
(
strtoupper
(
$rdata
[
'FREQ'
]))
{
case
'DAILY'
:
$this
->
setRecurType
(
self
::
RECUR_DAILY
);
break
;
case
'WEEKLY'
:
$this
->
setRecurType
(
self
::
RECUR_WEEKLY
);
if
(
isset
(
$rdata
[
'BYDAY'
]))
{
$days
=
explode
(
','
,
$rdata
[
'BYDAY'
]);
$mask
=
0
;
foreach
(
$days
as
$day
)
{
$mask
|=
$maskdays
[
$day
];
}
$this
->
setRecurOnDay
(
$mask
);
}
else
{
// Recur on the day of the week of the original
// recurrence.
$maskdays
=
array
(
Horde_Date
::
DATE_SUNDAY
=>
Horde_Date
::
MASK_SUNDAY
,
Horde_Date
::
DATE_MONDAY
=>
Horde_Date
::
MASK_MONDAY
,
Horde_Date
::
DATE_TUESDAY
=>
Horde_Date
::
MASK_TUESDAY
,
Horde_Date
::
DATE_WEDNESDAY
=>
Horde_Date
::
MASK_WEDNESDAY
,
Horde_Date
::
DATE_THURSDAY
=>
Horde_Date
::
MASK_THURSDAY
,
Horde_Date
::
DATE_FRIDAY
=>
Horde_Date
::
MASK_FRIDAY
,
Horde_Date
::
DATE_SATURDAY
=>
Horde_Date
::
MASK_SATURDAY
);
$this
->
setRecurOnDay
(
$maskdays
[
$this
->
start
->
dayOfWeek
()]);
}
break
;
case
'MONTHLY'
:
if
(
isset
(
$rdata
[
'BYDAY'
]))
{
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_WEEKDAY
);
if
(
preg_match
(
'/(-?[1-4])([A-Z]+)/'
,
$rdata
[
'BYDAY'
],
$m
))
{
$this
->
setRecurOnDay
(
$maskdays
[
$m
[
2
]]);
$this
->
setRecurNthWeekday
(
$m
[
1
]);
}
}
else
{
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_DATE
);
}
break
;
case
'YEARLY'
:
if
(
isset
(
$rdata
[
'BYYEARDAY'
]))
{
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DAY
);
}
elseif
(
isset
(
$rdata
[
'BYDAY'
]))
{
$this
->
setRecurType
(
self
::
RECUR_YEARLY_WEEKDAY
);
if
(
preg_match
(
'/(-?[1-4])([A-Z]+)/'
,
$rdata
[
'BYDAY'
],
$m
))
{
$this
->
setRecurOnDay
(
$maskdays
[
$m
[
2
]]);
$this
->
setRecurNthWeekday
(
$m
[
1
]);
}
if
(
$rdata
[
'BYMONTH'
])
{
$months
=
explode
(
','
,
$rdata
[
'BYMONTH'
]);
$this
->
setRecurByMonth
(
$months
);
}
}
else
{
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DATE
);
}
break
;
}
if
(
isset
(
$rdata
[
'UNTIL'
]))
{
list
(
$year
,
$month
,
$mday
)
=
sscanf
(
$rdata
[
'UNTIL'
],
'%04d%02d%02d'
);
$this
->
setRecurEnd
(
new
Horde_Date
(
array
(
'year'
=>
$year
,
'month'
=>
$month
,
'mday'
=>
$mday
,
'hour'
=>
23
,
'min'
=>
59
,
'sec'
=>
59
)));
}
if
(
isset
(
$rdata
[
'COUNT'
]))
{
$this
->
setRecurCount
(
$rdata
[
'COUNT'
]);
}
}
else
{
// No recurrence data - event does not recur.
$this
->
setRecurType
(
self
::
RECUR_NONE
);
}
}
/**
* Creates an iCalendar 2.0 recurrence rule.
*
* @link http://rfc.net/rfc2445.html#s4.3.10
* @link http://rfc.net/rfc2445.html#s4.8.5
* @link http://www.shuchow.com/vCalAddendum.html
*
* @param Horde_Icalendar $calendar A Horde_Icalendar object instance.
*
* @return string An iCalendar 2.0 conform RRULE value.
*/
public
function
toRRule20
(
$calendar
)
{
switch
(
$this
->
recurType
)
{
case
self
::
RECUR_NONE
:
return
''
;
case
self
::
RECUR_DAILY
:
$rrule
=
'FREQ=DAILY;INTERVAL='
.
$this
->
recurInterval
;
break
;
case
self
::
RECUR_WEEKLY
:
$rrule
=
'FREQ=WEEKLY;INTERVAL='
.
$this
->
recurInterval
.
';BYDAY='
;
$vcaldays
=
array
(
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
);
for
(
$i
=
$flag
=
0
;
$i
<=
7
;
++
$i
)
{
if
(
$this
->
recurOnDay
(
pow
(
2
,
$i
)))
{
if
(
$flag
)
{
$rrule
.=
','
;
}
$rrule
.=
$vcaldays
[
$i
];
$flag
=
true
;
}
}
break
;
case
self
::
RECUR_MONTHLY_DATE
:
$rrule
=
'FREQ=MONTHLY;INTERVAL='
.
$this
->
recurInterval
;
break
;
case
self
::
RECUR_MONTHLY_WEEKDAY
:
if
(
isset
(
$this
->
recurNthDay
))
{
$nth_weekday
=
$this
->
recurNthDay
;
$day_of_week
=
log
(
$this
->
recurData
,
2
);
}
else
{
$day_of_week
=
$this
->
start
->
dayOfWeek
();
$nth_weekday
=
(
int
)(
$this
->
start
->
mday
/
7
);
if
((
$this
->
start
->
mday
%
7
)
>
0
)
{
$nth_weekday
++;
}
}
$vcaldays
=
array
(
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
);
$rrule
=
'FREQ=MONTHLY;INTERVAL='
.
$this
->
recurInterval
.
';BYDAY='
.
$nth_weekday
.
$vcaldays
[
$day_of_week
];
break
;
case
self
::
RECUR_YEARLY_DATE
:
$rrule
=
'FREQ=YEARLY;INTERVAL='
.
$this
->
recurInterval
;
break
;
case
self
::
RECUR_YEARLY_DAY
:
$rrule
=
'FREQ=YEARLY;INTERVAL='
.
$this
->
recurInterval
.
';BYYEARDAY='
.
$this
->
start
->
dayOfYear
();
break
;
case
self
::
RECUR_YEARLY_WEEKDAY
:
if
(
isset
(
$this
->
recurNthDay
))
{
$nth_weekday
=
$this
->
recurNthDay
;
$day_of_week
=
log
(
$this
->
recurData
,
2
);
}
else
{
$day_of_week
=
$this
->
start
->
dayOfWeek
();
$nth_weekday
=
(
int
)(
$this
->
start
->
mday
/
7
);
if
((
$this
->
start
->
mday
%
7
)
>
0
)
{
$nth_weekday
++;
}
}
$months
=
!
empty
(
$this
->
recurMonths
)
?
join
(
','
,
$this
->
recurMonths
)
:
$this
->
start
->
month
;
$vcaldays
=
array
(
'SU'
,
'MO'
,
'TU'
,
'WE'
,
'TH'
,
'FR'
,
'SA'
);
$rrule
=
'FREQ=YEARLY;INTERVAL='
.
$this
->
recurInterval
.
';BYDAY='
.
$nth_weekday
.
$vcaldays
[
$day_of_week
]
.
';BYMONTH='
.
$this
->
start
->
month
;
break
;
}
if
(
$this
->
hasRecurEnd
())
{
$recurEnd
=
clone
$this
->
recurEnd
;
$rrule
.=
';UNTIL='
.
$calendar
->
_exportDateTime
(
$recurEnd
);
}
if
(
$count
=
$this
->
getRecurCount
())
{
$rrule
.=
';COUNT='
.
$count
;
}
return
$rrule
;
}
/**
* Parses the recurrence data from a hash.
*
* @param array $hash The hash to convert.
*
* @return boolean True if the hash seemed valid, false otherwise.
*/
public
function
fromHash
(
$hash
)
{
$this
->
reset
();
if
(!
isset
(
$hash
[
'interval'
])
||
!
isset
(
$hash
[
'cycle'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
$this
->
setRecurInterval
((
int
)
$hash
[
'interval'
]);
$month2number
=
array
(
'january'
=>
1
,
'february'
=>
2
,
'march'
=>
3
,
'april'
=>
4
,
'may'
=>
5
,
'june'
=>
6
,
'july'
=>
7
,
'august'
=>
8
,
'september'
=>
9
,
'october'
=>
10
,
'november'
=>
11
,
'december'
=>
12
,
);
$parse_day
=
false
;
$set_daymask
=
false
;
$update_month
=
false
;
$update_daynumber
=
false
;
$update_weekday
=
false
;
$nth_weekday
=
-
1
;
switch
(
$hash
[
'cycle'
])
{
case
'daily'
:
$this
->
setRecurType
(
self
::
RECUR_DAILY
);
break
;
case
'weekly'
:
$this
->
setRecurType
(
self
::
RECUR_WEEKLY
);
$parse_day
=
true
;
$set_daymask
=
true
;
break
;
case
'monthly'
:
if
(!
isset
(
$hash
[
'daynumber'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
switch
(
$hash
[
'type'
])
{
case
'daynumber'
:
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_DATE
);
$update_daynumber
=
true
;
break
;
case
'weekday'
:
$this
->
setRecurType
(
self
::
RECUR_MONTHLY_WEEKDAY
);
$this
->
setRecurNthWeekday
(
$hash
[
'daynumber'
]);
$parse_day
=
true
;
$set_daymask
=
true
;
break
;
}
break
;
case
'yearly'
:
if
(!
isset
(
$hash
[
'type'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
switch
(
$hash
[
'type'
])
{
case
'monthday'
:
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DATE
);
$update_month
=
true
;
$update_daynumber
=
true
;
break
;
case
'yearday'
:
if
(!
isset
(
$hash
[
'month'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
$this
->
setRecurType
(
self
::
RECUR_YEARLY_DAY
);
// Start counting days in January.
$hash
[
'month'
]
=
'january'
;
$update_month
=
true
;
$update_daynumber
=
true
;
break
;
case
'weekday'
:
if
(!
isset
(
$hash
[
'daynumber'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
$this
->
setRecurType
(
self
::
RECUR_YEARLY_WEEKDAY
);
$this
->
setRecurNthWeekday
(
$hash
[
'daynumber'
]);
$parse_day
=
true
;
$set_daymask
=
true
;
if
(
$hash
[
'month'
]
&&
isset
(
$month2number
[
$hash
[
'month'
]]))
{
$this
->
setRecurByMonth
(
$month2number
[
$hash
[
'month'
]]);
}
break
;
}
}
if
(
isset
(
$hash
[
'range-type'
])
&&
isset
(
$hash
[
'range'
]))
{
switch
(
$hash
[
'range-type'
])
{
case
'number'
:
$this
->
setRecurCount
((
int
)
$hash
[
'range'
]);
break
;
case
'date'
:
$recur_end
=
new
Horde_Date
(
$hash
[
'range'
]);
$recur_end
->
hour
=
23
;
$recur_end
->
min
=
59
;
$recur_end
->
sec
=
59
;
$this
->
setRecurEnd
(
$recur_end
);
break
;
}
}
// Need to parse <day>?
$last_found_day
=
-
1
;
if
(
$parse_day
)
{
if
(!
isset
(
$hash
[
'day'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
$mask
=
0
;
$bits
=
array
(
'monday'
=>
Horde_Date
::
MASK_MONDAY
,
'tuesday'
=>
Horde_Date
::
MASK_TUESDAY
,
'wednesday'
=>
Horde_Date
::
MASK_WEDNESDAY
,
'thursday'
=>
Horde_Date
::
MASK_THURSDAY
,
'friday'
=>
Horde_Date
::
MASK_FRIDAY
,
'saturday'
=>
Horde_Date
::
MASK_SATURDAY
,
'sunday'
=>
Horde_Date
::
MASK_SUNDAY
,
);
$days
=
array
(
'monday'
=>
Horde_Date
::
DATE_MONDAY
,
'tuesday'
=>
Horde_Date
::
DATE_TUESDAY
,
'wednesday'
=>
Horde_Date
::
DATE_WEDNESDAY
,
'thursday'
=>
Horde_Date
::
DATE_THURSDAY
,
'friday'
=>
Horde_Date
::
DATE_FRIDAY
,
'saturday'
=>
Horde_Date
::
DATE_SATURDAY
,
'sunday'
=>
Horde_Date
::
DATE_SUNDAY
,
);
foreach
(
$hash
[
'day'
]
as
$day
)
{
// Validity check.
if
(
empty
(
$day
)
||
!
isset
(
$bits
[
$day
]))
{
continue
;
}
$mask
|=
$bits
[
$day
];
$last_found_day
=
$days
[
$day
];
}
if
(
$set_daymask
)
{
$this
->
setRecurOnDay
(
$mask
);
}
}
if
(
$update_month
||
$update_daynumber
||
$update_weekday
)
{
if
(
$update_month
)
{
if
(
isset
(
$month2number
[
$hash
[
'month'
]]))
{
$this
->
start
->
month
=
$month2number
[
$hash
[
'month'
]];
}
}
if
(
$update_daynumber
)
{
if
(!
isset
(
$hash
[
'daynumber'
]))
{
$this
->
setRecurType
(
self
::
RECUR_NONE
);
return
false
;
}
$this
->
start
->
mday
=
$hash
[
'daynumber'
];
}
if
(
$update_weekday
)
{
$this
->
setNthWeekday
(
$nth_weekday
);
}
}
// Exceptions.
if
(
isset
(
$hash
[
'exceptions'
]))
{
$this
->
exceptions
=
$hash
[
'exceptions'
];
}
if
(
isset
(
$hash
[
'completions'
]))
{
$this
->
completions
=
$hash
[
'completions'
];
}
return
true
;
}
/**
* Export this object into a hash.
*
* @return array The recurrence hash.
*/
public
function
toHash
()
{
if
(
$this
->
getRecurType
()
==
self
::
RECUR_NONE
)
{
return
array
();
}
$day2number
=
array
(
0
=>
'sunday'
,
1
=>
'monday'
,
2
=>
'tuesday'
,
3
=>
'wednesday'
,
4
=>
'thursday'
,
5
=>
'friday'
,
6
=>
'saturday'
);
$month2number
=
array
(
1
=>
'january'
,
2
=>
'february'
,
3
=>
'march'
,
4
=>
'april'
,
5
=>
'may'
,
6
=>
'june'
,
7
=>
'july'
,
8
=>
'august'
,
9
=>
'september'
,
10
=>
'october'
,
11
=>
'november'
,
12
=>
'december'
);
$hash
=
array
(
'interval'
=>
$this
->
getRecurInterval
());
$start
=
$this
->
getRecurStart
();
switch
(
$this
->
getRecurType
())
{
case
self
::
RECUR_DAILY
:
$hash
[
'cycle'
]
=
'daily'
;
break
;
case
self
::
RECUR_WEEKLY
:
$hash
[
'cycle'
]
=
'weekly'
;
$bits
=
array
(
'monday'
=>
Horde_Date
::
MASK_MONDAY
,
'tuesday'
=>
Horde_Date
::
MASK_TUESDAY
,
'wednesday'
=>
Horde_Date
::
MASK_WEDNESDAY
,
'thursday'
=>
Horde_Date
::
MASK_THURSDAY
,
'friday'
=>
Horde_Date
::
MASK_FRIDAY
,
'saturday'
=>
Horde_Date
::
MASK_SATURDAY
,
'sunday'
=>
Horde_Date
::
MASK_SUNDAY
,
);
$days
=
array
();
foreach
(
$bits
as
$name
=>
$bit
)
{
if
(
$this
->
recurOnDay
(
$bit
))
{
$days
[]
=
$name
;
}
}
$hash
[
'day'
]
=
$days
;
break
;
case
self
::
RECUR_MONTHLY_DATE
:
$hash
[
'cycle'
]
=
'monthly'
;
$hash
[
'type'
]
=
'daynumber'
;
$hash
[
'daynumber'
]
=
$start
->
mday
;
break
;
case
self
::
RECUR_MONTHLY_WEEKDAY
:
$hash
[
'cycle'
]
=
'monthly'
;
$hash
[
'type'
]
=
'weekday'
;
$hash
[
'daynumber'
]
=
$start
->
weekOfMonth
();
$hash
[
'day'
]
=
array
(
$day2number
[
$start
->
dayOfWeek
()]);
break
;
case
self
::
RECUR_YEARLY_DATE
:
$hash
[
'cycle'
]
=
'yearly'
;
$hash
[
'type'
]
=
'monthday'
;
$hash
[
'daynumber'
]
=
$start
->
mday
;
$hash
[
'month'
]
=
$month2number
[
$start
->
month
];
break
;
case
self
::
RECUR_YEARLY_DAY
:
$hash
[
'cycle'
]
=
'yearly'
;
$hash
[
'type'
]
=
'yearday'
;
$hash
[
'daynumber'
]
=
$start
->
dayOfYear
();
break
;
case
self
::
RECUR_YEARLY_WEEKDAY
:
$hash
[
'cycle'
]
=
'yearly'
;
$hash
[
'type'
]
=
'weekday'
;
$hash
[
'daynumber'
]
=
$start
->
weekOfMonth
();
$hash
[
'day'
]
=
array
(
$day2number
[
$start
->
dayOfWeek
()]);
$hash
[
'month'
]
=
$month2number
[
$start
->
month
];
}
if
(
$this
->
hasRecurCount
())
{
$hash
[
'range-type'
]
=
'number'
;
$hash
[
'range'
]
=
$this
->
getRecurCount
();
}
elseif
(
$this
->
hasRecurEnd
())
{
$date
=
$this
->
getRecurEnd
();
$hash
[
'range-type'
]
=
'date'
;
$hash
[
'range'
]
=
$date
->
datestamp
();
}
else
{
$hash
[
'range-type'
]
=
'none'
;
$hash
[
'range'
]
=
''
;
}
// Recurrence exceptions
$hash
[
'exceptions'
]
=
$this
->
exceptions
;
$hash
[
'completions'
]
=
$this
->
completions
;
return
$hash
;
}
/**
* Returns a simple object suitable for json transport representing this
* object.
*
* Possible properties are:
* - t: type
* - i: interval
* - e: end date
* - c: count
* - d: data
* - co: completions
* - ex: exceptions
*
* @return object A simple object.
*/
public
function
toJson
()
{
$json
=
new
stdClass
;
$json
->
t
=
$this
->
recurType
;
$json
->
i
=
$this
->
recurInterval
;
if
(
$this
->
hasRecurEnd
())
{
$json
->
e
=
$this
->
recurEnd
->
toJson
();
}
if
(
$this
->
recurCount
)
{
$json
->
c
=
$this
->
recurCount
;
}
if
(
$this
->
recurData
)
{
$json
->
d
=
$this
->
recurData
;
}
if
(
$this
->
completions
)
{
$json
->
co
=
$this
->
completions
;
}
if
(
$this
->
exceptions
)
{
$json
->
ex
=
$this
->
exceptions
;
}
return
$json
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, May 22, 4:51 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
652679
Default Alt Text
Horde_Date_Recurrence.php (53 KB)
Attached To
Mode
R14 roundcubemail-plugins-kolab
Attached
Detach File
Event Timeline
Log In to Comment