1
|
|
|
<?php
|
|
|
|
|
2
|
|
|
/**
|
3
|
|
|
* Created by Ruslan Molodyko.
|
4
|
|
|
* Date: 12.09.2016
|
5
|
|
|
* Time: 6:33
|
6
|
|
|
*/
|
7
|
|
|
namespace samsonframework\container\definition\resolver\xml;
|
8
|
|
|
|
9
|
|
|
use samsonframework\container\definition\builder\DefinitionBuilder;
|
10
|
|
|
use samsonframework\container\definition\ClassDefinition;
|
11
|
|
|
use samsonframework\container\definition\exception\ClassDefinitionAlreadyExistsException;
|
12
|
|
|
use samsonframework\container\definition\exception\MethodDefinitionAlreadyExistsException;
|
13
|
|
|
use samsonframework\container\definition\exception\ParameterDefinitionAlreadyExistsException;
|
14
|
|
|
use samsonframework\container\definition\exception\PropertyDefinitionAlreadyExistsException;
|
15
|
|
|
use samsonframework\container\definition\MethodDefinition;
|
16
|
|
|
use samsonframework\container\definition\reference\BoolReference;
|
17
|
|
|
use samsonframework\container\definition\reference\ClassReference;
|
18
|
|
|
use samsonframework\container\definition\reference\CollectionItem;
|
19
|
|
|
use samsonframework\container\definition\reference\CollectionReference;
|
20
|
|
|
use samsonframework\container\definition\reference\ConstantReference;
|
21
|
|
|
use samsonframework\container\definition\reference\FloatReference;
|
22
|
|
|
use samsonframework\container\definition\reference\IntegerReference;
|
23
|
|
|
use samsonframework\container\definition\reference\NullReference;
|
24
|
|
|
use samsonframework\container\definition\reference\ParameterReference;
|
25
|
|
|
use samsonframework\container\definition\reference\ReferenceInterface;
|
26
|
|
|
use samsonframework\container\definition\reference\ServiceReference;
|
27
|
|
|
use samsonframework\container\definition\reference\StringReference;
|
28
|
|
|
use samsonframework\container\definition\resolver\exception\ReferenceNotImplementsException;
|
29
|
|
|
|
30
|
|
|
/**
|
31
|
|
|
* Class XmlResolver
|
32
|
|
|
*
|
33
|
|
|
* @author Ruslan Molodyko <[email protected]>
|
34
|
|
|
*/
|
35
|
|
|
class XmlResolver
|
36
|
|
|
{
|
37
|
|
|
/** How parameter presents in xml code */
|
38
|
|
|
const PARAMETERS_KEY = 'parameters';
|
39
|
|
|
/** How dependencies presents in xml code */
|
40
|
|
|
const DEPENDENCIES_KEY = 'dependencies';
|
41
|
|
|
/** How instance presents in xml code */
|
42
|
|
|
const INSTANCE_KEY = 'definition';
|
43
|
|
|
|
44
|
|
|
/**
|
45
|
|
|
* Resolve xml code
|
46
|
|
|
*
|
47
|
|
|
* @param DefinitionBuilder $definitionBuilder
|
48
|
|
|
* @param $xml
|
49
|
|
|
*
|
50
|
|
|
* @throws ClassDefinitionAlreadyExistsException
|
51
|
|
|
* @throws \InvalidArgumentException
|
52
|
|
|
* @throws PropertyDefinitionAlreadyExistsException
|
53
|
|
|
* @throws ReferenceNotImplementsException
|
54
|
|
|
* @throws MethodDefinitionAlreadyExistsException
|
55
|
|
|
* @throws ParameterDefinitionAlreadyExistsException
|
56
|
|
|
* @throws \samsonframework\container\definition\parameter\exception\ParameterAlreadyExistsException
|
57
|
|
|
*/
|
58
|
1 |
|
public function resolve(DefinitionBuilder $definitionBuilder, $xml)
|
59
|
|
|
{
|
60
|
|
|
/**
|
61
|
|
|
* Iterate config and resolve single instance
|
62
|
|
|
*
|
63
|
|
|
* @var string $key
|
64
|
|
|
* @var array $arrayData
|
65
|
|
|
*/
|
66
|
1 |
|
foreach ($this->xml2array(new \SimpleXMLElement($xml)) as $key => $arrayData) {
|
67
|
|
|
// Resolve parameters
|
68
|
1 |
|
if ($key === self::PARAMETERS_KEY) {
|
69
|
|
|
// Define parameters
|
70
|
1 |
|
foreach ($arrayData as $parameterKey => $parameterArray) {
|
71
|
1 |
|
$definitionBuilder->defineParameter($parameterKey, $this->resolveDependency($parameterArray));
|
72
|
|
|
}
|
73
|
|
|
}
|
74
|
|
|
// Resolve dependencies
|
75
|
1 |
|
if ($key === self::DEPENDENCIES_KEY) {
|
76
|
|
|
// Iterate instances
|
77
|
1 |
|
foreach ($arrayData as $dependencyKey => $definitionsArrayData) {
|
78
|
|
|
// Get only definition instances
|
79
|
1 |
|
if ($dependencyKey === self::INSTANCE_KEY) {
|
80
|
|
|
/**
|
81
|
|
|
* If we have only one instance we need to add array
|
82
|
|
|
* @var array $collection
|
83
|
|
|
*/
|
84
|
1 |
|
$collection = !array_key_exists(0,
|
85
|
1 |
|
$definitionsArrayData) ? [$definitionsArrayData] : $definitionsArrayData;
|
86
|
|
|
/**
|
87
|
|
|
* Iterate collection of instances
|
88
|
|
|
* @var array $definitionsArrayData
|
89
|
|
|
*/
|
90
|
1 |
|
foreach ($collection as $definitionArrayData) {
|
91
|
|
|
/**
|
92
|
|
|
* Create class definition
|
93
|
|
|
* @var ClassDefinition $classDefinition
|
94
|
|
|
*/
|
95
|
1 |
|
$classDefinition = $definitionBuilder->addDefinition($definitionArrayData['@attributes']['class']);
|
96
|
|
|
// Resolve constructor
|
97
|
1 |
|
if (array_key_exists('constructor', $definitionArrayData)) {
|
98
|
1 |
|
$this->resolveConstructor($classDefinition, $definitionArrayData['constructor']);
|
99
|
|
|
}
|
100
|
|
|
// Resolve methods
|
101
|
1 |
|
if (array_key_exists('methods', $definitionArrayData)) {
|
102
|
|
|
// Iteare methods
|
103
|
1 |
|
foreach ($definitionArrayData['methods'] as $methodName => $methodArray) {
|
104
|
1 |
|
$this->resolveMethod($classDefinition, $methodArray, $methodName);
|
105
|
|
|
}
|
106
|
|
|
}
|
107
|
|
|
// Resolve properties
|
108
|
1 |
|
if (array_key_exists('properties', $definitionArrayData)) {
|
109
|
|
|
// Iterate properties
|
110
|
1 |
|
foreach ($definitionArrayData['properties'] as $propertyName => $propertyArray) {
|
111
|
1 |
|
$this->resolveProperty($classDefinition, $propertyArray, $propertyName);
|
112
|
|
|
}
|
113
|
|
|
}
|
114
|
|
|
}
|
115
|
|
|
}
|
116
|
|
|
}
|
117
|
|
|
}
|
118
|
|
|
}
|
119
|
1 |
|
}
|
120
|
|
|
|
121
|
|
|
/**
|
122
|
|
|
* Resolve constructor
|
123
|
|
|
*
|
124
|
|
|
* @param ClassDefinition $classDefinition
|
125
|
|
|
* @param array $constructorArray
|
126
|
|
|
* @throws MethodDefinitionAlreadyExistsException
|
127
|
|
|
* @throws \InvalidArgumentException
|
128
|
|
|
* @throws ParameterDefinitionAlreadyExistsException
|
129
|
|
|
* @throws ReferenceNotImplementsException
|
130
|
|
|
*/
|
131
|
1 |
View Code Duplication |
public function resolveConstructor(ClassDefinition $classDefinition, array $constructorArray)
|
|
|
|
|
132
|
|
|
{
|
133
|
1 |
|
$methodDefinition = $classDefinition->defineConstructor();
|
134
|
1 |
|
if (array_key_exists('arguments', $constructorArray)) {
|
135
|
1 |
|
$this->resolveArguments($methodDefinition, $constructorArray['arguments']);
|
|
|
|
|
136
|
|
|
}
|
137
|
1 |
|
}
|
138
|
|
|
|
139
|
|
|
/**
|
140
|
|
|
* Resolve property
|
141
|
|
|
*
|
142
|
|
|
* @param ClassDefinition $classDefinition
|
143
|
|
|
* @param array $propertyArray
|
144
|
|
|
* @param string $propertyName
|
145
|
|
|
* @throws \InvalidArgumentException
|
146
|
|
|
* @throws ReferenceNotImplementsException
|
147
|
|
|
* @throws PropertyDefinitionAlreadyExistsException
|
148
|
|
|
*/
|
149
|
1 |
|
public function resolveProperty(ClassDefinition $classDefinition, array $propertyArray, string $propertyName)
|
150
|
|
|
{
|
151
|
1 |
|
$propertyDefinition = $classDefinition->defineProperty($propertyName);
|
152
|
1 |
|
$propertyDefinition->defineDependency($this->resolveDependency($propertyArray));
|
153
|
1 |
|
}
|
154
|
|
|
|
155
|
|
|
/**
|
156
|
|
|
* Resolve method
|
157
|
|
|
*
|
158
|
|
|
* @param ClassDefinition $classDefinition
|
159
|
|
|
* @param array $methodArray
|
160
|
|
|
* @param string $methodName
|
161
|
|
|
* @throws MethodDefinitionAlreadyExistsException
|
162
|
|
|
* @throws \InvalidArgumentException
|
163
|
|
|
* @throws ParameterDefinitionAlreadyExistsException
|
164
|
|
|
* @throws ReferenceNotImplementsException
|
165
|
|
|
*/
|
166
|
1 |
View Code Duplication |
public function resolveMethod(ClassDefinition $classDefinition, array $methodArray, string $methodName)
|
|
|
|
|
167
|
|
|
{
|
168
|
1 |
|
$methodDefinition = $classDefinition->defineMethod($methodName);
|
169
|
1 |
|
if (array_key_exists('arguments', $methodArray)) {
|
170
|
1 |
|
$this->resolveArguments($methodDefinition, $methodArray['arguments']);
|
|
|
|
|
171
|
|
|
}
|
172
|
1 |
|
}
|
173
|
|
|
|
174
|
|
|
/**
|
175
|
|
|
* Resolve method/constructor arguments
|
176
|
|
|
*
|
177
|
|
|
* @param MethodDefinition $methodDefinition
|
178
|
|
|
* @param array $arguments
|
179
|
|
|
* @throws ParameterDefinitionAlreadyExistsException
|
180
|
|
|
* @throws \InvalidArgumentException
|
181
|
|
|
* @throws ReferenceNotImplementsException
|
182
|
|
|
*/
|
183
|
1 |
|
public function resolveArguments(MethodDefinition $methodDefinition, array $arguments)
|
184
|
|
|
{
|
185
|
1 |
|
foreach ($arguments as $argumentName => $argumentValue) {
|
186
|
|
|
$methodDefinition
|
187
|
1 |
|
->defineParameter($argumentName)
|
188
|
1 |
|
->defineDependency($this->resolveDependency($argumentValue));
|
189
|
|
|
}
|
190
|
1 |
|
}
|
191
|
|
|
|
192
|
|
|
/**
|
193
|
|
|
* Resolve dependency
|
194
|
|
|
*
|
195
|
|
|
* @param $data
|
196
|
|
|
* @return ReferenceInterface
|
197
|
|
|
* @throws \InvalidArgumentException
|
198
|
|
|
* @throws ReferenceNotImplementsException
|
199
|
|
|
*/
|
200
|
1 |
|
public function resolveDependency($data): ReferenceInterface
|
201
|
|
|
{
|
202
|
|
|
// Get value type
|
203
|
1 |
|
$type = $data['@attributes']['type'] ?? 'string';
|
204
|
|
|
// Get value
|
205
|
1 |
|
$value = $data['@attributes']['value'] ?? null;
|
206
|
|
|
// When that is not a collection then value can not be null
|
207
|
1 |
|
if ($type !== 'collection' && $value === null) {
|
208
|
|
|
throw new \InvalidArgumentException(sprintf('Value for type "%s" have to be specified', $type));
|
209
|
|
|
}
|
210
|
|
|
// Resolve type
|
211
|
|
|
switch ($type) {
|
212
|
1 |
|
case 'text':
|
|
|
|
|
213
|
1 |
|
case 'string':
|
|
|
|
|
214
|
1 |
|
return new StringReference($value);
|
215
|
1 |
|
case 'int':
|
|
|
|
|
216
|
1 |
|
case 'integer':
|
|
|
|
|
217
|
|
|
return new IntegerReference($value);
|
218
|
1 |
|
case 'float':
|
219
|
|
|
return new FloatReference($value);
|
220
|
1 |
|
case 'boolean':
|
221
|
1 |
|
case 'bool':
|
222
|
|
|
return new BoolReference($value);
|
223
|
1 |
|
case 'class':
|
224
|
1 |
|
return new ClassReference($value);
|
225
|
1 |
|
case 'constant':
|
226
|
1 |
|
return new ConstantReference($value);
|
227
|
1 |
|
case 'service':
|
228
|
|
|
return new ServiceReference($value);
|
229
|
1 |
|
case 'null':
|
230
|
|
|
return new NullReference();
|
231
|
1 |
|
case 'parameter':
|
232
|
1 |
|
return new ParameterReference($value);
|
233
|
1 |
|
case 'collection':
|
234
|
1 |
|
return $this->resolveCollection($data);
|
235
|
|
|
default:
|
236
|
|
|
throw new ReferenceNotImplementsException();
|
237
|
|
|
}
|
238
|
|
|
}
|
239
|
|
|
|
240
|
|
|
/**
|
241
|
|
|
* Resolve collection type
|
242
|
|
|
*
|
243
|
|
|
* @param array $data
|
244
|
|
|
* @return CollectionReference
|
245
|
|
|
* @throws ReferenceNotImplementsException
|
246
|
|
|
* @throws \InvalidArgumentException
|
247
|
|
|
*/
|
248
|
1 |
|
public function resolveCollection(array $data): CollectionReference
|
249
|
|
|
{
|
250
|
1 |
|
$collection = new CollectionReference();
|
251
|
1 |
|
if (array_key_exists('item', $data)) {
|
252
|
|
|
/** @var array $itemCollection */
|
253
|
1 |
|
$itemCollection = array_key_exists('key', $data['item']) && array_key_exists('value', $data['item'])
|
254
|
1 |
|
? [$data['item']]
|
255
|
1 |
|
: $data['item'];
|
256
|
|
|
/** @var array $item */
|
257
|
1 |
|
foreach ($itemCollection as $item) {
|
258
|
1 |
|
$collection->addItem(new CollectionItem(
|
259
|
1 |
|
$this->resolveDependency($item['key']),
|
260
|
1 |
|
$this->resolveDependency($item['value'])
|
261
|
|
|
));
|
262
|
|
|
}
|
263
|
|
|
}
|
264
|
1 |
|
return $collection;
|
265
|
|
|
}
|
266
|
|
|
|
267
|
|
|
/**
|
268
|
|
|
* Convert xml to array
|
269
|
|
|
*
|
270
|
|
|
* @param $xmlObject
|
271
|
|
|
* @param array $out
|
272
|
|
|
* @return array
|
273
|
|
|
*/
|
274
|
1 |
|
protected function xml2array($xmlObject, array $out = []): array
|
275
|
|
|
{
|
276
|
1 |
|
foreach ((array)$xmlObject as $index => $node) {
|
277
|
1 |
|
$out[$index] = (is_object($node) || is_array($node)) ? $this->xml2array($node) : $node;
|
278
|
|
|
}
|
279
|
1 |
|
return $out;
|
280
|
|
|
}
|
281
|
|
|
}
|
282
|
|
|
|