1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace League\CLImate\TerminalObject\Router; |
4
|
|
|
|
5
|
|
|
use League\CLImate\Exceptions\InvalidArgumentException; |
6
|
|
|
use League\CLImate\Exceptions\UnexpectedValueException; |
7
|
|
|
use League\CLImate\Util\Helper; |
8
|
|
|
|
9
|
|
|
class ExtensionCollection |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* @var array collection |
13
|
|
|
*/ |
14
|
|
|
protected $collection = ['basic' => [], 'dynamic' => []]; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @var string $basic_interface |
18
|
|
|
*/ |
19
|
|
|
protected $basic_interface = 'League\CLImate\TerminalObject\Basic\BasicTerminalObjectInterface'; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var string $dynamic_interface |
23
|
|
|
*/ |
24
|
36 |
|
protected $dynamic_interface = 'League\CLImate\TerminalObject\Dynamic\DynamicTerminalObjectInterface'; |
25
|
|
|
|
26
|
36 |
|
public function __construct($key, $class) |
27
|
28 |
|
{ |
28
|
|
|
$this->createCollection($key, $class); |
29
|
28 |
|
} |
30
|
|
|
|
31
|
28 |
|
public function collection() |
32
|
|
|
{ |
33
|
|
|
return $this->collection; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Create the collection from the key/class |
38
|
|
|
* |
39
|
|
|
* @param string $original_key |
40
|
|
|
* @param string|object|array $original_class |
41
|
|
|
* |
42
|
36 |
|
* @return void |
43
|
|
|
*/ |
44
|
36 |
|
protected function createCollection($original_key, $original_class) |
45
|
|
|
{ |
46
|
36 |
|
$collection = $this->convertToArray($original_key, $original_class); |
47
|
36 |
|
|
48
|
28 |
|
foreach ($collection as $key => $class) { |
49
|
28 |
|
$this->validateExtension($class); |
50
|
28 |
|
$this->collection[$this->getType($class)][$this->getKey($key, $class)] = $class; |
51
|
|
|
} |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Convert the given class and key to an array of classes |
56
|
|
|
* |
57
|
|
|
* @param string|object|array $class |
58
|
|
|
* @param string $key Optional custom key instead of class name |
59
|
|
|
* |
60
|
36 |
|
* @return array |
61
|
|
|
*/ |
62
|
36 |
|
protected function convertToArray($key, $class) |
63
|
8 |
|
{ |
64
|
|
|
if (is_array($class)) { |
65
|
|
|
return $class; |
66
|
28 |
|
} |
67
|
|
|
|
68
|
|
|
return [$this->getKey($key, $class) => $class]; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Ensure that the extension is valid |
73
|
|
|
* |
74
|
36 |
|
* @param string|object|array $class |
75
|
|
|
*/ |
76
|
36 |
|
protected function validateExtension($class) |
77
|
32 |
|
{ |
78
|
28 |
|
$this->validateClassExists($class); |
|
|
|
|
79
|
|
|
$this->validateClassImplementation($class); |
|
|
|
|
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param string|object $class |
84
|
|
|
* |
85
|
36 |
|
* @throws UnexpectedValueException if extension class does not exist |
86
|
|
|
*/ |
87
|
36 |
|
protected function validateClassExists($class) |
88
|
4 |
|
{ |
89
|
|
|
if (is_string($class) && !class_exists($class)) { |
90
|
32 |
|
throw new UnexpectedValueException('Class does not exist: ' . $class); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* @param string|object $class |
96
|
|
|
* |
97
|
32 |
|
* @throws InvalidArgumentException if extension class does not implement either Dynamic or Basic interface |
98
|
|
|
*/ |
99
|
32 |
|
protected function validateClassImplementation($class) |
100
|
|
|
{ |
101
|
32 |
|
$str_class = is_string($class); |
102
|
32 |
|
|
103
|
|
|
$valid_implementation = (is_a($class, $this->basic_interface, $str_class) |
104
|
32 |
|
|| is_a($class, $this->dynamic_interface, $str_class)); |
105
|
4 |
|
|
106
|
4 |
|
if (!$valid_implementation) { |
107
|
|
|
throw new InvalidArgumentException('Class must implement either ' |
108
|
28 |
|
. $this->basic_interface . ' or ' . $this->dynamic_interface); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Determine the extension key based on the class |
114
|
|
|
* |
115
|
|
|
* @param string|null $key |
116
|
|
|
* @param string|object $class |
117
|
|
|
* |
118
|
36 |
|
* @return string |
119
|
|
|
*/ |
120
|
36 |
|
protected function getKey($key, $class) |
121
|
28 |
|
{ |
122
|
|
|
if ($key === null || !is_string($key)) { |
123
|
28 |
|
$class_path = (is_string($class)) ? $class : get_class($class); |
124
|
28 |
|
|
125
|
28 |
|
$key = explode('\\', $class_path); |
126
|
|
|
$key = end($key); |
127
|
36 |
|
} |
128
|
|
|
|
129
|
|
|
return Helper::snakeCase($key); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* Get the type of class the extension implements |
134
|
|
|
* |
135
|
|
|
* @param string|object $class |
136
|
|
|
* |
137
|
28 |
|
* @return string 'basic' or 'dynamic' |
138
|
|
|
*/ |
139
|
28 |
|
protected function getType($class) |
140
|
24 |
|
{ |
141
|
|
|
if (is_a($class, $this->basic_interface, is_string($class))) { |
142
|
|
|
return 'basic'; |
143
|
12 |
|
} |
144
|
|
|
|
145
|
|
|
return 'dynamic'; |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.