Completed
Push — master ( f99325...c38ca7 )
by Maxence
01:45
created

ElasticSearchPlatform::getVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * FullTextSearch_ElasticSearch - Use Elasticsearch to index the content of your nextcloud
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2018
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\FullTextSearch_ElasticSearch\Platform;
28
29
use Elasticsearch\Client;
30
use Elasticsearch\ClientBuilder;
31
use Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost;
32
use Elasticsearch\Common\Exceptions\MaxRetriesException;
33
use Exception;
34
use OCA\FullTextSearch\Exceptions\InterruptException;
35
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
36
use OCA\FullTextSearch\IFullTextSearchPlatform;
37
use OCA\FullTextSearch\IFullTextSearchProvider;
38
use OCA\FullTextSearch\Model\DocumentAccess;
39
use OCA\FullTextSearch\Model\Index;
40
use OCA\FullTextSearch\Model\IndexDocument;
41
use OCA\FullTextSearch\Model\Runner;
42
use OCA\FullTextSearch_ElasticSearch\AppInfo\Application;
43
use OCA\FullTextSearch_ElasticSearch\Exceptions\ConfigurationException;
44
use OCA\FullTextSearch_ElasticSearch\Service\ConfigService;
45
use OCA\FullTextSearch_ElasticSearch\Service\IndexService;
46
use OCA\FullTextSearch_ElasticSearch\Service\MiscService;
47
use OCA\FullTextSearch_ElasticSearch\Service\SearchService;
48
use OCP\AppFramework\QueryException;
49
50
51
class ElasticSearchPlatform implements IFullTextSearchPlatform {
52
53
	/** @var ConfigService */
54
	private $configService;
55
56
	/** @var IndexService */
57
	private $indexService;
58
59
	/** @var SearchService */
60
	private $searchService;
61
62
	/** @var MiscService */
63
	private $miscService;
64
65
	/** @var Client */
66
	private $client;
67
68
	/** @var Runner */
69
	private $runner;
70
71
72
	/**
73
	 * return a unique Id of the platform.
74
	 */
75
	public function getId() {
76
		return 'elastic_search';
77
	}
78
79
	/**
80
	 * return a unique Id of the platform.
81
	 */
82
	public function getName() {
83
		return 'Elasticsearch';
84
	}
85
86
87
	/**
88
	 * @return string
89
	 */
90
	public function getVersion() {
91
		return $this->configService->getAppValue('installed_version');
92
	}
93
94
//	public function getClient() {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
95
//		return $this->client;
96
//	}
97
98
99
	/**
100
	 * @param Runner $runner
101
	 */
102
	public function setRunner(Runner $runner) {
103
		$this->runner = $runner;
104
	}
105
106
	/**
107
	 * @param $action
108
	 *
109
	 * @throws InterruptException
110
	 * @throws TickDoesNotExistException
111
	 */
112
	private function updateRunner($action) {
113
		if ($this->runner === null) {
114
			return;
115
		}
116
117
		$this->runner->update($action);
118
	}
119
120
121
	/**
122
	 * @param $line
123
	 */
124
	private function outputRunner($line) {
125
		if ($this->runner === null) {
126
			return;
127
		}
128
129
		$this->runner->output($line);
130
	}
131
132
133
	/**
134
	 * Called when loading the platform.
135
	 *
136
	 * Loading some container and connect to ElasticSearch.
137
	 *
138
	 * @throws ConfigurationException
139
	 * @throws QueryException
140
	 */
141
	public function loadPlatform() {
142
		$app = new Application();
143
144
		$container = $app->getContainer();
145
		$this->configService = $container->query(ConfigService::class);
146
		$this->indexService = $container->query(IndexService::class);
147
		$this->searchService = $container->query(SearchService::class);
148
		$this->miscService = $container->query(MiscService::class);
149
150
		try {
151
			$this->connectToElastic($this->configService->getElasticHost());
152
		} catch (ConfigurationException $e) {
153
			throw $e;
154
		}
155
	}
156
157
158
	/**
159
	 * not used yet.
160
	 */
161
	public function testPlatform() {
162
	}
163
164
165
	/**
166
	 * called before any index
167
	 *
168
	 * We create a general index.
169
	 *
170
	 * @param IFullTextSearchProvider $provider
171
	 *
172
	 * @throws ConfigurationException
173
	 */
174
	public function initializeIndex(IFullTextSearchProvider $provider) {
175
		$this->indexService->initializeIndex($this->client);
176
177
		$provider->onInitializingIndex($this);
178
	}
179
180
181
	/**
182
	 * resetIndex();
183
	 *
184
	 * Called when admin wants to remove an index specific to a $provider.
185
	 * $provider can be null, meaning a reset of the whole index.
186
	 *
187
	 * @param IFullTextSearchProvider|null $provider
188
	 *
189
	 * @throws ConfigurationException
190
	 */
191
	public function resetIndex($provider) {
192
193
		if ($provider instanceof IFullTextSearchProvider) {
0 ignored issues
show
Bug introduced by
The class OCA\FullTextSearch\IFullTextSearchProvider does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
194
			// TODO: need to specify the map to remove
195
			// TODO: need to remove entries with type=providerId
196
			$provider->onResettingIndex($this);
197
		}
198
199
		$this->indexService->resetIndex($this->client);
200
	}
201
202
203
	/**
204
	 * {@inheritdoc}
205
	 */
206
	public function indexDocuments(IFullTextSearchProvider $provider, $documents) {
207
		$indexes = [];
208
		foreach ($documents as $document) {
209
			$index = $this->indexDocument($provider, $document);
210
			if ($index !== null) {
211
				$indexes[] = $index;
212
			}
213
		}
214
215
		return $indexes;
216
	}
217
218
219
	/**
220
	 * {@inheritdoc}
221
	 */
222
	public function indexDocument(IFullTextSearchProvider $provider, IndexDocument $document) {
223
224
		$this->updateRunner('indexDocument');
225
		$this->outputRunner(' . Indexing: ' . $document->getTitle());
226
227
		try {
228
			$result = $this->indexService->indexDocument($this, $this->client, $provider, $document);
229
			$this->outputRunner('  result: ' . json_encode($result));
230
231
			return $this->indexService->parseIndexResult($document->getIndex(), $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...
232
		} catch (Exception $e) {
233
			return $this->indexDocumentError($provider, $document, $e);
234
		}
235
236
	}
237
238
239
	/**
240
	 * @param IFullTextSearchProvider $provider
241
	 * @param IndexDocument $document
242
	 * @param Exception $e
243
	 *
244
	 * @return Index
245
	 * @throws ConfigurationException
246
	 */
247
	private function indexDocumentError(
248
		IFullTextSearchProvider $provider, IndexDocument $document, Exception $e
249
	) {
250
		$message = [
251
			'exception' => get_class($e),
252
			'message'   => $e->getMessage()
253
		];
254
255
		$document->setContent(null);
256
		$index = $document->getIndex();
257
		$index->unsetStatus(Index::INDEX_CONTENT);
258
		$index->setMessage(json_encode($message));
259
260
		$result = $this->indexService->indexDocument($this, $this->client, $provider, $document);
261
		$this->outputRunner('  result with no content: ' . json_encode($result));
262
263
		return $this->indexService->parseIndexResult($document->getIndex(), $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...
264
	}
265
266
267
	/**
268
	 * {@inheritdoc}
269
	 */
270
	public function deleteIndexes($indexes) {
271
		try {
272
			$this->indexService->deleteIndexes($this->client, $indexes);
273
		} catch (ConfigurationException $e) {
274
			throw $e;
275
		}
276
	}
277
278
279
	/**
280
	 * {@inheritdoc}
281
	 */
282
	public function searchDocuments(IFullTextSearchProvider $provider, DocumentAccess $access, $request
283
	) {
284
		try {
285
			return $this->searchService->searchDocuments(
286
				$this, $this->client, $provider, $access, $request
287
			);
288
		} catch (ConfigurationException $e) {
289
			throw $e;
290
		}
291
	}
292
293
294
	/**
295
	 * @param string $host
296
	 */
297
	private function connectToElastic($host) {
298
299
		try {
300
			$hosts = [MiscService::noEndSlash($host)];
301
			$this->client = ClientBuilder::create()
302
										 ->setHosts($hosts)
303
										 ->setRetries(2)
304
										 ->build();
305
306
		} catch (CouldNotConnectToHost $e) {
307
			echo 'CouldNotConnectToHost';
308
			$previous = $e->getPrevious();
309
			if ($previous instanceof MaxRetriesException) {
310
				echo "Max retries!";
311
			}
312
		} catch (Exception $e) {
313
			echo ' ElasticSearchPlatform::load() Exception --- ' . $e->getMessage() . "\n";
314
		}
315
	}
316
317
318
}