You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1186 lines
38 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
if (! defined('weekInSeconds')) {
define('weekInSeconds', 604800);
}
if (! defined('dayInSeconds')) {
define('dayInSeconds', 86400);
}
/**
*
*/
class CalRecurrence extends TikiLib
{
private $id;
private $calendarId;
private $start;
private $end;
private $allday;
private $locationId;
private $categoryId;
private $nlId;
private $priority;
private $status;
private $url;
private $lang;
private $name;
private $description;
private $weekly;
private $weekdays;
private $monthly;
private $dayOfMonth;
private $yearly;
private $dateOfYear; // format is mmdd
private $nbRecurrences;
private $startPeriod;
private $endPeriod;
private $user;
private $created;
private $lastModif;
private $initialItem;
private $uid;
private $uri;
/**
* @param $param
*/
public function __construct($param = -1)
{
parent::__construct();
if ($param > 0) {
$this->setId($param);
}
$this->setInitialItem([]);
$this->load();
}
public function load()
{
if ($this->getId() > 0) {
$query = "SELECT calendarId, start, end, allday, locationId, categoryId, nlId, priority, status, url, lang, name, description, weekly, weekdays, monthly, dayOfMonth,"
. "yearly, dateOfYear, nbRecurrences, startPeriod, endPeriod, user, created, lastModif, uri, uid FROM tiki_calendar_recurrence "
. "WHERE recurrenceId = ?";
$result = $this->query($query, [(int)$this->getId()]);
if ($row = $result->fetchRow()) {
$this->setCalendarId($row['calendarId']);
$this->setStart($row['start']);
$this->setEnd($row['end']);
$this->setAllday($row['allday']);
$this->setLocationId($row['locationId']);
$this->setCategoryId($row['categoryId']);
$this->setNlId($row['nlId']);
$this->setPriority($row['priority']);
$this->setStatus($row['status']);
$this->setUrl($row['url']);
$this->setLang($row['lang']);
$this->setName($row['name']);
$this->setDescription($row['description']);
$this->setWeekly($row['weekly'] == 1);
$this->setWeekdays($row['weekdays']);
$this->setMonthly($row['monthly'] == 1);
$this->setDayOfMonth($row['dayOfMonth']);
$this->setYearly($row['yearly'] == 1);
$this->setDateOfYear($row['dateOfYear']);
$this->setNbRecurrences($row['nbRecurrences']);
$this->setStartPeriod($row['startPeriod']);
$this->setEndPeriod($row['endPeriod']);
$this->setUser($row['user']);
$this->setCreated($row['created']);
$this->setLastModif($row['lastModif']);
$this->setUri($row['uri']);
$this->setUid($row['uid']);
}
}
}
public function updateDetails($data)
{
$this->setCalendarId($data['calendarId']);
$this->setStart(\DateTime::createFromFormat('U', $data['start'])->setTimezone(new \DateTimeZone('UTC'))->format('Hi'));
$this->setEnd(\DateTime::createFromFormat('U', $data['end'])->setTimezone(new \DateTimeZone('UTC'))->format('Hi'));
if (isset($data['newloc'])) {
$this->setLocationId($data['newloc']);
}
if (isset($data['newcat'])) {
$this->setCategoryId($data['newcat']);
}
if (isset($data['priority'])) {
$this->setPriority($data['priority']);
}
if (isset($data['status'])) {
$this->setStatus($data['status']);
}
if (isset($data['lang'])) {
$this->setLang($data['lang']);
}
if (isset($data['nlId'])) {
$this->setNlId($data['nlId']);
}
if (isset($data['url'])) {
$this->setUrl($data['url']);
}
if (isset($data['name'])) {
$this->setName($data['name']);
}
if (isset($data['description'])) {
$this->setDescription($data['description']);
}
if (isset($data['user'])) {
$this->setUser($data['user']);
}
if (isset($data['uri'])) {
$this->setUri($data['uri']);
}
if (isset($data['uid'])) {
$this->setUid($data['uid']);
}
}
/**
* When updating the recurrence rule,
* we are offered the the option to update all the recurrent events already created
* (i.e. $updateManuallyChanged = true), or only the events for which the changes on the rules
* have no incidence on the changes done manually (i.e. fields changed in the rule are not the fields changed
* in the event)
*/
public function save($updateManuallyChangedEvents = false)
{
if (! $this->isValid()) {
return false;
}
if ($this->getId() > 0) {
return $this->update($updateManuallyChangedEvents);
}
return $this->create();
}
/**
* Validation before storing (or updating) to the database.
* returns true if succeeds, false otherwise
*/
public function isValid()
{
// should be related to a calendar
if (! ($this->getCalendarId() > 0)) {
return false;
}
// should have valid start and end date
if (
! ($this->isAllday())
&& (! ($this->getStart() >= 0) || ! ($this->getEnd() >= 0) || ($this->getStart() > 2359) || ($this->getEnd() > 2359))
) {
return false;
}
// should be recurrent on "some" basis
if (! $this->isWeekly() && ! $this->isMonthly() && ! $this->isYearly()) {
return false;
}
// recurrence should be correctly defined
$weekdays = explode(',', $this->getWeekdays());
$weekdays = array_filter($weekdays, function ($day) {
return in_array($day, ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']);
});
if (
($this->isWeekly() && empty($weekdays))
|| ($this->isMonthly() && (is_null($this->getDayOfMonth()) || $this->getDayOfMonth() > 31 || $this->getDayOfMonth() < 1 || $this->getDayOfMonth() == ''))
|| ($this->isYearly() && (is_null($this->getDateOfYear()) || $this->getDateOfYear() > 1231 || $this->getDateOfYear() < 0101 || $this->getDateOfYear() == ''))
) {
return false;
}
// recurrence period should be defined
if (
(is_null($this->getNbRecurrences()) || ($this->getNbRecurrences() == '') || ($this->getNbRecurrences() == 0))
&& (is_null($this->getEndPeriod()) || ($this->getEndPeriod() == '') || ($this->getEndPeriod() < $this->getStartPeriod()))
) {
return false;
}
//
if (is_null($this->getNlId())) {
return false;
}
// should inform the language
if (is_null($this->getLang()) || $this->getLang() == "") {
return false;
}
// should have a name
if (is_null($this->getName()) || $this->getName() == "") {
return false;
}
return true;
}
/**
* @param null $fromTime
* @return mixed
*/
public function delete($fromTime = null)
{
global $user;
$tx = TikiDb::get()->begin();
if (is_null($fromTime)) {
$fromTime = time();
}
$calendarlib = TikiLib::lib('calendar');
$tiki_calendar_items = TikiDb::get()->table('tiki_calendar_items');
$calItemIds = $tiki_calendar_items->fetchColumn('calItemId', [
'recurrenceId' => $this->getId(),
'start' => $tiki_calendar_items->greaterThan($fromTime),
]);
foreach ($calItemIds as $calItemId) {
$calendarlib->drop_item($user, $calItemId, true);
}
// this seems to leave ones in the past alone by default but detatches them from the recurrence rule (odd)
$query = "UPDATE tiki_calendar_items SET recurrenceId = NULL WHERE recurrenceId = ?";
$bindvars = [(int)$this->getId()];
$this->query($query, $bindvars);
$query = "DELETE FROM tiki_calendar_recurrence WHERE recurrenceId = ?";
$bindvars = [(int)$this->getId()];
$ret = $this->query($query, $bindvars);
$tx->commit();
return $ret;
}
/**
* @return bool
*/
private function create()
{
$query = "INSERT INTO tiki_calendar_recurrence (calendarId, start, end, allday, locationId, categoryId, nlId, priority, status, url, lang, name, description, "
. "weekly, weekdays, monthly, dayOfMonth,yearly, dateOfYear, nbRecurrences, startPeriod, endPeriod, user, created, lastModif, uri, uid) "
. "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
$now = $this->now;
$bindvars = [
$this->getCalendarId(),
$this->getStart(),
$this->getEnd(),
$this->isAllday() ? 1 : 0,
$this->getLocationId() ?: 0,
$this->getCategoryId(),
$this->getNlId(),
$this->getPriority(),
$this->getStatus(),
$this->getUrl(),
$this->getLang(),
$this->getName(),
$this->getDescription(),
$this->isWeekly() ? 1 : 0,
$this->getWeekdays(),
$this->isMonthly() ? 1 : 0,
$this->getDayOfMonth(),
$this->isYearly() ? 1 : 0,
$this->getDateOfYear(),
$this->getNbRecurrences(),
$this->getStartPeriod(),
$this->getEndPeriod(),
$this->getUser(),
$now,
$now,
$this->getUri(),
$this->getUid(),
];
$result = $this->query($query, $bindvars);
if ($result) {
$this->setId($this->GetOne("SELECT `recurrenceId` FROM `tiki_calendar_recurrence` WHERE `created`=?", [$now]));
if ($this->getId() > 0) {
// create the recurrent events
$this->createEvents();
return true;
}
}
return false;
}
/**
* @param bool $updateManuallyChangedEvents
* @return bool
*/
private function update($updateManuallyChangedEvents = false)
{
$query = "UPDATE tiki_calendar_recurrence SET calendarId = ?, start = ?, end = ?, allday = ?, locationId = ?, categoryId = ?, nlId = ?, priority = ?, status = ?, "
. "url = ?, lang = ?, name = ?, description = ?, weekly = ?, weekdays = ?, monthly = ?, dayOfMonth = ?, yearly = ?, dateOfYear = ?, nbRecurrences = ?, "
. "startPeriod = ?, endPeriod = ?, user = ?, lastModif = ?, uri = ?, uid = ? WHERE recurrenceId = ?";
$now = time();
$bindvars = [
$this->getCalendarId(),
$this->getStart(),
$this->getEnd(),
$this->isAllday() ? 1 : 0,
$this->getLocationId(),
$this->getCategoryId(),
$this->getNlId(),
$this->getPriority(),
$this->getStatus(),
$this->getUrl(),
$this->getLang(),
$this->getName(),
$this->getDescription(),
$this->isWeekly() ? 1 : 0,
$this->getWeekdays(),
$this->isMonthly() ? 1 : 0,
$this->getDayOfMonth(),
$this->isYearly() ? 1 : 0,
$this->getDateOfYear(),
$this->getNbRecurrences(),
$this->getStartPeriod(),
$this->getEndPeriod(),
$this->getUser(),
$now,
$this->getUri(),
$this->getUid(),
$this->getId()
];
$oldRec = new CalRecurrence($this->getId()); // we'll need old version to compare fields.
$result = $this->query($query, $bindvars);
if ($result) {
// update the recurrent events, according to the way to handle the already changed events
$this->updateEvents($updateManuallyChangedEvents, $oldRec);
return true;
}
return false;
}
/**
* @return bool
*/
public function createEvents()
{
global $user;
$calendarlib = TikiLib::lib('calendar');
$vcalendar = $this->constructVCalendar();
$start = $vcalendar->VEVENT->DTSTART->getDateTime()->getTimeStamp();
$end = $this->getEndPeriod();
if (! $end) {
$end = strtotime(Tiki\SabreDav\CalDAVBackend::MAX_DATE);
}
$timezone = $vcalendar->VEVENT->DTSTART->getDateTime()->getTimezone();
$expanded = $vcalendar->expand(DateTime::createFromFormat('U', $start), DateTime::createFromFormat('U', $end), $timezone);
$tx = TikiDb::get()->begin();
foreach ($expanded->VEVENT as $vevent) {
$data = [
'calendarId' => $this->getCalendarId(),
'start' => $vevent->DTSTART->getDateTime()->getTimeStamp(),
'end' => $vevent->DTEND->getDateTime()->getTimeStamp(),
'locationId' => $this->getLocationId(),
'categoryId' => $this->getCategoryId(),
'nlId' => $this->getNlId(),
'priority' => $this->getPriority(),
'status' => $this->getStatus(),
'url' => $this->getUrl(),
'lang' => $this->getLang(),
'name' => $this->getName(),
'description' => $this->getDescription(),
'user' => $this->getUser(),
'created' => $this->getCreated(),
'lastmodif' => $this->getCreated(),
'allday' => $this->isAllday(),
'recurrenceId' => $this->getId(),
'changed' => 0,
];
$initial = $this->getInitialItem();
$diff = array_diff($data, $initial);
unset($diff['recurrenceId']);
if (empty($initial['lang'])) {
// manually created items seem to have lang == ''
unset($diff['lang']);
}
if (! empty($diff)) {
// different event, add a new one
$calendarlib->set_item($user, null, $data, [], true);
} else {
// original event, update the recurrence id
$initial['recurrenceId'] = $this->getId();
$calendarlib->set_item($user, $initial['calitemId'], $initial);
}
}
$tx->commit();
}
/**
* Attempts to update expanded recurring events in db based off changes in the recurring event record.
* Matches events by old schedule (before update) and original start date.
* TODO: this currently does not support EXDATE exclusions (i.e. individual event deletes) from recurring schedule
* because we match by position in the event list. In the future, this can be expanded to support EXDATE exclusions
* in order to sync deleted events here and in Tiki\SabreDav\CalDAVBackend.
* @param bool $updateManuallyChangedEvents
* @param $oldRec
*/
public function updateEvents($updateManuallyChangedEvents, $oldRec)
{
global $user;
global $prefs;
$query = "SELECT calitemId,calendarId, start, end, allday, locationId, categoryId, nlId, priority, status, url, lang, name, description, "
. "user, created, lastModif, changed, recurrenceStart "
. "FROM tiki_calendar_items WHERE recurrenceId = ? ORDER BY start";
$bindvars = [(int)$this->getId()];
$existing = $this->fetchAll($query, $bindvars);
$changedFields = $this->compareFields($oldRec);
if (! $changedFields) {
if ($prefs['feature_categories'] == 'y') {
$tx = TikiDb::get()->begin();
foreach ($existing as $eventItem) {
TikiLib::lib('calendar')->update_item_categories($eventItem['calitemId'], $_REQUEST['cat_managed'], $_REQUEST['cat_categories'], $eventItem['name'], $eventItem['description']);
}
$tx->commit();
}
return;
}
$vcalendar = $oldRec->constructVCalendar();
$start = $vcalendar->VEVENT->DTSTART->getDateTime()->getTimeStamp();
$end = $oldRec->getEndPeriod();
if (! $end) {
$end = strtotime(Tiki\SabreDav\CalDAVBackend::MAX_DATE);
}
$old_expanded = $vcalendar->expand(DateTime::createFromFormat('U', $start), DateTime::createFromFormat('U', $end));
$vcalendar = $this->constructVCalendar();
$start = $vcalendar->VEVENT->DTSTART->getDateTime()->getTimeStamp();
$end = $oldRec->getEndPeriod();
if (! $end) {
$end = strtotime(Tiki\SabreDav\CalDAVBackend::MAX_DATE);
}
$new_expanded = $vcalendar->expand(DateTime::createFromFormat('U', $start), DateTime::createFromFormat('U', $end));
$tx = TikiDb::get()->begin();
foreach ($new_expanded->VEVENT as $key => $vevent) {
$found = false;
if (! empty($old_expanded->VEVENT[$key]->DTSTART)) {
$old_start = $old_expanded->VEVENT[$key]->DTSTART->getDateTime()->getTimeStamp();
foreach ($existing as $row) {
if (($row['recurrenceStart'] && $row['recurrenceStart'] == $old_start) || $row['start'] == $old_start) {
$found = $row;
break;
}
}
}
if (! $found) {
// create it
$data = [
'calendarId' => $this->getCalendarId(),
'start' => $vevent->DTSTART->getDateTime()->getTimeStamp(),
'end' => $vevent->DTEND->getDateTime()->getTimeStamp(),
'locationId' => $this->getLocationId(),
'categoryId' => $this->getCategoryId(),
'nlId' => $this->getNlId(),
'priority' => $this->getPriority(),
'status' => $this->getStatus(),
'url' => $this->getUrl(),
'lang' => $this->getLang(),
'name' => $this->getName(),
'description' => $this->getDescription(),
'user' => $this->getUser(),
'created' => $this->getCreated(),
'lastmodif' => $this->getCreated(),
'allday' => $this->isAllday(),
'recurrenceId' => $this->getId(),
'changed' => 0,
];
TikiLib::lib('calendar')->set_item($user, null, $data, [], true);
} elseif ($found['changed'] == 0 || $updateManuallyChangedEvents) {
// update with changes
foreach ($changedFields as $field) {
if (substr($field, 0, 1) != "_") {
$found[$field] = $this->$field;
}
}
$changedFieldsOfEvent = $this->compareFieldsOfEvent($found, $oldRec);
foreach ($changedFieldsOfEvent as $field) {
if (substr($field, 0, 1) == "_") {
$found['start'] = $vevent->DTSTART->getDateTime()->getTimeStamp();
$found['end'] = $vevent->DTEND->getDateTime()->getTimeStamp();
if ($found['changed']) {
$found['recurrenceStart'] = $found['start'];
}
break;
}
}
// keep changed flag as this event might still be changed and we only updated some of the fields here
TikiLib::lib('calendar')->set_item($user, $found['calitemId'], $found, [], true);
}
}
$tx->commit();
}
/**
* Update individual events in a recurring event series that were manually tweaked in clients.
*/
public function updateOverrides($events)
{
global $user;
$query = "SELECT calitemId,calendarId, start, end, allday, locationId, categoryId, nlId, priority, status, url, lang, name, description, "
. "user, created, lastModif, changed, recurrenceStart "
. "FROM tiki_calendar_items WHERE recurrenceId = ? ORDER BY start";
$bindvars = [(int)$this->getId()];
$existing = $this->fetchAll($query, $bindvars);
foreach ($events as $event) {
foreach ($existing as $row) {
if (($row['recurrenceStart'] && $row['recurrenceStart'] == $event['recurrenceStart']) || $row['start'] == $event['recurrenceStart']) {
$event['calendarId'] = $row['calendarId'];
TikiLib::lib('calendar')->set_item($user, $row['calitemId'], $event, [], true);
break;
}
}
}
}
/**
* @param $oldRec
* @return array
*/
public function compareFields($oldRec)
{
$result = [];
if ($this->getCalendarId() != $oldRec->getCalendarId()) {
$result[] = "calendarId";
}
if ($this->getStart() != $oldRec->getStart()) {
$result[] = "_start";
}
if ($this->getEnd() != $oldRec->getEnd()) {
$result[] = "_end";
}
if ($this->isAllday() != $oldRec->isAllday()) {
$result[] = "allday";
}
if ($this->getLocationId() != $oldRec->getLocationId() && ! ($this->getLocationId() == '' && $oldRec->getLocationId() == 0)) {
$result[] = "locationId";
}
if ($this->getCategoryId() != $oldRec->getCategoryId() && ! ($this->getCategoryId() == '' && $oldRec->getCategoryId() == 0)) {
$result[] = "categoryId";
}
if ($this->getNlId() != $oldRec->getNlId()) {
$result[] = "nlId";
}
if ($this->getPriority() != $oldRec->getPriority() && ! ($oldRec->getPriority() == '' && $oldRec->getPriority() == 0)) {
$result[] = "priority";
}
if ($this->getStatus() != $oldRec->getStatus()) {
$result[] = "status";
}
if ($this->getUrl() != $oldRec->getUrl()) {
$result[] = "url";
}
if ($this->getLang() != $oldRec->getLang()) {
$result[] = "lang";
}
if ($this->getName() != $oldRec->getName()) {
$result[] = "name";
}
if ($this->getDescription() != $oldRec->getDescription()) {
$result[] = "description";
}
if ($this->isWeekly() && ($this->getWeekdays() != $oldRec->getWeekdays())) {
$result[] = "_weekdays";
}
if ($this->isMonthly() && ($this->getDayOfMonth() != $oldRec->getDayOfMonth())) {
$result[] = "_dayOfMonth";
}
if ($this->isYearly() && ($this->getDateOfYear() != $oldRec->getDateOfYear())) {
$result[] = "_dateOfYear";
}
return $result;
}
/**
* @param $evt
* @param $oldRec
* @return array
*/
public function compareFieldsOfEvent($evt, $oldRec)
{
$result = [];
if ($evt['calendarId'] != $oldRec->getCalendarId()) {
$result[] = "calendarId";
}
if (TikiLib::date_format2('Hi', $evt['start']) != $oldRec->getStart()) {
$result[] = "start";
}
// checking the end is double check : is it the right hour ? is it the same day ?
if ((TikiLib::date_format2('Hi', $evt['end']) != $oldRec->getEnd()) || (TikiLib::date_format2('Ymd', $evt['start']) != TikiLib::date_format2('Ymd', $evt['end']))) {
$result[] = "end";
}
if ($evt['allday'] != $oldRec->isAllday()) {
$result[] = "allday";
}
if ($evt['locationId'] != $oldRec->getLocationId()) {
$result[] = "locationId";
}
if ($evt['categoryId'] != $oldRec->getCategoryId()) {
$result[] = "categoryId";
}
if ($evt['nlId'] != $oldRec->getNlId()) {
$result[] = "nlId";
}
if ($evt['priority'] != $oldRec->getPriority()) {
$result[] = "priority";
}
if ($evt['status'] != $oldRec->getStatus()) {
$result[] = "status";
}
if ($evt['url'] != $oldRec->getUrl()) {
$result[] = "url";
}
if ($evt['lang'] != $oldRec->getLang()) {
$result[] = "lang";
}
if ($evt['name'] != $oldRec->getName()) {
$result[] = "name";
}
if ($evt['description'] != $oldRec->getDescription()) {
$result[] = "description";
}
if (TikiLib::date_format2('Hi', $evt['start']) != str_pad($oldRec->getStart(), 4, "0", STR_PAD_LEFT)) {
$result[] = "_start";
}
if (TikiLib::date_format2('Hi', $evt['end']) != str_pad($oldRec->getEnd(), 4, "0", STR_PAD_LEFT)) {
$result[] = "_end";
}
if ($oldRec->isWeekly()) {
if (TikiLib::date_format2('w', $evt['start']) != $oldRec->getWeekdays()) {
$result[] = "_weekdays";
}
} elseif ($oldRec->isMonthly()) {
if (TikiLib::date_format2('d', $evt['start']) != $oldRec->getDayOfMonth()) {
$result[] = "_dayOfMonth";
}
} elseif ($oldRec->isYearly()) {
if (TikiLib::date_format2('md', $evt['start']) != $oldRec->getDateOfYear()) {
$result[] = "_dateOfYear";
}
}
return $result;
}
public function fillUid($uid)
{
$this->query("update `tiki_calendar_recurrence` set `uid` = ? where `recurrenceId` = ?", [$uid, $this->getId()]);
}
public function getFirstItemId()
{
$query = "SELECT calitemId FROM `tiki_calendar_items` WHERE recurrenceId = ? ORDER BY calitemId";
$result = $this->query($query, [(int)$this->getId()]);
if ($row = $result->fetchRow()) {
return $row['calitemId'];
}
return null;
}
public function constructVCalendar()
{
static $calendar_timezones = [];
if (isset($calendar_timezones[$this->getCalendarId()])) {
$timezone = $calendar_timezones[$this->getCalendarId()];
} else {
$calendar = TikiLib::lib('calendar')->get_calendar($this->getCalendarId());
$timezone = TikiLib::lib('tiki')->get_display_timezone($calendar['user']);
$calendar_timezones[$this->getCalendarId()] = $timezone;
}
if ($this->isAllday()) {
$startOffset = 0;
$endOffset = 86399;
} else {
$startOffset = str_pad($this->getStart(), 4, '0', STR_PAD_LEFT);
$startOffset = substr($startOffset, 0, 2) * 60 * 60 + substr($startOffset, -2) * 60;
$endOffset = str_pad($this->getEnd(), 4, '0', STR_PAD_LEFT);
$endOffset = substr($endOffset, 0, 2) * 60 * 60 + substr($endOffset, -2) * 60;
}
// peculiarity here is that start/end period are in user's timezone (dtzone) but start/end offsets are in UTC hours
$dtzone = new DateTimeZone($timezone);
$dtstart = DateTime::createFromFormat('U', $this->getStartPeriod() + $startOffset);
$dtstart->setTimezone($dtzone);
$dtstart->setTimestamp($dtstart->getTimestamp() + $dtstart->getOffset());
$dtend = DateTime::createFromFormat('U', $this->getStartPeriod() + $endOffset);
$dtend->setTimezone($dtzone);
$dtend->setTimestamp($dtend->getTimestamp() + $dtend->getOffset());
$data = [
'CREATED' => DateTime::createFromFormat('U', $this->getCreated() ?? 0)->format('Ymd\THis\Z'),
'DTSTAMP' => DateTime::createFromFormat('U', $this->getLastModif() ?? 0)->format('Ymd\THis\Z'),
'LAST-MODIFIED' => DateTime::createFromFormat('U', $this->getLastModif() ?? 0)->format('Ymd\THis\Z'),
'SUMMARY' => $this->getName(),
'PRIORITY' => $this->getPriority(),
'TRANSP' => 'OPAQUE',
'DTSTART' => $dtstart,
'DTEND' => $dtend,
];
if (! empty($this->getUid())) {
$data['UID'] = $this->getUid();
}
if (! empty($this->getDescription())) {
$data['DESCRIPTION'] = $this->getDescription();
}
$locations = TikiLib::lib('calendar')->list_locations($this->getCalendarId());
if (! empty($locations[$this->getLocationId()])) {
$data['LOCATION'] = $locations[$this->getLocationId()];
}
$categories = TikiLib::lib('calendar')->list_categories($this->getCategoryId());
if (! empty($categories[$this->getCategoryId()])) {
$data['CATEGORIES'] = $categories[$this->getCategoryId()];
}
if (! empty($this->getUrl())) {
$data['URL'] = $this->getUrl();
}
$weekdays = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
if ($this->isWeekly()) {
$rrule = 'FREQ=WEEKLY;BYDAY=' . $this->getWeekdays();
} elseif ($this->isMonthly()) {
$rrule = 'FREQ=MONTHLY;BYMONTHDAY=' . $this->getDayOfMonth();
} elseif ($this->isYearly()) {
$doy = $this->getDateOfYear();
$day = substr($doy, -2);
$month = substr($doy, 0, strlen($doy) - 2);
$rrule = 'FREQ=YEARLY;BYMONTH=' . $month . ';BYMONTHDAY=' . $day;
} else {
$rrule = 'FREQ=DAILY';
}
if ($this->getNbRecurrences() > 0) {
$rrule .= ';COUNT=' . $this->getNbRecurrences();
} else {
$rrule .= ';UNTIL=' . DateTime::createFromFormat('U', $this->getEndPeriod())->format('Ymd\THis\Z');
}
$data['RRULE'] = $rrule;
$vcalendar = new Sabre\VObject\Component\VCalendar();
$vevent = $vcalendar->add('VEVENT', $data);
if ((string)$vevent->UID != $this->getUid()) {
// save UID for Tiki-generated calendar events as this must not change in the future
// SabreDav automatically generates UID value if none is present
$this->fillUid((string)$vevent->UID);
}
return $vcalendar;
}
/**
* @return array
*/
public function toArray()
{
return [
'id' => $this->getId(),
'weekly' => $this->isWeekly(),
'weekdays' => explode(',', $this->getWeekdays()),
'monthly' => $this->isMonthly(),
'dayOfMonth' => $this->getDayOfMonth(),
'yearly' => $this->isYearly(),
'dateOfYear' => $this->getDateOfYear(),
'dateOfYear_month' => floor($this->getDateOfYear() / 100),
'dateOfYear_day' => $this->getDateOfYear() - 100 * floor($this->getDateOfYear() / 100),
'nbRecurrences' => $this->getNbRecurrences(),
'startPeriod' => $this->getStartPeriod(),
'endPeriod' => $this->getEndPeriod(),
'user' => $this->getUser(),
'created' => $this->getCreated(),
'lastModif' => $this->getLastModif()
];
}
public function getId()
{
return $this->id;
}
/**
* @param $value
*/
public function setId($value)
{
$this->id = $value;
}
public function getCalendarId()
{
return $this->calendarId;
}
/**
* @param $value
*/
public function setCalendarId($value)
{
$this->calendarId = $value;
}
public function getStart()
{
return $this->start;
}
/**
* @param $value
*/
public function setStart($value)
{
$this->start = $value;
}
public function getEnd()
{
return $this->end;
}
/**
* @param $value
*/
public function setEnd($value)
{
$this->end = $value;
}
public function isAllday()
{
return $this->allday;
}
/**
* @param $value
*/
public function setAllday($value)
{
$this->allday = $value;
}
public function getLocationId()
{
return $this->locationId;
}
/**
* @param $value
*/
public function setLocationId($value)
{
$this->locationId = $value;
}
public function getCategoryId()
{
return $this->categoryId;
}
/**
* @param $value
*/
public function setCategoryId($value)
{
$this->categoryId = $value;
}
public function getNlId()
{
return $this->nlId;
}
/**
* @param $value
*/
public function setNlId($value)
{
$this->nlId = $value;
}
public function getPriority()
{
return $this->priority;
}
/**
* @param $value
*/
public function setPriority($value)
{
$this->priority = $value;
}
public function getStatus()
{
return $this->status;
}
/**
* @param $value
*/
public function setStatus($value)
{
$this->status = $value;
}
public function getUrl()
{
return $this->url;
}
/**
* @param $value
*/
public function setUrl($value)
{
$this->url = $value;
}
public function getLang()
{
return $this->lang;
}
/**
* @param $value
*/
public function setLang($value)
{
$this->lang = $value;
}
public function getName()
{
return $this->name;
}
/**
* @param $value
*/
public function setName($value)
{
$this->name = $value;
}
public function getDescription()
{
return $this->description;
}
/**
* @param $value
*/
public function setDescription($value)
{
$this->description = $value;
}
public function isWeekly()
{
return $this->weekly;
}
/**
* @param $value
*/
public function setWeekly($value)
{
$this->weekly = $value;
}
public function getWeekdays()
{
return $this->weekdays;
}
/**
* @param $value
*/
public function setWeekdays($value)
{
$this->weekdays = $value;
}
public function isMonthly()
{
return $this->monthly;
}
/**
* @param $value
*/
public function setMonthly($value)
{
$this->monthly = $value;
}
public function getDayOfMonth()
{
return $this->dayOfMonth;
}
/**
* @param $value
*/
public function setDayOfMonth($value)
{
$this->dayOfMonth = $value;
}
public function isYearly()
{
return $this->yearly;
}
/**
* @param $value
*/
public function setYearly($value)
{
$this->yearly = $value;
}
public function getDateOfYear()
{
return $this->dateOfYear;
}
/**
* @param $value
*/
public function setDateOfYear($value)
{
$this->dateOfYear = $value;
}
public function getNbRecurrences()
{
return $this->nbRecurrences;
}
/**
* @param $value
*/
public function setNbRecurrences($value)
{
$this->nbRecurrences = $value;
}
public function getStartPeriod()
{
return $this->startPeriod;
}
/**
* @param $value
*/
public function setStartPeriod($value)
{
$this->startPeriod = $value ? $value : $this->now;
}
public function getEndPeriod()
{
return $this->endPeriod;
}
/**
* @param $value
*/
public function setEndPeriod($value)
{
$this->endPeriod = $value;
}
public function getUser()
{
return $this->user;
}
/**
* @param $value
*/
public function setUser($value)
{
$this->user = $value;
}
public function getCreated()
{
return $this->created;
}
/**
* @param $value
*/
public function setCreated($value)
{
$this->created = $value;
}
public function getLastModif()
{
return $this->lastModif;
}
/**
* @param $value
*/
public function setLastModif($value)
{
$this->lastModif = $value;
}
/**
* Calendar item to create recurrences from
*
* @return array
*/
public function getInitialItem(): array
{
return $this->initialItem;
}
/**
* @param array $value
*/
public function setInitialItem(array $value)
{
$this->initialItem = $value;
}
public function getUid()
{
return $this->uid;
}
/**
* @param $value
*/
public function setUid($value)
{
$this->uid = $value;
}
public function getUri()
{
return $this->uri;
}
/**
* @param $value
*/
public function setUri($value)
{
$this->uri = $value;
}
}