@@ -2391,6 +2391,10 @@ private function searchCalendarObjects(IQueryBuilder $query, ?DateTimeInterface
23912391 }
23922392
23932393 try {
2394+ // The time-range filter is hardcoded to VEVENT: Sabre only
2395+ // expands VEVENT recurrences (EventIterator is VEVENT-only and
2396+ // VTodo::isInTimeRange ignores RRULE), so other component types
2397+ // would not be filtered correctly here.
23942398 $ isValid = $ this ->validateFilterForObject ($ row , [
23952399 'name ' => 'VCALENDAR ' ,
23962400 'comp-filters ' => [
@@ -2494,13 +2498,24 @@ private function transformSearchProperty(Property $prop) {
24942498 }
24952499
24962500 /**
2501+ * Search calendar objects across a principal's calendars.
2502+ *
2503+ * This returns the stored calendar objects and does not expand recurring
2504+ * events. Callers that need the concrete occurrence for a requested time
2505+ * range must expand recurrences from `calendardata` themselves.
2506+ *
2507+ * Note: when a `timerange` option is given, the precise filtering assumes
2508+ * VEVENT components (see searchCalendarObjects()). Passing other component
2509+ * types together with a `timerange` would drop all results.
2510+ *
24972511 * @param string $principalUri
24982512 * @param string $pattern
24992513 * @param array $componentTypes
25002514 * @param array $searchProperties
25012515 * @param array $searchParameters
25022516 * @param array $options
2503- * @return array
2517+ *
2518+ * @return list<array{uri: string, calendarid: int, calendartype: int, calendardata: string}>
25042519 */
25052520 public function searchPrincipalUri (string $ principalUri ,
25062521 string $ pattern ,
@@ -2516,6 +2531,11 @@ public function searchPrincipalUri(string $principalUri,
25162531 $ calendarOr = [];
25172532 $ searchOr = [];
25182533
2534+ $ start = null ;
2535+ $ end = null ;
2536+
2537+ // Todo: The retries when $hasLimit && $hasTimeRange from https://github.com/nextcloud/server/pull/45222 should also be applied here to the calendarObjectIdQuery
2538+
25192539 // Fetch calendars and subscription
25202540 $ calendars = $ this ->getCalendarsForUser ($ principalUri );
25212541 $ subscriptions = $ this ->getSubscriptionsForUser ($ principalUri );
@@ -2594,19 +2614,21 @@ public function searchPrincipalUri(string $principalUri,
25942614 if (isset ($ options ['offset ' ])) {
25952615 $ calendarObjectIdQuery ->setFirstResult ($ options ['offset ' ]);
25962616 }
2597- if (isset ($ options ['timerange ' ])) {
2598- if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2599- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2600- 'lastoccurence ' ,
2601- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['start ' ]->getTimeStamp ()),
2602- ));
2603- }
2604- if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2605- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2606- 'firstoccurence ' ,
2607- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['end ' ]->getTimeStamp ()),
2608- ));
2609- }
2617+ if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2618+ /** @var DateTimeInterface $start */
2619+ $ start = $ options ['timerange ' ]['start ' ];
2620+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2621+ 'lastoccurence ' ,
2622+ $ calendarObjectIdQuery ->createNamedParameter ($ start ->getTimestamp ()),
2623+ ));
2624+ }
2625+ if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2626+ /** @var DateTimeInterface $end */
2627+ $ end = $ options ['timerange ' ]['end ' ];
2628+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2629+ 'firstoccurence ' ,
2630+ $ calendarObjectIdQuery ->createNamedParameter ($ end ->getTimestamp ()),
2631+ ));
26102632 }
26112633
26122634 $ result = $ calendarObjectIdQuery ->executeQuery ();
@@ -2621,17 +2643,16 @@ public function searchPrincipalUri(string $principalUri,
26212643 ->from ('calendarobjects ' )
26222644 ->where ($ query ->expr ()->in ('id ' , $ query ->createNamedParameter ($ matches , IQueryBuilder::PARAM_INT_ARRAY )));
26232645
2624- $ result = $ query ->executeQuery ();
2625- $ calendarObjects = [];
2626- while (($ array = $ result ->fetchAssociative ()) !== false ) {
2627- $ array ['calendarid ' ] = (int )$ array ['calendarid ' ];
2628- $ array ['calendartype ' ] = (int )$ array ['calendartype ' ];
2629- $ array ['calendardata ' ] = $ this ->readBlob ($ array ['calendardata ' ]);
2646+ $ calendarObjects = $ this ->searchCalendarObjects ($ query , $ start , $ end );
26302647
2631- $ calendarObjects [] = $ array ;
2632- }
2633- $ result ->closeCursor ();
2634- return $ calendarObjects ;
2648+ return array_values (array_map (function ($ event ) {
2649+ return [
2650+ 'uri ' => (string )$ event ['uri ' ],
2651+ 'calendarid ' => (int )$ event ['calendarid ' ],
2652+ 'calendartype ' => (int )$ event ['calendartype ' ],
2653+ 'calendardata ' => (string )$ this ->readBlob ($ event ['calendardata ' ]),
2654+ ];
2655+ }, $ calendarObjects ));
26352656 }, $ this ->db );
26362657 }
26372658
0 commit comments