Completed
Push — master ( 347a51...ad246f )
by Maxence
02:23
created

ProviderService::getProvider()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch - Full text search framework for 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\Service;
32
33
34
use Exception;
35
use OC\App\AppManager;
36
use OCA\FullTextSearch\AppInfo\Application;
37
use OCA\FullTextSearch\Exceptions\ProviderDoesNotExistException;
38
use OCA\FullTextSearch\Exceptions\ProviderIsNotCompatibleException;
39
use OCA\FullTextSearch\Exceptions\ProviderIsNotUniqueException;
40
use OCA\FullTextSearch\Exceptions\ProviderOptionsDoesNotExistException;
41
use OCA\FullTextSearch\Model\ProviderWrapper;
42
use OCP\AppFramework\QueryException;
43
use OCP\FullTextSearch\IFullTextSearchProvider;
44
use OCP\FullTextSearch\Service\IProviderService;
45
use OCP\Util;
46
47
48
/**
49
 * Class ProviderService
50
 *
51
 * @package OCA\FullTextSearch\Service
52
 */
53
class ProviderService implements IProviderService {
54
55
56
	/** @var AppManager */
57
	private $appManager;
58
59
	/** @var ConfigService */
60
	private $configService;
61
62
	/** @var MiscService */
63
	private $miscService;
64
65
	/** @var ProviderWrapper[] */
66
	private $providers = [];
67
68
	/** @var bool */
69
	private $providersLoaded = false;
70
71
72
	/**
73
	 * ProviderService constructor.
74
	 *
75
	 * @param AppManager $appManager
76
	 * @param ConfigService $configService
77
	 * @param MiscService $miscService
78
	 */
79
	public function __construct(
80
		AppManager $appManager, ConfigService $configService, MiscService $miscService
81
	) {
82
		$this->appManager = $appManager;
83
		$this->configService = $configService;
84
		$this->miscService = $miscService;
85
	}
86
87
88
	/**
89
	 * Load all FullTextSearchProviders set in any info.xml file
90
	 *
91
	 * @throws Exception
92
	 */
93 View Code Duplication
	private function loadProviders() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
94
		if ($this->providersLoaded) {
95
			return;
96
		}
97
98
		try {
99
			$apps = $this->appManager->getInstalledApps();
100
			foreach ($apps as $appId) {
101
				$this->loadProvidersFromApp($appId);
102
			}
103
		} catch (Exception $e) {
104
			$this->miscService->log($e->getMessage());
105
		}
106
107
		$this->providersLoaded = true;
108
	}
109
110
111
	/**
112
	 * @param string $appId
113
	 * @param string $providerId
114
	 *
115
	 * @throws ProviderIsNotCompatibleException
116
	 * @throws ProviderIsNotUniqueException
117
	 * @throws QueryException
118
	 */
119
	public function loadProvider(string $appId, string $providerId) {
120
121
		$provider = \OC::$server->query((string)$providerId);
122
		if (!($provider instanceof IFullTextSearchProvider)) {
0 ignored issues
show
Bug introduced by
The class OCP\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...
123
			throw new ProviderIsNotCompatibleException(
124
				$providerId . ' is not a compatible IFullTextSearchProvider'
125
			);
126
		}
127
128
		$this->providerIdMustBeUnique($provider);
129
130
		try {
131
			$provider->loadProvider();
132
			$wrapper = new ProviderWrapper($appId, $provider);
133
			$wrapper->setVersion($this->configService->getAppVersion($appId));
134
			$this->providers[] = $wrapper;
135
		} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
136
		}
137
	}
138
139
140
	/**
141
	 * @return ProviderWrapper[]
142
	 * @throws Exception
143
	 */
144
	public function getProviders(): array {
145
		$this->loadProviders();
146
147
		return $this->providers;
148
	}
149
150
	/**
151
	 * @return IFullTextSearchProvider[]
152
	 * @throws Exception
153
	 */
154
	public function getConfiguredProviders(): array {
155
		$this->loadProviders();
156
157
		$providers = [];
158
		foreach ($this->providers as $providerWrapper) {
159
			$provider = $providerWrapper->getProvider();
160
			if ($this->isProviderIndexed($provider->getId())) {
161
				$providers[] = $provider;
162
			}
163
		}
164
165
		return $providers;
166
	}
167
168
169
	/**
170
	 * @param array $providerList
171
	 *
172
	 * @return IFullTextSearchProvider[]
173
	 * @throws Exception
174
	 * @throws ProviderDoesNotExistException
175
	 */
176
	public function getFilteredProviders(array $providerList): array {
177
		$this->loadProviders();
178
179
		$providers = $this->getConfiguredProviders();
180
		if (in_array('all', $providerList)) {
181
			return $providers;
182
		}
183
184
		$ret = [];
185
		foreach ($providerList as $providerId) {
186
			if ($this->isProviderIndexed($providerId)) {
187
				$providerWrapper = $this->getProvider($providerId);
188
				$ret[] = $providerWrapper->getProvider();
189
			}
190
		}
191
192
		return $ret;
193
	}
