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

AFactory::isValid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
dl 0
loc 2
ccs 2
cts 2
cp 1
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 1
crap 1
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 1
	public function get(string $name): object {
32 1
		$needle = strtolower($name);
33 1
		if (isset($this->instances[$needle])) {
34
			return $this->instances[$needle];
35
		}
36
37 1
		foreach ($this->getFqcnList() as $fqcn) {
38 1
			$type = $this->typeFrom($fqcn);
39 1
			if ($type !== $needle && $fqcn !== $name) {
40 1
				continue;
41
			}
42
			$instance = \OCP\Server::get($fqcn);
43
			$this->instances[$type] = $instance;
44
			return $instance;
45
		}
46
47 1
		throw new \InvalidArgumentException("Invalid type <$name>");
48
	}
49
50
	/** @return array<string> */
51 2
	public function getFqcnList(): array {
52 2
		if (!empty($this->fqcn)) {
53
			return $this->fqcn;
54
		}
55
56 2
		$loader = require __DIR__ . '/../../vendor/autoload.php';
57 2
		foreach ($loader->getClassMap() as $fqcn => $_) {
58 2
			$type = $this->typeFrom($fqcn);
59 2
			if ($type === null) {
60 2
				continue;
61
			}
62 2
			if (!is_subclass_of($fqcn, $this->getBaseClass(), true)) {
63
				continue;
64
			}
65 2
			$this->fqcn[] = $fqcn;
66
		}
67 2
		return $this->fqcn;
68
	}
69
70 2
	protected function typeFrom(string $fqcn): ?string {
71 2
		$prefix = $this->getPrefix();
72 2
		if (strncmp($fqcn, $prefix, strlen($prefix)) !== 0) {
73 2
			return null;
74
		}
75 2
		$suffix = $this->getSuffix();
76 2
		if (!str_ends_with($fqcn, $suffix)) {
77 1
			return null;
78
		}
79 2
		$type = substr($fqcn, strlen($prefix));
80 2
		$type = substr($type, 0, -strlen('\\' . $suffix));
81 2
		if (strpos($type, '\\') !== false || $type === '') {
82
			return null;
83
		}
84 2
		return strtolower($type);
85
	}
86
}
87