@@ -2386,6 +2386,10 @@ private function searchCalendarObjects(IQueryBuilder $query, ?DateTimeInterface
23862386 }
23872387
23882388 try {
2389+ // The time-range filter is hardcoded to VEVENT: Sabre only
2390+ // expands VEVENT recurrences (EventIterator is VEVENT-only and
2391+ // VTodo::isInTimeRange ignores RRULE), so other component types
2392+ // would not be filtered correctly here.
23892393 $ isValid = $ this ->validateFilterForObject ($ row , [
23902394 'name ' => 'VCALENDAR ' ,
23912395 'comp-filters ' => [
@@ -2489,13 +2493,24 @@ private function transformSearchProperty(Property $prop) {
24892493 }
24902494
24912495 /**
2496+ * Search calendar objects across a principal's calendars.
2497+ *
2498+ * This returns the stored calendar objects and does not expand recurring
2499+ * events. Callers that need the concrete occurrence for a requested time
2500+ * range must expand recurrences from `calendardata` themselves.
2501+ *
2502+ * Note: when a `timerange` option is given, the precise filtering assumes
2503+ * VEVENT components (see searchCalendarObjects()). Passing other component
2504+ * types together with a `timerange` would drop all results.
2505+ *
24922506 * @param string $principalUri
24932507 * @param string $pattern
24942508 * @param array $componentTypes
24952509 * @param array $searchProperties
24962510 * @param array $searchParameters
24972511 * @param array $options
2498- * @return array
2512+ *
2513+ * @return list<array{uri: string, calendarid: int, calendartype: int, calendardata: string}>
24992514 */
25002515 public function searchPrincipalUri (string $ principalUri ,
25012516 string $ pattern ,
@@ -2511,6 +2526,11 @@ public function searchPrincipalUri(string $principalUri,
25112526 $ calendarOr = [];
25122527 $ searchOr = [];
25132528
2529+ $ start = null ;
2530+ $ end = null ;
2531+
2532+ // Todo: The retries when $hasLimit && $hasTimeRange from https://github.com/nextcloud/server/pull/45222 should also be applied here to the calendarObjectIdQuery
2533+
25142534 // Fetch calendars and subscription
25152535 $ calendars = $ this ->getCalendarsForUser ($ principalUri );
25162536 $ subscriptions = $ this ->getSubscriptionsForUser ($ principalUri );
@@ -2589,19 +2609,21 @@ public function searchPrincipalUri(string $principalUri,
25892609 if (isset ($ options ['offset ' ])) {
25902610 $ calendarObjectIdQuery ->setFirstResult ($ options ['offset ' ]);
25912611 }
2592- if (isset ($ options ['timerange ' ])) {
2593- if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2594- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2595- 'lastoccurence ' ,
2596- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['start ' ]->getTimeStamp ()),
2597- ));
2598- }
2599- if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2600- $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2601- 'firstoccurence ' ,
2602- $ calendarObjectIdQuery ->createNamedParameter ($ options ['timerange ' ]['end ' ]->getTimeStamp ()),
2603- ));
2604- }
2612+ if (isset ($ options ['timerange ' ]['start ' ]) && $ options ['timerange ' ]['start ' ] instanceof DateTimeInterface) {
2613+ /** @var DateTimeInterface $start */
2614+ $ start = $ options ['timerange ' ]['start ' ];
2615+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->gt (
2616+ 'lastoccurence ' ,
2617+ $ calendarObjectIdQuery ->createNamedParameter ($ start ->getTimestamp ()),
2618+ ));
2619+ }
2620+ if (isset ($ options ['timerange ' ]['end ' ]) && $ options ['timerange ' ]['end ' ] instanceof DateTimeInterface) {
2621+ /** @var DateTimeInterface $end */
2622+ $ end = $ options ['timerange ' ]['end ' ];
2623+ $ calendarObjectIdQuery ->andWhere ($ calendarObjectIdQuery ->expr ()->lt (
2624+ 'firstoccurence ' ,
2625+ $ calendarObjectIdQuery ->createNamedParameter ($ end ->getTimestamp ()),
2626+ ));
26052627 }
26062628
26072629 $ result = $ calendarObjectIdQuery ->executeQuery ();
@@ -2616,17 +2638,16 @@ public function searchPrincipalUri(string $principalUri,
26162638 ->from ('calendarobjects ' )
26172639 ->where ($ query ->expr ()->in ('id ' , $ query ->createNamedParameter ($ matches , IQueryBuilder::PARAM_INT_ARRAY )));
26182640
2619- $ result = $ query ->executeQuery ();
2620- $ calendarObjects = [];
2621- while (($ array = $ result ->fetchAssociative ()) !== false ) {
2622- $ array ['calendarid ' ] = (int )$ array ['calendarid ' ];
2623- $ array ['calendartype ' ] = (int )$ array ['calendartype ' ];
2624- $ array ['calendardata ' ] = $ this ->readBlob ($ array ['calendardata ' ]);
2641+ $ calendarObjects = $ this ->searchCalendarObjects ($ query , $ start , $ end );
26252642
2626- $ calendarObjects [] = $ array ;
2627- }
2628- $ result ->closeCursor ();
2629- return $ calendarObjects ;
2643+ return array_values (array_map (function ($ event ) {
2644+ return [
2645+ 'uri ' => (string )$ event ['uri ' ],
2646+ 'calendarid ' => (int )$ event ['calendarid ' ],
2647+ 'calendartype ' => (int )$ event ['calendartype ' ],
2648+ 'calendardata ' => (string )$ this ->readBlob ($ event ['calendardata ' ]),
2649+ ];
2650+ }, $ calendarObjects ));
26302651 }, $ this ->db );
26312652 }
26322653
0 commit comments