|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace ConfigToken; |
|
4
|
|
|
|
|
5
|
|
|
use ConfigToken\Exception\NotRegisteredException; |
|
6
|
|
|
use ConfigToken\TokenResolver\TokenResolverFactory; |
|
7
|
|
|
use ConfigToken\TokenResolver\Types\RegisteredTokenResolver; |
|
8
|
|
|
use ConfigToken\TokenResolver\Types\ScopeTokenResolver; |
|
9
|
|
|
use ConfigToken\TreeCompiler\Exception\TokenResolverDefinitionException; |
|
10
|
|
|
use ConfigToken\TreeCompiler\Exception\TreeCompilerFormatException; |
|
11
|
|
|
use ConfigToken\TreeCompiler\Exception\CircularReferenceException; |
|
12
|
|
|
use ConfigToken\TreeCompiler\XrefResolver\Exception\UnknownXrefException; |
|
13
|
|
|
use ConfigToken\TreeCompiler\XrefResolver\Exception\XrefResolverFormatException; |
|
14
|
|
|
use ConfigToken\TreeCompiler\XrefResolver\Types\InlineXrefResolver; |
|
15
|
|
|
use ConfigToken\TreeCompiler\XrefResolver\Types\UrlXrefResolver; |
|
16
|
|
|
use ConfigToken\TreeCompiler\XrefResolver\Types\LocalFileXrefResolver; |
|
17
|
|
|
use ConfigToken\TreeCompiler\Xref; |
|
18
|
|
|
use ConfigToken\TreeCompiler\XrefCollection; |
|
19
|
|
|
use ConfigToken\TreeCompiler\XrefTokenResolver; |
|
20
|
|
|
use ConfigToken\TreeCompiler\XrefTokenResolverCollection; |
|
21
|
|
|
use ConfigToken\TreeSerializer\TreeSerializerFactory; |
|
22
|
|
|
|
|
23
|
|
|
|
|
24
|
|
|
class TreeCompiler |
|
25
|
|
|
{ |
|
26
|
|
|
/** @var string */ |
|
27
|
|
|
protected $includeKey = 'include'; |
|
28
|
|
|
/** @var string */ |
|
29
|
|
|
protected $includeXrefKey = 'xref'; |
|
30
|
|
|
/** @var string */ |
|
31
|
|
|
protected $includeXrefTypeKey = 'type'; |
|
32
|
|
|
/** @var string */ |
|
33
|
|
|
protected $includeXrefLocationKey = 'src'; |
|
34
|
|
|
/** @var string */ |
|
35
|
|
|
protected $includeXrefDataKey = 'data'; |
|
36
|
|
|
/** @var string */ |
|
37
|
|
|
protected $includeXrefResolversKey = 'resolve'; |
|
38
|
|
|
/** @var string */ |
|
39
|
|
|
protected $includeMainKey = 'main'; |
|
40
|
|
|
/** @var string */ |
|
41
|
|
|
protected $xrefTokenResolverTypeKey = 'type'; |
|
42
|
|
|
/** @var string */ |
|
43
|
|
|
protected $xrefTokenResolverOptionsKey = 'options'; |
|
44
|
|
|
/** @var string */ |
|
45
|
|
|
protected $xrefTokenResolverValuesKey = 'values'; |
|
46
|
|
|
/** @var string */ |
|
47
|
|
|
protected $xrefTokenResolverValuesXrefKey = 'values-xref'; |
|
48
|
|
|
/** @var string */ |
|
49
|
|
|
protected $xrefTokenResolverOptionIgnoreUnknownTokensKey = 'ignore-unknown-tokens'; |
|
50
|
|
|
/** @var string */ |
|
51
|
|
|
protected $xrefTokenResolverOptionIgnoreUnknownFiltersKey = 'ignore-unknown-filters'; |
|
52
|
|
|
/** @var string */ |
|
53
|
|
|
protected $xrefTokenResolverOptionTokenRegexKey = 'token-regex'; |
|
54
|
|
|
/** @var string */ |
|
55
|
|
|
protected $xrefTokenResolverOptionTokenPrefixKey = 'token-prefix'; |
|
56
|
|
|
/** @var string */ |
|
57
|
|
|
protected $xrefTokenResolverOptionTokenSuffixKey = 'token-suffix'; |
|
58
|
|
|
/** @var string */ |
|
59
|
|
|
protected $xrefTokenResolverOptionTokenFilterDelimiterKey = 'token-filter-delimiter'; |
|
60
|
|
|
/** @var string */ |
|
61
|
|
|
protected $xrefTokenResolverOptionScopeTokenNameKey = 'scope-token-name'; |
|
62
|
|
|
/** @var string */ |
|
63
|
|
|
protected $xrefTokenResolverOptionScopeTokenNameDelimiterKey = 'scope-token-name-delimiter'; |
|
64
|
|
|
/** @var string */ |
|
65
|
|
|
protected $xrefTokenResolverOptionScopeTokenLevelDelimiterKey = 'scope-token-level-delimiter'; |
|
66
|
|
|
/** @var string */ |
|
67
|
|
|
protected $xrefTokenResolverOptionIgnoreOutOfScopeKey = 'ignore-out-of-scope'; |
|
68
|
|
|
/** @var array */ |
|
69
|
|
|
protected $xrefTokenResolverOptionKeys = array(); |
|
70
|
|
|
/** @var array */ |
|
71
|
|
|
protected $xrefTokenResolverRequiredOptionKeys = array(); |
|
72
|
|
|
/** @var string[] */ |
|
73
|
|
|
protected $xrefTokenResolverOptionSetterMapping = array(); |
|
74
|
|
|
|
|
75
|
|
|
/** @var string */ |
|
76
|
|
|
protected $removeKey = 'remove'; |
|
77
|
|
|
/** @var string */ |
|
78
|
|
|
protected $addKey = 'add'; |
|
79
|
|
|
/** @var string */ |
|
80
|
|
|
protected $xrefTypeAndLocationDelimiter = ':'; |
|
81
|
|
|
|
|
82
|
|
|
/** @var XrefCollection */ |
|
83
|
|
|
protected $xrefs; |
|
84
|
|
|
|
|
85
|
|
|
const INCLUDE_TYPE_GROUP = 'group'; |
|
86
|
|
|
const INCLUDE_TYPE_XREF = 'xref'; |
|
87
|
|
|
|
|
88
|
7 |
|
public function __construct(XrefCollection $xrefs = null) |
|
89
|
|
|
{ |
|
90
|
7 |
|
if (!isset($xrefs)) { |
|
91
|
7 |
|
$xrefs = new XrefCollection(); |
|
92
|
7 |
|
} |
|
93
|
7 |
|
$this->xrefs = $xrefs; |
|
94
|
7 |
|
$stringType = gettype(''); |
|
95
|
7 |
|
$booleanType = gettype(true); |
|
96
|
7 |
|
$this->xrefTokenResolverOptionKeys = array( |
|
97
|
7 |
|
RegisteredTokenResolver::getBaseType() => array( |
|
98
|
7 |
|
$this->xrefTokenResolverOptionIgnoreUnknownTokensKey => $booleanType, |
|
99
|
7 |
|
$this->xrefTokenResolverOptionIgnoreUnknownFiltersKey => $booleanType, |
|
100
|
7 |
|
$this->xrefTokenResolverOptionTokenRegexKey => $stringType, |
|
101
|
7 |
|
$this->xrefTokenResolverOptionTokenPrefixKey => $stringType, |
|
102
|
7 |
|
$this->xrefTokenResolverOptionTokenSuffixKey => $stringType, |
|
103
|
7 |
|
$this->xrefTokenResolverOptionTokenFilterDelimiterKey => $stringType, |
|
104
|
7 |
|
), |
|
105
|
7 |
|
ScopeTokenResolver::getBaseType() => array( |
|
106
|
7 |
|
$this->xrefTokenResolverOptionIgnoreUnknownTokensKey => $booleanType, |
|
107
|
7 |
|
$this->xrefTokenResolverOptionIgnoreUnknownFiltersKey => $booleanType, |
|
108
|
7 |
|
$this->xrefTokenResolverOptionIgnoreOutOfScopeKey => $booleanType, |
|
109
|
7 |
|
$this->xrefTokenResolverOptionTokenRegexKey => $stringType, |
|
110
|
7 |
|
$this->xrefTokenResolverOptionTokenPrefixKey => $stringType, |
|
111
|
7 |
|
$this->xrefTokenResolverOptionTokenSuffixKey => $stringType, |
|
112
|
7 |
|
$this->xrefTokenResolverOptionTokenFilterDelimiterKey => $stringType, |
|
113
|
7 |
|
$this->xrefTokenResolverOptionScopeTokenNameKey => $stringType, |
|
114
|
7 |
|
$this->xrefTokenResolverOptionScopeTokenNameDelimiterKey => $stringType, |
|
115
|
7 |
|
$this->xrefTokenResolverOptionScopeTokenLevelDelimiterKey => $stringType, |
|
116
|
|
|
) |
|
117
|
7 |
|
); |
|
118
|
7 |
|
$this->xrefTokenResolverRequiredOptionKeys = array( |
|
119
|
7 |
|
RegisteredTokenResolver::getBaseType() => array(), |
|
120
|
7 |
|
ScopeTokenResolver::getBaseType() => array( |
|
121
|
7 |
|
$this->xrefTokenResolverOptionScopeTokenNameKey => true, |
|
122
|
|
|
) |
|
123
|
7 |
|
); |
|
124
|
7 |
|
} |
|
125
|
|
|
|
|
126
|
7 |
|
public function getXrefs() |
|
127
|
|
|
{ |
|
128
|
7 |
|
return $this->xrefs; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* Get include key. |
|
133
|
|
|
* |
|
134
|
|
|
* @return string |
|
135
|
|
|
*/ |
|
136
|
|
|
public function getIncludeKey() |
|
137
|
|
|
{ |
|
138
|
|
|
return $this->includeKey; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* Set include key. |
|
143
|
|
|
* |
|
144
|
|
|
* @param string $value The new value. |
|
145
|
|
|
* @return $this |
|
146
|
|
|
*/ |
|
147
|
|
|
public function setIncludeKey($value) |
|
148
|
|
|
{ |
|
149
|
|
|
$this->includeKey = $value; |
|
150
|
|
|
return $this; |
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
/** |
|
154
|
|
|
* Recursively remove the keys of one array from another. |
|
155
|
|
|
* |
|
156
|
|
|
* @param array $toRemove The array containing the keys to be removed. |
|
157
|
|
|
* @param array $removeFrom The array from which to remove keys. |
|
158
|
|
|
*/ |
|
159
|
1 |
|
public function recursiveRemoveData(array &$toRemove, array &$removeFrom) |
|
160
|
|
|
{ |
|
161
|
1 |
|
foreach ($toRemove as $keyToRemove => $childKeysToRemove) { |
|
162
|
1 |
|
if (is_array($childKeysToRemove)) { |
|
163
|
|
|
if (isset($removeFrom[$keyToRemove]) && is_array($removeFrom[$keyToRemove])) { |
|
164
|
|
|
$this->recursiveRemoveData($toRemove[$keyToRemove], $removeFrom[$keyToRemove]); |
|
165
|
|
|
} |
|
166
|
1 |
|
} else if (array_key_exists($keyToRemove, $removeFrom)) { |
|
167
|
1 |
|
unset($removeFrom[$keyToRemove]); |
|
168
|
1 |
|
} |
|
169
|
1 |
|
} |
|
170
|
1 |
|
} |
|
171
|
|
|
|
|
172
|
|
|
/** |
|
173
|
|
|
* Recursively add and override keys from one array into another. |
|
174
|
|
|
* |
|
175
|
|
|
* @param array $addFrom The source array. |
|
176
|
|
|
* @param array $addTo The destination array. |
|
177
|
|
|
*/ |
|
178
|
5 |
|
public function recursiveAddData(array &$addFrom, array &$addTo) |
|
179
|
|
|
{ |
|
180
|
5 |
|
if (empty($addTo)) { |
|
181
|
|
|
/** @noinspection PhpUnusedLocalVariableInspection */ |
|
182
|
5 |
|
$addTo = $addFrom; |
|
183
|
5 |
|
return; |
|
184
|
|
|
} |
|
185
|
2 |
|
foreach ($addFrom as $keyToAdd => $childKeys) { |
|
186
|
2 |
|
if (is_array($childKeys)) { |
|
187
|
|
|
if (isset($addTo[$keyToAdd]) && is_array($addTo[$keyToAdd])) { |
|
188
|
|
|
$this->recursiveAddData($addFrom[$keyToAdd], $addTo[$keyToAdd]); |
|
189
|
|
|
continue; |
|
190
|
|
|
} |
|
191
|
|
|
} |
|
192
|
2 |
|
$addTo[$keyToAdd] = $addFrom[$keyToAdd]; |
|
193
|
2 |
|
} |
|
194
|
2 |
|
} |
|
195
|
|
|
|
|
196
|
|
|
/** |
|
197
|
|
|
* Retrieve a list of Xref keys to be resolved. |
|
198
|
|
|
* |
|
199
|
|
|
* @param Xref $xref |
|
200
|
|
|
* @param array $xrefDataInclude |
|
201
|
|
|
* @param array $xrefDataIncludeXrefs |
|
202
|
|
|
* @param string $includeType |
|
203
|
|
|
* @param string|array $includeTypeValue |
|
204
|
|
|
* @return array |
|
205
|
|
|
* |
|
206
|
|
|
* @throws XrefResolverFormatException |
|
207
|
|
|
*/ |
|
208
|
7 |
|
protected function getXrefKeysToBeResolved(Xref $xref, $xrefDataInclude, $xrefDataIncludeXrefs, |
|
209
|
|
|
$includeType, $includeTypeValue) |
|
210
|
|
|
{ |
|
211
|
7 |
|
$result = array(); |
|
212
|
|
|
switch ($includeType) { |
|
213
|
7 |
|
case static::INCLUDE_TYPE_XREF: |
|
214
|
|
|
$missing = array(); |
|
215
|
|
|
if (!is_array($includeTypeValue)) { |
|
216
|
|
|
throw new XrefResolverFormatException( |
|
217
|
|
|
$xref, |
|
218
|
|
|
sprintf( |
|
219
|
|
|
'Include type value must be an array, %s given.', |
|
220
|
|
|
gettype($includeTypeValue) |
|
221
|
|
|
) |
|
222
|
|
|
); |
|
223
|
|
|
} |
|
224
|
|
|
foreach ($includeTypeValue as $xrefKey) { |
|
225
|
|
|
if (!isset($xrefDataIncludeXrefs[$xrefKey])) { |
|
226
|
|
|
$missing[] = $xrefKey; |
|
227
|
|
|
} |
|
228
|
|
|
} |
|
229
|
|
|
if (empty($missing)) { |
|
230
|
|
|
unset($missing); |
|
231
|
|
|
} else { |
|
232
|
|
|
throw new XrefResolverFormatException( |
|
233
|
|
|
$xref, |
|
234
|
|
|
sprintf( |
|
235
|
|
|
"Required to explicitly include the list of Xref keys [\"%s\"] " . |
|
236
|
|
|
"but unable to find [\"%s\"].", |
|
237
|
|
|
implode('", "', $includeTypeValue), |
|
238
|
|
|
implode('", "', $missing) |
|
239
|
|
|
) |
|
240
|
|
|
); |
|
241
|
|
|
} |
|
242
|
|
|
$result = $includeTypeValue; |
|
243
|
|
|
break; |
|
244
|
7 |
|
case static::INCLUDE_TYPE_GROUP: |
|
245
|
7 |
|
if (!isset($xrefDataInclude[$includeTypeValue])) { |
|
246
|
|
|
throw new XrefResolverFormatException( |
|
247
|
|
|
$xref, |
|
248
|
|
|
sprintf( |
|
249
|
|
|
"Unable to find the required include group of Xref keys named \"%s\"", |
|
250
|
|
|
$includeTypeValue |
|
251
|
|
|
) |
|
252
|
|
|
); |
|
253
|
|
|
} |
|
254
|
7 |
|
$result = $xrefDataInclude[$includeTypeValue]; |
|
255
|
7 |
|
break; |
|
256
|
|
|
} |
|
257
|
7 |
|
return $result; |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
/** |
|
261
|
|
|
* @param $xrefKey |
|
262
|
|
|
* @param $tokenResolverDefinitionIndex |
|
263
|
|
|
* @param $tokenResolverBaseType |
|
264
|
|
|
* @param $options |
|
265
|
|
|
* @throws TokenResolverDefinitionException |
|
266
|
|
|
*/ |
|
267
|
5 |
|
protected function validateXrefTokenResolverOptions($xrefKey, $tokenResolverDefinitionIndex, $tokenResolverBaseType, |
|
268
|
|
|
$options) |
|
269
|
|
|
{ |
|
270
|
5 |
|
if (!is_array($options)) { |
|
271
|
|
|
throw new TokenResolverDefinitionException( |
|
272
|
|
|
sprintf( |
|
273
|
|
|
'The "%s" key for token resolver definition at index %d for Xref key "%s" must be an associative array.', |
|
274
|
|
|
$this->xrefTokenResolverOptionsKey, |
|
275
|
|
|
$tokenResolverDefinitionIndex, |
|
276
|
|
|
$xrefKey |
|
277
|
|
|
) |
|
278
|
|
|
); |
|
279
|
|
|
} |
|
280
|
5 |
|
$required = $this->xrefTokenResolverRequiredOptionKeys[$tokenResolverBaseType]; |
|
281
|
5 |
|
$unknown = array(); |
|
282
|
5 |
|
$found = array(); |
|
283
|
5 |
|
foreach ($options as $optionKey => $optionValue) { |
|
284
|
5 |
|
if (!isset($this->xrefTokenResolverOptionKeys[$tokenResolverBaseType][$optionKey])) { |
|
285
|
|
|
$unknown[] = $optionKey; |
|
286
|
|
|
} else { |
|
287
|
5 |
|
$found[$optionKey] = $optionValue; |
|
288
|
5 |
|
if (isset($required[$optionKey])) { |
|
289
|
|
|
unset($required[$optionKey]); |
|
290
|
|
|
} |
|
291
|
|
|
} |
|
292
|
5 |
|
} |
|
293
|
5 |
View Code Duplication |
if (count($required) > 0) { |
|
|
|
|
|
|
294
|
|
|
throw new TokenResolverDefinitionException( |
|
295
|
|
|
sprintf( |
|
296
|
|
|
'Missing required option(s) "%s" for token resolver definition based on the "%s" type identifier at ' . |
|
297
|
|
|
'index %d for Xref key "%s".', |
|
298
|
|
|
implode('", "', $required), |
|
299
|
|
|
$tokenResolverBaseType, |
|
300
|
|
|
$this->xrefTokenResolverOptionsKey, |
|
301
|
|
|
$tokenResolverDefinitionIndex, |
|
302
|
|
|
$xrefKey |
|
303
|
|
|
) |
|
304
|
|
|
); |
|
305
|
|
|
} |
|
306
|
5 |
View Code Duplication |
if (count($unknown) > 0) { |
|
|
|
|
|
|
307
|
|
|
throw new TokenResolverDefinitionException( |
|
308
|
|
|
sprintf( |
|
309
|
|
|
'Unknown option(s) "%s" for token resolver definition based on the "%s" type identifier at ' . |
|
310
|
|
|
'index %d for Xref key "%s".', |
|
311
|
|
|
implode('", "', $unknown), |
|
312
|
|
|
$tokenResolverBaseType, |
|
313
|
|
|
$this->xrefTokenResolverOptionsKey, |
|
314
|
|
|
$tokenResolverDefinitionIndex, |
|
315
|
|
|
$xrefKey |
|
316
|
|
|
) |
|
317
|
|
|
); |
|
318
|
|
|
} |
|
319
|
5 |
|
foreach ($found as $optionKey => $optionValue) { |
|
320
|
5 |
|
$valueType = gettype($optionValue); |
|
321
|
5 |
|
$expectedValueType = $this->xrefTokenResolverOptionKeys[$tokenResolverBaseType][$optionKey]; |
|
322
|
5 |
|
if ($valueType != $expectedValueType) { |
|
323
|
|
|
throw new TokenResolverDefinitionException( |
|
324
|
|
|
sprintf( |
|
325
|
|
|
'Wrong type "%s" instead of "%s" for option "%s" for token resolver definition based on the ' . |
|
326
|
|
|
'"%s" type identifier at index %d for Xref key "%s".', |
|
327
|
|
|
$valueType, |
|
328
|
|
|
$expectedValueType, |
|
329
|
|
|
$tokenResolverBaseType, |
|
330
|
|
|
$this->xrefTokenResolverOptionsKey, |
|
331
|
|
|
$tokenResolverDefinitionIndex, |
|
332
|
|
|
$xrefKey |
|
333
|
|
|
) |
|
334
|
|
|
); |
|
335
|
|
|
} |
|
336
|
5 |
|
} |
|
337
|
5 |
|
} |
|
338
|
|
|
|
|
339
|
|
|
/** |
|
340
|
|
|
* @param string $xrefKey |
|
341
|
|
|
* @param string|array $xrefInfo |
|
342
|
|
|
* @param XrefTokenResolverCollection $xrefTokenResolvers |
|
343
|
|
|
* @param Xref[] $xrefPath |
|
344
|
|
|
* @return Xref|mixed |
|
345
|
|
|
* @throws TreeCompilerFormatException |
|
346
|
|
|
* @throws \Exception |
|
347
|
|
|
*/ |
|
348
|
7 |
|
protected function parseXrefInfo($xrefKey, $xrefInfo, XrefTokenResolverCollection $xrefTokenResolvers = null, $xrefPath) |
|
349
|
|
|
{ |
|
350
|
7 |
|
$xrefData = null; |
|
351
|
7 |
|
if (gettype($xrefInfo) == 'string') { |
|
352
|
1 |
|
list($xrefType, $xrefLocation) = Xref::parseDefinitionString($xrefInfo, $this->xrefTypeAndLocationDelimiter); |
|
353
|
1 |
|
} else { |
|
354
|
7 |
|
if (!is_array($xrefInfo)) { |
|
355
|
|
|
throw new TreeCompilerFormatException( |
|
356
|
|
|
sprintf( |
|
357
|
|
|
'The Xref definition key "%s" must be a string with the format xref_type %s xref_location ' . |
|
358
|
|
|
'or an associative array with the keys "%s" for type and "%s" for location.', |
|
359
|
|
|
$this->xrefTypeAndLocationDelimiter, |
|
360
|
|
|
$this->includeXrefTypeKey, |
|
361
|
|
|
$this->includeXrefLocationKey |
|
362
|
|
|
) |
|
363
|
|
|
); |
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
7 |
|
$requiredKeyErrorMessage = 'The "%s" key is missing from the Xref definition with the key "%s".'; |
|
367
|
7 |
View Code Duplication |
if (!isset($xrefInfo[$this->includeXrefTypeKey])) { |
|
|
|
|
|
|
368
|
|
|
throw new TreeCompilerFormatException( |
|
369
|
|
|
sprintf($requiredKeyErrorMessage, $this->includeXrefTypeKey, $xrefKey) |
|
370
|
|
|
); |
|
371
|
|
|
} |
|
372
|
7 |
|
$xrefType = $xrefInfo[$this->includeXrefTypeKey]; |
|
373
|
7 |
|
if ($xrefType == InlineXrefResolver::getType()) { |
|
374
|
|
View Code Duplication |
if (!isset($xrefInfo[$this->includeXrefDataKey])) { |
|
|
|
|
|
|
375
|
|
|
throw new TreeCompilerFormatException( |
|
376
|
|
|
sprintf($requiredKeyErrorMessage, $this->includeXrefDataKey, $xrefKey) |
|
377
|
|
|
); |
|
378
|
|
|
} |
|
379
|
|
|
$xrefData = $xrefInfo[$this->includeXrefDataKey]; |
|
380
|
|
|
$xrefLocation = Xref::computeId($xrefType, serialize($xrefData)); |
|
381
|
|
|
} else { |
|
382
|
7 |
View Code Duplication |
if (!isset($xrefInfo[$this->includeXrefLocationKey])) { |
|
|
|
|
|
|
383
|
|
|
throw new TreeCompilerFormatException( |
|
384
|
|
|
sprintf($requiredKeyErrorMessage, $this->includeXrefLocationKey, $xrefKey) |
|
385
|
|
|
); |
|
386
|
|
|
} |
|
387
|
7 |
|
$xrefLocation = $xrefInfo[$this->includeXrefLocationKey]; |
|
388
|
|
|
} |
|
389
|
|
|
} |
|
390
|
|
|
|
|
391
|
7 |
|
if (isset($xrefData)) { |
|
392
|
|
|
if (isset($xrefTokenResolvers)) { |
|
393
|
|
|
$xrefTokenResolvers->applyToArray($xrefData); |
|
394
|
|
|
} |
|
395
|
|
|
} else { |
|
396
|
7 |
|
if (isset($xrefTokenResolvers)) { |
|
397
|
3 |
|
$xrefLocation = $xrefTokenResolvers->applyToString($xrefLocation); |
|
398
|
3 |
|
} |
|
399
|
7 |
|
$xrefLocation = Xref::computeAbsoluteLocation($xrefType, $xrefLocation, $xrefPath); |
|
400
|
|
|
} |
|
401
|
|
|
|
|
402
|
7 |
|
$xrefId = Xref::computeId($xrefType, $xrefLocation); |
|
403
|
7 |
|
if ($this->xrefs->hasById($xrefId)) { |
|
404
|
7 |
|
return $this->xrefs[$xrefId]; |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
$xref = new Xref($xrefType, $xrefLocation); |
|
408
|
|
|
if (isset($xrefData)) { |
|
409
|
|
|
$xref->setData($xrefData)->setResolved(true); |
|
410
|
|
|
} |
|
411
|
|
|
return $xref; |
|
412
|
|
|
} |
|
413
|
|
|
|
|
414
|
|
|
/** |
|
415
|
|
|
* Parse the array corresponding to the $includeKey:$includeXrefKey:<xref name>:$includeXrefResolveKey. |
|
416
|
|
|
* |
|
417
|
|
|
* @param string $xrefKey |
|
418
|
|
|
* @param array $tokenResolversInfo |
|
419
|
|
|
* @param XrefTokenResolverCollection $tokenResolvers |
|
420
|
|
|
* @param Xref[] $xrefPath |
|
421
|
|
|
* @return XrefTokenResolverCollection |
|
422
|
|
|
* @throws \Exception |
|
423
|
|
|
*/ |
|
424
|
7 |
|
protected function parseXrefTokenResolverDefinitions($xrefKey, $tokenResolversInfo, XrefTokenResolverCollection $tokenResolvers = null, $xrefPath) |
|
425
|
|
|
{ |
|
426
|
7 |
|
$resolverValues = array(); |
|
427
|
7 |
|
$tokenResolverDefinitionIndex = 0; |
|
428
|
|
|
// validate |
|
429
|
7 |
|
if (!is_array($tokenResolversInfo)) { |
|
430
|
|
|
throw new TokenResolverDefinitionException( |
|
431
|
|
|
sprintf( |
|
432
|
|
|
'Token resolver definitions at index %d for Xref key "%s" must be an array. (%s)', |
|
433
|
|
|
$tokenResolverDefinitionIndex, |
|
434
|
|
|
$xrefKey, |
|
435
|
|
|
json_encode($tokenResolversInfo) |
|
436
|
|
|
) |
|
437
|
|
|
); |
|
438
|
|
|
} |
|
439
|
7 |
|
foreach ($tokenResolversInfo as $tokenResolverKey => $tokenResolverInfo) { |
|
440
|
7 |
|
if (!is_array($tokenResolverInfo)) { |
|
441
|
1 |
|
throw new TokenResolverDefinitionException( |
|
442
|
1 |
|
sprintf( |
|
443
|
1 |
|
'Token resolver definition at index %d for Xref key "%s" must be an associative array. (%s)', |
|
444
|
1 |
|
$tokenResolverKey, |
|
445
|
1 |
|
$xrefKey, |
|
446
|
1 |
|
json_encode($tokenResolversInfo) |
|
447
|
1 |
|
) |
|
448
|
1 |
|
); |
|
449
|
|
|
} |
|
450
|
6 |
|
if (!isset($tokenResolverInfo[$this->xrefTokenResolverTypeKey])) { |
|
451
|
1 |
|
throw new TokenResolverDefinitionException( |
|
452
|
1 |
|
sprintf( |
|
453
|
1 |
|
"Token resolver definition at index %d for Xref key \"%s\" is missing the \"%s\" type identifier key.\n%s", |
|
454
|
1 |
|
$tokenResolverDefinitionIndex, |
|
455
|
1 |
|
$xrefKey, |
|
456
|
1 |
|
$this->xrefTokenResolverTypeKey, |
|
457
|
1 |
|
json_encode($tokenResolverInfo) |
|
458
|
1 |
|
) |
|
459
|
1 |
|
); |
|
460
|
|
|
} |
|
461
|
5 |
|
$tokenResolverType = $tokenResolverInfo[$this->xrefTokenResolverTypeKey]; |
|
462
|
5 |
|
if (!TokenResolverFactory::isRegisteredByType($tokenResolverType)) { |
|
463
|
|
|
throw new TokenResolverDefinitionException( |
|
464
|
|
|
sprintf( |
|
465
|
|
|
'Unknown token resolver type identifier "%s" at index %d for Xref key "%s".', |
|
466
|
|
|
$tokenResolverType, |
|
467
|
|
|
$tokenResolverDefinitionIndex, |
|
468
|
|
|
$xrefKey |
|
469
|
|
|
) |
|
470
|
|
|
); |
|
471
|
|
|
} |
|
472
|
5 |
|
$hasValues = isset($tokenResolverInfo[$this->xrefTokenResolverValuesKey]); |
|
473
|
5 |
|
$hasValuesXref = isset($tokenResolverInfo[$this->xrefTokenResolverValuesXrefKey]); |
|
474
|
5 |
|
if ((!$hasValues) && (!$hasValuesXref)) { |
|
475
|
|
|
throw new TokenResolverDefinitionException( |
|
476
|
|
|
sprintf( |
|
477
|
|
|
'Token resolver definition at index %d for Xref key "%s" does not have a "%s" key or a "%s" key.', |
|
478
|
|
|
$tokenResolverDefinitionIndex, |
|
479
|
|
|
$xrefKey, |
|
480
|
|
|
$this->xrefTokenResolverValuesKey, |
|
481
|
|
|
$this->xrefTokenResolverValuesXrefKey |
|
482
|
|
|
) |
|
483
|
|
|
); |
|
484
|
|
|
} |
|
485
|
5 |
|
$tokenResolverBaseType = TokenResolverFactory::getBaseTypeForType($tokenResolverType); |
|
486
|
5 |
|
if (isset($tokenResolverInfo[$this->xrefTokenResolverOptionsKey])) { |
|
487
|
5 |
|
$options = $tokenResolverInfo[$this->xrefTokenResolverOptionsKey]; |
|
488
|
5 |
|
$this->validateXrefTokenResolverOptions( |
|
489
|
5 |
|
$xrefKey, |
|
490
|
5 |
|
$tokenResolverDefinitionIndex, |
|
491
|
5 |
|
$tokenResolverBaseType, |
|
492
|
|
|
$options |
|
493
|
5 |
|
); |
|
494
|
5 |
|
} |
|
495
|
5 |
|
if ($hasValues) { |
|
496
|
5 |
|
$values = $tokenResolverInfo[$this->xrefTokenResolverValuesKey]; |
|
497
|
5 |
|
} else { // has values xref |
|
498
|
1 |
|
$xrefInfo = $tokenResolverInfo[$this->xrefTokenResolverValuesXrefKey]; |
|
499
|
1 |
|
$xref = $this->parseXrefInfo( |
|
500
|
1 |
|
sprintf('%s.%s[%d]', $xrefKey, $this->includeXrefResolversKey, $tokenResolverDefinitionIndex), |
|
501
|
1 |
|
$xrefInfo, |
|
502
|
1 |
|
$tokenResolvers, |
|
503
|
|
|
$xrefPath |
|
504
|
1 |
|
); |
|
505
|
|
|
// pass down current token resolvers |
|
506
|
1 |
|
$values = $this->recursiveCompileXref($xref, $tokenResolvers, null, null, $xrefPath); |
|
507
|
|
|
} |
|
508
|
5 |
|
if (!is_array($values)) { |
|
509
|
|
|
throw new TokenResolverDefinitionException( |
|
510
|
|
|
sprintf( |
|
511
|
|
|
'The "%s" key must be an associative array for token resolver definition at ' . |
|
512
|
|
|
'index %d for Xref key "%s".', |
|
513
|
|
|
$this->xrefTokenResolverValuesKey, |
|
514
|
|
|
$tokenResolverDefinitionIndex, |
|
515
|
|
|
$xrefKey |
|
516
|
|
|
) |
|
517
|
|
|
); |
|
518
|
|
|
} |
|
519
|
5 |
|
$resolverValues[$tokenResolverKey] = $values; |
|
520
|
5 |
|
$tokenResolverDefinitionIndex++; |
|
521
|
5 |
|
} |
|
522
|
|
|
|
|
523
|
5 |
|
$result = new XrefTokenResolverCollection(); |
|
524
|
|
|
// parse |
|
525
|
5 |
|
foreach ($tokenResolversInfo as $tokenResolverKey => $tokenResolverInfo) { |
|
526
|
5 |
|
if (isset($tokenResolverInfo[$this->xrefTokenResolverOptionsKey])) { |
|
527
|
5 |
|
$options = $tokenResolverInfo[$this->xrefTokenResolverOptionsKey]; |
|
528
|
5 |
|
} else { |
|
529
|
|
|
$options = null; |
|
530
|
|
|
} |
|
531
|
5 |
|
$tokenResolver = TokenResolverFactory::get($tokenResolverInfo[$this->xrefTokenResolverTypeKey]); |
|
532
|
5 |
|
$xrefTokenResolver = new XrefTokenResolver($tokenResolver); |
|
533
|
5 |
|
$values = $resolverValues[$tokenResolverKey]; |
|
534
|
5 |
|
$xrefTokenResolver->setRegisteredTokenValues($values); |
|
535
|
5 |
|
if (isset($options)) { |
|
536
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionIgnoreUnknownTokensKey])) { |
|
537
|
|
|
$tokenResolver->setIgnoreUnknownTokens($options[$this->xrefTokenResolverOptionIgnoreUnknownTokensKey]); |
|
538
|
|
|
} |
|
539
|
5 |
|
if ($tokenResolver::getBaseType() == ScopeTokenResolver::getBaseType()) { |
|
540
|
|
|
/** @var ScopeTokenResolver $tokenResolver */ |
|
541
|
|
|
if (isset($options[$this->xrefTokenResolverOptionScopeTokenNameKey])) { |
|
542
|
|
|
$tokenResolver->setScopeTokenName($options[$this->xrefTokenResolverOptionScopeTokenNameKey]); |
|
543
|
|
|
} |
|
544
|
|
|
if (isset($options[$this->xrefTokenResolverOptionScopeTokenNameDelimiterKey])) { |
|
545
|
|
|
$tokenResolver->setScopeTokenNameDelimiter($options[$this->xrefTokenResolverOptionScopeTokenNameDelimiterKey]); |
|
546
|
|
|
} |
|
547
|
|
|
if (isset($options[$this->xrefTokenResolverOptionScopeTokenLevelDelimiterKey])) { |
|
548
|
|
|
$tokenResolver->setScopeLevelDelimiter($options[$this->xrefTokenResolverOptionScopeTokenLevelDelimiterKey]); |
|
549
|
|
|
} |
|
550
|
|
|
if (isset($options[$this->xrefTokenResolverOptionIgnoreOutOfScopeKey])) { |
|
551
|
|
|
$tokenResolver->setIgnoreOutOfScope($options[$this->xrefTokenResolverOptionIgnoreOutOfScopeKey]); |
|
552
|
|
|
} |
|
553
|
|
|
} |
|
554
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionIgnoreUnknownFiltersKey])) { |
|
555
|
|
|
$xrefTokenResolver->setIgnoreUnknownFilters($options[$this->xrefTokenResolverOptionIgnoreUnknownFiltersKey]); |
|
556
|
|
|
} |
|
557
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionTokenRegexKey])) { |
|
558
|
|
|
$xrefTokenResolver->setTokenRegex($options[$this->xrefTokenResolverOptionTokenRegexKey]); |
|
559
|
|
|
} |
|
560
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionTokenPrefixKey])) { |
|
561
|
5 |
|
$xrefTokenResolver->setTokenPrefix($options[$this->xrefTokenResolverOptionTokenPrefixKey]); |
|
562
|
5 |
|
} |
|
563
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionTokenSuffixKey])) { |
|
564
|
5 |
|
$xrefTokenResolver->setTokenSuffix($options[$this->xrefTokenResolverOptionTokenSuffixKey]); |
|
565
|
5 |
|
} |
|
566
|
5 |
|
if (isset($options[$this->xrefTokenResolverOptionTokenFilterDelimiterKey])) { |
|
567
|
|
|
$xrefTokenResolver->setTokenFilterDelimiter($options[$this->xrefTokenResolverOptionTokenFilterDelimiterKey]); |
|
568
|
|
|
} |
|
569
|
5 |
|
} |
|
570
|
5 |
|
$result->add($xrefTokenResolver); |
|
571
|
5 |
|
} |
|
572
|
5 |
|
return $result; |
|
573
|
|
|
} |
|
574
|
|
|
|
|
575
|
|
|
/** |
|
576
|
|
|
* Recursively resolve Xrefs and compile data. |
|
577
|
|
|
* |
|
578
|
|
|
* @param Xref $xref |
|
579
|
|
|
* @param XrefTokenResolverCollection $tokenResolvers |
|
580
|
|
|
* @param string|null $includeType |
|
581
|
|
|
* @param string|array|null $includeTypeValue |
|
582
|
|
|
* @param array $xrefPath |
|
583
|
|
|
* @return array |
|
584
|
|
|
* |
|
585
|
|
|
* @throws CircularReferenceException |
|
586
|
|
|
* @throws Exception\AlreadyRegisteredException |
|
587
|
|
|
* @throws TreeCompiler\XrefResolver\Exception\UnknownXrefTypeException |
|
588
|
|
|
* @throws UnknownXrefException |
|
589
|
|
|
* @throws XrefResolverFormatException |
|
590
|
|
|
* @throws \Exception |
|
591
|
|
|
*/ |
|
592
|
7 |
|
protected function recursiveCompileXref(Xref $xref, XrefTokenResolverCollection $tokenResolvers = null, |
|
593
|
|
|
$includeType = null, $includeTypeValue = null, &$xrefPath) |
|
594
|
|
|
{ |
|
595
|
7 |
|
static $XREF_KEY = 0; |
|
596
|
7 |
|
static $XREF_RESOLVERS_KEY = 1; |
|
597
|
|
|
|
|
598
|
7 |
|
if (!isset($includeType)) { |
|
599
|
7 |
|
$includeType = static::INCLUDE_TYPE_GROUP; |
|
600
|
7 |
|
} |
|
601
|
|
|
|
|
602
|
|
|
switch ($includeType) { |
|
603
|
7 |
|
case static::INCLUDE_TYPE_GROUP: |
|
604
|
7 |
|
if (!isset($includeTypeValue)) { |
|
605
|
7 |
|
$includeTypeValue = $this->includeMainKey; |
|
606
|
7 |
|
} else if (gettype($includeTypeValue) != 'string') { |
|
607
|
|
|
throw new XrefResolverFormatException( |
|
608
|
|
|
$xref, |
|
609
|
|
|
sprintf( |
|
610
|
|
|
"Include type value must be a string representing the include group name. " . |
|
611
|
|
|
"\"%s\" given instead.", |
|
612
|
|
|
gettype($includeTypeValue) |
|
613
|
|
|
) |
|
614
|
|
|
); |
|
615
|
|
|
} |
|
616
|
7 |
|
break; |
|
617
|
|
|
case static::INCLUDE_TYPE_XREF: |
|
618
|
|
|
if (!is_array($includeTypeValue) || empty($includeTypeValue)) { |
|
619
|
|
|
throw new XrefResolverFormatException( |
|
620
|
|
|
$xref, |
|
621
|
|
|
"Include type value must be a non-empty array of strings for named includes." |
|
622
|
|
|
); |
|
623
|
|
|
} |
|
624
|
|
|
break; |
|
625
|
|
|
default: |
|
626
|
|
|
throw new \Exception(sprintf('Unknown include type "%s".', $includeType)); |
|
627
|
|
|
} |
|
628
|
7 |
|
$mustIncludeSpecificGroup = $includeTypeValue != $this->includeMainKey; |
|
629
|
|
|
|
|
630
|
7 |
|
$xref->resolve(); |
|
631
|
|
|
|
|
632
|
7 |
|
$xrefData = $xref->getData(); |
|
633
|
7 |
|
if (empty($xrefData)) { |
|
634
|
|
|
if (!is_array($xrefData)) { |
|
635
|
|
|
throw new XrefResolverFormatException( |
|
636
|
|
|
$xref, |
|
637
|
|
|
"De-serialized data must be an array." |
|
638
|
|
|
); |
|
639
|
|
|
} |
|
640
|
|
|
return array(); |
|
641
|
|
|
} |
|
642
|
|
|
|
|
643
|
7 |
View Code Duplication |
if ((!isset($xrefData[$this->includeKey])) || (!is_array($xrefData[$this->includeKey]))) { |
|
|
|
|
|
|
644
|
|
|
switch ($includeType) { |
|
645
|
5 |
|
case static::INCLUDE_TYPE_XREF: |
|
646
|
|
|
throw new XrefResolverFormatException( |
|
647
|
|
|
$xref, |
|
648
|
|
|
sprintf( |
|
649
|
|
|
"Required to explicitly include the list of Xref keys [\"%s\"] " . |
|
650
|
|
|
"but the \"%s\" key is missing from the first level.", |
|
651
|
|
|
implode('", "', $includeTypeValue), |
|
652
|
|
|
$this->includeKey |
|
653
|
|
|
) |
|
654
|
|
|
); |
|
655
|
5 |
|
case static::INCLUDE_TYPE_GROUP: |
|
656
|
5 |
|
if (!$mustIncludeSpecificGroup) { |
|
657
|
5 |
|
if (isset($xrefData[$this->addKey])) { |
|
658
|
1 |
|
$result = $xrefData[$this->addKey]; |
|
659
|
1 |
|
} else { |
|
660
|
5 |
|
if (isset($xrefData[$this->removeKey])) { |
|
661
|
|
|
unset($xrefData[$this->removeKey]); |
|
662
|
|
|
} |
|
663
|
5 |
|
$result = $xrefData; |
|
664
|
|
|
} |
|
665
|
5 |
|
if (isset($tokenResolvers)) { |
|
666
|
5 |
|
$tokenResolvers->applyToArray($result); |
|
667
|
5 |
|
} |
|
668
|
5 |
|
return $result; |
|
669
|
|
|
} |
|
670
|
|
|
throw new XrefResolverFormatException( |
|
671
|
|
|
$xref, |
|
672
|
|
|
sprintf( |
|
673
|
|
|
"Required to explicitly include the \"%s\" group of Xref keys " . |
|
674
|
|
|
"but the \"%s\" key is missing from the first level.", |
|
675
|
|
|
$includeTypeValue, |
|
676
|
|
|
$this->includeKey |
|
677
|
|
|
) |
|
678
|
|
|
); |
|
679
|
|
|
} |
|
680
|
|
|
} |
|
681
|
7 |
|
$xrefDataInclude = &$xrefData[$this->includeKey]; |
|
682
|
|
|
|
|
683
|
7 |
View Code Duplication |
if ((!isset($xrefDataInclude[$this->includeXrefKey])) || (!is_array($xrefDataInclude[$this->includeXrefKey]))) { |
|
|
|
|
|
|
684
|
|
|
switch ($includeType) { |
|
685
|
|
|
case static::INCLUDE_TYPE_XREF: |
|
686
|
|
|
throw new XrefResolverFormatException( |
|
687
|
|
|
$xref, |
|
688
|
|
|
sprintf( |
|
689
|
|
|
"Required to explicitly include the list of Xref keys [\"%s\"] " . |
|
690
|
|
|
"but the \"%s\" key is missing from the \"%s\" key on the first level.", |
|
691
|
|
|
implode('", "', $includeTypeValue), |
|
692
|
|
|
$this->includeXrefKey, |
|
693
|
|
|
$this->includeKey |
|
694
|
|
|
) |
|
695
|
|
|
); |
|
696
|
|
|
case static::INCLUDE_TYPE_GROUP: |
|
697
|
|
|
if (!$mustIncludeSpecificGroup) { |
|
698
|
|
|
if (isset($xrefData[$this->addKey])) { |
|
699
|
|
|
$result = $xrefData[$this->addKey]; |
|
700
|
|
|
} else { |
|
701
|
|
|
if (isset($xrefData[$this->removeKey])) { |
|
702
|
|
|
unset($xrefData[$this->removeKey]); |
|
703
|
|
|
} |
|
704
|
|
|
$result = $xrefData; |
|
705
|
|
|
} |
|
706
|
|
|
if (isset($tokenResolvers)) { |
|
707
|
|
|
$tokenResolvers->applyToArray($result); |
|
708
|
|
|
} |
|
709
|
|
|
return $result; |
|
710
|
|
|
} |
|
711
|
|
|
throw new XrefResolverFormatException( |
|
712
|
|
|
$xref, |
|
713
|
|
|
sprintf( |
|
714
|
|
|
"Required to explicitly include the \"%s\" group of Xref keys " . |
|
715
|
|
|
"but the \"%s\" key is missing from the \"%s\" key on the first level.", |
|
716
|
|
|
$includeTypeValue, |
|
717
|
|
|
$this->includeXrefKey, |
|
718
|
|
|
$this->includeKey |
|
719
|
|
|
) |
|
720
|
|
|
); |
|
721
|
|
|
} |
|
722
|
|
|
} |
|
723
|
7 |
|
$xrefDataIncludeXrefs = &$xrefDataInclude[$this->includeXrefKey]; |
|
724
|
|
|
|
|
725
|
7 |
|
$xrefKeysToBeResolved = $this->getXrefKeysToBeResolved( |
|
726
|
7 |
|
$xref, |
|
727
|
7 |
|
$xrefDataInclude, |
|
728
|
7 |
|
$xrefDataIncludeXrefs, |
|
729
|
7 |
|
$includeType, |
|
730
|
|
|
$includeTypeValue |
|
731
|
7 |
|
); |
|
732
|
|
|
|
|
733
|
7 |
|
$xrefsToBeParsed = array(); |
|
734
|
7 |
|
foreach ($xrefKeysToBeResolved as $xrefKeyToBeResolved) { |
|
735
|
7 |
|
if (!isset($xrefDataIncludeXrefs[$xrefKeyToBeResolved])) { |
|
736
|
|
|
throw new UnknownXrefException( |
|
737
|
|
|
sprintf( |
|
738
|
|
|
"Unable to find the required Xref definition named \"%s\".", |
|
739
|
|
|
$xrefKeyToBeResolved |
|
740
|
|
|
) |
|
741
|
|
|
); |
|
742
|
|
|
} |
|
743
|
7 |
|
$xrefsToBeParsed[$xrefKeyToBeResolved] = $xrefDataIncludeXrefs[$xrefKeyToBeResolved]; |
|
744
|
7 |
|
} |
|
745
|
7 |
|
unset($xrefDataIncludeXrefs); |
|
746
|
|
|
|
|
747
|
7 |
|
$xrefId = $xref->getId(); |
|
748
|
7 |
|
$xrefPath[$xrefId] = $xref; |
|
749
|
|
|
|
|
750
|
7 |
|
$xrefsToBeResolved = array(); |
|
751
|
7 |
|
foreach ($xrefsToBeParsed as $xrefKey => $xrefInfo) { |
|
752
|
7 |
|
$includedXref = $this->parseXrefInfo( |
|
753
|
7 |
|
$xrefKey, |
|
754
|
7 |
|
$xrefInfo, |
|
755
|
7 |
|
$tokenResolvers, |
|
756
|
|
|
$xrefPath |
|
757
|
7 |
|
); |
|
758
|
|
|
|
|
759
|
7 |
|
if (is_array($xrefInfo) && isset($xrefInfo[$this->includeXrefResolversKey])) { |
|
760
|
7 |
|
$xrefTokenResolvers = $this->parseXrefTokenResolverDefinitions( |
|
761
|
7 |
|
$xrefKey, |
|
762
|
7 |
|
$xrefInfo[$this->includeXrefResolversKey], |
|
763
|
7 |
|
$tokenResolvers, |
|
764
|
|
|
$xrefPath |
|
765
|
7 |
|
); |
|
766
|
5 |
|
} else { |
|
767
|
2 |
|
$xrefTokenResolvers = null; |
|
768
|
|
|
} |
|
769
|
|
|
|
|
770
|
5 |
|
$xrefsToBeResolved[] = array( |
|
771
|
5 |
|
$XREF_KEY => $includedXref, |
|
772
|
|
|
$XREF_RESOLVERS_KEY => $xrefTokenResolvers |
|
773
|
5 |
|
); |
|
774
|
5 |
|
} |
|
775
|
|
|
|
|
776
|
|
|
/** @var array $includedXrefs */ |
|
777
|
5 |
|
$result = array(); |
|
778
|
5 |
|
foreach ($xrefsToBeResolved as $xrefToBeResolved) { |
|
779
|
|
|
/** @var Xref $includedXref */ |
|
780
|
5 |
|
$includedXref = $xrefToBeResolved[$XREF_KEY]; |
|
781
|
5 |
|
if (isset($xrefPath[$includedXref->getId()])) { |
|
782
|
|
|
throw new CircularReferenceException( |
|
783
|
|
|
sprintf( |
|
784
|
|
|
'Tree compiler encountered circular reference at "%s" in path ["%s"].', |
|
785
|
|
|
sprintf('%s:%s', $includedXref->getType(), $includedXref->getLocation()), |
|
786
|
|
|
implode('", "', $xrefPath) |
|
787
|
|
|
) |
|
788
|
|
|
); |
|
789
|
|
|
} |
|
790
|
5 |
|
$this->xrefs->add($includedXref); |
|
791
|
|
|
/** @var XrefTokenResolverCollection $includeTokenResolvers */ |
|
792
|
5 |
|
$includeTokenResolvers = $xrefToBeResolved[$XREF_RESOLVERS_KEY]; |
|
793
|
5 |
|
if (isset($includeTokenResolvers)) { |
|
794
|
5 |
|
$downTokenResolvers = $includeTokenResolvers; |
|
795
|
5 |
|
} else { |
|
796
|
2 |
|
$downTokenResolvers = new XrefTokenResolverCollection(); |
|
797
|
|
|
} |
|
798
|
5 |
|
if (isset($tokenResolvers)) { |
|
799
|
3 |
|
$downTokenResolvers->addCollection($tokenResolvers); |
|
800
|
3 |
|
} |
|
801
|
5 |
|
$includeData = $this->recursiveCompileXref( |
|
802
|
5 |
|
$includedXref, |
|
803
|
5 |
|
$downTokenResolvers, |
|
804
|
5 |
|
static::INCLUDE_TYPE_GROUP, |
|
805
|
5 |
|
$this->includeMainKey, |
|
806
|
|
|
$xrefPath |
|
807
|
5 |
|
); |
|
808
|
5 |
|
$this->recursiveAddData($includeData, $result); |
|
809
|
5 |
|
} |
|
810
|
5 |
|
unset($xrefPath[$xrefId]); |
|
811
|
|
|
|
|
812
|
5 |
View Code Duplication |
if (isset($xrefData[$this->removeKey])) { |
|
|
|
|
|
|
813
|
1 |
|
if (isset($tokenResolvers)) { |
|
814
|
1 |
|
$tokenResolvers->applyToArray($xrefData[$this->removeKey]); |
|
815
|
1 |
|
} |
|
816
|
1 |
|
$this->recursiveRemoveData($xrefData[$this->removeKey], $result); |
|
817
|
1 |
|
} |
|
818
|
|
|
|
|
819
|
5 |
View Code Duplication |
if (isset($xrefData[$this->addKey])) { |
|
|
|
|
|
|
820
|
1 |
|
if (isset($tokenResolvers)) { |
|
821
|
1 |
|
$tokenResolvers->applyToArray($xrefData[$this->addKey]); |
|
822
|
1 |
|
} |
|
823
|
1 |
|
$this->recursiveAddData($xrefData[$this->addKey], $result); |
|
824
|
1 |
|
} |
|
825
|
|
|
|
|
826
|
5 |
|
return $result; |
|
827
|
|
|
} |
|
828
|
|
|
|
|
829
|
7 |
|
public function compileXref(Xref $xref, $includeType = null, $includeTypeValue = null) |
|
830
|
|
|
{ |
|
831
|
7 |
|
$xrefPath = array(); |
|
832
|
7 |
|
$compiledData = $this->recursiveCompileXref($xref, null, $includeType, $includeTypeValue, $xrefPath); |
|
833
|
5 |
|
return $compiledData; |
|
834
|
|
|
} |
|
835
|
|
|
|
|
836
|
|
|
public function compileLocalFile($inputFileName, $includeType = null, $includeKeyValue = null) |
|
837
|
|
|
{ |
|
838
|
|
|
$xref = new Xref(LocalFileXrefResolver::getType(), $inputFileName); |
|
839
|
|
|
return $this->compileXref($xref, $includeType, $includeKeyValue); |
|
840
|
|
|
} |
|
841
|
|
|
|
|
842
|
|
|
public function compileUrl($inputUrl, $includeType = null, $includeKeyValue = null) |
|
843
|
|
|
{ |
|
844
|
|
|
$xref = new Xref(UrlXrefResolver::getType(), $inputUrl); |
|
845
|
|
|
return $this->compileXref($xref, $includeType, $includeKeyValue); |
|
846
|
|
|
} |
|
847
|
|
|
|
|
848
|
|
|
public function save(array $tree, $fileName) |
|
849
|
|
|
{ |
|
850
|
|
|
$fileExtension = pathinfo($fileName, PATHINFO_EXTENSION); |
|
851
|
|
|
if (!TreeSerializerFactory::isRegisteredByFileExtension($fileExtension)) { |
|
852
|
|
|
throw new NotRegisteredException( |
|
853
|
|
|
sprintf( |
|
854
|
|
|
'Unable to find serializer for extension "%s".', |
|
855
|
|
|
$fileExtension |
|
856
|
|
|
) |
|
857
|
|
|
); |
|
858
|
|
|
} |
|
859
|
|
|
$serializer = TreeSerializerFactory::getByFileExtension($fileExtension); |
|
860
|
|
|
$serializedTree = $serializer->serialize($tree); |
|
861
|
|
|
file_put_contents($fileName, $serializedTree); |
|
862
|
|
|
} |
|
863
|
|
|
} |
|
864
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.