9797use Sabre \VObject \Recur \EventIterator ;
9898use Symfony \Component \EventDispatcher \EventDispatcherInterface ;
9999use Symfony \Component \EventDispatcher \GenericEvent ;
100+ use function array_column ;
100101use function array_merge ;
101102use function array_values ;
102103use function explode ;
103104use function is_array ;
104105use function is_resource ;
105106use function pathinfo ;
106107use function rewind ;
108+ use function settype ;
107109use function sprintf ;
108110use function str_replace ;
109111use function strtolower ;
@@ -142,20 +144,19 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
142144 public const CLASSIFICATION_CONFIDENTIAL = 2 ;
143145
144146 /**
145- * List of CalDAV properties, and how they map to database field names
147+ * List of CalDAV properties, and how they map to database field names and their type
146148 * Add your own properties by simply adding on to this array.
147149 *
148- * Note that only string-based properties are supported here.
149- *
150150 * @var array
151+ * @psalm-var array<string, string[]>
151152 */
152153 public $ propertyMap = [
153- '{DAV:}displayname ' => 'displayname ' ,
154- '{urn:ietf:params:xml:ns:caldav}calendar-description ' => 'description ' ,
155- '{urn:ietf:params:xml:ns:caldav}calendar-timezone ' => 'timezone ' ,
156- '{http://apple.com/ns/ical/}calendar-order ' => 'calendarorder ' ,
157- '{http://apple.com/ns/ical/}calendar-color ' => 'calendarcolor ' ,
158- '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => 'deleted_at ' ,
154+ '{DAV:}displayname ' => [ 'displayname ' , ' string ' ] ,
155+ '{urn:ietf:params:xml:ns:caldav}calendar-description ' => [ 'description ' , ' string ' ] ,
156+ '{urn:ietf:params:xml:ns:caldav}calendar-timezone ' => [ 'timezone ' , ' string ' ] ,
157+ '{http://apple.com/ns/ical/}calendar-order ' => [ 'calendarorder ' , ' int ' ] ,
158+ '{http://apple.com/ns/ical/}calendar-color ' => [ 'calendarcolor ' , ' string ' ] ,
159+ '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => [ 'deleted_at ' , ' int ' ] ,
159160 ];
160161
161162 /**
@@ -164,13 +165,13 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
164165 * @var array
165166 */
166167 public $ subscriptionPropertyMap = [
167- '{DAV:}displayname ' => 'displayname ' ,
168- '{http://apple.com/ns/ical/}refreshrate ' => 'refreshrate ' ,
169- '{http://apple.com/ns/ical/}calendar-order ' => 'calendarorder ' ,
170- '{http://apple.com/ns/ical/}calendar-color ' => 'calendarcolor ' ,
171- '{http://calendarserver.org/ns/}subscribed-strip-todos ' => 'striptodos ' ,
172- '{http://calendarserver.org/ns/}subscribed-strip-alarms ' => 'stripalarms ' ,
173- '{http://calendarserver.org/ns/}subscribed-strip-attachments ' => 'stripattachments ' ,
168+ '{DAV:}displayname ' => [ 'displayname ' , ' string ' ] ,
169+ '{http://apple.com/ns/ical/}refreshrate ' => [ 'refreshrate ' , ' string ' ] ,
170+ '{http://apple.com/ns/ical/}calendar-order ' => [ 'calendarorder ' , ' int ' ] ,
171+ '{http://apple.com/ns/ical/}calendar-color ' => [ 'calendarcolor ' , ' string ' ] ,
172+ '{http://calendarserver.org/ns/}subscribed-strip-todos ' => [ 'striptodos ' , ' bool ' ] ,
173+ '{http://calendarserver.org/ns/}subscribed-strip-alarms ' => [ 'stripalarms ' , ' string ' ] ,
174+ '{http://calendarserver.org/ns/}subscribed-strip-attachments ' => [ 'stripattachments ' , ' string ' ] ,
174175 ];
175176
176177 /**
@@ -351,7 +352,7 @@ public function getDeletedCalendars(int $deletedBefore): array {
351352 public function getCalendarsForUser ($ principalUri ) {
352353 $ principalUriOriginal = $ principalUri ;
353354 $ principalUri = $ this ->convertPrincipal ($ principalUri , true );
354- $ fields = array_values ($ this ->propertyMap );
355+ $ fields = array_column ($ this ->propertyMap , 0 );
355356 $ fields [] = 'id ' ;
356357 $ fields [] = 'uri ' ;
357358 $ fields [] = 'synctoken ' ;
@@ -392,10 +393,7 @@ public function getCalendarsForUser($principalUri) {
392393 '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_OWNCLOUD . '}owner-principal ' => $ this ->convertPrincipal ($ principalUri , !$ this ->legacyEndpoint ),
393394 ];
394395
395- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
396- $ calendar [$ xmlName ] = $ row [$ dbName ];
397- }
398-
396+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
399397 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
400398 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
401399
@@ -411,7 +409,7 @@ public function getCalendarsForUser($principalUri) {
411409
412410 $ principals [] = $ principalUri ;
413411
414- $ fields = array_values ($ this ->propertyMap );
412+ $ fields = array_column ($ this ->propertyMap , 0 );
415413 $ fields [] = 'a.id ' ;
416414 $ fields [] = 'a.uri ' ;
417415 $ fields [] = 'a.synctoken ' ;
@@ -469,10 +467,7 @@ public function getCalendarsForUser($principalUri) {
469467 $ readOnlyPropertyName => $ readOnly ,
470468 ];
471469
472- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
473- $ calendar [$ xmlName ] = $ row [$ dbName ];
474- }
475-
470+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
476471 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
477472 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
478473
@@ -489,7 +484,7 @@ public function getCalendarsForUser($principalUri) {
489484 */
490485 public function getUsersOwnCalendars ($ principalUri ) {
491486 $ principalUri = $ this ->convertPrincipal ($ principalUri , true );
492- $ fields = array_values ($ this ->propertyMap );
487+ $ fields = array_column ($ this ->propertyMap , 0 );
493488 $ fields [] = 'id ' ;
494489 $ fields [] = 'uri ' ;
495490 $ fields [] = 'synctoken ' ;
@@ -518,10 +513,8 @@ public function getUsersOwnCalendars($principalUri) {
518513 '{ ' . Plugin::NS_CALDAV . '}supported-calendar-component-set ' => new SupportedCalendarComponentSet ($ components ),
519514 '{ ' . Plugin::NS_CALDAV . '}schedule-calendar-transp ' => new ScheduleCalendarTransp ($ row ['transparent ' ]?'transparent ' :'opaque ' ),
520515 ];
521- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
522- $ calendar [$ xmlName ] = $ row [$ dbName ];
523- }
524516
517+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
525518 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
526519 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
527520
@@ -556,7 +549,7 @@ private function getUserDisplayName($uid) {
556549 * @return array
557550 */
558551 public function getPublicCalendars () {
559- $ fields = array_values ($ this ->propertyMap );
552+ $ fields = array_column ($ this ->propertyMap , 0 );
560553 $ fields [] = 'a.id ' ;
561554 $ fields [] = 'a.uri ' ;
562555 $ fields [] = 'a.synctoken ' ;
@@ -595,10 +588,7 @@ public function getPublicCalendars() {
595588 '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_OWNCLOUD . '}public ' => (int )$ row ['access ' ] === self ::ACCESS_PUBLIC ,
596589 ];
597590
598- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
599- $ calendar [$ xmlName ] = $ row [$ dbName ];
600- }
601-
591+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
602592 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
603593 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
604594
@@ -617,7 +607,7 @@ public function getPublicCalendars() {
617607 * @throws NotFound
618608 */
619609 public function getPublicCalendar ($ uri ) {
620- $ fields = array_values ($ this ->propertyMap );
610+ $ fields = array_column ($ this ->propertyMap , 0 );
621611 $ fields [] = 'a.id ' ;
622612 $ fields [] = 'a.uri ' ;
623613 $ fields [] = 'a.synctoken ' ;
@@ -663,10 +653,7 @@ public function getPublicCalendar($uri) {
663653 '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_OWNCLOUD . '}public ' => (int )$ row ['access ' ] === self ::ACCESS_PUBLIC ,
664654 ];
665655
666- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
667- $ calendar [$ xmlName ] = $ row [$ dbName ];
668- }
669-
656+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
670657 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
671658 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
672659
@@ -679,7 +666,7 @@ public function getPublicCalendar($uri) {
679666 * @return array|null
680667 */
681668 public function getCalendarByUri ($ principal , $ uri ) {
682- $ fields = array_values ($ this ->propertyMap );
669+ $ fields = array_column ($ this ->propertyMap , 0 );
683670 $ fields [] = 'id ' ;
684671 $ fields [] = 'uri ' ;
685672 $ fields [] = 'synctoken ' ;
@@ -717,10 +704,7 @@ public function getCalendarByUri($principal, $uri) {
717704 '{ ' . Plugin::NS_CALDAV . '}schedule-calendar-transp ' => new ScheduleCalendarTransp ($ row ['transparent ' ]?'transparent ' :'opaque ' ),
718705 ];
719706
720- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
721- $ calendar [$ xmlName ] = $ row [$ dbName ];
722- }
723-
707+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
724708 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
725709 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
726710
@@ -732,7 +716,7 @@ public function getCalendarByUri($principal, $uri) {
732716 * @return array|null
733717 */
734718 public function getCalendarById ($ calendarId ) {
735- $ fields = array_values ($ this ->propertyMap );
719+ $ fields = array_column ($ this ->propertyMap , 0 );
736720 $ fields [] = 'id ' ;
737721 $ fields [] = 'uri ' ;
738722 $ fields [] = 'synctoken ' ;
@@ -769,10 +753,7 @@ public function getCalendarById($calendarId) {
769753 '{ ' . Plugin::NS_CALDAV . '}schedule-calendar-transp ' => new ScheduleCalendarTransp ($ row ['transparent ' ]?'transparent ' :'opaque ' ),
770754 ];
771755
772- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
773- $ calendar [$ xmlName ] = $ row [$ dbName ];
774- }
775-
756+ $ calendar = $ this ->rowToCalendar ($ row , $ calendar );
776757 $ calendar = $ this ->addOwnerPrincipalToCalendar ($ calendar );
777758 $ calendar = $ this ->addResourceTypeToCalendar ($ row , $ calendar );
778759
@@ -783,7 +764,7 @@ public function getCalendarById($calendarId) {
783764 * @param $subscriptionId
784765 */
785766 public function getSubscriptionById ($ subscriptionId ) {
786- $ fields = array_values ($ this ->subscriptionPropertyMap );
767+ $ fields = array_column ($ this ->subscriptionPropertyMap , 0 );
787768 $ fields [] = 'id ' ;
788769 $ fields [] = 'uri ' ;
789770 $ fields [] = 'source ' ;
@@ -815,13 +796,7 @@ public function getSubscriptionById($subscriptionId) {
815796 '{http://sabredav.org/ns}sync-token ' => $ row ['synctoken ' ]?$ row ['synctoken ' ]:'0 ' ,
816797 ];
817798
818- foreach ($ this ->subscriptionPropertyMap as $ xmlName => $ dbName ) {
819- if (!is_null ($ row [$ dbName ])) {
820- $ subscription [$ xmlName ] = $ row [$ dbName ];
821- }
822- }
823-
824- return $ subscription ;
799+ return $ this ->rowToSubscription ($ row , $ subscription );
825800 }
826801
827802 /**
@@ -863,7 +838,7 @@ public function createCalendar($principalUri, $calendarUri, array $properties) {
863838 $ values ['transparent ' ] = (int ) ($ properties [$ transp ]->getValue () === 'transparent ' );
864839 }
865840
866- foreach ($ this ->propertyMap as $ xmlName => $ dbName ) {
841+ foreach ($ this ->propertyMap as $ xmlName => [ $ dbName, $ type ] ) {
867842 if (isset ($ properties [$ xmlName ])) {
868843 $ values [$ dbName ] = $ properties [$ xmlName ];
869844 }
@@ -912,7 +887,7 @@ public function updateCalendar($calendarId, PropPatch $propPatch) {
912887 $ newValues [$ fieldName ] = (int ) ($ propertyValue ->getValue () === 'transparent ' );
913888 break ;
914889 default :
915- $ fieldName = $ this ->propertyMap [$ propertyName ];
890+ $ fieldName = $ this ->propertyMap [$ propertyName ][ 0 ] ;
916891 $ newValues [$ fieldName ] = $ propertyValue ;
917892 break ;
918893 }
@@ -1109,7 +1084,7 @@ public function getDeletedCalendarObjects(int $deletedBefore): array {
11091084 'size ' => (int ) $ row ['size ' ],
11101085 'component ' => strtolower ($ row ['componenttype ' ]),
11111086 'classification ' => (int ) $ row ['classification ' ],
1112- '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => $ row ['deleted_at ' ],
1087+ '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => $ row ['deleted_at ' ] === null ? $ row [ ' deleted_at ' ] : ( int ) $ row [ ' deleted_at ' ] ,
11131088 ];
11141089 }
11151090 $ stmt ->closeCursor ();
@@ -1148,7 +1123,7 @@ public function getDeletedCalendarObjectsByPrincipal(string $principalUri): arra
11481123 'size ' => (int )$ row ['size ' ],
11491124 'component ' => strtolower ($ row ['componenttype ' ]),
11501125 'classification ' => (int )$ row ['classification ' ],
1151- '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => $ row ['deleted_at ' ],
1126+ '{ ' . \OCA \DAV \DAV \Sharing \Plugin::NS_NEXTCLOUD . '}deleted-at ' => $ row ['deleted_at ' ] === null ? $ row [ ' deleted_at ' ] : ( int ) $ row [ ' deleted_at ' ] ,
11521127 ];
11531128 }
11541129 $ stmt ->closeCursor ();
@@ -2452,7 +2427,7 @@ public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limi
24522427 * @return array
24532428 */
24542429 public function getSubscriptionsForUser ($ principalUri ) {
2455- $ fields = array_values ($ this ->subscriptionPropertyMap );
2430+ $ fields = array_column ($ this ->subscriptionPropertyMap , 0 );
24562431 $ fields [] = 'id ' ;
24572432 $ fields [] = 'uri ' ;
24582433 $ fields [] = 'source ' ;
@@ -2480,13 +2455,7 @@ public function getSubscriptionsForUser($principalUri) {
24802455 '{http://sabredav.org/ns}sync-token ' => $ row ['synctoken ' ]?$ row ['synctoken ' ]:'0 ' ,
24812456 ];
24822457
2483- foreach ($ this ->subscriptionPropertyMap as $ xmlName => $ dbName ) {
2484- if (!is_null ($ row [$ dbName ])) {
2485- $ subscription [$ xmlName ] = $ row [$ dbName ];
2486- }
2487- }
2488-
2489- $ subscriptions [] = $ subscription ;
2458+ $ subscriptions [] = $ this ->rowToSubscription ($ row , $ subscription );
24902459 }
24912460
24922461 return $ subscriptions ;
@@ -2517,7 +2486,7 @@ public function createSubscription($principalUri, $uri, array $properties) {
25172486
25182487 $ propertiesBoolean = ['striptodos ' , 'stripalarms ' , 'stripattachments ' ];
25192488
2520- foreach ($ this ->subscriptionPropertyMap as $ xmlName => $ dbName ) {
2489+ foreach ($ this ->subscriptionPropertyMap as $ xmlName => [ $ dbName, $ type ] ) {
25212490 if (array_key_exists ($ xmlName , $ properties )) {
25222491 $ values [$ dbName ] = $ properties [$ xmlName ];
25232492 if (in_array ($ dbName , $ propertiesBoolean )) {
@@ -2579,7 +2548,7 @@ public function updateSubscription($subscriptionId, PropPatch $propPatch) {
25792548 if ($ propertyName === '{http://calendarserver.org/ns/}source ' ) {
25802549 $ newValues ['source ' ] = $ propertyValue ->getHref ();
25812550 } else {
2582- $ fieldName = $ this ->subscriptionPropertyMap [$ propertyName ];
2551+ $ fieldName = $ this ->subscriptionPropertyMap [$ propertyName ][ 0 ] ;
25832552 $ newValues [$ fieldName ] = $ propertyValue ;
25842553 }
25852554 }
@@ -3263,4 +3232,42 @@ private function addResourceTypeToCalendar(array $row, array $calendar): array {
32633232 }
32643233 return $ calendar ;
32653234 }
3235+
3236+ /**
3237+ * Amend the calendar info with database row data
3238+ *
3239+ * @param array $row
3240+ * @param array $calendar
3241+ *
3242+ * @return array
3243+ */
3244+ private function rowToCalendar ($ row , array $ calendar ): array {
3245+ foreach ($ this ->propertyMap as $ xmlName => [$ dbName , $ type ]) {
3246+ $ value = $ row [$ dbName ];
3247+ if ($ value !== null ) {
3248+ settype ($ value , $ type );
3249+ }
3250+ $ calendar [$ xmlName ] = $ value ;
3251+ }
3252+ return $ calendar ;
3253+ }
3254+
3255+ /**
3256+ * Amend the subscription info with database row data
3257+ *
3258+ * @param array $row
3259+ * @param array $subscription
3260+ *
3261+ * @return array
3262+ */
3263+ private function rowToSubscription ($ row , array $ subscription ): array {
3264+ foreach ($ this ->subscriptionPropertyMap as $ xmlName => [$ dbName , $ type ]) {
3265+ $ value = $ row [$ dbName ];
3266+ if ($ value !== null ) {
3267+ settype ($ value , $ type );
3268+ }
3269+ $ subscription [$ xmlName ] = $ value ;
3270+ }
3271+ return $ subscription ;
3272+ }
32663273}
0 commit comments