194
195
196
	/**
197
	 * @param string $providerId
198
	 *
199
	 * @return ProviderWrapper
200
	 * @throws Exception
201
	 * @throws ProviderDoesNotExistException
202
	 */
203
	public function getProvider(string $providerId): ProviderWrapper {
204
205
		$providers = $this->getProviders();
206
		foreach ($providers as $providerWrapper) {
207
			$provider = $providerWrapper->getProvider();
208
			if ($provider->getId() === $providerId) {
209
				return $providerWrapper;
210
			}
211
		}
212
213
		throw new ProviderDoesNotExistException('Provider \'' . $providerId . '\' does not exist');
214
	}
215
216
217
	/**
218
	 * @param string $providerId
219
	 *
220
	 * @return bool
221
	 */
222
	public function isProviderIndexed(string $providerId): bool {
223
		try {
224
			$indexed = $this->configService->getProviderOptions(
225
				$providerId, ConfigService::PROVIDER_INDEXED
226
			);
227
		} catch (ProviderOptionsDoesNotExistException $e) {
228
			return false;
229
		}
230
231
		if ($indexed === '1') {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $indexed === '1';.
Loading history...
232
			return true;
233
		}
234
235
		return false;
236
237
	}
238
239
240
	/**
241
	 * @param IFullTextSearchProvider $provider
242
	 * @param bool $boolean
243
	 */
244
	public function setProviderAsIndexed(IFullTextSearchProvider $provider, bool $boolean) {
245
		$this->configService->setProviderOptions(
246
			$provider->getId(), ConfigService::PROVIDER_INDEXED, (($boolean) ? '1' : '0')
247
		);
248
	}
249
250
251
	/**
252
	 *
253
	 */
254
	public function setProvidersAsNotIndexed() {
255
		$this->configService->resetProviderOptions(ConfigService::PROVIDER_INDEXED);
256
	}
257
258
259
	/**
260
	 * @param string $appId
261
	 *
262
	 * @throws ProviderIsNotCompatibleException
263
	 * @throws ProviderIsNotUniqueException
264
	 * @throws QueryException
265
	 */
266
	private function loadProvidersFromApp(string $appId) {
267
		$appInfo = $this->appManager->getAppInfo($appId);
268 View Code Duplication
		if (!is_array($appInfo) || !key_exists('fulltextsearch', $appInfo)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
269
			|| !key_exists('provider', $appInfo['fulltextsearch'])) {
270
			return;
271
		}
272
273
		$providers = $appInfo['fulltextsearch']['provider'];
274
		if (!is_array($providers)) {
275
			$providers = [$providers];
276
		}
277
278
		$this->loadProvidersFromList($appId, $providers);
279
	}
280
281
282
	/**
283
	 * @param string $appId
284
	 * @param array $providers
285
	 *
286
	 * @throws ProviderIsNotCompatibleException
287
	 * @throws ProviderIsNotUniqueException
288
	 * @throws QueryException
289
	 */
290
	private function loadProvidersFromList(string $appId, array $providers) {
291
		if (!is_array($providers)) {
292
			$providers = [$providers];
293
		}
294
295
		foreach ($providers AS $provider) {
296
			$this->loadProvider($appId, $provider);
297
		}
298
	}
299
300
301
	/**
302
	 * @param IFullTextSearchProvider $provider
303
	 *
304
	 * @throws ProviderIsNotUniqueException
305
	 * @throws Exception
306
	 */
307
	private function providerIdMustBeUnique(IFullTextSearchProvider $provider) {
308
		foreach ($this->providers AS $providerWrapper) {
309
			$knownProvider = $providerWrapper->getProvider();
310
			if ($knownProvider->getId() === $provider->getId()) {
311
				throw new ProviderIsNotUniqueException(
312
					'FullTextSearchProvider ' . $provider->getId() . ' already exist'
313
				);
314
			}
315
		}
316
	}
317
318
319
	/**
320
	 * @param IFullTextSearchProvider[] $providers
321
	 *
322
	 * @return array
323
	 */
324
	public function serialize(array $providers): array {
325
		$arr = [];
326
		foreach ($providers as $provider) {
327
			$arr[] = [
328
				'id'   => $provider->getId(),
329
				'name' => $provider->getName()
330
			];
331
		}
332
333
		return $arr;
334
	}
335
336
337
	/**
338
	 *
339
	 */
340
	public function addJavascriptAPI() {
341
		Util::addStyle(Application::APP_NAME, 'fulltextsearch');
342
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.api');
343
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.settings');
344
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.searchbox');
345
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.result');
346
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1.navigation');
347
		Util::addScript(Application::APP_NAME, 'fulltextsearch.v1');
348
	}
349
350
351
}
352