Passed
Pull Request — master (#686)
by Vitor
04:56
created

AFactory::getFqcnList()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5.0144

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 17
ccs 11
cts 12
cp 0.9167
rs 9.6111
cc 5
nc 5
nop 0
crap 5.0144
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * SPDX-FileCopyrightText: 2025 LibreCode coop and contributors
6
 * SPDX-License-Identifier: AGPL-3.0-or-later
7
 */
8
9
namespace OCA\TwoFactorGateway\Provider;
10
11
/**
12
 * @template T of object
13
 */
14
abstract class AFactory {
15
	/** @var array<string, T> */
16
	protected array $instances = [];
17
	/** @var array<string> */
18
	protected array $fqcn = [];
19
20
	abstract protected function getPrefix(): string;
21
22
	abstract protected function getSuffix(): string;
23
24
	/** @return class-string<T> */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
25
	abstract protected function getBaseClass(): string;
26
27
	/**
28
	 * @param class-string<T> $name
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
29
	 * @return T
30
	 */
31 2
	public function get(string $name): object {
32 2
		$needle = match(str_contains($name, '\\')) {
33 1
			true => $this->typeFrom($name),
34 1
			false => strtolower($name),
35 2
		};
36 2
		if (isset($this->instances[$needle])) {
37
			return $this->instances[$needle];
38
		}
39
40 2
		foreach ($this->getFqcnList() as $fqcn) {
41 2
			$type = $this->typeFrom($fqcn);
42 2
			if ($type !== $needle) {
43 2
				continue;
44
			}
45 1
			$instance = \OCP\Server::get($fqcn);
46 1
			$this->instances[$type] = $instance;
47 1
			return $instance;
48
		}
49
50 1
		throw new \InvalidArgumentException("Invalid type <$name>");
51
	}
52
53
	/** @return array<string> */
54 3
	public function getFqcnList(): array {
55 3
		if (!empty($this->fqcn)) {
56 1
			return $this->fqcn;
57
		}
58
59 3
		$loader = require __DIR__ . '/../../vendor/autoload.php';
60 3
		foreach ($loader->getClassMap() as $fqcn => $_) {
61 3
			$type = $this->typeFrom($fqcn);
62 3
			if ($type === null) {
63 3
				continue;
64
			}
65 3
			if (!is_subclass_of($fqcn, $this->getBaseClass(), true)) {
66
				continue;
67
			}
68 3
			$this->fqcn[] = $fqcn;
69
		}
70 3
		return $this->fqcn;
71
	}
72
73 3
	protected function typeFrom(string $fqcn): ?string {
74 3
		$prefix = $this->getPrefix();
75 3
		if (strncmp($fqcn, $prefix, strlen($prefix)) !== 0) {
76 3
			return null;
77
		}
78 3
		$suffix = $this->getSuffix();
79 3
		if (!str_ends_with($fqcn, $suffix)) {
80 2
			return null;
81
		}
82 3
		$type = substr($fqcn, strlen($prefix));
83 3
		$type = substr($type, 0, -strlen('\\' . $suffix));
84 3
		if (strpos($type, '\\') !== false || $type === '') {
85
			return null;
86
		}
87 3
		return strtolower($type);
88
	}
89
}
90