From 5fb2562332ca74f44b6085629f980113d0551077 Mon Sep 17 00:00:00 2001
From: Georg Ehrke <developer@georgehrke.com>
Date: Fri, 24 Jul 2020 14:57:52 +0200
Subject: Implement Contacts Backend for Unified Search

Signed-off-by: Georg Ehrke <developer@georgehrke.com>
---
 apps/dav/lib/CardDAV/CardDavBackend.php | 61 ++++++++++++++++++++++++++++-----
 1 file changed, 53 insertions(+), 8 deletions(-)

(limited to 'apps/dav/lib/CardDAV')

diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php
index 9d602025c7a..3b3474cdd01 100644
--- a/apps/dav/lib/CardDAV/CardDavBackend.php
+++ b/apps/dav/lib/CardDAV/CardDavBackend.php
@@ -951,7 +951,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
 	}
 
 	/**
-	 * search contact
+	 * Search contacts in a specific address-book
 	 *
 	 * @param int $addressBookId
 	 * @param string $pattern which should match within the $searchProperties
@@ -962,11 +962,55 @@ class CardDavBackend implements BackendInterface, SyncSupport {
 	 * 	- 'offset' - Set the offset for the limited search results
 	 * @return array an array of contacts which are arrays of key-value-pairs
 	 */
-	public function search($addressBookId, $pattern, $searchProperties, $options = []) {
+	public function search($addressBookId, $pattern, $searchProperties, $options = []): array {
+		return $this->searchByAddressBookIds([$addressBookId], $pattern, $searchProperties, $options);
+	}
+
+	/**
+	 * Search contacts in all address-books accessible by a user
+	 *
+	 * @param string $principalUri
+	 * @param string $pattern
+	 * @param array $searchProperties
+	 * @param array $options
+	 * @return array
+	 */
+	public function searchPrincipalUri(string $principalUri,
+									   string $pattern,
+									   array $searchProperties,
+									   array $options = []): array {
+		$addressBookIds = array_map(static function ($row):int {
+			return (int) $row['id'];
+		}, $this->getAddressBooksForUser($principalUri));
+
+		return $this->searchByAddressBookIds($addressBookIds, $pattern, $searchProperties, $options);
+	}
+
+	/**
+	 * @param array $addressBookIds
+	 * @param string $pattern
+	 * @param array $searchProperties
+	 * @param array $options
+	 * @return array
+	 */
+	private function searchByAddressBookIds(array $addressBookIds,
+											string $pattern,
+											array $searchProperties,
+											array $options = []): array {
 		$escapePattern = !\array_key_exists('escape_like_param', $options) || $options['escape_like_param'] !== false;
 
 		$query2 = $this->db->getQueryBuilder();
-		$or = $query2->expr()->orX();
+
+		$addressBookOr =  $query2->expr()->orX();
+		foreach ($addressBookIds as $addressBookId) {
+			$addressBookOr->add($query2->expr()->eq('cp.addressbookid', $query2->createNamedParameter($addressBookId)));
+		}
+
+		if ($addressBookOr->count() === 0) {
+			return [];
+		}
+
+		$propertyOr = $query2->expr()->orX();
 		foreach ($searchProperties as $property) {
 			if ($escapePattern) {
 				if ($property === 'EMAIL' && strpos($pattern, ' ') !== false) {
@@ -980,17 +1024,17 @@ class CardDavBackend implements BackendInterface, SyncSupport {
 				}
 			}
 
-			$or->add($query2->expr()->eq('cp.name', $query2->createNamedParameter($property)));
+			$propertyOr->add($query2->expr()->eq('cp.name', $query2->createNamedParameter($property)));
 		}
 
-		if ($or->count() === 0) {
+		if ($propertyOr->count() === 0) {
 			return [];
 		}
 
 		$query2->selectDistinct('cp.cardid')
 			->from($this->dbCardsPropertiesTable, 'cp')
-			->andWhere($query2->expr()->eq('cp.addressbookid', $query2->createNamedParameter($addressBookId)))
-			->andWhere($or);
+			->andWhere($addressBookOr)
+			->andWhere($propertyOr);
 
 		// No need for like when the pattern is empty
 		if ('' !== $pattern) {
@@ -1016,7 +1060,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
 		}, $matches);
 
 		$query = $this->db->getQueryBuilder();
-		$query->select('c.carddata', 'c.uri')
+		$query->select('c.addressbookid', 'c.carddata', 'c.uri')
 			->from($this->dbCardsTable, 'c')
 			->where($query->expr()->in('c.id', $query->createNamedParameter($matches, IQueryBuilder::PARAM_INT_ARRAY)));
 
@@ -1026,6 +1070,7 @@ class CardDavBackend implements BackendInterface, SyncSupport {
 		$result->closeCursor();
 
 		return array_map(function ($array) {
+			$array['addressbookid'] = (int) $array['addressbookid'];
 			$modified = false;
 			$array['carddata'] = $this->readBlob($array['carddata'], $modified);
 			if ($modified) {
-- 
cgit v1.2.3