[dev] Kronolith_Integration_ToIcalendarTest and dealing with recurrence exceptions

Michael J Rubinsky mrubinsk at horde.org
Sat Jun 25 06:50:45 UTC 2011


Quoting Gunnar Wrobel <wrobel at horde.org>:

> Hi!
>
> I started converting more of our application test suites to PHPUnit  
> and I am currently focusing on Kronolith. The test mentioned above  
> ("Kronolith_Integration_ToIcalendarTest") is hard to convert from  
> the Horde 3 version because of the way recurrence exceptions are  
> handled. You can disable the "markTestIncomplete()" in the  
> "ToIcalendarTest" in order to see what I refer to. The problem is  
> caused by the section that handles recurrence exceptions in the  
> Kronolith_Event::toiCalendar() function.

I couldn't find the test that you are referring to here...am I missing  
some new branch or something?

> This sections fetches a complete driver and searches for the  
> "baseid". "baseid" however seems to work only with the SQL backend.

The information obtained by using baseid needs to work for any backend  
that both supports exceptions and can be exported to iCalendar, so we  
will need to look at this. The baseid and exceptionoriginaldate  
properties are used in other places in kronolith code as well. This  
functionality will need to be added to the other drivers that are to  
support exceptions.

> Which I would like to avoid as the amount of setup code - even if  
> done in SQLite - is much more complex and it seems unnecessary to  
> simply export an event to iCal. So I tried using a mock "Ical"  
> driver instead but that one fails because the search function is  
> unhappy about the missing stdClass->start and ->end properties.

This is a bug. Just pushed a fix that allows for empty values for  
these properties in the base driver (recently fixed in the sql driver,  
neglected to check/fix in the base driver class).


> So my impression is that this section is only meant to be valid for  
> the SQL backend and then it would be strange to find it in  
> Kronolith_Event.

No, as stated above, this needs to work for any driver that can  
support exceptions. However, after looking through the code while  
composing this email it's obvious this is currently broken for any  
driver other than SQL, so will need to be fixed.

> I assume the fact that the event needs to query the driver again is  
> an optimization to lazy load the recurrence exceptions only in case  
> they are required.

Sort of. What's happening there is this (my apologies if this is  
already obvious to you - not sure how deep into it you are currently):

$event->recurrence->getExceptions() only ever returns just the dates  
for a recurring event's exceptions. It contains no information  
_at_all_ about what the exception is. It could be that the event is  
totally skipped that day or it could be the event was moved to a  
different time on the same day, or a different day completely.

The function of the baseid field is to tie an event that represents an  
exception to the "parent" recurring event. Similarly, the  
exceptionoriginaldate field ties the exception's event object to a  
specific exception date. These were meant as client code facing  
properties. The driver should now how to use these to get the data  
they need.

In other words, if an exception is added to a recurring event with a  
UID of abc123 that has an exception added on 3/20/2011 that moves the  
event to 3/21/2011: the 3/20/2011 date would exist in the  
getExceptions() result for event abc123, a new event would be created  
for the 3/21/2011 event that would have the baseid eq to abc123, and a  
exceptionoriginaldate property set to 3/20/2011

Ok. So, what's going on in the Kronolith_Event::toiCalendar() method  
(and to a similar extent, in toASAppointment() method) is that we need  
to know more than just what date the exceptions are on. We need to  
know if the event was deleted or, if not deleted, the new event  
details. We search on the baseid property to pull all events that  
represent exceptions to the "parent" event. We then iterate through  
all those exceptions and, using the exceptionoriginaldate property of  
each of those exception events, remove this date from the list of  
known exception dates. Any dates left over after these have been  
removed must be exceptions that are deleted, not just rescheduled.

> I'd be tempted to convert that into a callback function that gets  
> set in the constructor and allows the event to query the recurrence  
> exceptions from the driver on demand.

I agree it might be reasonable to abstract this part out since some  
drivers might be able to do this in a more efficient way, though I'm  
not sure why a callback would be better instead of just a private  
method defined in each Kronolith_Event subclass that can support  
exceptions?

Regardless, we need a consistent way of representing exception  
information on the client facing side - and that's currently the role  
that baseid and exceptionoriginaldate properties play. I'm not at all  
familiar with Kolab to know how it would store recurring  
events/exceptions or obtain this information.

Hope this makes sense...almost 3am here and the brain is not quite up  
to speed :)

-- 
mike

The Horde Project (www.horde.org)
mrubinsk at horde.org



More information about the dev mailing list