@@ -2353,6 +2353,10 @@ private function searchCalendarObjects(IQueryBuilder $query, ?DateTimeInterface
23532353 }
23542354
23552355 try {
2356+ // The time-range filter is hardcoded to VEVENT: Sabre only
2357+ // expands VEVENT recurrences (EventIterator is VEVENT-only and
2358+ // VTodo::isInTimeRange ignores RRULE), so other component types
2359+ // would not be filtered correctly here.
23562360 $ isValid = $ this ->validateFilterForObject ($ row , [
23572361 'name ' => 'VCALENDAR ' ,
23582362 'comp-filters ' => [
@@ -2456,13 +2460,24 @@ private function transformSearchProperty(Property $prop) {
24562460 }
24572461
24582462 /**
2463+ * Search calendar objects across a principal's calendars.
2464+ *
2465+ * This returns the stored calendar objects and does not expand recurring
2466+ * events. Callers that need the concrete occurrence for a requested time
2467+ * range must expand recurrences from `calendardata` themselves.
2468+ *
2469+ * Note: when a `timerange` option is given, the precise filtering assumes
2470+ * VEVENT components (see searchCalendarObjects()). Passing other component
2471+ * types together with a `timerange` would drop all results.
2472+ *
24592473 * @param string $principalUri
24602474 * @param string $pattern
24612475 * @param array $componentTypes
24622476 * @param array $searchProperties
24632477 * @param array $searchParameters
24642478 * @param array $options
2465- * @return array
2479+ *
2480+ * @return list<array{uri: string, calendarid: int, calendartype: int, calendardata: string}>
24662481 */
24672482 public function searchPrincipalUri (string $ principalUri ,
24682483 string $ pattern ,
@@ -2478,6 +2493,11 @@ public function searchPrincipalUri(string $principalUri,
24782493 $ calendarOr = [];
24792494 $ searchOr = [];
24802495
2496+ $ start = null ;
2497+ $ end = null ;
2498+
2499+ // Todo: The retries when $hasLimit && $hasTimeRange from https://github.com/nextcloud/server/pull/45222 should also be applied here to the calendarObjectIdQuery
2500+
24812501 // Fetch calendars and subscription
24822502 $ calendars = $ this ->getCalendarsForUser ($ principalUri );
24832503 $ subscriptions = $ this ->getSubscriptionsForUser ($ principalUri );
@@ -2556,19 +2576,21 @@ public function searchPrincipalUri(string $principalUri,
25562576 if (isset ($ options ['offset ' ])) {
25572577 $ calendarObjectIdQuery ->setFirstResult ($ options ['offset ' ]);
25582578 }
2559- if (isset ($ options ['timerange ' ])) {
2560- if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2561- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2562- 'lastoccurence ' ,
2563- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['start ' ]->getTimeStamp ()),
2564- ));
2565- }
2566- if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2567- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2568- 'firstoccurence ' ,
2569- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['end ' ]->getTimeStamp ()),
2570- ));
2571- }
2579+ if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2580+ /** @var DateTimeInterface $start */
2581+ $ start = $ options ['timerange ' ]['start ' ];
2582+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2583+ 'lastoccurence ' ,
2584+ $ calendarObjectIdQuery ->createNamedParameter ($ start ->getTimestamp ()),
2585+ ));
2586+ }
2587+ if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2588+ /** @var DateTimeInterface $end */
2589+ $ end = $ options ['timerange ' ]['end ' ];
2590+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2591+ 'firstoccurence ' ,
2592+ $ calendarObjectIdQuery ->createNamedParameter ($ end ->getTimestamp ()),
2593+ ));
25722594 }
25732595
25742596 $ result = $ calendarObjectIdQuery ->executeQuery ();
@@ -2583,17 +2605,16 @@ public function searchPrincipalUri(string $principalUri,
25832605 ->from ('calendarobjects ' )
25842606 ->where ($ query ->expr ()->in ('id ' , $ query ->createNamedParameter ($ matches , IQueryBuilder::PARAM_INT_ARRAY )));
25852607
2586- $ result = $ query ->executeQuery ();
2587- $ calendarObjects = [];
2588- while (($ array = $ result ->fetchAssociative ()) !== false ) {
2589- $ array ['calendarid ' ] = (int )$ array ['calendarid ' ];
2590- $ array ['calendartype ' ] = (int )$ array ['calendartype ' ];
2591- $ array ['calendardata ' ] = $ this ->readBlob ($ array ['calendardata ' ]);
2608+ $ calendarObjects = $ this ->searchCalendarObjects ($ query , $ start , $ end );
25922609
2593- $ calendarObjects [] = $ array ;
2594- }
2595- $ result ->closeCursor ();
2596- return $ calendarObjects ;
2610+ return array_values (array_map (function ($ event ) {
2611+ return [
2612+ 'uri ' => (string )$ event ['uri ' ],
2613+ 'calendarid ' => (int )$ event ['calendarid ' ],
2614+ 'calendartype ' => (int )$ event ['calendartype ' ],
2615+ 'calendardata ' => (string )$ this ->readBlob ($ event ['calendardata ' ]),
2616+ ];
2617+ }, $ calendarObjects ));
25972618 }, $ this ->db );
25982619 }
25992620
0 commit comments