147 public function map($json, $object)
149 if ($this->bEnforceMapType && !is_object($json)) {
150 throw new InvalidArgumentException(
151 'JsonMapper::map() requires first argument to be an object'
152 .
', ' . gettype($json) .
' given.'
155 if (!is_object($object) && (!is_string($object) || !class_exists($object))) {
156 throw new InvalidArgumentException(
157 'JsonMapper::map() requires second argument to '
158 .
'be an object or existing class name'
159 .
', ' . gettype($object) .
' given.'
163 if (is_string($object)) {
167 $strClassName = get_class($object);
168 $rc =
new ReflectionClass($object);
169 $strNs = $rc->getNamespaceName();
170 $providedProperties = array();
171 foreach ($json as $key => $jvalue) {
173 $providedProperties[$key] =
true;
177 if (!isset($this->arInspectedClasses[$strClassName][$key])) {
178 $this->arInspectedClasses[$strClassName][$key]
182 list($hasProperty, $accessor, $type, $isNullable)
183 = $this->arInspectedClasses[$strClassName][$key];
186 if ($this->bExceptionOnUndefinedProperty) {
188 'JSON property "' . $key .
'" does not exist'
189 .
' in object of type ' . $strClassName
191 }
else if ($this->undefinedPropertyHandler !==
null) {
192 $undefinedPropertyKey = call_user_func(
193 $this->undefinedPropertyHandler,
194 $object, $key, $jvalue
197 if (is_string($undefinedPropertyKey)) {
198 list($hasProperty, $accessor, $type, $isNullable)
204 'Property {property} does not exist in {class}',
205 array(
'property' => $key,
'class' => $strClassName)
214 if ($accessor ===
null) {
215 if ($this->bExceptionOnUndefinedProperty) {
217 'JSON property "' . $key .
'" has no public setter method'
218 .
' in object of type ' . $strClassName
223 'Property {property} has no public setter method in {class}',
224 array(
'property' => $key,
'class' => $strClassName)
229 if ($isNullable || !$this->bStrictNullTypes) {
230 if ($jvalue ===
null) {
235 }
else if ($jvalue ===
null) {
237 'JSON property "' . $key .
'" in class "'
238 . $strClassName .
'" must not be NULL'
245 if ($type ===
null || $type ===
'mixed') {
259 'JSON property "' . $key .
'" in class "'
260 . $strClassName .
'" is of type ' . gettype($jvalue) .
' and'
261 .
' cannot be converted to ' . $type
264 settype($jvalue, $type);
272 'Empty type at property "'
273 . $strClassName .
'::$' . $key .
'"'
275 }
else if (strpos($type,
'|')) {
277 'Cannot decide which of the union types shall be used: '
287 $subtype = substr($type, 0, -2);
288 }
else if (substr($type, -1) ==
']') {
289 list($proptype, $subtype) = explode(
'[', substr($type, 0, -1));
290 if ($proptype ==
'array') {
299 if (is_a($type,
'ArrayAccess',
true)) {
304 if ($array !==
null) {
305 if (!is_array($jvalue) && $this->
isFlatType(gettype($jvalue))) {
307 'JSON property "' . $key .
'" must be an array, '
308 . gettype($jvalue) .
' given'
314 $child = $this->
mapArray($jvalue, $array, $subtype, $key);
315 }
else if ($this->
isFlatType(gettype($jvalue))) {
318 if ($this->bStrictObjectTypeChecking) {
320 'JSON property "' . $key .
'" must be an object, '
321 . gettype($jvalue) .
' given'
327 $this->
map($jvalue, $child);
332 if ($this->bExceptionOnMissingData) {
336 if ($this->bRemoveUndefinedAttributes) {
340 if ($this->postMappingMethod !==
null
341 && $rc->hasMethod($this->postMappingMethod)
343 $refDeserializePostMethod = $rc->getMethod(
344 $this->postMappingMethod
346 $refDeserializePostMethod->setAccessible(
true);
347 $refDeserializePostMethod->invoke(
348 $object, ...$this->postMappingMethodArguments
441 public function mapArray($json, $array, $class =
null, $parent_key =
'')
443 $originalClass = $class;
444 foreach ($json as $key => $jvalue) {
445 $class = $this->getMappedType($originalClass, $jvalue);
446 if ($class ===
null) {
447 $array[$key] = $jvalue;
448 }
else if ($this->isArrayOfType($class)) {
449 $array[$key] = $this->mapArray(
452 substr($class, 0, -2)
454 }
else if ($this->isFlatType(gettype($jvalue))) {
457 if ($this->isSimpleType($class)) {
458 settype($jvalue, $class);
459 $array[$key] = $jvalue;
461 if ($this->bStrictObjectTypeChecking) {
464 .
' "' . ($parent_key ? $parent_key :
'?') .
'"'
465 .
' (array key "' . $key .
'") must be an object, '
466 . gettype($jvalue) .
' given'
470 $array[$key] = $this->createInstance(
471 $class,
true, $jvalue
474 }
else if ($this->isFlatType($class)) {
476 'JSON property "' . ($parent_key ? $parent_key :
'?') .
'"'
477 .
' is an array of type "' . $class .
'"'
478 .
' but contained a value of type'
479 .
' "' . gettype($jvalue) .
'"'
481 }
else if (is_a($class,
'ArrayObject',
true)) {
482 $array[$key] = $this->mapArray(
484 $this->createInstance($class)
487 $array[$key] = $this->map(
488 $jvalue, $this->createInstance($class,
false, $jvalue)
511 $setter =
'set' . $this->getCamelCaseName($name);
513 if ($rc->hasMethod($setter)) {
514 $rmeth = $rc->getMethod($setter);
515 if ($rmeth->isPublic() || $this->bIgnoreVisibility) {
517 $rparams = $rmeth->getParameters();
518 if (count($rparams) > 0) {
519 $isNullable = $rparams[0]->allowsNull();
520 $ptype = $rparams[0]->getType();
521 if ($ptype !==
null) {
522 $typeName = $this->stringifyReflectionType($ptype);
525 if ($typeName !==
'array') {
535 $docblock = $rmeth->getDocComment();
536 $annotations = static::parseAnnotations($docblock);
538 if (!isset($annotations[
'param'][0])) {
539 return array(
true, $rmeth,
null, $isNullable);
541 list($type) = explode(
' ', trim($annotations[
'param'][0]));
542 return array(
true, $rmeth, $type, $this->isNullable($type));
551 if ($class->hasProperty($name)) {
552 $rprop = $class->getProperty($name);
554 }
while ($rprop ===
null && $class = $class->getParentClass());
556 if ($rprop ===
null) {
558 foreach ($rc->getProperties() as $p) {
559 if ((strcasecmp($p->name, $name) === 0)) {
566 if ($rprop !==
null) {
567 if ($rprop->isPublic() || $this->bIgnoreVisibility) {
568 $docblock = $rprop->getDocComment();
569 if (PHP_VERSION_ID >= 80000 && $docblock ===
false
570 && $class->hasMethod(
'__construct')
572 $docblock = $class->getMethod(
'__construct')->getDocComment();
574 $annotations = static::parseAnnotations($docblock);
576 if (!isset($annotations[
'var'][0])) {
577 if (PHP_VERSION_ID >= 80000 && $rprop->hasType()
578 && isset($annotations[
'param'])
580 foreach ($annotations[
'param'] as $param) {
581 if (strpos($param,
'$' . $rprop->getName()) !==
false) {
582 list($type) = explode(
' ', $param);
584 true, $rprop, $type, $this->isNullable($type)
592 if (PHP_VERSION_ID >= 70400 && $rprop->hasType()) {
593 $rPropType = $rprop->getType();
594 $propTypeName = $this->stringifyReflectionType($rPropType);
595 if ($this->isSimpleType($propTypeName)) {
600 $rPropType->allowsNull()
607 '\\' . ltrim($propTypeName,
'\\'),
608 $rPropType->allowsNull()
612 return array(
true, $rprop,
null,
false);
616 list($type) = explode(
' ', $annotations[
'var'][0]);
618 return array(
true, $rprop, $type, $this->isNullable($type));
621 return array(
true,
null,
null,
false);
626 return array(
false,
null,
null,
false);
674 $object, $accessor, $value
676 if (!$accessor->isPublic() && $this->bIgnoreVisibility) {
677 $accessor->setAccessible(
true);
679 if ($accessor instanceof ReflectionProperty) {
680 $accessor->setValue($object, $value);
681 }
else if (is_array($value) && $this->hasVariadicArrayType($accessor)) {
682 $accessor->invoke($object, ...$value);
685 $accessor->invoke($object, $value);
735 if (isset($this->classMap[$type])) {
736 $target = $this->classMap[$type];
737 }
else if (is_string($type) && $type !==
'' && $type[0] ==
'\\'
738 && isset($this->classMap[substr($type, 1)])
740 $target = $this->classMap[substr($type, 1)];
746 if (is_callable($target)) {
747 $type = $target($type, $jvalue);