See More

*/ final class ObjectEncoder implements Feature\ElementAware, XmlEncoder { /** * @param class-string $className */ public function __construct( private readonly string $className ) { } /** * @return Iso */ public function iso(Context $context): Iso { $objectAccess = lazy(static fn (): ObjectAccess => ObjectAccess::forContext($context)); return new Iso( /** * @param TObj|array $value * @return non-empty-string */ function (object|array $value) use ($context, $objectAccess) : string { return $this->to($context, $objectAccess(), $value); }, /** * @param non-empty-string|Element $value * @return TObj */ function (string|Element $value) use ($context, $objectAccess) : object { return $this->from( $context, $objectAccess(), ($value instanceof Element ? $value : Element::fromString($value)) ); } ); } /** * @param TObj|array $data * * @return non-empty-string */ private function to(Context $context, ObjectAccess $objectAccess, object|array $data): string { /** @var object $data */ $data = is_array($data) ? (object) $data : $data; $defaultAction = writeChildren([]); $children = [ XsiAttributeBuilder::forEncodedValue( $context, $this, $data, forceIncludeXsiTargetNamespace: !$objectAccess->isAnyPropertyQualified, ), ]; foreach ($objectAccess->properties as $normalizePropertyName => $property) { /** @var mixed $value */ $value = $objectAccess->encodeReaders[$normalizePropertyName]($data); if ($value === null && match ($objectAccess->onNull[$normalizePropertyName]) { NullValueHandling::Write => false, NullValueHandling::Skip => true, NullValueHandling::SkipWhenAbsent => !property_is_initialized($data, $normalizePropertyName), }) { continue; } $iso = $objectAccess->isos[$normalizePropertyName]; $children[] = match(true) { $objectAccess->isAttribute[$normalizePropertyName] => $value !== null ? (new AttributeBuilder( $property->getType(), (string) $iso->to($value) ))(...) : $defaultAction, $property->getName() === '_' => $value !== null ? buildValue((string) $iso->to($value)) : (new NilAttributeBuilder())(...), default => raw((string) $iso->to($value)) }; } return (new XsdTypeXmlElementWriter())( $context, writeChildren($children) ); } /** * @return TObj */ private function from(Context $context, ObjectAccess $objectAccess, Element $data): object { $lookup = ElementLookup::fromElement($data); /** @var Iso, array> $objectData */ $objectData = object_data($this->className); $result = []; foreach ($objectAccess->isos as $normalizePropertyName => $iso) { /** @var Element|ElementList|string|null $value */ $value = $objectAccess->decodeReaders[$normalizePropertyName]($lookup); /** * @var mixed * @psalm-suppress PossiblyNullArgument */ $result[$normalizePropertyName] = match(true) { $objectAccess->isAttribute[$normalizePropertyName] => $iso->from($value), $value !== null => $iso->from($value), default => $objectAccess->decodeDefaultValues[$normalizePropertyName], }; } return $objectData->from($result); } }