1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Archivr; |
4
|
|
|
|
5
|
|
|
use Archivr\Exception\Exception; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* todo: Consider replacement by reference implementation |
9
|
|
|
*/ |
10
|
|
|
abstract class AbstractFactory |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* Class is a singleton |
14
|
|
|
*/ |
15
|
|
|
private function __construct() {} |
16
|
|
|
|
17
|
|
|
protected static $factoryMaps = []; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Returns true if this factory provides the service of the given name. |
21
|
|
|
* |
22
|
|
|
* @param string $name |
23
|
|
|
* @return bool |
24
|
|
|
*/ |
25
|
|
|
public static function provides(string $name): bool |
26
|
|
|
{ |
27
|
|
|
static::loadFactoryMap(); |
28
|
|
|
|
29
|
|
|
return isset(static::$factoryMaps[static::class][$name]); |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Returns array of all service names that this factory provides. |
34
|
|
|
* |
35
|
|
|
* @return array |
36
|
|
|
*/ |
37
|
|
|
public static function getProvidedServiceNames(): array |
38
|
|
|
{ |
39
|
|
|
static::loadFactoryMap(); |
40
|
|
|
|
41
|
|
|
return array_keys(static::$factoryMaps[static::class]); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Creates and returns the service under the given name. |
46
|
|
|
* |
47
|
|
|
* @param string $name |
48
|
|
|
* @param array ...$params Parameters passed to the actual factory. |
49
|
|
|
* @return mixed |
50
|
|
|
* @throws Exception |
51
|
|
|
*/ |
52
|
|
|
public static function create(string $name, ...$params) |
53
|
|
|
{ |
54
|
|
|
static::loadFactoryMap(); |
55
|
|
|
|
56
|
|
|
$factoryMap = static::$factoryMaps[static::class]; |
57
|
|
|
|
58
|
|
|
if (!isset($factoryMap[$name])) |
59
|
|
|
{ |
60
|
|
|
throw new \InvalidArgumentException(sprintf('Factory "%s" does not provide "%s".', static::class, $name)); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
$factory = $factoryMap[$name]; |
64
|
|
|
|
65
|
|
|
if (is_string($factory)) |
66
|
|
|
{ |
67
|
|
|
$instance = new $factory(...$params); |
68
|
|
|
} |
69
|
|
|
elseif ($factory instanceof \Closure) |
70
|
|
|
{ |
71
|
|
|
$instance = $factory(...$params); |
72
|
|
|
} |
73
|
|
|
elseif (is_object($factory)) |
74
|
|
|
{ |
75
|
|
|
$instance = $factory; |
76
|
|
|
} |
77
|
|
|
else |
78
|
|
|
{ |
79
|
|
|
throw new \LogicException(); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
// check for correct interface/class if requirement is set |
83
|
|
|
if ($type = static::requiresInstanceOf()) |
84
|
|
|
{ |
85
|
|
|
if (!($instance instanceof $type)) |
86
|
|
|
{ |
87
|
|
|
throw new Exception(sprintf('Factory closure for "%s" does not return instance of %s. %s given.', $name, $type, is_object($instance) ? get_class($instance) : gettype($instance))); |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
return $instance; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Registers a n |
96
|
|
|
* |
97
|
|
|
* @param string $name |
98
|
|
|
* @param string|\Closure|object $factory |
99
|
|
|
* @param bool $allowOverride |
100
|
|
|
*/ |
101
|
|
|
public static function registerFactory(string $name, $factory, bool $allowOverride = false): void |
102
|
|
|
{ |
103
|
|
|
static::loadFactoryMap(); |
104
|
|
|
|
105
|
|
|
if (!$allowOverride && isset(static::$factoryMaps[static::class][$name])) |
106
|
|
|
{ |
107
|
|
|
throw new \RuntimeException(sprintf('Trying to register a factory named "%s" to "%s" which already exists.', $name, static::class)); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if (is_string($factory)) |
111
|
|
|
{ |
112
|
|
|
if (!class_exists($factory)) |
113
|
|
|
{ |
114
|
|
|
throw new \RuntimeException(sprintf('Trying to register factory named "%s" to "%s" as class name "%s" which does not exist.', $name, static::class, $factory)); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
elseif ($factory instanceof \Closure) |
|
|
|
|
118
|
|
|
{ |
119
|
|
|
// cannot really validate |
120
|
|
|
} |
121
|
|
|
elseif (is_object($factory)) |
122
|
|
|
{ |
123
|
|
|
if ($type = static::requiresInstanceOf()) |
124
|
|
|
{ |
125
|
|
|
if (!($factory instanceof $type)) |
126
|
|
|
{ |
127
|
|
|
throw new \RuntimeException(sprintf('Trying to register service instance named "%s" to "%s" as which is not an instance of "%s".', $name, static::class, $type)); |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
else |
132
|
|
|
{ |
133
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid factory of type "%s" named "%s" given to "%s".', gettype($factory), $name, static::class)); |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
static::$factoryMaps[static::class][$name] = $factory; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Can return an instance/class name that the factories have to return an instance of. |
141
|
|
|
* |
142
|
|
|
* @return string |
143
|
|
|
*/ |
144
|
|
|
protected static function requiresInstanceOf(): string |
145
|
|
|
{ |
146
|
|
|
return null; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
protected static function loadFactoryMap(): void |
150
|
|
|
{ |
151
|
|
|
if (!isset(static::$factoryMaps[static::class])) |
152
|
|
|
{ |
153
|
|
|
static::$factoryMaps[static::class] = static::getFactoryMap(); |
154
|
|
|
} |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* Has to return map of names to factory closures. |
159
|
|
|
* |
160
|
|
|
* @return array |
161
|
|
|
*/ |
162
|
|
|
abstract protected static function getFactoryMap(): array; |
163
|
|
|
} |
164
|
|
|
|
This check looks for the bodies of
elseif
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
elseif
bodies can be removed. If you have an empty elseif but statements in theelse
branch, consider inverting the condition.