Completed
Push — master ( c3c93d...f456aa )
by Maxence
03:02 queued 11s
created

InterfaceService   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 6
dl 0
loc 271
rs 9.1199
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A setCurrentInterface() 0 3 1
A getCurrentInterface() 0 7 2
A hasCurrentInterface() 0 3 1
B setCurrentInterfaceFromRequest() 0 29 6
A getInterfaceFromInstance() 0 5 1
A setCurrentInterfaceFromInstance() 0 6 2
A getInterfaces() 0 22 3
B getCloudInstance() 0 18 9
B getCloudPath() 0 41 11
A getLocalInstance() 0 10 3
A getTestingInstance() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like InterfaceService often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use InterfaceService, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\Service;
33
34
35
use daita\MySmallPhpTools\Traits\TArrayTools;
36
use daita\MySmallPhpTools\Traits\TStringTools;
37
use OCA\Circles\Db\RemoteRequest;
38
use OCA\Circles\Exceptions\RemoteNotFoundException;
39
use OCA\Circles\Exceptions\UnknownInterfaceException;
40
use OCP\IRequest;
41
use OCP\IURLGenerator;
42
43
44
/**
45
 * Class InterfaceService
46
 *
47
 * @package OCA\Circles\Service
48
 */
49
class InterfaceService {
50
51
	const IFACE0 = 1;
52
	const IFACE1 = 2;
53
	const IFACE2 = 3;
54
	const IFACE3 = 4;
55
	const IFACE4 = 5;
56
	const IFACE_INTERNAL = 6;
57
	const IFACE_FRONTAL = 7;
58
	const IFACE_TEST = 99;
59
60
	public static $LIST_IFACE = [
61
		self::IFACE_INTERNAL => 'internal',
62
		self::IFACE_FRONTAL  => 'frontal',
63
		self::IFACE0         => 'iface0',
64
		self::IFACE1         => 'iface1',
65
		self::IFACE2         => 'iface2',
66
		self::IFACE3         => 'iface3',
67
		self::IFACE4         => 'iface4',
68
	];
69
70
71
	use TStringTools;
72
	use TArrayTools;
73
74
75
	/** @var IURLGenerator */
76
	private $urlGenerator;
77
78
	/** @var RemoteRequest */
79
	private $remoteRequest;
80
81
	/** @var ConfigService */
82
	private $configService;
83
84
85
	/** @var int */
86
	private $currentInterface = 0;
87
88
	/** @var int */
89
	private $outgoingInterface = 0;
90
91
92
	/**
93
	 * InterfaceService constructor.
94
	 *
95
	 * @param IURLGenerator $urlGenerator
96
	 * @param RemoteRequest $remoteRequest
97
	 * @param ConfigService $configService
98
	 */
99
	public function __construct(
100
		IURLGenerator $urlGenerator,
101
		RemoteRequest $remoteRequest,
102
		ConfigService $configService
103
	) {
104
		$this->urlGenerator = $urlGenerator;
105
		$this->remoteRequest = $remoteRequest;
106
		$this->configService = $configService;
107
	}
108
109
110
	/**
111
	 * @param int $interface
112
	 */
113
	public function setCurrentInterface(int $interface): void {
114
		$this->currentInterface = $interface;
115
	}
116
117
	/**
118
	 * @return int
119
	 * @throws UnknownInterfaceException
120
	 */
121
	public function getCurrentInterface(): int {
122
		if ($this->currentInterface === 0) {
123
			throw new UnknownInterfaceException('interface not initialized');
124
		}
125
126
		return $this->currentInterface;
127
	}
128
129
	/**
130
	 * @return bool
131
	 */
132
	public function hasCurrentInterface(): bool {
133
		return ($this->currentInterface !== 0);
134
	}
135
136
137
	/**
138
	 * @param IRequest $request
139
	 * @param string $testToken
140
	 */
141
	public function setCurrentInterfaceFromRequest(IRequest $request, string $testToken = ''): void {
142
		$testing = [
143
			self::IFACE_INTERNAL => $this->configService->getInternalInstance(),
144
			self::IFACE_FRONTAL  => $this->configService->getFrontalInstance(),
145
			self::IFACE0         => $this->configService->getIfaceInstance(self::IFACE0),
146
			self::IFACE1         => $this->configService->getIfaceInstance(self::IFACE1),
147
			self::IFACE2         => $this->configService->getIfaceInstance(self::IFACE2),
148
			self::IFACE3         => $this->configService->getIfaceInstance(self::IFACE3),
149
			self::IFACE4         => $this->configService->getIfaceInstance(self::IFACE4),
150
		];
151
152
		if ($testToken !== ''
153
			&& $testToken === $this->configService->getAppValue(ConfigService::IFACE_TEST_TOKEN)) {
154
			$testing[self::IFACE_TEST] = $this->getTestingInstance();
155
		}
156
157
		$serverHost = strtolower($request->getServerHost());
158
		if ($serverHost === '') {
159
			return;
160
		}
161
162
		foreach ($testing as $iface => $instance) {
163
			if ($serverHost === strtolower($instance)) {
164
				$this->setCurrentInterface($iface);
165
166
				return;
167
			}
168
		}
169
	}
170
171
172
	/**
173
	 * @param string $instance
174
	 *
175
	 * @return int
176
	 * @throws RemoteNotFoundException
177
	 */
178
	public function getInterfaceFromInstance(string $instance): int {
179
		$remoteInstance = $this->remoteRequest->getFromInstance($instance);
180
181
		return $remoteInstance->getInterface();
182
	}
183
184
	/**
185
	 *
186
	 */
187
	public function setCurrentInterfaceFromInstance(string $instance): void {
188
		try {
189
			$this->setCurrentInterface($this->getInterfaceFromInstance($instance));
190
		} catch (RemoteNotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
191
		}
192
	}
193
194
195
	/**
196
	 * @param bool $useString
197
	 *
198
	 * @return array
199
	 */
200
	public function getInterfaces(bool $useString = false): array {
201
		$interfaces = [
202
			self::IFACE_INTERNAL => $this->configService->getInternalInstance(),
203
			self::IFACE_FRONTAL  => $this->configService->getFrontalInstance(),
204
			self::IFACE0         => $this->configService->getIfaceInstance(InterfaceService::IFACE0),
205
			self::IFACE1         => $this->configService->getIfaceInstance(InterfaceService::IFACE1),
206
			self::IFACE2         => $this->configService->getIfaceInstance(InterfaceService::IFACE2),
207
			self::IFACE3         => $this->configService->getIfaceInstance(InterfaceService::IFACE3),
208
			self::IFACE4         => $this->configService->getIfaceInstance(InterfaceService::IFACE4)
209
		];
210
211
		if (!$useString) {
212
			return $interfaces;
213
		}
214
215
		$detailed = [];
216
		foreach ($interfaces as $id => $iface) {
217
			$detailed[self::$LIST_IFACE[$id]] = $iface;
218
		}
219
220
		return $detailed;
221
	}
222
223
224
	/**
225
	 * use this only if interface must be defined. If not, use getLocalInstance()
226
	 *
227
	 * @throws UnknownInterfaceException
228
	 */
229
	public function getCloudInstance(): string {
230
		switch ($this->getCurrentInterface()) {
231
			case self::IFACE_INTERNAL:
232
				return $this->configService->getInternalInstance();
233
			case self::IFACE_FRONTAL:
234
				return $this->configService->getFrontalInstance();
235
			case self::IFACE0:
236
			case self::IFACE1:
237
			case self::IFACE2:
238
			case self::IFACE3:
239
			case self::IFACE4:
240
				return $this->configService->getIfaceInstance($this->getCurrentInterface());
241
			case self::IFACE_TEST:
242
				return $this->getTestingInstance();
243
		}
244
245
		throw new UnknownInterfaceException('unknown configured interface');
246
	}
247
248
249
	/**
250
	 * @throws UnknownInterfaceException
251
	 */
252
	public function getCloudPath(string $route = '', array $args = []): string {
253
		$scheme = '';
254
		switch ($this->getCurrentInterface()) {
255
			case self::IFACE_INTERNAL:
256
				$scheme = $this->configService->getAppValue(ConfigService::INTERNAL_CLOUD_SCHEME);
257
				break;
258
			case self::IFACE_FRONTAL:
259
				$scheme = $this->configService->getAppValue(ConfigService::FRONTAL_CLOUD_SCHEME);
260
				break;
261
			case self::IFACE0:
262
				$scheme = $this->configService->getAppValue(ConfigService::IFACE0_CLOUD_SCHEME);
263
				break;
264
			case self::IFACE1:
265
				$scheme = $this->configService->getAppValue(ConfigService::IFACE1_CLOUD_SCHEME);
266
				break;
267
			case self::IFACE2:
268
				$scheme = $this->configService->getAppValue(ConfigService::IFACE2_CLOUD_SCHEME);
269
				break;
270
			case self::IFACE3:
271
				$scheme = $this->configService->getAppValue(ConfigService::IFACE3_CLOUD_SCHEME);
272
				break;
273
			case self::IFACE4:
274
				$scheme = $this->configService->getAppValue(ConfigService::IFACE4_CLOUD_SCHEME);
275
				break;
276
			case self::IFACE_TEST:
277
				$scheme = $this->configService->getAppValue(ConfigService::IFACE_TEST_SCHEME);
278
				break;
279
		}
280
281
		if ($scheme === '') {
282
			throw new UnknownInterfaceException('misconfigured scheme');
283
		}
284
285
		$base = $scheme . '://' . $this->getCloudInstance();
286
287
		if ($route === '') {
288
			return $base;
289
		}
290
291
		return $base . $this->urlGenerator->linkToRoute($route, $args);
292
	}
293
294
295
	/**
296
	 * should be used when unsure about the used Interface
297
	 *
298
	 * @return string
299
	 */
300
	public function getLocalInstance(): string {
301
		if ($this->hasCurrentInterface()) {
302
			try {
303
				return $this->getCloudInstance();
304
			} catch (UnknownInterfaceException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
305
			}
306
		}
307
308
		return $this->configService->getLoopbackInstance();
309
	}
310
311
312
	/**
313
	 * @return string
314
	 */
315
	private function getTestingInstance(): string {
316
		return $this->configService->getAppValue(ConfigService::IFACE_TEST_ID);
317
	}
318
319
}
320
321