Use Sabre/VObject v4, Partial PHP8 support

This commit is contained in:
Aleksander Machniak 2022-11-29 15:54:43 +01:00
parent 48027bc26e
commit f5d95d5a92
31 changed files with 274 additions and 215 deletions

View file

@ -1312,7 +1312,7 @@ $("#rcmfd_new_category").keypress(function(event) {
if (!empty($change['date'])) {
$dt = $lib->adjust_timezone($change['date']);
if ($dt instanceof DateTime) {
if ($dt instanceof DateTimeInterface) {
$change['date'] = $this->rc->format_date($dt, $dtformat, false);
}
}

View file

@ -24,7 +24,7 @@
}
],
"require": {
"php": ">=5.4.0",
"php": ">=7.4.0",
"roundcube/plugin-installer": ">=0.1.3",
"kolab/libcalendaring": ">=3.4.0",
"kolab/libkolab": ">=3.4.0"

View file

@ -745,12 +745,14 @@ class caldav_calendar extends kolab_storage_dav_folder
// Modify invitation status class name, when invitation calendars are disabled
// we'll use opacity only for declined/needs-action events
$record['className'] = str_replace('-invitation', '', $record['className']);
$record['className'] = !empty($record['className']) ? str_replace('-invitation', '', $record['className']) : '';
}
// add instance identifier to first occurrence (master event)
$recurrence_id_format = libcalendaring::recurrence_id_format($master_event ? $master_event : $record);
if (!$noinst && !empty($record['recurrence']) && empty($record['recurrence_id']) && empty($record['_instance'])) {
if (!$noinst && !empty($record['recurrence']) && !empty($record['start'])
&& empty($record['recurrence_id']) && empty($record['_instance'])
) {
$record['_instance'] = $record['start']->format($recurrence_id_format);
}
else if (isset($record['recurrence_date']) && is_a($record['recurrence_date'], 'DateTime')) {

View file

@ -136,6 +136,7 @@ class caldav_driver extends kolab_driver
$parents = array_keys($this->calendars);
foreach ($folders as $id => $cal) {
$parent_id = null;
/*
$path = explode('/', $cal->name);

View file

@ -790,8 +790,8 @@ abstract class calendar_driver
try {
$bday = $contact['birthday'];
if (!$bday instanceof DateTime) {
$bday = new DateTime($bday, new DateTimezone('UTC'));
if (!$bday instanceof DateTimeInterface) {
$bday = new DateTime($bday, new DateTimeZone('UTC'));
}
$bday->_dateonly = true;
}

View file

@ -587,7 +587,8 @@ class database_driver extends calendar_driver
$b = isset($event[$prop]) ? $event[$prop] : null;
if (!empty($event['allday']) && ($prop == 'start' || $prop == 'end')
&& $a instanceof DateTime && $b instanceof DateTime
&& $a instanceof DateTimeInterface
&& $b instanceof DateTimeInterface
) {
$a = $a->format('Y-m-d');
$b = $b->format('Y-m-d');
@ -1464,7 +1465,7 @@ class database_driver extends calendar_driver
private function serialize_alarms($valarms)
{
foreach ((array)$valarms as $i => $alarm) {
if ($alarm['trigger'] instanceof DateTime) {
if ($alarm['trigger'] instanceof DateTimeInterface) {
$valarms[$i]['trigger'] = '@' . $alarm['trigger']->format('c');
}
}

View file

@ -1339,7 +1339,7 @@ class kolab_driver extends calendar_driver
$recurrence_id = rcube_utils::anytodatetime($exception['_instance'], $old['start']->getTimezone());
}
if ($recurrence_id instanceof DateTime) {
if ($recurrence_id instanceof DateTimeInterface) {
$recurrence_id->add($date_shift);
$event['recurrence']['EXCEPTIONS'][$i]['recurrence_date'] = $recurrence_id;
$event['recurrence']['EXCEPTIONS'][$i]['_instance'] = $recurrence_id->format($recurrence_id_format);
@ -1604,13 +1604,13 @@ class kolab_driver extends calendar_driver
public static function merge_exception_dates(&$event, $overlay)
{
// compute date offset from the exception
if ($overlay['start'] instanceof DateTime && $overlay['recurrence_date'] instanceof DateTime) {
if ($overlay['start'] instanceof DateTimeInterface && $overlay['recurrence_date'] instanceof DateTimeInterface) {
$date_offset = $overlay['recurrence_date']->diff($overlay['start']);
}
foreach (['start', 'end'] as $prop) {
$value = $overlay[$prop];
if (isset($event[$prop]) && $event[$prop] instanceof DateTime) {
if (isset($event[$prop]) && $event[$prop] instanceof DateTimeInterface) {
// set date value if overlay is an exception of the current instance
if (substr($overlay['_instance'], 0, 8) == substr($event['_instance'], 0, 8)) {
$event[$prop]->setDate(intval($value->format('Y')), intval($value->format('n')), intval($value->format('j')));

View file

@ -11,6 +11,6 @@ Provides utility functions for calendar-related modules such as
iCal parsing and exporting is done with the help of the Sabre VObject
library [1]. It needs to be insalled with Roundcube using composer:
$ composer require "sabre/vobject" "~3.3.3"
$ composer require "sabre/vobject" "~4.5.1"
[1]: http://sabre.io/vobject/

View file

@ -24,8 +24,8 @@
}
],
"require": {
"php": ">=5.4.0",
"php": ">=7.4.0",
"roundcube/plugin-installer": ">=0.1.3",
"sabre/vobject": "~3.5.3"
"sabre/vobject": "~4.5.1"
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* DateTime wrapper. Main reason for its existence is that
* you can't set undefined properties on DateTime without
* a deprecation warning on PHP >= 8.1
*
* @author Aleksander Machniak <machniak@apheleia-it.ch>
*
* Copyright (C) 2022, Apheleia IT AG <contact@apheleia-it.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class libcalendaring_datetime extends DateTime
{
public $_dateonly = false;
}

View file

@ -472,7 +472,7 @@ class libcalendaring_itip
if ($key == 'allday') {
$event[$key] = $event[$key] == 'true';
}
$value = $existing[$key] instanceof DateTime ? $existing[$key]->format('c') : $existing[$key];
$value = $existing[$key] instanceof DateTimeInterface ? $existing[$key]->format('c') : $existing[$key];
$num++;
$got += intval($value == $event[$key]);
}
@ -671,7 +671,7 @@ class libcalendaring_itip
// For replies we need more metadata
foreach (array('start', 'end', 'due', 'allday', 'recurrence', 'location') as $key) {
if (isset($event[$key])) {
$metadata[$key] = $event[$key] instanceof DateTime ? $event[$key]->format('c') : $event[$key];
$metadata[$key] = $event[$key] instanceof DateTimeInterface ? $event[$key]->format('c') : $event[$key];
}
}
}

View file

@ -35,7 +35,7 @@ class libcalendaring_recurrence
/**
* Default constructor
*
* @param object calendar The calendar plugin instance
* @param calendar The calendar plugin instance
*/
function __construct($lib)
{
@ -49,8 +49,8 @@ class libcalendaring_recurrence
/**
* Initialize recurrence engine
*
* @param array The recurrence properties
* @param object DateTime The recurrence start date
* @param array The recurrence properties
* @param DateTime The recurrence start date
*/
public function init($recurrence, $start = null)
{
@ -80,7 +80,7 @@ class libcalendaring_recurrence
/**
* Setter for (new) recurrence start date
*
* @param object DateTime The recurrence start date
* @param DateTime The recurrence start date
*/
public function set_start($start)
{
@ -94,7 +94,7 @@ class libcalendaring_recurrence
/**
* Get date/time of the next occurence of this event
*
* @return mixed DateTime object or False if recurrence ended
* @return DateTime|int|false object or False if recurrence ended
*/
public function next()
{
@ -127,15 +127,15 @@ class libcalendaring_recurrence
public function end()
{
// recurrence end date is given
if ($this->recurrence['UNTIL'] instanceof DateTime) {
if ($this->recurrence['UNTIL'] instanceof DateTimeInterface) {
return $this->recurrence['UNTIL'];
}
// take the last RDATE entry if set
if (is_array($this->recurrence['RDATE']) && !empty($this->recurrence['RDATE'])) {
$last = end($this->recurrence['RDATE']);
if ($last instanceof DateTime) {
return $last;
if ($last instanceof DateTimeInterface) {
return $last;
}
}

View file

@ -194,7 +194,7 @@ class libcalendaring extends rcube_plugin
$dt = rcube_utils::anytodatetime($dt);
}
if ($dt instanceof DateTime && empty($dt->_dateonly) && !$dateonly) {
if ($dt instanceof DateTimeInterface && empty($dt->_dateonly) && !$dateonly) {
$dt->setTimezone($this->timezone);
}
@ -517,8 +517,8 @@ class libcalendaring extends rcube_plugin
*/
public static function to_client_alarms($valarms)
{
return array_map(function($alarm){
if ($alarm['trigger'] instanceof DateTime) {
return array_map(function($alarm) {
if ($alarm['trigger'] instanceof DateTimeInterface) {
$alarm['trigger'] = '@' . $alarm['trigger']->format('U');
}
else if ($trigger = libcalendaring::parse_alarm_value($alarm['trigger'])) {
@ -601,7 +601,7 @@ class libcalendaring extends rcube_plugin
break;
}
if ($trigger instanceof DateTime) {
if ($trigger instanceof DateTimeInterface) {
$text .= ' ' . $rcube->gettext(array(
'name' => 'libcalendaring.alarmat',
'vars' => array('datetime' => $rcube->format_date($trigger))
@ -681,7 +681,7 @@ class libcalendaring extends rcube_plugin
foreach ($rec['valarms'] as $alarm) {
$notify_time = null;
if ($alarm['trigger'] instanceof DateTime) {
if ($alarm['trigger'] instanceof DateTimeInterface) {
$notify_time = $alarm['trigger'];
}
else if (is_string($alarm['trigger'])) {
@ -1335,7 +1335,7 @@ class libcalendaring extends rcube_plugin
{
$instance_date = !empty($event['recurrence_date']) ? $event['recurrence_date'] : $event['start'];
if ($instance_date instanceof DateTime) {
if ($instance_date instanceof DateTimeInterface) {
// According to RFC5545 (3.8.4.4) RECURRENCE-ID format should
// be date/date-time depending on the main event type, not the exception
if ($allday === null) {

View file

@ -24,6 +24,8 @@
use \Sabre\VObject;
use \Sabre\VObject\DateTimeParser;
require_once __DIR__ . '/lib/libcalendaring_datetime.php';
/**
* Class to parse and build vCalendar (iCalendar) files
*
@ -421,7 +423,7 @@ class libvcalendar implements Iterator
}
// map other attributes to internal fields
foreach ($ve->children as $prop) {
foreach ($ve->children() as $prop) {
if (!($prop instanceof VObject\Property))
continue;
@ -640,7 +642,7 @@ class libvcalendar implements Iterator
$trigger = null;
$alarm = array();
foreach ($valarm->children as $prop) {
foreach ($valarm->children() as $prop) {
$value = strval($prop);
switch ($prop->name) {
@ -708,14 +710,14 @@ class libvcalendar implements Iterator
}
// assign current timezone to event start/end
if (!empty($event['start']) && $event['start'] instanceof DateTime) {
if (!empty($event['start']) && $event['start'] instanceof DateTimeInterface) {
$this->_apply_timezone($event['start']);
}
else {
unset($event['start']);
}
if (!empty($event['end']) && $event['end'] instanceof DateTime) {
if (!empty($event['end']) && $event['end'] instanceof DateTimeInterface) {
$this->_apply_timezone($event['end']);
}
else {
@ -752,7 +754,7 @@ class libvcalendar implements Iterator
// For date-only we'll keep the date and time intact
if (!empty($date->_dateonly)) {
$dt = new DateTime(null, $this->timezone);
$dt = new libcalendaring_datetime(null, $this->timezone);
$dt->setDate($date->format('Y'), $date->format('n'), $date->format('j'));
$dt->setTime($date->format('G'), $date->format('i'), 0);
$date = $dt;
@ -770,7 +772,7 @@ class libvcalendar implements Iterator
$this->freebusy = array('_type' => 'freebusy', 'periods' => array());
$seen = array();
foreach ($ve->children as $prop) {
foreach ($ve->children() as $prop) {
if (!($prop instanceof VObject\Property))
continue;
@ -857,26 +859,29 @@ class libvcalendar implements Iterator
public static function convert_datetime($prop, $as_array = false)
{
if (empty($prop)) {
return $as_array ? array() : null;
return $as_array ? [] : null;
}
else if ($prop instanceof VObject\Property\iCalendar\DateTime) {
if ($prop instanceof VObject\Property\ICalendar\DateTime) {
if (count($prop->getDateTimes()) > 1) {
$dt = array();
$dt = [];
$dateonly = !$prop->hasTime();
foreach ($prop->getDateTimes() as $item) {
$item = libcalendaring_datetime::createFromImmutable($item);
$item->_dateonly = $dateonly;
$dt[] = $item;
}
}
else {
$dt = $prop->getDateTime();
$dt = libcalendaring_datetime::createFromImmutable($prop->getDateTime());
if (!$prop->hasTime()) {
$dt->_dateonly = true;
}
}
}
else if ($prop instanceof VObject\Property\iCalendar\Period) {
$dt = array();
else if ($prop instanceof VObject\Property\ICalendar\Period) {
$dt = [];
foreach ($prop->getParts() as $val) {
try {
list($start, $end) = explode('/', $val);
@ -891,20 +896,21 @@ class libvcalendar implements Iterator
else {
$end = DateTimeParser::parseDateTime($end);
}
$dt[] = array($start, $end);
$dt[] = [libcalendaring_datetime::createFromImmutable($start), libcalendaring_datetime::createFromImmutable($end)];
}
catch (Exception $e) {
// ignore single date parse errors
}
}
}
else if ($prop instanceof \DateTime) {
$dt = $prop;
else if ($prop instanceof \DateTimeInterface) {
$dt = libcalendaring_datetime::createFromImmutable($prop);
}
// force return value to array if requested
if ($as_array && !is_array($dt)) {
$dt = empty($dt) ? array() : array($dt);
$dt = empty($dt) ? [] : [$dt];
}
return $dt;
@ -1082,7 +1088,7 @@ class libvcalendar implements Iterator
}
// we're exporting a recurrence instance only
if (!$recurrence_id && !empty($event['recurrence_date']) && $event['recurrence_date'] instanceof DateTime) {
if (!$recurrence_id && !empty($event['recurrence_date']) && $event['recurrence_date'] instanceof DateTimeInterface) {
$recurrence_id = $this->datetime_prop($cal, 'RECURRENCE-ID', $event['recurrence_date'], false, !empty($event['allday']));
if (!empty($event['thisandfuture'])) {
$recurrence_id->add('RANGE', 'THISANDFUTURE');
@ -1124,7 +1130,7 @@ class libvcalendar implements Iterator
// add EXDATEs each one per line (for Thunderbird Lightning)
if (is_array($exdates)) {
foreach ($exdates as $exdate) {
if ($exdate instanceof DateTime) {
if ($exdate instanceof DateTimeInterface) {
$ve->add($this->datetime_prop($cal, 'EXDATE', $exdate));
}
}
@ -1186,7 +1192,7 @@ class libvcalendar implements Iterator
foreach ($event['valarms'] as $alarm) {
$va = $cal->createComponent('VALARM');
$va->action = $alarm['action'];
if ($alarm['trigger'] instanceof DateTime) {
if ($alarm['trigger'] instanceof DateTimeInterface) {
$va->add($this->datetime_prop($cal, 'TRIGGER', $alarm['trigger'], true, null, true));
}
else {
@ -1228,7 +1234,7 @@ class libvcalendar implements Iterator
if (!empty($val[3])) {
$va->add('TRIGGER', $val[3]);
}
else if ($val[0] instanceof DateTime) {
else if ($val[0] instanceof DateTimeInterface) {
$va->add($this->datetime_prop($cal, 'TRIGGER', $val[0], true, null, true));
}
$ve->add($va);

View file

@ -21,9 +21,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class libcalendaring_test extends PHPUnit\Framework\TestCase
class LibcalendaringTest extends PHPUnit\Framework\TestCase
{
function setUp()
function setUp(): void
{
require_once __DIR__ . '/../libcalendaring.php';
}
@ -176,9 +176,9 @@ class libcalendaring_test extends PHPUnit\Framework\TestCase
$s = libcalendaring::to_rrule($rrule);
$this->assertRegExp('/FREQ='.$rrule['FREQ'].'/', $s, "Recurrence Frequence");
$this->assertRegExp('/INTERVAL='.$rrule['INTERVAL'].'/', $s, "Recurrence Interval");
$this->assertRegExp('/BYDAY='.$rrule['BYDAY'].'/', $s, "Recurrence BYDAY");
$this->assertRegExp('/UNTIL=20250501T160000Z/', $s, "Recurrence End date (in UTC)");
$this->assertMatchesRegularExpression('/FREQ='.$rrule['FREQ'].'/', $s, "Recurrence Frequence");
$this->assertMatchesRegularExpression('/INTERVAL='.$rrule['INTERVAL'].'/', $s, "Recurrence Interval");
$this->assertMatchesRegularExpression('/BYDAY='.$rrule['BYDAY'].'/', $s, "Recurrence BYDAY");
$this->assertMatchesRegularExpression('/UNTIL=20250501T160000Z/', $s, "Recurrence End date (in UTC)");
}
}

View file

@ -21,9 +21,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class libvcalendar_test extends PHPUnit\Framework\TestCase
class LibvcalendarTest extends PHPUnit\Framework\TestCase
{
function setUp()
private $attachment_data;
function setUp(): void
{
require_once __DIR__ . '/../libvcalendar.php';
require_once __DIR__ . '/../libcalendaring.php';
@ -41,12 +43,12 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals(1, count($events));
$event = $events[0];
$this->assertInstanceOf('DateTime', $event['created'], "'created' property is DateTime object");
$this->assertInstanceOf('DateTime', $event['changed'], "'changed' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $event['created'], "'created' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $event['changed'], "'changed' property is DateTime object");
$this->assertEquals('UTC', $event['created']->getTimezone()->getName(), "'created' date is in UTC");
$this->assertInstanceOf('DateTime', $event['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTime', $event['end'], "'end' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $event['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $event['end'], "'end' property is DateTime object");
$this->assertEquals('08-01', $event['start']->format('m-d'), "Start date is August 1st");
$this->assertTrue($event['allday'], "All-day event flag");
@ -81,7 +83,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
{
$ical = new libvcalendar();
$ical->fopen(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8');
$events = array();
$events = [];
foreach ($ical as $event) {
$events[] = $event;
}
@ -98,7 +100,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$event = $events[0];
$this->assertEquals(1, count($events), "Import event data");
$this->assertInstanceOf('DateTime', $event['created'], "Created date field");
$this->assertInstanceOf('DateTimeInterface', $event['created'], "Created date field");
$this->assertFalse(array_key_exists('changed', $event), "No changed date field");
}
@ -139,7 +141,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$attachment = $event['attachments'][0];
$this->assertEquals('text/html', $attachment['mimetype'], "Attachment mimetype attribute");
$this->assertEquals('calendar.html', $attachment['name'], "Attachment filename (X-LABEL) attribute");
$this->assertContains('<title>Kalender</title>', $attachment['data'], "Attachment content (decoded)");
$this->assertStringContainsString('<title>Kalender</title>', $attachment['data'], "Attachment content (decoded)");
// recurrence rules
$events = $ical->import_from_file(__DIR__ . '/resources/recurring.ics', 'UTF-8');
@ -150,10 +152,10 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals('MONTHLY', $rrule['FREQ'], "Recurrence frequency");
$this->assertEquals('1', $rrule['INTERVAL'], "Recurrence interval");
$this->assertEquals('3WE', $rrule['BYDAY'], "Recurrence frequency");
$this->assertInstanceOf('DateTime', $rrule['UNTIL'], "Recurrence end date");
$this->assertInstanceOf('DateTimeInterface', $rrule['UNTIL'], "Recurrence end date");
$this->assertEquals(2, count($rrule['EXDATE']), "Recurrence EXDATEs");
$this->assertInstanceOf('DateTime', $rrule['EXDATE'][0], "Recurrence EXDATE as DateTime");
$this->assertInstanceOf('DateTimeInterface', $rrule['EXDATE'][0], "Recurrence EXDATE as DateTime");
$this->assertTrue(is_array($rrule['EXCEPTIONS']));
$this->assertEquals(1, count($rrule['EXCEPTIONS']), "Recurrence Exceptions");
@ -161,7 +163,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$exception = $rrule['EXCEPTIONS'][0];
$this->assertEquals($event['uid'], $event['uid'], "Exception UID");
$this->assertEquals('Recurring Test (Exception)', $exception['title'], "Exception title");
$this->assertInstanceOf('DateTime', $exception['start'], "Exception start");
$this->assertInstanceOf('DateTimeInterface', $exception['start'], "Exception start");
// categories, class
$this->assertEquals('libcalendaring tests', join(',', (array)$event['categories']), "Event categories");
@ -169,7 +171,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
// parse a recurrence chain instance
$events = $ical->import_from_file(__DIR__ . '/resources/recurrence-id.ics', 'UTF-8');
$this->assertEquals(1, count($events), "Fall back to Component::getComponents() when getBaseComponents() is empty");
$this->assertInstanceOf('DateTime', $events[0]['recurrence_date'], "Recurrence-ID as date");
$this->assertInstanceOf('DateTimeInterface', $events[0]['recurrence_date'], "Recurrence-ID as date");
$this->assertTrue($events[0]['thisandfuture'], "Range=THISANDFUTURE");
$this->assertEquals(count($events[0]['exceptions']), 1, "Second VEVENT as exception");
@ -218,16 +220,16 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals('EMAIL', $valarm['action'], "Second alarm item (action)");
$this->assertEquals('-P1D', $valarm['trigger'], "Second alarm item (trigger)");
$this->assertEquals('This is the reminder message', $valarm['summary'], "Email alarm text");
$this->assertInstanceOf('DateTime', $event['valarms'][2]['trigger'], "Absolute trigger date/time");
$this->assertInstanceOf('DateTimeInterface', $event['valarms'][2]['trigger'], "Absolute trigger date/time");
// test alarms export
$ics = $ical->export(array($event));
$this->assertContains('ACTION:DISPLAY', $ics, "Display alarm block");
$this->assertContains('ACTION:EMAIL', $ics, "Email alarm block");
$this->assertContains('DESCRIPTION:This is the first event reminder', $ics, "Alarm description");
$this->assertContains('SUMMARY:This is the reminder message', $ics, "Email alarm summary");
$this->assertContains('ATTENDEE:mailto:reminder-recipient@example.org', $ics, "Email alarm recipient");
$this->assertContains('TRIGGER;VALUE=DATE-TIME:20130812', $ics, "Date-Time trigger");
$ics = $ical->export([$event]);
$this->assertStringContainsString('ACTION:DISPLAY', $ics, "Display alarm block");
$this->assertStringContainsString('ACTION:EMAIL', $ics, "Email alarm block");
$this->assertStringContainsString('DESCRIPTION:This is the first event reminder', $ics, "Alarm description");
$this->assertStringContainsString('SUMMARY:This is the reminder message', $ics, "Email alarm summary");
$this->assertStringContainsString('ATTENDEE:mailto:reminder-recipient@example.org', $ics, "Email alarm recipient");
$this->assertStringContainsString('TRIGGER;VALUE=DATE-TIME:20130812', $ics, "Date-Time trigger");
}
/**
@ -281,7 +283,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals("Kolab, Thomas", $event['attendees'][3]['name'], "Unescaped");
$ics = $ical->export($events);
$this->assertContains('ATTENDEE;CN="Kolab, Thomas";PARTSTAT=', $ics, "Quoted attendee parameters");
$this->assertStringContainsString('ATTENDEE;CN="Kolab, Thomas";PARTSTAT=', $ics, "Quoted attendee parameters");
}
/**
@ -294,8 +296,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$event = $events[0];
$this->assertEquals(9, count($event['recurrence']['RDATE']));
$this->assertInstanceOf('DateTime', $event['recurrence']['RDATE'][0]);
$this->assertInstanceOf('DateTime', $event['recurrence']['RDATE'][1]);
$this->assertInstanceOf('DateTimeInterface', $event['recurrence']['RDATE'][0]);
$this->assertInstanceOf('DateTimeInterface', $event['recurrence']['RDATE'][1]);
}
/**
@ -307,8 +309,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$ical->import_from_file(__DIR__ . '/resources/freebusy.ifb', 'UTF-8');
$freebusy = $ical->freebusy;
$this->assertInstanceOf('DateTime', $freebusy['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTime', $freebusy['end'], "'end' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $freebusy['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $freebusy['end'], "'end' property is DateTime object");
$this->assertEquals(11, count($freebusy['periods']), "Number of freebusy periods defined");
$periods = $ical->get_busy_periods();
$this->assertEquals(9, count($periods), "Number of busy periods found");
@ -325,7 +327,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$freebusy = $ical->freebusy;
$this->assertEquals(0, count($freebusy['periods']), "Ignore 0-length freebudy periods");
$this->assertContains('dummy', $freebusy['comment'], "Parse comment");
$this->assertStringContainsString('dummy', $freebusy['comment'], "Parse comment");
}
function test_vtodo()
@ -334,8 +336,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$tasks = $ical->import_from_file(__DIR__ . '/resources/vtodo.ics', 'UTF-8', true);
$task = $tasks[0];
$this->assertInstanceOf('DateTime', $task['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTime', $task['due'], "'due' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $task['start'], "'start' property is DateTime object");
$this->assertInstanceOf('DateTimeInterface', $task['due'], "'due' property is DateTime object");
$this->assertEquals('-1D:DISPLAY', $task['alarms'], "Taks alarm value");
$this->assertEquals('IN-PROCESS', $task['status'], "Task status property");
$this->assertEquals(1, count($task['x-custom']), "Custom properties");
@ -346,14 +348,12 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals('COMPLETED', $completed['status'], "Task status=completed when COMPLETED property is present");
$this->assertEquals(100, $completed['complete'], "Task percent complete value");
$ics = $ical->export(array($completed));
$this->assertRegExp('/COMPLETED(;VALUE=DATE-TIME)?:[0-9TZ]+/', $ics, "Export COMPLETED property");
$ics = $ical->export([$completed]);
$this->assertMatchesRegularExpression('/COMPLETED(;VALUE=DATE-TIME)?:[0-9TZ]+/', $ics, "Export COMPLETED property");
}
/**
* Test for iCal export from internal hash array representation
*
*
*/
function test_export()
{
@ -372,46 +372,46 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$event['start']->setTimezone(new DateTimezone('America/Montreal'));
$event['end']->setTimezone(new DateTimezone('Europe/Berlin'));
$ics = $ical->export(array($event), 'REQUEST', false, array($this, 'get_attachment_data'), true);
$ics = $ical->export([$event], 'REQUEST', false, [$this, 'get_attachment_data'], true);
$this->assertContains('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN");
$this->assertStringContainsString('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN");
$this->assertContains('BEGIN:VTIMEZONE', $ics, "VTIMEZONE encapsulation BEGIN");
$this->assertContains('TZID:Europe/Berlin', $ics, "Timezone ID");
$this->assertContains('TZOFFSETFROM:+0100', $ics, "Timzone transition FROM");
$this->assertContains('TZOFFSETTO:+0200', $ics, "Timzone transition TO");
$this->assertContains('TZOFFSETFROM:-0400', $ics, "TZOFFSETFROM with negative offset (Bug T428)");
$this->assertContains('TZOFFSETTO:-0500', $ics, "TZOFFSETTO with negative offset (Bug T428)");
$this->assertContains('END:VTIMEZONE', $ics, "VTIMEZONE encapsulation END");
$this->assertStringContainsString('BEGIN:VTIMEZONE', $ics, "VTIMEZONE encapsulation BEGIN");
$this->assertStringContainsString('TZID:Europe/Berlin', $ics, "Timezone ID");
$this->assertStringContainsString('TZOFFSETFROM:+0100', $ics, "Timzone transition FROM");
$this->assertStringContainsString('TZOFFSETTO:+0200', $ics, "Timzone transition TO");
$this->assertStringContainsString('TZOFFSETFROM:-0400', $ics, "TZOFFSETFROM with negative offset (Bug T428)");
$this->assertStringContainsString('TZOFFSETTO:-0500', $ics, "TZOFFSETTO with negative offset (Bug T428)");
$this->assertStringContainsString('END:VTIMEZONE', $ics, "VTIMEZONE encapsulation END");
$this->assertContains('BEGIN:VEVENT', $ics, "VEVENT encapsulation BEGIN");
$this->assertStringContainsString('BEGIN:VEVENT', $ics, "VEVENT encapsulation BEGIN");
$this->assertSame(2, substr_count($ics, 'DTSTAMP'), "Duplicate DTSTAMP (T1148)");
$this->assertContains('UID:ac6b0aee-2519-4e5c-9a25-48c57064c9f0', $ics, "Event UID");
$this->assertContains('SEQUENCE:' . $event['sequence'], $ics, "Export Sequence number");
$this->assertContains('DESCRIPTION:*Exported by', $ics, "Export Description");
$this->assertContains('ORGANIZER;CN=Rolf Test:mailto:rolf@', $ics, "Export organizer");
$this->assertRegExp('/ATTENDEE.*;ROLE=REQ-PARTICIPANT/', $ics, "Export Attendee ROLE");
$this->assertRegExp('/ATTENDEE.*;PARTSTAT=NEEDS-ACTION/', $ics, "Export Attendee Status");
$this->assertRegExp('/ATTENDEE.*;RSVP=TRUE/', $ics, "Export Attendee RSVP");
$this->assertRegExp('/:mailto:rolf2@/', $ics, "Export Attendee mailto:");
$this->assertStringContainsString('UID:ac6b0aee-2519-4e5c-9a25-48c57064c9f0', $ics, "Event UID");
$this->assertStringContainsString('SEQUENCE:' . $event['sequence'], $ics, "Export Sequence number");
$this->assertStringContainsString('DESCRIPTION:*Exported by', $ics, "Export Description");
$this->assertStringContainsString('ORGANIZER;CN=Rolf Test:mailto:rolf@', $ics, "Export organizer");
$this->assertMatchesRegularExpression('/ATTENDEE.*;ROLE=REQ-PARTICIPANT/', $ics, "Export Attendee ROLE");
$this->assertMatchesRegularExpression('/ATTENDEE.*;PARTSTAT=NEEDS-ACTION/', $ics, "Export Attendee Status");
$this->assertMatchesRegularExpression('/ATTENDEE.*;RSVP=TRUE/', $ics, "Export Attendee RSVP");
$this->assertMatchesRegularExpression('/:mailto:rolf2@/', $ics, "Export Attendee mailto:");
$rrule = $event['recurrence'];
$this->assertRegExp('/RRULE:.*FREQ='.$rrule['FREQ'].'/', $ics, "Export Recurrence Frequence");
$this->assertRegExp('/RRULE:.*INTERVAL='.$rrule['INTERVAL'].'/', $ics, "Export Recurrence Interval");
$this->assertRegExp('/RRULE:.*UNTIL=20140718T215959Z/', $ics, "Export Recurrence End date");
$this->assertRegExp('/RRULE:.*BYDAY='.$rrule['BYDAY'].'/', $ics, "Export Recurrence BYDAY");
$this->assertRegExp('/EXDATE.*:20131218/', $ics, "Export Recurrence EXDATE");
$this->assertMatchesRegularExpression('/RRULE:.*FREQ='.$rrule['FREQ'].'/', $ics, "Export Recurrence Frequence");
$this->assertMatchesRegularExpression('/RRULE:.*INTERVAL='.$rrule['INTERVAL'].'/', $ics, "Export Recurrence Interval");
$this->assertMatchesRegularExpression('/RRULE:.*UNTIL=20140718T215959Z/', $ics, "Export Recurrence End date");
$this->assertMatchesRegularExpression('/RRULE:.*BYDAY='.$rrule['BYDAY'].'/', $ics, "Export Recurrence BYDAY");
$this->assertMatchesRegularExpression('/EXDATE.*:20131218/', $ics, "Export Recurrence EXDATE");
$this->assertContains('BEGIN:VALARM', $ics, "Export VALARM");
$this->assertContains('TRIGGER;RELATED=END:-PT12H', $ics, "Export Alarm trigger");
$this->assertStringContainsString('BEGIN:VALARM', $ics, "Export VALARM");
$this->assertStringContainsString('TRIGGER;RELATED=END:-PT12H', $ics, "Export Alarm trigger");
$this->assertRegExp('/ATTACH.*;VALUE=BINARY/', $ics, "Embed attachment");
$this->assertRegExp('/ATTACH.*;ENCODING=BASE64/', $ics, "Attachment B64 encoding");
$this->assertRegExp('!ATTACH.*;FMTTYPE=text/html!', $ics, "Attachment mimetype");
$this->assertRegExp('!ATTACH.*;X-LABEL=calendar.html!', $ics, "Attachment filename with X-LABEL");
$this->assertMatchesRegularExpression('/ATTACH.*;VALUE=BINARY/', $ics, "Embed attachment");
$this->assertMatchesRegularExpression('/ATTACH.*;ENCODING=BASE64/', $ics, "Attachment B64 encoding");
$this->assertMatchesRegularExpression('!ATTACH.*;FMTTYPE=text/html!', $ics, "Attachment mimetype");
$this->assertMatchesRegularExpression('!ATTACH.*;X-LABEL=calendar.html!', $ics, "Attachment filename with X-LABEL");
$this->assertContains('END:VEVENT', $ics, "VEVENT encapsulation END");
$this->assertContains('END:VCALENDAR', $ics, "VCALENDAR encapsulation END");
$this->assertStringContainsString('END:VEVENT', $ics, "VEVENT encapsulation END");
$this->assertStringContainsString('END:VCALENDAR', $ics, "VCALENDAR encapsulation END");
}
/**
@ -429,8 +429,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$num = count($events);
$ics = $ical->export($events, null, false);
$this->assertContains('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN");
$this->assertContains('END:VCALENDAR', $ics, "VCALENDAR encapsulation END");
$this->assertStringContainsString('BEGIN:VCALENDAR', $ics, "VCALENDAR encapsulation BEGIN");
$this->assertStringContainsString('END:VCALENDAR', $ics, "VCALENDAR encapsulation END");
$this->assertEquals($num, substr_count($ics, 'BEGIN:VEVENT'), "VEVENT encapsulation BEGIN");
$this->assertEquals($num, substr_count($ics, 'END:VEVENT'), "VEVENT encapsulation END");
}
@ -460,7 +460,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$exception2['end']->setDate(2013, 11, 13);
$exception2['title'] = 'Recurring Exception';
$events[0]['recurrence']['EXCEPTIONS'] = array($exception1, $exception2);
$events[0]['recurrence']['EXCEPTIONS'] = [$exception1, $exception2];
$ics = $ical->export($events, null, false);
@ -469,30 +469,30 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$this->assertEquals($num, substr_count($ics, 'UID:'.$event['uid']), "Recurrence Exceptions with same UID");
$this->assertEquals($num, substr_count($ics, 'END:VEVENT'), "VEVENT encapsulation END");
$this->assertContains('RECURRENCE-ID;TZID=Europe/Zurich:20130814', $ics, "Recurrence-ID (1) being the exception date");
$this->assertContains('RECURRENCE-ID;TZID=Europe/Zurich:20131113', $ics, "Recurrence-ID (2) being the exception date");
$this->assertContains('SUMMARY:'.$exception2['title'], $ics, "Exception title");
$this->assertStringContainsString('RECURRENCE-ID;TZID=Europe/Zurich:20130814', $ics, "Recurrence-ID (1) being the exception date");
$this->assertStringContainsString('RECURRENCE-ID;TZID=Europe/Zurich:20131113', $ics, "Recurrence-ID (2) being the exception date");
$this->assertStringContainsString('SUMMARY:'.$exception2['title'], $ics, "Exception title");
}
function test_export_valid_rrules()
{
$event = array(
$event = [
'uid' => '1234567890',
'start' => new DateTime('now'),
'end' => new DateTime('now + 30min'),
'title' => 'test_export_valid_rrules',
'recurrence' => array(
'recurrence' => [
'FREQ' => 'DAILY',
'COUNT' => 5,
'EXDATE' => array(),
'RDATE' => array(),
),
);
'EXDATE' => [],
'RDATE' => [],
],
];
$ical = new libvcalendar();
$ics = $ical->export(array($event), null, false, null, false);
$ics = $ical->export([$event], null, false, null, false);
$this->assertNotContains('EXDATE=', $ics);
$this->assertNotContains('RDATE=', $ics);
$this->assertStringNotContainsString('EXDATE=', $ics);
$this->assertStringNotContainsString('RDATE=', $ics);
}
/**
@ -504,7 +504,7 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$events = $ical->import_from_file(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8');
$ics = $ical->export($events, null, false);
$this->assertContains('RDATE:20140520T020000Z', $ics, "VALUE=PERIOD is translated into single DATE-TIME values");
$this->assertStringContainsString('RDATE:20140520T020000Z', $ics, "VALUE=PERIOD is translated into single DATE-TIME values");
}
/**
@ -522,8 +522,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
ob_end_clean();
$this->assertTrue($return, "Return true on successful writing");
$this->assertContains('BEGIN:VCALENDAR', $output, "VCALENDAR encapsulation BEGIN");
$this->assertContains('END:VCALENDAR', $output, "VCALENDAR encapsulation END");
$this->assertStringContainsString('BEGIN:VCALENDAR', $output, "VCALENDAR encapsulation BEGIN");
$this->assertStringContainsString('END:VCALENDAR', $output, "VCALENDAR encapsulation END");
$this->assertEquals($num, substr_count($output, 'BEGIN:VEVENT'), "VEVENT encapsulation BEGIN");
$this->assertEquals($num, substr_count($output, 'END:VEVENT'), "VEVENT encapsulation END");
}
@ -537,10 +537,10 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
$utctime = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01 12:00:00', new DateTimeZone('UTC')));
$asutctime = $ical->datetime_prop($cal, 'DTSTART', new DateTime('2013-09-01 12:00:00', new DateTimeZone('Europe/Berlin')), true);
$this->assertContains('TZID=Europe/Berlin', $localtime->serialize());
$this->assertContains('VALUE=DATE', $localdate->serialize());
$this->assertContains('20130901T120000Z', $utctime->serialize());
$this->assertContains('20130901T100000Z', $asutctime->serialize());
$this->assertStringContainsString('TZID=Europe/Berlin', $localtime->serialize());
$this->assertStringContainsString('VALUE=DATE', $localdate->serialize());
$this->assertStringContainsString('20130901T120000Z', $utctime->serialize());
$this->assertStringContainsString('20130901T100000Z', $asutctime->serialize());
}
function test_get_vtimezone()
@ -578,8 +578,8 @@ class libvcalendar_test extends PHPUnit\Framework\TestCase
// DateTimezone as input data
$vtz = libvcalendar::get_vtimezone(new DateTimezone('Pacific/Chatham'));
$this->assertInstanceOf('\Sabre\VObject\Component', $vtz);
$this->assertContains('TZOFFSETFROM:+1245', $vtz->serialize());
$this->assertContains('TZOFFSETTO:+1345', $vtz->serialize());
$this->assertStringContainsString('TZOFFSETFROM:+1245', $vtz->serialize());
$this->assertStringContainsString('TZOFFSETTO:+1345', $vtz->serialize());
// Making sure VTIMEZOONE contains at least one STANDARD/DAYLIGHT component
// when there's only one transition in specified time period (T5626)

View file

@ -24,8 +24,9 @@
}
],
"require": {
"php": ">=5.3.0",
"php": ">=7.4.0",
"roundcube/plugin-installer": ">=0.1.3",
"kolab/libcalendaring": ">=3.4.0",
"pear/http_request2": "~2.3.0",
"caxy/php-htmldiff": "~0.1.7"
}

View file

@ -4,7 +4,7 @@
* Recurrence computation class for xcal-based Kolab format objects
*
* Utility class to compute instances of recurring events.
* It requires the libcalendaring PHP module to be installed and loaded.
* It requires the libcalendaring PHP extension to be installed and loaded.
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
@ -24,6 +24,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class kolab_date_recurrence
{
private /* EventCal */ $engine;
@ -63,9 +64,9 @@ class kolab_date_recurrence
/**
* Get date/time of the next occurence of this event
*
* @param boolean Return a Unix timestamp instead of a DateTime object
* @param bool Return a Unix timestamp instead of a DateTime object
*
* @return mixed DateTime object/unix timestamp or False if recurrence ended
* @return DateTime|int|false Object/unix timestamp or False if recurrence ended
*/
public function next_start($timestamp = false)
{
@ -127,7 +128,7 @@ class kolab_date_recurrence
$event = $this->object->to_array();
// recurrence end date is given
if ($event['recurrence']['UNTIL'] instanceof DateTime) {
if ($event['recurrence']['UNTIL'] instanceof DateTimeInterface) {
return $event['recurrence']['UNTIL'];
}
@ -139,7 +140,7 @@ class kolab_date_recurrence
}
// determine a reasonable end date if none given
if (!$event['recurrence']['COUNT'] && $event['end'] instanceof DateTime) {
if (!$event['recurrence']['COUNT'] && $event['end'] instanceof DateTimeInterface) {
$end_dt = clone $event['end'];
$end_dt->add(new DateInterval('P100Y'));

View file

@ -25,6 +25,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
require_once __DIR__ . '/../../libcalendaring/lib/libcalendaring_datetime.php';
abstract class kolab_format
{
public static $timezone;
@ -211,7 +213,7 @@ abstract class kolab_format
{
// use timezone information from datetime or global setting
if (!$tz && $tz !== false) {
if ($datetime instanceof DateTime)
if ($datetime instanceof DateTimeInterface)
$tz = $datetime->getTimezone();
if (!$tz)
$tz = self::$timezone;
@ -222,19 +224,19 @@ abstract class kolab_format
try {
// got a unix timestamp (in UTC)
if (is_numeric($datetime)) {
$datetime = new DateTime('@'.$datetime, new DateTimeZone('UTC'));
$datetime = new libcalendaring_datetime('@'.$datetime, new DateTimeZone('UTC'));
if ($tz) $datetime->setTimezone($tz);
}
else if (is_string($datetime) && strlen($datetime)) {
$datetime = $tz ? new DateTime($datetime, $tz) : new DateTime($datetime);
$datetime = $tz ? new libcalendaring_datetime($datetime, $tz) : new libcalendaring_datetime($datetime);
}
else if ($datetime instanceof DateTime) {
else if ($datetime instanceof DateTimeInterface) {
$datetime = clone $datetime;
}
}
catch (Exception $e) {}
if ($datetime instanceof DateTime) {
if ($datetime instanceof DateTimeInterface) {
if ($dest_tz instanceof DateTimeZone && $dest_tz !== $datetime->getTimezone()) {
$datetime->setTimezone($dest_tz);
$tz = $dest_tz;
@ -272,7 +274,7 @@ abstract class kolab_format
* @param cDateTime The libkolabxml datetime object
* @param DateTimeZone The timezone to convert the date to
*
* @return DateTime PHP datetime instance
* @return libcalendaring_datetime PHP datetime instance
*/
public static function php_datetime($cdt, $dest_tz = null)
{
@ -280,19 +282,23 @@ abstract class kolab_format
return null;
}
$d = new DateTime;
$d->setTimezone($dest_tz ?: self::$timezone);
$d = new libcalendaring_datetime(null, self::$timezone);
try {
if ($tzs = $cdt->timezone()) {
$tz = new DateTimeZone($tzs);
$d->setTimezone($tz);
}
else if ($cdt->isUTC()) {
$d->setTimezone(new DateTimeZone('UTC'));
}
if ($dest_tz) {
$d->setTimezone($dest_tz);
}
else {
try {
if ($tzs = $cdt->timezone()) {
$tz = new DateTimeZone($tzs);
$d->setTimezone($tz);
}
else if ($cdt->isUTC()) {
$d->setTimezone(new DateTimeZone('UTC'));
}
}
catch (Exception $e) { }
}
catch (Exception $e) { }
$d->setDate($cdt->year(), $cdt->month(), $cdt->day());

View file

@ -112,7 +112,7 @@ class kolab_format_event extends kolab_format_xcal
}
}
if ($object['recurrence_date'] && $object['recurrence_date'] instanceof DateTime) {
if ($object['recurrence_date'] && $object['recurrence_date'] instanceof DateTimeInterface) {
if ($object['recurrence']) {
// unset recurrence_date for master events with rrule
$object['recurrence_date'] = null;
@ -236,9 +236,9 @@ class kolab_format_event extends kolab_format_xcal
$object = $this->to_array();
$recurrence_id_format = libkolab::recurrence_id_format($object);
$instance_id = $recurrence_id instanceof DateTime ? $recurrence_id->format($recurrence_id_format) : strval($recurrence_id);
$instance_id = $recurrence_id instanceof DateTimeInterface ? $recurrence_id->format($recurrence_id_format) : strval($recurrence_id);
if ($object['recurrence_date'] instanceof DateTime) {
if ($object['recurrence_date'] instanceof DateTimeInterface) {
if ($object['recurrence_date']->format($recurrence_id_format) == $instance_id) {
$result = $object;
}

View file

@ -123,7 +123,7 @@ class kolab_format_task extends kolab_format_xcal
*/
public function get_reference_date()
{
if ($this->data['due'] && $this->data['due'] instanceof DateTime) {
if ($this->data['due'] && $this->data['due'] instanceof DateTimeInterface) {
return $this->data['due'];
}

View file

@ -166,7 +166,7 @@ abstract class kolab_format_xcal extends kolab_format
}
}
if ($object['start'] instanceof DateTime) {
if ($object['start'] instanceof DateTimeInterface) {
$start_tz = $object['start']->getTimezone();
}
@ -183,7 +183,7 @@ abstract class kolab_format_xcal extends kolab_format
}
else if ($until = self::php_datetime($rr->end(), $start_tz)) {
$refdate = $this->get_reference_date();
if ($refdate && $refdate instanceof DateTime && !$refdate->_dateonly) {
if ($refdate && $refdate instanceof DateTimeInterface && empty($refdate->_dateonly)) {
$until->setTime($refdate->format('G'), $refdate->format('i'), 0);
}
$object['recurrence']['UNTIL'] = $until;
@ -412,7 +412,7 @@ abstract class kolab_format_xcal extends kolab_format
$this->obj->setOrganizer($organizer);
}
if ($object['start'] instanceof DateTime) {
if ($object['start'] instanceof DateTimeInterface) {
$start_tz = $object['start']->getTimezone();
}
@ -536,7 +536,7 @@ abstract class kolab_format_xcal extends kolab_format
$alarm = new Alarm(strval($valarm['summary'] ?: $object['title']));
}
if (is_object($valarm['trigger']) && $valarm['trigger'] instanceof DateTime) {
if (is_object($valarm['trigger']) && $valarm['trigger'] instanceof DateTimeInterface) {
$alarm->setStart(self::get_datetime($valarm['trigger'], new DateTimeZone('UTC')));
}
else if (preg_match('/^@([0-9]+)$/', $valarm['trigger'], $m)) {
@ -618,7 +618,7 @@ abstract class kolab_format_xcal extends kolab_format
*/
public function get_reference_date()
{
if ($this->data['start'] && $this->data['start'] instanceof DateTime) {
if ($this->data['start'] && $this->data['start'] instanceof DateTimeInterface) {
return $this->data['start'];
}
@ -719,7 +719,12 @@ abstract class kolab_format_xcal extends kolab_format
foreach ($this->_scheduling_properties ?: self::$scheduling_properties as $prop) {
$a = $old[$prop];
$b = $object[$prop];
if ($object['allday'] && ($prop == 'start' || $prop == 'end') && $a instanceof DateTime && $b instanceof DateTime) {
if ($object['allday']
&& ($prop == 'start' || $prop == 'end')
&& $a instanceof DateTimeInterface
&& $b instanceof DateTimeInterface
) {
$a = $a->format('Y-m-d');
$b = $b->format('Y-m-d');
}

View file

@ -1051,7 +1051,7 @@ class kolab_storage_cache
foreach ($this->data_props as $prop) {
if (isset($object[$prop])) {
$data[$prop] = $object[$prop];
if ($data[$prop] instanceof DateTime) {
if ($data[$prop] instanceof DateTimeInterface) {
$data[$prop] = array(
'cl' => 'DateTime',
'dt' => $data[$prop]->format('Y-m-d H:i:s'),

View file

@ -72,7 +72,7 @@ class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
/*** Implement PHP Countable interface ***/
public function count()
public function count(): int
{
return count($this->index);
}
@ -80,7 +80,7 @@ class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
/*** Implement PHP ArrayAccess interface ***/
public function offsetSet($offset, $value)
public function offsetSet($offset, $value): void
{
if (is_string($value)) {
$uid = $value;
@ -106,16 +106,17 @@ class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
}
}
public function offsetExists($offset)
public function offsetExists($offset): bool
{
return isset($this->index[$offset]);
}
public function offsetUnset($offset)
public function offsetUnset($offset): void
{
unset($this->index[$offset]);
}
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (isset($this->chunk[$offset])) {
@ -163,28 +164,28 @@ class kolab_storage_dataset implements Iterator, ArrayAccess, Countable
/*** Implement PHP Iterator interface ***/
#[ReturnTypeWillChange]
public function current()
{
return $this->offsetGet($this->iteratorkey);
}
public function key()
public function key(): int
{
return $this->iteratorkey;
}
public function next()
public function next(): void
{
$this->iteratorkey++;
return $this->valid();
}
public function rewind()
public function rewind(): void
{
$this->iteratorkey = 0;
}
public function valid()
public function valid(): bool
{
return !empty($this->index[$this->iteratorkey]);
}

View file

@ -627,7 +627,7 @@ class kolab_storage_dav_cache extends kolab_storage_cache
foreach ($this->data_props as $prop) {
if (isset($object[$prop])) {
$data[$prop] = $object[$prop];
if ($data[$prop] instanceof DateTime) {
if ($data[$prop] instanceof DateTimeInterface) {
$data[$prop] = array(
'cl' => 'DateTime',
'dt' => $data[$prop]->format('Y-m-d H:i:s'),
@ -651,17 +651,11 @@ class kolab_storage_dav_cache extends kolab_storage_cache
*/
protected function _unserialize($sql_arr, $noread = false, $fast_mode = false)
{
if (!empty($sql_arr['data'])) {
if ($object = json_decode($sql_arr['data'], true)) {
$object['_type'] = $sql_arr['type'] ?: $this->folder->type;
$object['uid'] = $sql_arr['uid'];
$object['etag'] = $sql_arr['etag'];
}
}
if (!empty($fast_mode) && !empty($object)) {
if (!empty($sql_arr['data']) && ($object = json_decode($sql_arr['data'], true))) {
foreach ($this->data_props as $prop) {
if (isset($object[$prop]) && is_array($object[$prop]) && $object[$prop]['cl'] == 'DateTime') {
if (isset($object[$prop]) && is_array($object[$prop])
&& isset($object[$prop]['cl']) && $object[$prop]['cl'] == 'DateTime'
) {
$object[$prop] = new DateTime($object[$prop]['dt'], new DateTimeZone($object[$prop]['tz']));
}
else if (!isset($object[$prop]) && isset($sql_arr[$prop])) {
@ -677,6 +671,12 @@ class kolab_storage_dav_cache extends kolab_storage_cache
$object['changed'] = new DateTime($sql_arr['changed']);
}
$object['_type'] = !empty($sql_arr['type']) ? $sql_arr['type'] : $this->folder->type;
$object['uid'] = $sql_arr['uid'];
$object['etag'] = $sql_arr['etag'];
}
if (!empty($fast_mode) && !empty($object)) {
unset($object['_raw']);
}
else if ($noread) {

View file

@ -29,16 +29,16 @@ class kolab_storage_dav_folder extends kolab_storage_folder
/**
* Object constructor
*/
public function __construct($dav, $attributes, $type_annotation = '')
public function __construct($dav, $attributes, $type = '')
{
$this->attributes = $attributes;
$this->href = $this->attributes['href'];
$this->id = md5($this->dav->url . '/' . $this->href);
$this->id = md5($dav->url . '/' . $this->href);
$this->dav = $dav;
$this->valid = true;
list($this->type, $suffix) = explode('.', $type_annotation);
list($this->type, $suffix) = strpos($type, '.') ? explode('.', $type) : [$type, ''];
$this->default = $suffix == 'default';
$this->subtype = $this->default ? '' : $suffix;

View file

@ -184,7 +184,7 @@ class libkolab extends rcube_plugin
array_walk($result['changes'], function(&$change) use ($dtformat, $rcmail) {
if ($change['date']) {
$dt = rcube_utils::anytodatetime($change['date']);
if ($dt instanceof DateTime) {
if ($dt instanceof DateTimeInterface) {
$change['date'] = $rcmail->format_date($dt, $dtformat);
}
}

View file

@ -21,9 +21,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class kolab_date_recurrence_test extends PHPUnit\Framework\TestCase
class KolabDateRecurrenceTest extends PHPUnit\Framework\TestCase
{
function setUp()
function setUp(): void
{
$rcube = rcmail::get_instance();
$rcube->plugins->load_plugin('libkolab', true, true);
@ -251,11 +251,11 @@ class kolab_date_recurrence_test extends PHPUnit\Framework\TestCase
date_default_timezone_set('America/New_York');
$start = new DateTime('2017-08-31 11:00:00', new DateTimeZone('Europe/Berlin'));
$event = array(
$event = [
'start' => $start,
'recurrence' => array('FREQ' => 'WEEKLY', 'INTERVAL' => '1'),
'recurrence' => ['FREQ' => 'WEEKLY', 'INTERVAL' => '1'],
'allday' => true,
);
];
$object = kolab_format::factory('event', 3.0);
$object->set($event);
@ -265,6 +265,6 @@ class kolab_date_recurrence_test extends PHPUnit\Framework\TestCase
$this->assertEquals($start->format('2017-09-07 H:i:s'), $next['start']->format('Y-m-d H:i:s'), 'Same time');
$this->assertEquals($start->getTimezone()->getName(), $next['start']->getTimezone()->getName(), 'Same timezone');
$this->assertSame($next['start']->_dateonly, true, '_dateonly flag');
$this->assertSame(true, $next['start']->_dateonly, '_dateonly flag');
}
}

View file

@ -1,6 +1,6 @@
<?php
class kolab_storage_config_test extends PHPUnit\Framework\TestCase
class KolabStorageConfigTest extends PHPUnit\Framework\TestCase
{
private $params_personal = array(
'folder' => 'Archive',
@ -29,7 +29,7 @@ class kolab_storage_config_test extends PHPUnit\Framework\TestCase
);
private $url_other = 'imap:///user/lucy.white%40example.org/Mailings/378?message-id=%3C22448899%40example.org%3E&date=Tue%2C+14+Apr+2015+14%3A14%3A30+%2B0200&subject=Happy+Holidays';
public static function setUpBeforeClass()
public static function setUpBeforeClass(): void
{
$rcube = rcmail::get_instance();
$rcube->plugins->load_plugin('libkolab', true, true);
@ -38,11 +38,14 @@ class kolab_storage_config_test extends PHPUnit\Framework\TestCase
return;
}
// Unset mock'ed storage from the Roundcube core tests
$rcmail->storage = null;
if ($rcube->config->get('tests_username')) {
$authenticated = $rcube->login(
$rcube->config->get('tests_username'),
$rcube->config->get('tests_password'),
$rcube->config->get('default_host'),
$rcube->config->get('imap_host', $rcube->config->get('default_host')),
false
);

View file

@ -21,9 +21,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class kolab_storage_folder_test extends PHPUnit\Framework\TestCase
class KolabStorageFolderTest extends PHPUnit\Framework\TestCase
{
public static function setUpBeforeClass()
public static function setUpBeforeClass(): void
{
// load libkolab plugin
$rcmail = rcmail::get_instance();
@ -33,11 +33,14 @@ class kolab_storage_folder_test extends PHPUnit\Framework\TestCase
return;
}
// Unset mock'ed storage from the Roundcube core tests
$rcmail->storage = null;
if ($rcmail->config->get('tests_username')) {
$authenticated = $rcmail->login(
$rcmail->config->get('tests_username'),
$rcmail->config->get('tests_password'),
$rcmail->config->get('default_host'),
$rcmail->config->get('imap_host', $rcmail->config->get('default_host')),
false
);

View file

@ -18,7 +18,7 @@ Add these config options used by the libkolab tests:
$config['default_host'] = '<kolab-server>';
// disable all plugins
$config['plugins'] = array();
$config['plugins'] = [];
```
WARNING