%PDF- %PDF-
Direktori : /home/vacivi36/intranet.vacivitta.com.br/protected/modules/calendar/interfaces/ |
Current File : /home/vacivi36/intranet.vacivitta.com.br/protected/modules/calendar/interfaces/VCalendar.php |
<?php namespace humhub\modules\calendar\interfaces; use DateTime; use Exception; use humhub\modules\calendar\helpers\CalendarUtils; use humhub\modules\calendar\helpers\RecurrenceHelper; use humhub\modules\calendar\interfaces\event\CalendarEventIF; use humhub\modules\calendar\interfaces\event\legacy\CalendarEventIFWrapper; use humhub\modules\calendar\interfaces\participation\CalendarEventParticipationIF; use humhub\modules\calendar\interfaces\recurrence\RecurrentEventIF; use humhub\modules\calendar\Module; use humhub\modules\user\models\User; use yii\base\Model; use Sabre\VObject; /** * Class VCalendar serves as wrapper around sabledavs vobject api. * */ class VCalendar extends Model { const PRODID = '-//HumHub Org//HumHub Calendar 0.7//EN'; const PARTICIPATION_STATUS_ACCEPTED = 'ACCEPTED'; const PARTICIPATION_STATUS_DECLINED = 'DECLINED'; const PARTICIPATION_STATUS_TENTATIVE = 'TENTATIVE'; /** * @var */ public $name; public $method = 'PUBLISH'; /** * @var VObject\Component\VCalendar */ private $vcalendar; /** * @param CalendarEventIF[] $items * @return VCalendar */ public static function withEvents($items, $tz = null) { $instance = (new static()); $instance->addTimeZone($tz); if(!is_array($items)) { $items = [$items]; } foreach ($items as $item) { if(is_array($item)) { $item = new CalendarEventIFWrapper(['options' => $item]); } $instance->addVEvent($item); } return $instance; } public function addTimeZone($tz) { if($tz && is_string($tz)) { $this->vcalendar->add($this->generate_vtimezone($tz)); } return $this; } public function init() { parent::init(); $this->initVObject(); } /** * @return void */ private function initVObject() { /** * X-WR-CALNAME * X-WR-CALDESC * X-WR-TIMEZONE * X-PUBLISHED-TTL */ $this->vcalendar = new VObject\Component\VCalendar([ 'PRODID' => static::PRODID, 'METHOD' => $this->method, ]); } public function getInstance() { return $this->vcalendar; } public function serialize() { return $this->vcalendar->serialize(); } private $uids = []; /** * @param CalendarEventIF $item * @param bool $isRecurrenceChild * @param bool $initRecurrenceChildren * @return static * @throws Exception */ private function addVEvent(CalendarEventIF $item, bool $isRecurrenceChild = false, bool $initRecurrenceChildren = true) { $dtend = clone $item->getEndDateTime(); if (!$isRecurrenceChild) { $uid = $item->getUid(); if (!$uid || in_array($uid, $this->uids)) { return $this; } } if ($item->isAllDay() && $dtend->format('H:i') === '23:59') { // Translate for legacy events $dtend->modify('+1 hour')->setTime(0,0,0); } $dtStart = clone $item->getStartDateTime(); $dtEnd = clone $item->getEndDateTime(); if (!$item->isAllDay()) { $dtStart->setTimezone(CalendarUtils::getStartTimeZone($item)); $dtEnd->setTimezone(CalendarUtils::getStartTimeZone($item)); } $result = [ 'UID' => $item->getUid(), 'DTSTART' => $dtStart, 'DTEND' => $dtEnd, 'SUMMARY' => $item->getTitle(), ]; if (!empty($item->getLocation())) { $result['LOCATION'] = $item->getLocation(); } if (!empty($item->getDescription())) { $result['DESCRIPTION'] = $item->getDescription(); } if ($item instanceof RecurrentEventIF && RecurrenceHelper::isRecurrent($item)) { if (RecurrenceHelper::isRecurrentRoot($item)) { $result['RRULE'] = $item->getRRule(); // Note: VObject supports the EXDATE property for exclusions, but not yet the RDATE and EXRULE properties if (!empty($item->getExdate())) { $result['EXDATE'] = []; foreach (explode(',', $item->getExdate()) as $exdate) { $result['EXDATE'][] = $exdate; } } if ($initRecurrenceChildren) { $recurrenceItems = $item->getRecurrenceInstances()->all(); } } else if (RecurrenceHelper::isRecurrentInstance($item)) { $recurrenceId = new DateTime($item->getRecurrenceId()); $recurrenceId->setTimezone(CalendarUtils::getStartTimeZone($item)); $result['RECURRENCE-ID'] = $recurrenceId; } } else { $this->setLegacyRecurrentData($item, $result); } if ($item->getSequence() !== null) { $result['SEQUENCE'] = $item->getSequence(); } $lastModified = $item->getLastModified(); if($lastModified) { $result['LAST-MODIFIED'] = $lastModified; } $evt = $this->vcalendar->add('VEVENT', $result); if ($isRecurrenceChild) { return $this; } $this->uids[] = $uid; if (!empty($recurrenceItems)) { foreach ($recurrenceItems as $recurrenceItem) { $this->addVEvent($recurrenceItem, true); } } if ($item->isAllDay()) { if (isset($evt->DTSTART)) { $evt->DTSTART['VALUE'] = 'DATE'; } if (isset($evt->DTEND)) { $evt->DTEND['VALUE'] = 'DATE'; } } $module = Module::instance(); if($item instanceof CalendarEventParticipationIF) { if($module->icsOrganizer) { $organizer = $item->getOrganizer(); if($organizer instanceof User) { $evt->add('ORGANIZER', ['CN' => $this->getCN($organizer)]); } } /** This should be configurable because its may not be desired. foreach ($item->findParticipants([CalendarEventParticipationIF::PARTICIPATION_STATUS_ACCEPTED])->limit(20)->all() as $user) { /* @var $user User $evt->add('ATTENDEE', $this->getCN($user)); } if(!empty($item->getExternalParticipants())) { foreach ($item->getExternalParticipants() as $email) { $evt->add('ATTENDEE', 'MAILTO:'.$email); } } **/ } return $this; } private function setLegacyRecurrentData($item, &$result) { if(!$item instanceof CalendarEventIFWrapper) { return; } if ($item->getRRule()) { $result['RRULE'] = $item->getRRule(); } // Note: VObject supports the EXDATE property for exclusions, but not yet the RDATE and EXRULE properties if (!empty($item->getExdate())) { $result['EXDATE'] = []; foreach (explode(',', $item->getExdate()) as $exdate) { $result['EXDATE'][] = $exdate; } } } private function getCN(User $user) { $result = $user->getDisplayName(); if($user->email) { $result .= ':MAILTO:'.$user->email; } return $result; } /** * Returns a VTIMEZONE component for a Olson timezone identifier * with daylight transitions covering the given date range. * * @param string Timezone ID as used in PHP's Date functions * @param integer Unix timestamp with first date/time in this timezone * @param integer Unix timestap with last date/time in this timezone * * @return mixed A Sabre\VObject\Component object representing a VTIMEZONE definition * or false if no timezone information is available * @throws Exception */ function generate_vtimezone($tzid, $from = 0, $to = 0) { if (!$from) $from = time(); if (!$to) $to = $from; try { $tz = new \DateTimeZone($tzid); } catch (Exception $e) { return false; } // get all transitions for one year back/ahead $year = 86400 * 360; $transitions = $tz->getTransitions($from - $year, $to + $year); $vcalendar = new VObject\Component\VCalendar(); $vt = $vcalendar->createComponent('VTIMEZONE'); $vt->TZID = $tz->getName(); $std = null; $dst = null; foreach ($transitions as $i => $trans) { $cmp = null; // skip the first entry... if ($i == 0) { // ... but remember the offset for the next TZOFFSETFROM value $tzfrom = $trans['offset'] / 3600; continue; } // daylight saving time definition if ($trans['isdst']) { $t_dst = $trans['ts']; $dst = $vcalendar->createComponent('DAYLIGHT'); $cmp = $dst; } // standard time definition else { $t_std = $trans['ts']; $std = $vcalendar->createComponent('STANDARD'); $cmp = $std; } if ($cmp) { $dt = new DateTime($trans['time']); $offset = $trans['offset'] / 3600; $cmp->DTSTART = $dt->format('Ymd\THis'); $cmp->TZOFFSETFROM = sprintf('%s%02d%02d', $tzfrom >= 0 ? '+' : '', floor($tzfrom), ($tzfrom - floor($tzfrom)) * 60); $cmp->TZOFFSETTO = sprintf('%s%02d%02d', $offset >= 0 ? '+' : '', floor($offset), ($offset - floor($offset)) * 60); // add abbreviated timezone name if available if (!empty($trans['abbr'])) { $cmp->TZNAME = $trans['abbr']; } $tzfrom = $offset; $vt->add($cmp); } // we covered the entire date range if ($std && $dst && min($t_std, $t_dst) < $from && max($t_std, $t_dst) > $to) { break; } } // add X-MICROSOFT-CDO-TZID if available $microsoftExchangeMap = array_flip(VObject\TimeZoneUtil::$microsoftExchangeMap); if (array_key_exists($tz->getName(), $microsoftExchangeMap)) { $vt->add('X-MICROSOFT-CDO-TZID', $microsoftExchangeMap[$tz->getName()]); } return $vt; } /** * @param $items CalendarEventIF|CalendarEventIF[]|array * @param $initRecurrenceChildren bool * @return VCalendar * @throws Exception */ public function add($items, bool $initRecurrenceChildren = true) { if (!is_array($items)) { $items = [$items]; } foreach ($items as $item) { $this->addVEvent($item, false, $initRecurrenceChildren); } return $this; } }