/
MarshallService.php
550 lines (522 loc) · 23.6 KB
/
MarshallService.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
<?php
/***************************************************************
* Copyright notice
*
* (c) 2014 Claus Due <claus@namelesscoder.net>
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
* DomainObject Marshaling Service
*
* A (slower) replacement for using serialize() on Extbase
* DomainObjects. Please note that this Service is significantly
* slower than serialization and native (fx. WDDX) marshaling -
* but it IS very much compatible with Extbase DomainObjects.
*
* Serialisation of DomainObjects is complicated in Extbase
* extensions. DateTime objects cannot be serialized,
* ObjectStorages may present problems - and worst of all,
* serialize() has severe issues with Unicode support, reporting
* incorrect string lengths which cause unserialize() to fail
* _silently_ (E_NOTICE is given with an offset that causes the
* error).
*
* This Service aims to make all of the above a non-issue while
* also enabling byte-safe transmission of the serialised objects.
* This Service...
*
* - Does NOT support marshaling Closures. Never marshal Closures!
* - Serializes to a JSON structure with each object nested in
* a small meta-configuration describing class name etc.
* - Encodes unicode characters as escaped byte sequences which
* are much safer for transmission.
* - Avoids NULL-bytes in the serialised representation.
* - Supports recursive objects.
* - Supports ObjectStorage and inflation hereof.
* - Serialises private and protected property values as well.
* - Preserves every UID and clean states across marshaling.
* - Skips properties annotated with a @dontmarshal tag signature.
*
* Can in theory be used to store "snapshots" of DomainObjects with
* every single related object instance and DateTime, UID etc. which
* can be inflated and ->update()'ed via a matching Repository. But
* its primary use is the byte-safe network marshaled transmission
* of complex Extbase DomainObject instances.
*
* PLEASE NOTE: if the output is used in JSON, private and protected
* property values become exposed with no way of determining the
* original access scope. This could potentially pose problems and/or
* present a security risk!
*
* The Service has a built-in safety feature which allows inflation
* of related objects ONLY when the class of those objects are valid
* according to the ClassReflection of the original class. By also
* specifying a (list of) allowed root classes you can completely
* secure the inflation process.
*
* Output is safe for use with SOAP, XML-RPC, JSON (requires a JS-
* based manual inflation due to the use of meta-nesting of objects)
* etc. and can be compressed using any compression routine.
*
* @author Claus Due
* @package Tool
* @subpackage Service
*/
class Tx_Tool_Service_MarshallService implements t3lib_Singleton {
const TYPE_CLOSURE = 'Closure';
const TYPE_DATETIME = 'DateTime';
const TYPE_DOMAINOBJECT = 'DomainObject';
const TYPE_ARRAY = 'Array';
const TYPE_ARRAYOBJECT = 'ArrayObject';
const TYPE_OBJECT = 'Object';
const TYPE_OBJECTSTORAGE = 'ObjectStorage';
/**
* @var array
*/
protected $unsupportedTypes = array(
self::TYPE_CLOSURE
);
/**
* @var array
*/
protected $rewrites = array(
'Tx_Extbase_Persistence_LazyObjectStorage' => 'Tx_Extbase_Persistence_ObjectStorage',
'TYPO3\\CMS\\Extbase\\Persistence\\LazyObjectStorage' => 'TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage',
'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyObjectStorage' => 'TYPO3\\CMS\\Extbase\\Persistence\\ObjectStorage',
);
/**
* @var Tx_Extbase_Object_ObjectManagerInterface
*/
protected $objectManager;
/**
* @var Tx_Tool_Service_JsonService
*/
protected $jsonService;
/**
* @var Tx_Extbase_Reflection_Service
*/
protected $reflectionService;
/**
* @param Tx_Extbase_Object_ObjectManagerInterface $objectManager
*/
public function injectObjectManager(Tx_Extbase_Object_ObjectManagerInterface $objectManager) {
$this->objectManager = $objectManager;
}
/**
* @param Tx_Tool_Service_JsonService $jsonService
* @return void
*/
public function injectJsonService(Tx_Tool_Service_JsonService $jsonService) {
$this->jsonService = $jsonService;
}
/**
* @param Tx_Extbase_Reflection_Service $reflectionService
* @return void
*/
public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
$this->reflectionService = $reflectionService;
}
/**
* Marshall (deflate, encode) an object instance down to a JSON-based structure.
*
* Throws a RuntimeException if trying to marshall unsupported types (i.e. Closures)
*
* @param object $object
* @return string
* @throws RuntimeException
*/
public function marshall($object) {
ini_set('memory_limit', '2048M');
$encountered = array();
$marshaled = $this->deflatePropertyValue($object, $encountered);
$encoded = $this->jsonService->encode($marshaled);
return $encoded;
}
/**
* Unmarshals (inflates, decodes) a JSON-based structure up to an object instance.
*
* @param string $string
* @param mixed $allowedRootClassOrClasses A string class name or an array of ROOT OBJECT class names which are permitted
* @return object|NULL
* @throws RuntimeException
*/
public function unmarshall($string, $allowedRootClassOrClasses = NULL) {
$string = trim($string);
$decoded = $this->jsonService->decode($string);
if (NULL === $decoded) {
throw new Exception('Unable to unmarshall a marshaled object; the decoded result was NULL. ' .
'Marshaled object data: ' . var_export($string, TRUE), 1361052486);
}
if (TRUE === isset($decoded['class'])) {
$rootClassName = $decoded['class'];
if (is_array($allowedRootClassOrClasses) === TRUE) {
$rootClassIsPermitted = in_array($rootClassName, $allowedRootClassOrClasses);
} else {
$rootClassIsPermitted = ($rootClassName === $allowedRootClassOrClasses || $allowedRootClassOrClasses === NULL);
}
if ($rootClassIsPermitted === FALSE) {
throw new RuntimeException('Attempt to unmarshall a disallowed root object class: "' . $rootClassName . '".', 1358284604);
}
} elseif (TRUE === is_null($decoded)) {
throw new RuntimeException('Unable to unmarshall input, return value was NULL. Input was: ' . $string, 1360854250);
}
$encounteredObjectInstancesForReuse = array();
$unmarshaled = $this->inflatePropertyValue($decoded, $encounteredObjectInstancesForReuse);
return $unmarshaled;
}
/**
* Does $propertyName on $instance contain a data type which supports deflation?
*
* @param object $instance Instance of an object, DomainObject included
* @param string $propertyName String name of property on DomainObject instance which is up for assertion
* @return boolean
* @throws RuntimeException
*/
protected function assertSupportsDeflation($instance, $propertyName) {
$className = get_class($instance);
$gettableProperties = $this->reflectionService->getClassPropertyNames($className);
if (FALSE === in_array($propertyName, $gettableProperties)) {
return FALSE;
}
try {
$value = Tx_Extbase_Reflection_ObjectAccess::getProperty($instance, $propertyName, TRUE);
} catch (RuneimeException $error) {
$getter = 'get' . ucfirst($propertyName);
if (FALSE === method_exists($instance, $getter)) {
return FALSE;
}
t3lib_div::sysLog('MarshallService encountered an error while attempting to retrieve the value of ' .
$className . '::$' . $propertyName . ' - assuming safe deflation is possible', 'site', t3lib_div::SYSLOG_SEVERITY_NOTICE);
return TRUE;
}
return (FALSE === $value instanceof Closure);
}
/**
* May $propertyName on $instance be deflated according to doc comment tags?
*
* @param object $instance Instance of an object, DomainObject included
* @param string $propertyName String name of property on DomainObject instance which is up for assertion
* @return boolean
* @throws RuntimeException
*/
protected function assertAllowsDeflation($instance, $propertyName) {
if (self::TYPE_CLOSURE === gettype($instance)) {
return FALSE;
}
return TRUE;
}
/**
* May $propertyName on $className be inflated if target is a $propertyType instance and doc comment tags allow?
*
* @param string $className String class name of the class being inflated
* @param string $propertyName String name of property being inflated on class
* @param string $propertyType String type of the property being inflated according to input, asserted against Reflection
* @return boolean
*/
protected function assertAllowsInflation($className, $propertyName, $propertyType) {
$type = $this->assertTargetInstanceClassName($className, $propertyName);
return ($type === $propertyType || FALSE !== strpos($type, $propertyType));
}
/**
* Does the target $propertyName on $className contain a data type which supports inflation?
*
* @param string $className String class name of the class being inflated
* @param string $propertyName String name of property being inflated on class
* @param string $propertyType String type of the property being inflated according to input, asserted against blacklist
* @return boolean
*/
protected function assertSupportsInflation($className, $propertyName, $propertyType) {
$tags = $this->reflectionService->getPropertyTagsValues($className, $propertyName);
if (TRUE === isset($tags['dontmarshall'])) {
return FALSE;
}
return TRUE;
}
/**
* Returns the string object class name of $property on $instanceOrClassName - or NULL if target $property is not of type object.
*
* @param mixed $instanceOrClassName
* @param string $propertyName
* @return string|NULL
*/
protected function assertTargetInstanceClassName($instanceOrClassName, $propertyName) {
$className = (TRUE === is_object($instanceOrClassName) ? get_class($instanceOrClassName) : $instanceOrClassName);
$type = $this->reflectionService->getPropertyTagValues($className, $propertyName, 'var');
$bracketPosition = strpos($type, '<');
if (FALSE !== $bracketPosition) {
$type = substr($type, $bracketPosition + 1);
$type = substr($type, 0, -1);
}
$squareBracketPosition = strpos($type, '[');
if (FALSE !== $squareBracketPosition) {
$type = substr($type, 0, $squareBracketPosition);
}
return (class_exists($type) ? $type : NULL);
}
/**
* Inflates a single value $propertyValue by up-casting it to an instance/variable of type $propertyType.
*
* @param array $metaConfigurationAndDeflatedValue The deflated configuration and value
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return mixed
*/
protected function inflatePropertyValue(array $metaConfigurationAndDeflatedValue, array &$encounteredClassesIndexedBySplHash) {
$propertyType = $metaConfigurationAndDeflatedValue['type'];
$propertyValue = $metaConfigurationAndDeflatedValue['value'];
$unmarshaled = $propertyValue;
if ($propertyType === self::TYPE_DATETIME) {
$unmarshaled = $this->inflateDateTime($propertyValue);
} elseif ($propertyType === self::TYPE_DOMAINOBJECT) {
$unmarshaled = $this->inflateObject($metaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
} elseif ($propertyType === self::TYPE_ARRAYOBJECT || $propertyType === self::TYPE_OBJECTSTORAGE) {
$unmarshaled = $this->inflateArrayObject($metaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
} elseif ($propertyType === self::TYPE_OBJECT) {
$unmarshaled = $this->inflateObject($metaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
} elseif (is_array($propertyValue) === TRUE) {
$unmarshaled = $this->inflateArray($metaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
}
return $unmarshaled;
}
/**
* Deflates a single instance/variable into a meta-information-wrapped deflated value (array of meta plus deflated value).
*
* @param mixed $propertyValue The complex-type inflated/original instance or variable
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return array
*/
protected function deflatePropertyValue($propertyValue, array &$encounteredClassesIndexedBySplHash) {
$metaInformationAndDeflatedValue = array();
if ($propertyValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_DOMAINOBJECT;
$metaInformationAndDeflatedValue['hash'] = spl_object_hash($propertyValue);
$metaInformationAndDeflatedValue['class'] = get_class($propertyValue);
$metaInformationAndDeflatedValue['value'] = $this->deflateObject($propertyValue, $encounteredClassesIndexedBySplHash);
} elseif ($propertyValue instanceof DateTime) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_DATETIME;
$metaInformationAndDeflatedValue['value'] = $this->deflateDateTime($propertyValue);
} elseif ($propertyValue instanceof Tx_Extbase_Persistence_ObjectStorage) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_OBJECTSTORAGE;
$metaInformationAndDeflatedValue['class'] = get_class($propertyValue);
$metaInformationAndDeflatedValue['value'] = $this->deflateArray(iterator_to_array($propertyValue), $encounteredClassesIndexedBySplHash);
} elseif ($propertyValue instanceof ArrayObject) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_ARRAYOBJECT;
$metaInformationAndDeflatedValue['hash'] = spl_object_hash($propertyValue);
$metaInformationAndDeflatedValue['class'] = get_class($propertyValue);
$metaInformationAndDeflatedValue['value'] = $this->deflateArrayObject($propertyValue, $encounteredClassesIndexedBySplHash);
} elseif (is_array($propertyValue) === TRUE) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_ARRAY;
$metaInformationAndDeflatedValue['value'] = $this->deflateArray($propertyValue, $encounteredClassesIndexedBySplHash);
} elseif (is_object($propertyValue) === TRUE) {
$metaInformationAndDeflatedValue['type'] = self::TYPE_OBJECT;
$metaInformationAndDeflatedValue['class'] = get_class($propertyValue);
$metaInformationAndDeflatedValue['value'] = $this->deflateObject($propertyValue, $encounteredClassesIndexedBySplHash);
} else {
$metaInformationAndDeflatedValue['type'] = gettype($propertyValue);
$metaInformationAndDeflatedValue['value'] = $propertyValue;
}
return $metaInformationAndDeflatedValue;
}
/**
* Deflates a DateTime value down to a UNIX timestamp (negative supported, 64-bit safe) integer.
*
* @param DateTime $dateTime
* @return integer
*/
protected function deflateDateTime(DateTime $dateTime) {
$timestamp = $dateTime->format('U');
return $timestamp;
}
/**
* Inflates a deflated "meta-information-plus-deflated-value" array up to a DateTime instance.
*
* @param mixed $metaConfigurationAndDeflatedValueOrTimestamp The deflated configuration and value or a plain UNIX timestamp
* @return DateTime
*/
protected function inflateDateTime($metaConfigurationAndDeflatedValueOrTimestamp) {
if (FALSE === is_array($metaConfigurationAndDeflatedValueOrTimestamp)) {
$timestamp = $metaConfigurationAndDeflatedValueOrTimestamp;
} else {
$timestamp = $metaConfigurationAndDeflatedValueOrTimestamp['value'];
}
$dateTime = DateTime::createFromFormat('U', $timestamp);
return $dateTime;
}
/**
* Deflates a DomainObject instance down to an array of meta-configuration and deflated value
*
* @param object $object
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return array
* @throws RuntimeException
*/
protected function deflateObject($object, array &$encounteredClassesIndexedBySplHash) {
$className = get_class($object);
$objectReflection = new ReflectionObject($object);
$marshaled = array();
$hash = spl_object_hash($object);
if (TRUE === isset($encounteredClassesIndexedBySplHash[$hash])) {
return $hash;
}
$encounteredClassesIndexedBySplHash[$hash] = $hash;
foreach ($objectReflection->getProperties() as $propertyReflection) {
unset($propertyValue);
$propertyName = $propertyReflection->getName();
$supportsDeflation = $this->assertSupportsDeflation($object, $propertyName);
if (FALSE === $supportsDeflation) {
continue;
}
$allowsDeflation = $this->assertAllowsDeflation($object, $propertyName);
if (FALSE === $allowsDeflation) {
throw new RuntimeException('Attempt to marshal a prohibited type (property "' .
$propertyName . '" on class "' . $className . '")', 1358282768);
}
if (method_exists($propertyReflection, 'setAccessible') === TRUE) {
$propertyReflection->setAccessible(TRUE);
$propertyValue = $propertyReflection->getValue($object);
$propertyReflection->setAccessible(FALSE);
} else {
$getter = 'get' . ucfirst($propertyName);
if (method_exists($object, $getter) === TRUE) {
$propertyValue = $object->$getter();
}
}
if (isset($propertyValue) === TRUE) {
$metaConfigurationAndDeflatedValue = $this->deflatePropertyValue($propertyValue, $encounteredClassesIndexedBySplHash);
$marshaled[$propertyName] = $metaConfigurationAndDeflatedValue;
}
}
return $marshaled;
}
/**
* Inflates a deflated "meta-information-plus-deflated-value" array up to a DomainObject instance.
*
* @param array $metaConfigurationAndDeflatedValue The deflated configuration and value
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return Tx_Extbase_DomainObject_DomainObjectInterface
*/
protected function inflateObject(array $metaConfigurationAndDeflatedValue, array &$encounteredClassesIndexedBySplHash) {
if (is_string($metaConfigurationAndDeflatedValue['value'])) {
$possibleHash = $metaConfigurationAndDeflatedValue['value'];
if (isset($encounteredClassesIndexedBySplHash[$possibleHash]) === TRUE) {
return $encounteredClassesIndexedBySplHash[$possibleHash];
}
return NULL;
}
$className = $metaConfigurationAndDeflatedValue['class'];
if (TRUE === isset($this->rewrites[$className])) {
$className = $this->rewrites[$className];
}
$hash = $metaConfigurationAndDeflatedValue['hash'];
$instance = $this->objectManager->create($className);
$objectReflection = new ReflectionObject($instance);
$encounteredClassesIndexedBySplHash[$hash] = $instance;
foreach ($metaConfigurationAndDeflatedValue['value'] as $propertyName => $propertyMetaConfigurationAndDeflatedValue) {
$propertyMetaConfigurationAndDeflatedValue = $metaConfigurationAndDeflatedValue['value'][$propertyName];
$propertyReflection = $objectReflection->getProperty($propertyName);
$inflatedValue = $this->inflatePropertyValue($propertyMetaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
if (method_exists($propertyReflection, 'setAccessible') === TRUE) {
$propertyReflection->setAccessible(TRUE);
$propertyReflection->setValue($instance, $inflatedValue);
$propertyReflection->setAccessible(FALSE);
} else {
// on PHP 5.2, there's no way to directly set the property - we'll have to use the setter method if one exists
// and if one does not exists, silently ignore the property. This will limit the output but prevent breakage.
$setter = 'set' . ucfirst($propertyName);
if (method_exists($instance, $setter)) {
$instance->$setter($inflatedValue);
}
}
}
return $instance;
}
/**
* Deflates an ArrayObject into a "meta-information-plus-simple-array" array. Also deflates all members of the ArrayAccess
* instance into the appropriate types while also respecting doc comment annotations.
*
* @param ArrayObject $arrayObject An instance of a ArrayObject source
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return array
*/
protected function deflateArrayObject(ArrayObject $arrayObject, array &$encounteredClassesIndexedBySplHash) {
return $this->deflateArray(iterator_to_array($arrayObject, TRUE), $encounteredClassesIndexedBySplHash);
}
/**
* Inflates a "meta-information-plus-simple-array" up to the configured type of ArrayObject instance. Also inflates all
* nested, deflated configurations up into members on the ArrayObject instance, using the appropriate inflation method.
*
* @param array $metaConfigurationAndDeflatedValue
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return ArrayObject
*/
protected function inflateArrayObject(array $metaConfigurationAndDeflatedValue, array &$encounteredClassesIndexedBySplHash) {
$className = $metaConfigurationAndDeflatedValue['class'];
if (TRUE === isset($this->rewrites[$className])) {
$className = $this->rewrites[$className];
}
if (is_string($metaConfigurationAndDeflatedValue['value']) === TRUE) {
$possibleHash = $metaConfigurationAndDeflatedValue['value'];
if (isset($encounteredClassesIndexedBySplHash[$possibleHash]) === TRUE) {
return $encounteredClassesIndexedBySplHash[$possibleHash];
}
return NULL;
}
$instance = $this->objectManager->create($className);
foreach ($metaConfigurationAndDeflatedValue['value'] as $index => $memberMetaConfigurationAndDeflatedValue) {
$inflatedMember = $this->inflatePropertyValue($memberMetaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
if ($instance instanceof Tx_Extbase_Persistence_ObjectStorage) {
$instance->attach($inflatedMember);
} elseif ($instance instanceof ArrayAccess || is_array($instance) === TRUE) {
$instance[$index] = $inflatedMember;
}
}
return $instance;
}
/**
* Deflates an array down into a "meta-information-plus-simple-array" array. Also deflates all members of the array into the
* appropriate types while also respecting doc comment annotations.
*
* @param array $array An array source
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return array
*/
protected function deflateArray(array $array, array &$encounteredClassesIndexedBySplHash) {
$deflated = array();
foreach ($array as $index => $member) {
$memberMetaConfigurationAndDeflatedValue = $this->deflatePropertyValue($member, $encounteredClassesIndexedBySplHash);
$deflated[$index] = $memberMetaConfigurationAndDeflatedValue;
}
return $deflated;
}
/**
* Inflates a "meta-information-plus-simple-array" up to the configured type of ArrayAccess instance. Also inflates all
* nested, deflated configurations up into members on the ArrayAccess instance, using the appropriate inflation method.
*
* @param array $metaConfigurationAndDeflatedValue
* @param array $encounteredClassesIndexedBySplHash A cumulative array of encountered objects indexed by SPL hash
* @return array
*/
protected function inflateArray(array $metaConfigurationAndDeflatedValue, array &$encounteredClassesIndexedBySplHash) {
$array = array();
foreach ($metaConfigurationAndDeflatedValue['value'] as $index => $memberMetaConfigurationAndDeflatedValue) {
$array[$index] = $this->inflatePropertyValue($memberMetaConfigurationAndDeflatedValue, $encounteredClassesIndexedBySplHash);
}
return $array;
}
}