'Boolean',
'CustomRecursionType' => 'Int',
'DailyInterval' => 'Int',
'WeeklyInterval' => 'Int',
'MonthlyInterval' => 'Int',
'MonthlyRecursionType1' => 'Int',
'MonthlyRecursionType2' => 'Int',
'MonthlyIndex' => 'Int',
'MonthlyDayOfWeek' => 'Int'
);
static $has_many = array (
'DateTimes' => 'CalendarDateTime',
'Exceptions' => 'RecurringException'
);
static $has_one = array (
'Calendar' => 'Calendar'
);
static $many_many = array (
'RecurringDaysOfWeek' => 'RecurringDayOfWeek',
'RecurringDaysOfMonth' => 'RecurringDayOfMonth'
);
static $icon = "event_calendar/images/event";
protected $datetime_class = null;
protected $datetime_object = null;
protected $ts = null;
protected $allowedDaysOfWeek = array();
protected $allowedDaysOfMonth = array();
protected $exceptions = null;
const DAY = 86400;
const WEEK = 604800;
public function getDateTimeClass()
{
if($this->datetime_class !== null)
return $this->datetime_class;
$class = get_class($this);
$has_manys = eval("return $class::\$has_many;");
if(is_array($has_manys)) {
foreach($has_manys as $c) {
if($c == 'CalendarDateTime' || is_subclass_of($c, 'CalendarDateTime')) {
$this->datetime_class = $c;
return $this->datetime_class;
}
}
}
}
public function getDateTimeObject()
{
if($this->datetime_object !== null)
return $this->datetime_object;
$c = $this->getDateTimeClass();
$this->datetime_object = new $c;
return $this->datetime_object;
}
protected static function map_interval($max = 10)
{
$map = array();
for($i=1;$i <= $max;$i++) {$map[$i] = $i;}
return $map;
}
protected static function map_days_of_month()
{
return DataObject::get("RecurringDayOfMonth",null,"Value ASC")->toDropdownMap('ID', 'Value');
}
protected static function map_days_of_week()
{
return DataObject::get("RecurringDayOfWeek",null,"Value ASC")->toDropdownMap('ID', 'Skey');
}
public static function days_of_week_lookup()
{
return array (
'0' => _t('CalendarEvent.SUNDAY','Sunday'),
'1' => _t('CalendarEvent.MONDAY','Monday'),
'2' => _t('CalendarEvent.TUESDAY','Tuesday'),
'3' => _t('CalendarEvent.WEDNESDAY','Wednesday'),
'4' => _t('CalendarEvent.THURSDAY','Thursday'),
'5' => _t('CalendarEvent.FRIDAY','Friday'),
'6' => _t('CalendarEvent.SATURDAY','Saturday')
);
}
protected static function map_monthly_index()
{
return array (
'1' => _t('CalendarEvent.FIRST','First'),
'2' => _t('CalendarEvent.SECOND','Second'),
'3' => _t('CalendarEvent.THIRD','Third'),
'4' => _t('CalendarEvent.FOURTH','Fourth'),
'5' => _t('CalendarEvent.LAST','Last')
);
}
protected function initDates()
{
if($this->ts === null) {
if($datetime = DataObject::get_one($this->getDateTimeClass(), "EventID = {$this->ID}")) {
$this->ts = strtotime($datetime->StartDate);
}
}
if($this->CustomRecursionType == 2 && empty($this->allowedDaysOfWeek)) {
if($days_of_week = $this->getManyManyComponents('RecurringDaysOfWeek')) {
foreach($days_of_week as $day)
$this->allowedDaysOfWeek[] = $day->Value;
}
}
else if($this->CustomRecursionType == 3 && empty($this->allowedDaysOfWeek)) {
if($days_of_month = $this->getManyManyComponents('RecurringDaysOfMonth')) {
foreach($days_of_month as $day)
$this->allowedDaysOfMonth[] = $day->Value;
}
}
if($this->exceptions === null) {
$this->exceptions = array();
if($exceptions = $this->getComponents('Exceptions')) {
foreach($exceptions as $exception)
$this->exceptions[] = $exception->ExceptionDate;
}
}
}
public function getCMSFields()
{
$f = parent::getCMSFields();
$dt = _t('CalendarEvent.DATESANDTIMES','Dates and Times');
$f->addFieldsToTab("Root.Content.$dt", array (
new LiteralField('wrapper1','
'),
$this->getDateTimeObject()->getDateTimeTable($this->ID),
new LiteralField('wrapper_close1','
'),
new LiteralField('alert_message', ''),
new CheckboxField('Recursion',_t('CalendarEvent.REPEATEVENT','Repeat this event')),
new OptionsetField(
'CustomRecursionType',
_t('CalendarEvent.DESCRIBEINTERVAL','Describe the interval at which this event recurs.'),
array (
'1' => _t('CalendarEvent.DAILY','Daily'),
'2' => _t('CalendarEvent.WEEKLY','Weekly'),
'3' => _t('CalendarEvent.MONTHLY','Monthly')
)
),
new LiteralField('wrapper2',''),
new FieldGroup(
new LabelField($name = "every1", $title = _t("CalendarEvent.EVERY","Every ")),
new DropdownField('DailyInterval', '', self::map_interval()),
new LabelField($name = "days",$title = _t("CalendarEvent.DAYS"," day(s)"))
),
new LiteralField('wrapper_close2', '
'),
new LiteralField('wrapper3',''),
new FieldGroup(
new LabelField($name = "every2", $title = _t("CalendarEvent.EVERY","Every ")),
new DropdownField('WeeklyInterval', '', self::map_interval()),
new LabelField($name = "weeks", $title = _t("CalendarEvent.WEEKS", " weeks"))
),
new CheckboxSetField('RecurringDaysOfWeek', _t('CalendarEvent.ONFOLLOWINGDAYS','On the following day(s)...'), self::map_days_of_week()),
new LiteralField('wrapper_close3', '
'),
new LiteralField('wrapper4',''),
new FieldGroup(
new LabelField($name="every3", $title = _t("CalendarEvent.EVERY","Every ")),
new DropdownField('MonthlyInterval', '', self::map_interval()),
new LabelField($name = "months", $title = _t("CalendarEvent.MONTHS"," month(s)"))
),
new OptionsetField('MonthlyRecursionType1','', array('1' => _t('CalendarEvent.ONTHESEDATES','On these date(s)...'))),
new CheckboxSetField('RecurringDaysOfMonth', '', self::map_days_of_month()),
new OptionsetField('MonthlyRecursionType2','', array('1' => _t('CalendarEvent.ONTHE','On the...'))),
new FieldGroup(
new DropdownField('MonthlyIndex','',self::map_monthly_index()),
new DropdownField('MonthlyDayOfWeek','', self::days_of_week_lookup()),
new LabelField( $name = "ofthemonth", $title = _t("CalendarEvent.OFTHEMONTH"," of the month."))
),
new LiteralField('wrapper_close4', '
'),
new LiteralField('wrapper_5',''),
new HeaderField($title = _t('CalendarEvent.ANYEXCEPTIONS','Any exceptions to this pattern? Add the dates below.'), $headingLevel = '3'),
$this->getExceptionsTable(),
new LiteralField('wrapper_close5','
')
));
return $f;
}
private function getExceptionsTable()
{
$table = new TableField(
'Exceptions',
'RecurringException',
array('ExceptionDate' => _t('CalendarEvent.DATE','Date')),
array('ExceptionDate' => 'DatePickerField'),
null,
"CalendarEventID = $this->ID"
);
$table->setExtraData(array(
'CalendarEventID' => $this->ID
));
return $table;
}
public function onBeforeWrite()
{
// If the user has changed recursion types, we need to wipe out all
// the empty fields that may result from resetting the TableField.
if($empties = DataObject::get($this->getDateTimeClass(), "StartDate IS NULL")) {
foreach($empties as $empty)
$empty->delete();
}
parent::onBeforeWrite();
}
public function MultipleDates()
{
return DataObject::get($this->getDateTimeClass(),"EventID = $this->ID","StartDate ASC")->Count() > 1;
}
public function DateAndTime()
{
return DataObject::get($this->getDateTimeClass(),"EventID = $this->ID","StartDate ASC");
}
public function UpcomingDates($limit = 3)
{
return DataObject::get($this->getDateTimeClass(),"EventID = {$this->ID} AND StartDate >= DATE(NOW())","StartDate ASC","",$limit);
}
public function OtherDates()
{
if(!$date = CalendarUtil::getDateFromURL()) {
$date_obj = DataObject::get_one($this->getDateTimeClass(),"EventID = {$this->ID}", "StartDate ASC");
if(!$date_obj) return false;
else $date = $date_obj->StartDate;
}
if($date) {
$cal = $this->Calendar();
if($this->Recursion == 1) {
$datetime_obj = DataObject::get_one($this->getDateTimeClass(), "EventID = {$this->ID}");
$datetime_obj->StartDate = $date;
return $cal->getNextRecurringEvents($this, $datetime_obj);
}
else {
if($dates = DataObject::get($this->getDateTimeClass(), "EventID = {$this->ID} AND StartDate != '".$date."'","StartDate ASC","",$cal->OtherDatesCount))
return CalendarUtil::CollapseDatesAndTimes($dates);
}
}
else
return false;
}
public function CurrentDate()
{
$date = false;
if(!$date = CalendarUtil::getDateFromURL()) {
if($obj = DataObject::get_one($this->getDateTimeClass(),"EventID = {$this->ID}", "StartDate ASC"))
$date = $obj->StartDate;
}
if($date) {
if($this->Recursion) {
$datetime = DataObject::get_one($this->getDateTimeClass(), "EventID = {$this->ID}");
$datetime->StartDate = $date;
return $datetime;
}
elseif($dates = DataObject::get($this->getDateTimeClass(), "EventID = {$this->ID} AND StartDate = '".$date."'"))
return CalendarUtil::CollapseDatesAndTimes($dates);
else
return false;
}
}
public function Dates()
{
return CalendarUtil::CollapseDatesAndTimes($this->DateAndTime());
}
public function recursionHappensOn($ts)
{
$this->initDates();
if($this->ts === null)
return false;
$objTestDate = new sfDate($ts);
$objStartDate = new sfDate($this->ts);
// Current date is before the recurring event begins.
if($objTestDate->get() < $objStartDate->get())
return false;
elseif(in_array($objTestDate->date(), $this->exceptions))
return false;
switch($this->CustomRecursionType)
{
// Daily
case 1:
return $this->DailyInterval ? (($ts - $this->ts) / self::DAY) % $this->DailyInterval == 0 : false;
break;
// Weekly
case 2:
return ((($objTestDate->firstDayOfWeek()->get() - $objStartDate->firstDayOfWeek()->get()) / self::WEEK) % $this->WeeklyInterval == 0)
&&
(in_array($objTestDate->reset()->format('w'), $this->allowedDaysOfWeek));
break;
// Monthly
case 3:
if(CalendarUtil::differenceInMonths($objTestDate,$objStartDate) % $this->MonthlyInterval == 0) {
// A given set of dates in the month e.g. 2 and 15.
if($this->MonthlyRecursionType1 == 1) {
return (in_array($objTestDate->reset()->format('j'), $this->allowedDaysOfMonth));
}
// e.g. "First Monday of the month"
elseif($this->MonthlyRecursionType2 == 1) {
// Last day of the month?
if($this->MonthlyIndex == 5)
$targetDate = $objTestDate->addMonth()->firstDayOfMonth()->previousDay($this->MonthlyDayOfWeek)->dump();
else {
$objTestDate->subtractMonth()->finalDayOfMonth();
for($i=0; $i < $this->MonthlyIndex; $i++)
$objTestDate->nextDay($this->MonthlyDayOfWeek)->dump();
$targetDate = $objTestDate->dump();
}
return $objTestDate->reset()->dump() == $targetDate;
}
else
return false;
}
else
return false;
}
}
}
class CalendarEvent_Controller extends Page_Controller
{
public function init()
{
RSSFeed::linkToFeed($this->Parent()->Link() . "rss", _t("CalendarEvent.RSSFEED","RSS Feed of this calendar"));
parent::init();
Requirements::css('event_calendar/css/calendar.css');
Requirements::javascript(THIRDPARTY_DIR.'/jquery/jquery.js');
Requirements::javascript('event_calendar/javascript/calendar_core.js');
}
protected $date_from_url;
public function RSSLink()
{
return $this->Parent()->Link('rss');
}
protected function Widget($type)
{
if($date = CalendarUtil::getDateFromURL())
$date_obj = new sfDate($date);
elseif($date = DataObject::get_one($this->getDateTimeClass(),"EventID = {$this->ID}", "StartDate ASC"))
$date_obj = new sfDate($date->StartDate);
else
return false;
return new $type($this->Parent(),$date_obj,$date_obj);
}
public function CalendarWidget()
{
return $this->Widget('CalendarWidget');
}
public function MonthNavigator()
{
return $this->Widget('MonthNavigator');
}
public function LiveCalendarWidget()
{
return $this->Widget('LiveCalendarWidget');
}
public function MonthJumper() {
if($date = CalendarUtil::getDateFromURL())
$date_obj = new sfDate($date);
elseif($date = DataObject::get_one($this->getDateTimeClass(),"EventID = {$this->ID}", "StartDate ASC"))
$date_obj = new sfDate($date->StartDate);
else
return false;
return $this->Parent()->MonthJumper();
}
public function CalendarFilterForm()
{
if($date = CalendarUtil::getDateFromURL())
$date_obj = new sfDate($date);
elseif($date = DataObject::get_one($this->getDateTimeClass(),"EventID = {$this->ID}", "StartDate ASC"))
$date_obj = new sfDate($date->StartDate);
else
return false;
$controller_name = $this->Parent()->class."_Controller";
if(class_exists($controller_name)) {
$controller = new $controller_name($this->Parent());
$controller->parseURL();
return $controller->CalendarFilterForm($date_obj);
}
}
public function CalendarBackLink()
{
$filters = Calendar::buildFilterString();
if(isset($_GET['CalendarStart'])) {
$suffix = "view/";
$suffix .= $_GET['CalendarStart'];
if(isset($_GET['CalendarEnd'])) {
$suffix .= "/" . $_GET['CalendarEnd'];
}
}
else
$suffix = "";
$suffix .= !empty($filters) ? "?" . $filters : "";
return $this->Parent()->Link() . $suffix;
}
public function view()
{
return array();
}
}
?>