Completed
Pull Request — master (#76)
by Maxence
01:21
created

SearchService::getDocumentInfos()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8977
c 0
b 0
f 0
cc 6
nc 6
nop 2
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch_ElasticSearch - Use Elasticsearch to index the content of your nextcloud
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\FullTextSearch_ElasticSearch\Service;
32
33
34
use daita\MySmallPhpTools\Traits\TArrayTools;
35
use Elasticsearch\Client;
36
use Exception;
37
use OC\FullTextSearch\Model\DocumentAccess;
38
use OC\FullTextSearch\Model\IndexDocument;
39
use OCA\FullTextSearch_ElasticSearch\Exceptions\ConfigurationException;
40
use OCA\FullTextSearch_ElasticSearch\Exceptions\SearchQueryGenerationException;
41
use OCP\FullTextSearch\Model\IDocumentAccess;
42
use OCP\FullTextSearch\Model\IIndexDocument;
43
use OCP\FullTextSearch\Model\ISearchResult;
44
45
46
/**
47
 * Class SearchService
48
 *
49
 * @package OCA\FullTextSearch_ElasticSearch\Service
50
 */
51
class SearchService {
52
53
54
	use TArrayTools;
55
56
57
	/** @var SearchMappingService */
58
	private $searchMappingService;
59
60
	/** @var MiscService */
61
	private $miscService;
62
63
64
	/**
65
	 * SearchService constructor.
66
	 *
67
	 * @param SearchMappingService $searchMappingService
68
	 * @param MiscService $miscService
69
	 */
70
	public function __construct(
71
		SearchMappingService $searchMappingService, MiscService $miscService
72
	) {
73
		$this->searchMappingService = $searchMappingService;
74
		$this->miscService = $miscService;
75
	}
76
77
	/**
78
	 * @param Client $client
79
	 * @param ISearchResult $searchResult
80
	 * @param IDocumentAccess $access
81
	 *
82
	 * @throws Exception
83
	 */
84
	public function searchRequest(
85
		Client $client, ISearchResult $searchResult, IDocumentAccess $access
86
	) {
87
		try {
88
			$query = $this->searchMappingService->generateSearchQuery(
89
				$searchResult->getRequest(), $access, $searchResult->getProvider()
90
																   ->getId()
91
			);
92
		} catch (SearchQueryGenerationException $e) {
93
			return;
94
		}
95
96
		try {
97
			$result = $client->search($query['params']);
98
		} catch (Exception $e) {
99
			$this->miscService->log(
100
				'debug - request: ' . json_encode($searchResult->getRequest()) . '   - query: '
101
				. json_encode($query)
102
			);
103
			throw $e;
104
		}
105
106
		$this->updateSearchResult($searchResult, $result);
0 ignored issues
show
Documentation introduced by
$result is of type callable, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107
108
		foreach ($result['hits']['hits'] as $entry) {
109
			$searchResult->addDocument($this->parseSearchEntry($entry, $access->getViewerId()));
110
		}
111
	}
112
113
114
	/**
115
	 * @param Client $client
116
	 * @param string $providerId
117
	 * @param string $documentId
118
	 *
119
	 * @return IIndexDocument
120
	 * @throws ConfigurationException
121
	 */
122
	public function getDocument(Client $client, string $providerId, string $documentId
123
	): IIndexDocument {
124
		$query = $this->searchMappingService->getDocumentQuery($providerId, $documentId);
125
		$result = $client->get($query);
126
127
		$access = new DocumentAccess($result['_source']['owner']);
128
		$access->setUsers($result['_source']['users']);
129
		$access->setGroups($result['_source']['groups']);
130
		$access->setCircles($result['_source']['circles']);
131
		$access->setLinks($result['_source']['links']);
132
133
		$index = new IndexDocument($providerId, $documentId);
134
		$index->setAccess($access);
135
		$index->setMetaTags($result['_source']['metatags']);
136
		$index->setSubTags($result['_source']['subtags']);
137
		$index->setTags($result['_source']['tags']);
138
//		$index->setMore($result['_source']['more']);
139
		$index->setHash($result['_source']['hash']);
140
		$index->setSource($result['_source']['source']);
141
		$index->setTitle($result['_source']['title']);
142
		$index->setParts($result['_source']['parts']);
143
144
		$this->getDocumentInfos($index, $result['_source']);
145
146
		$content = $this->get('content', $result['_source'], '');
147
		$index->setContent($content);
148
149
		return $index;
150
	}
151
152
153
	/**
154
	 * @param IndexDocument $index
155
	 * @param $source
156
	 */
157
	private function getDocumentInfos(IndexDocument $index, $source) {
158
		$ak = array_keys($source);
159
		foreach ($ak as $k) {
160
			if (substr($k, 0, 5) !== 'info_') {
161
				continue;
162
			}
163
			$value = $source[$k];
164
			if (is_array($value)) {
165
				$index->setInfoArray($k, $value);
166
				continue;
167
			}
168
169
			if (is_bool($value)) {
170
				$index->setInfoBool($k, $value);
171
				continue;
172
			}
173
174
			if (is_numeric($value)) {
175
				$index->setInfoInt($k, (int)$value);
176
				continue;
177
			}
178
179
			$index->setInfo($k, (string)$value);
180
		}
181
	}
182
183
184
	/**
185
	 * @param ISearchResult $searchResult
186
	 * @param array $result
187
	 */
188
	private function updateSearchResult(ISearchResult $searchResult, array $result) {
189
		$searchResult->setRawResult(json_encode($result));
190
191
		$total = $result['hits']['total'];
192
		if (is_array($total)) {
193
			$total = $total['value'];
194
		}
195
196
		$searchResult->setTotal($total);
197
		$searchResult->setMaxScore($this->getInt('max_score', $result['hits'], 0));
198
		$searchResult->setTime($result['took']);
199
		$searchResult->setTimedOut($result['timed_out']);
200
	}
201
202
203
	/**
204
	 * @param array $entry
205
	 * @param string $viewerId
206
	 *
207
	 * @return IIndexDocument
208
	 */
209
	private function parseSearchEntry(array $entry, string $viewerId): IIndexDocument {
210
		$access = new DocumentAccess();
211
		$access->setViewerId($viewerId);
212
213
		list($providerId, $documentId) = explode(':', $entry['_id'], 2);
214
		$document = new IndexDocument($providerId, $documentId);
215
		$document->setAccess($access);
216
		$document->setHash($this->get('hash', $entry['_source']));
217
		$document->setScore($this->get('_score', $entry, '0'));
218
		$document->setSource($this->get('source', $entry['_source']));
219
		$document->setTitle($this->get('title', $entry['_source']));
220
221
		$document->setExcerpts(
222
			$this->parseSearchEntryExcerpts(
223
				(array_key_exists('highlight', $entry)) ? $entry['highlight'] : []
224
			)
225
		);
226
227
		return $document;
228
	}
229
230
231
	private function parseSearchEntryExcerpts(array $highlights): array {
232
		$result = [];
233
		foreach (array_keys($highlights) as $source) {
234
			foreach ($highlights[$source] as $highlight) {
235
				$result[] =
236
					[
237
						'source'  => $source,
238
						'excerpt' => $highlight
239
					];
240
			}
241
		}
242
243
		return $result;
244
	}
245
246
}
247
248