From 7b94f1e45016d85b58f705e3b9bd8cd40d9aca15 Mon Sep 17 00:00:00 2001 From: Daniel Carbone Date: Tue, 28 Jan 2025 11:45:45 -0600 Subject: [PATCH] its currently broken, but lots of work towards better xml serialization --- files/constants.php | 6 +- src/Utilities/ImportUtils.php | 42 +++++-- src/Version/Definition/Property.php | 20 +-- src/Version/Definition/Type.php | 63 +++++++--- .../core/encoding/enum_value_xml_location.php | 3 +- .../core/types/interface_contained_type.php | 14 ++- .../core/types/interface_element_type.php | 85 +++++++++++++ .../interface_primitive_container_type.php | 79 ++++++++++++ .../core/types/interface_primitive_type.php | 34 +---- .../core/types/interface_resource_type.php | 85 +++++++++++++ template/core/types/interface_type.php | 52 +------- template/versions/types/class_default.php | 81 +++++++----- .../types/properties/methods/default.php | 28 ++++- .../serialization/json/unserialize/header.php | 22 +++- .../serialization/xml/serialize/body.php | 119 +++++++++++------- .../serialization/xml/serialize/header.php | 17 ++- .../serialization/xml/unserialize/body.php | 4 +- .../serialization/xml/unserialize/header.php | 19 ++- .../versions/types/validation/methods.php | 2 +- 19 files changed, 545 insertions(+), 230 deletions(-) create mode 100644 template/core/types/interface_element_type.php create mode 100644 template/core/types/interface_primitive_container_type.php create mode 100644 template/core/types/interface_resource_type.php diff --git a/files/constants.php b/files/constants.php index eb6bc735..53c078d0 100644 --- a/files/constants.php +++ b/files/constants.php @@ -108,9 +108,13 @@ // Core types entities const PHPFHIR_TYPES_INTERFACE_TYPE = 'TypeInterface'; +const PHPFHIR_TYPES_INTERFACE_PRIMITIVE_TYPE = 'PrimitiveTypeInterface'; +const PHPFHIR_TYPES_INTERFACE_PRIMITIVE_CONTAINER_TYPE = 'PrimitiveContainerTypeInterface'; +const PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE = 'ElementTypeInterface'; +const PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE = 'ResourceTypeInterface'; + const PHPFHIR_TYPES_INTERFACE_CONTAINED_TYPE = 'ContainedTypeInterface'; const PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER = 'CommentContainerInterface'; -const PHPFHIR_TYPES_INTERFACE_PRIMITIVE_TYPE = 'PrimitiveTypeInterface'; const PHPFHIR_TYPES_TRAIT_COMMENT_CONTAINER = 'CommentContainerTrait'; diff --git a/src/Utilities/ImportUtils.php b/src/Utilities/ImportUtils.php index 0fcac075..75ca521c 100644 --- a/src/Utilities/ImportUtils.php +++ b/src/Utilities/ImportUtils.php @@ -82,13 +82,11 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo $typeKind = $type->getKind(); - if (!$type->isAbstract()) { + if (!$type->isAbstract() && !$type->isPrimitiveOrListType()) { $imports->addCoreFileImportsByName( PHPFHIR_ENCODING_CLASSNAME_XML_WRITER, - PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION, PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG, PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG, - PHPFHIR_TYPES_INTERFACE_TYPE, ); } @@ -100,6 +98,28 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo $imports->addImport($namespace, $trait); } + if ($type->isPrimitiveOrListType() || $type->hasPrimitiveOrListParent()) { + + } else if ($type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) { + $imports->addCoreFileImportsByName( + PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE, + ); + } else if ($type->isResourceType() || $type->hasResourceTypeParent()) { + $imports->addCoreFileImportsByName( + PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE, + ); + } else { + $imports->addCoreFileImportsByName( + PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE, + ); + } + + if ($type->isValueContainer() || $type->hasValueContainerParent()) { + $imports->addCoreFileImportsByName( + PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION, + ); + } + $imports->addVersionCoreFileImportsByName( $type->getVersion(), PHPFHIR_VERSION_CLASSNAME_VERSION, @@ -130,10 +150,6 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo ); } - if ($type->isPrimitiveOrListType() || $type->isValueContainer() || $type->isPrimitiveContainer()) { - $imports->addCoreFileImportsByName(PHPFHIR_ENCODING_TRAIT_VALUE_XML_LOCATION); - } - if ($restrictionBaseType = $type->getRestrictionBaseFHIRType()) { $imports->addImport( $restrictionBaseType->getFullyQualifiedNamespace(false), @@ -147,6 +163,10 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo continue; } + if ($property->isSerializableAsXMLAttribute()) { + $imports->addCoreFileImportsByName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); + } + $ptk = $propertyType->getKind(); // if (null !== $property->getOverloadedProperty() && !$ptk->isOneOf(TypeKindEnum::PRIMITIVE, TypeKindEnum::LIST)) { @@ -166,8 +186,12 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo $imports->addVersionCoreFileImportsByName($type->getVersion(), PHPFHIR_VERSION_CLASSNAME_VERSION); } else { if ($ptk === TypeKindEnum::PRIMITIVE_CONTAINER) { - $primType = $propertyType->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME)->getValueFHIRType(); - $imports->addImport($primType->getFullyQualifiedNamespace(false), $primType->getClassName()); + $primType = $propertyType + ->getProperties() + ->getProperty(PHPFHIR_VALUE_PROPERTY_NAME)->getValueFHIRType(); + $imports->addImport( + $primType->getFullyQualifiedNamespace(false), $primType->getClassName() + ); } $imports->addImport( diff --git a/src/Version/Definition/Property.php b/src/Version/Definition/Property.php index 2afe1ef3..e59084a0 100644 --- a/src/Version/Definition/Property.php +++ b/src/Version/Definition/Property.php @@ -500,11 +500,11 @@ public function getOverloadedProperty(): null|Property } /** - * This method will panic if this is a primitive type. Deal with it, also make it better later. + * Returns true if this property may be represented as an XML attribute on the parent element. * * @return bool */ - public function requiresXMLLocation(): bool + public function isSerializableAsXMLAttribute(): bool { $propType = $this->getValueFHIRType(); if (null === $propType || $this->isCollection()) { @@ -515,22 +515,6 @@ public function requiresXMLLocation(): bool || $propType->isPrimitiveOrListType(); } - /** - * @return string - */ - public function defaultXMLLocationEnumValue(): string - { - if (!$this->requiresXMLLocation()) { - throw new \RuntimeException(sprintf( - 'Type "%s" property "%s" does not support XML location setting', - $this->getMemberOf()->getFHIRName(), - $this->getName(), - )); - } - - return $this->getValueFHIRType()->isValueContainer() ? 'ELEMENT' : 'ATTRIBUTE'; - } - /** * @return string */ diff --git a/src/Version/Definition/Type.php b/src/Version/Definition/Type.php index ceab2482..a9c28387 100644 --- a/src/Version/Definition/Type.php +++ b/src/Version/Definition/Type.php @@ -569,7 +569,15 @@ public function hasPrimitiveContainerParent(): bool */ public function isResourceType(): bool { - return str_contains($this->getFullyQualifiedNamespace(false), '\\FHIRResource\\'); + return $this->_fhirName === 'Resource' + || $this->_fhirName === 'DomainResource' + || str_contains($this->getFullyQualifiedNamespace(false), '\\FHIRResource\\') + || str_contains($this->getFullyQualifiedNamespace(false), '\\FHIRDomainResource\\'); + } + + public function hasResourceTypeParent(): bool + { + return $this->hasParent() && $this->_parentType->isResourceType(); } /** @@ -776,6 +784,14 @@ public function setContainedType(bool $containedType): Type return $this; } + /** + * @return bool + */ + public function hasContainedTypeParent(): bool + { + return $this->hasParent() && $this->_parentType->isContainedType(); + } + /** * @return bool */ @@ -817,30 +833,43 @@ public function hasValueContainerParent(): bool public function getDirectlyImplementedInterfaces(): array { $interfaces = []; - $parentType = $this->getParentType(); $coreFiles = $this->_version->getConfig()->getCoreFiles(); $versionCoreFiles = $this->_version->getCoreFiles(); - if (null === $parentType) { - if ($this->isCommentContainer()) { - $interfaces[PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER] = $coreFiles - ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER) - ->getFullyQualifiedNamespace(false); - } - if ($this->isContainedType()) { - $interfaces[PHPFHIR_VERSION_INTERFACE_VERSION_CONTAINED_TYPE] = $versionCoreFiles - ->getCoreFileByEntityName(PHPFHIR_VERSION_INTERFACE_VERSION_CONTAINED_TYPE) - ->getFullyQualifiedNamespace(false); - } else if ($this->getKind() === TypeKindEnum::PRIMITIVE) { + // first, determine which base type interface it must implement + if ($this->isPrimitiveOrListType()) { + if (!$this->hasPrimitiveOrListParent()) { $interfaces[PHPFHIR_TYPES_INTERFACE_PRIMITIVE_TYPE] = $coreFiles ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_PRIMITIVE_TYPE) ->getFullyQualifiedNamespace(false); - } else { - $interfaces[PHPFHIR_TYPES_INTERFACE_TYPE] = $coreFiles - ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_TYPE) + } + } else if ($this->isPrimitiveContainer()) { + if (!$this->hasPrimitiveContainerParent()) { + $interfaces[PHPFHIR_TYPES_INTERFACE_PRIMITIVE_CONTAINER_TYPE] = $coreFiles + ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_PRIMITIVE_CONTAINER_TYPE) + ->getFullyQualifiedNamespace(false); + } + } else if ($this->isResourceType()) { + if (!$this->hasResourceTypeParent()) { + $interfaces[PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE] = $coreFiles + ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE) ->getFullyQualifiedNamespace(false); } - } elseif ($this->isContainedType() && !$parentType->isContainedType()) { + } else if (!$this->hasParent()) { + $interfaces[PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE] = $coreFiles + ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE) + ->getFullyQualifiedNamespace(false); + } + + // comment container types + if ($this->isCommentContainer() && !$this->hasCommentContainerParent()) { + $interfaces[PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER] = $coreFiles + ->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER) + ->getFullyQualifiedNamespace(false); + } + + // types that can be contained within a resource container type + if ($this->isContainedType() && !$this->hasContainedTypeParent()) { $interfaces[PHPFHIR_VERSION_INTERFACE_VERSION_CONTAINED_TYPE] = $versionCoreFiles ->getCoreFileByEntityName(PHPFHIR_VERSION_INTERFACE_VERSION_CONTAINED_TYPE) ->getFullyQualifiedNamespace(false); diff --git a/template/core/encoding/enum_value_xml_location.php b/template/core/encoding/enum_value_xml_location.php index 3df71246..7ea41989 100644 --- a/template/core/encoding/enum_value_xml_location.php +++ b/template/core/encoding/enum_value_xml_location.php @@ -28,7 +28,8 @@ enum : string { - case ATTRIBUTE = 'attribute'; + case PARENT_ATTRIBUTE = 'parent_attribute'; + case LOCAL_ATTRIBUTE = 'local_attribute'; case ELEMENT = 'element'; } getCoreFiles(); +$resourceTypeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE); + +$imports = $coreFile->getImports(); +$imports->addCoreFileImports($resourceTypeInterface); + ob_start(); echo 'declare(strict_types=1); @@ -26,14 +34,16 @@ getBasePHPFHIRCopyrightComment(true); ?> + + /** - * Interface + * Interface getEntityName(); ?> * * This is a meta interface that must never be directly implemented by a class. It exists purely to ensure type safety * throughout the base package. */ -interface extends +interface getEntityName(); ?> extends getEntityName(); ?> { /** diff --git a/template/core/types/interface_element_type.php b/template/core/types/interface_element_type.php new file mode 100644 index 00000000..4d317e97 --- /dev/null +++ b/template/core/types/interface_element_type.php @@ -0,0 +1,85 @@ +getCoreFiles(); + +$typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_TYPE); +$serializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG); +$unserializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG); +$xmlWriterClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_XML_WRITER); + +$imports = $coreFile->getimports(); + +$imports->addCoreFileImports($typeInterface, $serializeConfigClass, $unserializeConfigClass, $xmlWriterClass); + +ob_start(); +echo 'declare(strict_types=1); + +namespace getFullyQualifiedNamespace(false); ?>; + +getBasePHPFHIRCopyrightComment(true); ?> + + + +interface getEntityName(); ?> extends getEntityName(); ?>, \JsonSerializable + +{ + /** + * Returns the root XMLNS value found in the source. Null indicates no "xmlns" was found. Only defined when + * unserializing XML, and only used when serializing XML. + * + * @return null|string + */ + public function _getSourceXMLNS(): null|string; + + /** + * @param string|\SimpleXMLElement $element + * @param null|getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created. + * @param null|getFullyQualifiedName(true); ?> $config + * @return static + */ + public static function xmlUnserialize(string|\SimpleXMLElement $element, + null|getEntityName(); ?> $type = null, + null|getEntityName() ?> $config = null): self; + + /** + * @param null|getFullyQualifiedName(true); ?> $xw + * @param null|getFullyQualifiedName(true); ?> $config + * @return getFullyQualifiedName(true); ?> + + */ + public function xmlSerialize(null|getEntityName(); ?> $xw = null, + null|getEntityName(); ?> $config = null): getEntityName(); ?>; + + /** + * @param string|array|\stdClass $json Raw or already un-encoded JSON + * @param null|getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created. + * @param null|getFullyQualifiedName(true); ?> $config + * @return static + */ + public static function jsonUnserialize(string|array|\stdClass $json, + null|getEntityName(); ?> $type = null, + null|getEntityName(); ?> $config = null): self; +} + +getCoreFiles(); + +$elementInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE); +$serializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG); +$xmlWriterClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_XML_WRITER); +$xmlValueLocationEnum = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); + +$imports = $coreFile->getimports(); + +$imports->addCoreFileImports( + $elementInterface, + $serializeConfigClass, + $xmlWriterClass, + $xmlValueLocationEnum, +); + +ob_start(); +echo 'declare(strict_types=1); + +namespace getFullyQualifiedNamespace(false); ?>; + +getBasePHPFHIRCopyrightComment(true); ?> + + + +interface getEntityName(); ?> extends getEntityName(); ?> + +{ + /** + * Must return the appropriate "formatted" stringified version of this type's contained primitive type's value + * + * @return string + */ + public function _getFormattedValue(): string; + + /** + * Must return true if this primitive container type has a field set other than "value". This is used during + * serialization. + * + * @return bool + */ + public function _nonValueFieldDefined(): bool; + + /** + * @param null|getFullyQualifiedName(true); ?> $xw + * @param null|getFullyQualifiedName(true); ?> $config + * @param null|getFullyQualifiedName(true); ?> $valueLocation + * @return getFullyQualifiedName(true); ?> + + */ + public function xmlSerialize(null|getEntityName(); ?> $xw = null, + null|getEntityName(); ?> $config = null, + null|getEntityName(); ?> $valueLocation = null): getEntityName(); ?>; +} + +getCoreFiles(); +$typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_TYPE); $valueXMLLocationEnum = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); $imports = $coreFile->getImports(); -$imports->addCoreFileImportsByName( - PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION, -); +$imports->addCoreFileImports($typeInterface, $valueXMLLocationEnum); ob_start(); echo 'declare(strict_types=1); @@ -39,40 +38,13 @@ -interface extends \JsonSerializable +interface getEntityName(); ?> extends getEntityName(); ?>, \JsonSerializable { - /** - * Returns the FHIR name represented by this Type - * - * @return string - */ - public function _getFHIRTypeName(): string; - - /** - * Must return an associative array in structure ["field" => ["rule" => {constraint}]] to be used during validation - * - * @return array - */ - public function _getValidationRules(): array; - - /** - * Must return associative array where, if there are validation errors, the keys are the names of fields within the - * type that failed validation. The value must be a string message describing the manner of error - * - * @return array - */ - public function _getValidationErrors(): array; - /** * Must return the appropriate "formatted" stringified version of this primitive type's value * * @return string */ public function _getFormattedValue(): string; - - /** - * @return string - */ - public function __toString(): string; } getCoreFiles(); + +$typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_TYPE); +$serializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG); +$unserializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG); +$xmlWriterClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_XML_WRITER); + +$imports = $coreFile->getimports(); + +$imports->addCoreFileImports($typeInterface, $serializeConfigClass, $unserializeConfigClass, $xmlWriterClass); + +ob_start(); +echo 'declare(strict_types=1); + +namespace getFullyQualifiedNamespace(false); ?>; + +getBasePHPFHIRCopyrightComment(true); ?> + + + +interface getEntityName(); ?> extends getEntityName(); ?>, \JsonSerializable + +{ + /** + * Returns the root XMLNS value found in the source. Null indicates no "xmlns" was found. Only defined when + * unserializing XML, and only used when serializing XML. + * + * @return null|string + */ + public function _getSourceXMLNS(): null|string; + + /** + * @param string|\SimpleXMLElement $element + * @param null|getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created. + * @param null|getFullyQualifiedName(true); ?> $config + * @return static + */ + public static function xmlUnserialize(string|\SimpleXMLElement $element, + null|getEntityName(); ?> $type = null, + null|getEntityName() ?> $config = null): self; + + /** + * @param null|getFullyQualifiedName(true); ?> $xw + * @param null|getFullyQualifiedName(true); ?> $config + * @return getFullyQualifiedName(true); ?> + + */ + public function xmlSerialize(null|getEntityName(); ?> $xw = null, + null|getEntityName(); ?> $config = null): getEntityName(); ?>; + + /** + * @param string|array|\stdClass $json Raw or already un-encoded JSON + * @param null|getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created. + * @param null|getFullyQualifiedName(true); ?> $config + * @return static + */ + public static function jsonUnserialize(string|array|\stdClass $json, + null|getEntityName(); ?> $type = null, + null|getEntityName(); ?> $config = null): self; +} + +getImports(); - -$imports->addCoreFileImportsByName( - PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG, - PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG, - PHPFHIR_ENCODING_CLASSNAME_XML_WRITER, -); - $coreFiles = $config->getCoreFiles(); $serializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG); $unserializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG); $xmlWriterClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_XML_WRITER); +$imports = $coreFile->getImports(); + +$imports->addCoreFileImports($serializeConfigClass, $unserializeConfigClass, $xmlWriterClass); + ob_start(); echo 'declare(strict_types=1); @@ -45,7 +40,7 @@ -interface extends \JsonSerializable +interface getEntityName(); ?> { /** * Returns the FHIR name represented by this Type @@ -54,14 +49,6 @@ interface extends \JsonSerializable */ public function _getFHIRTypeName(): string; - /** - * Returns the root XMLNS value found in the source. Null indicates no "xmlns" was found. Only defined when - * unserializing XML, and only used when serializing XML. - * - * @return null|string - */ - public function _getSourceXMLNS(): null|string; - /** * Must return an associative array in structure ["field" => ["rule" => {constraint}]] to be used during validation * @@ -77,35 +64,6 @@ public function _getValidationRules(): array; */ public function _getValidationErrors(): array; - /** - * @param string|\SimpleXMLElement $element - * @param null|static $type Instance of this class to unserialize into. If left null, a new instance will be created. - * @param null|getFullyQualifiedName(true); ?> $config - * @return static - */ - public static function xmlUnserialize(string|\SimpleXMLElement $element, - null| $type = null, - null| $config = null): self; - - /** - * @param null|getFullyQualifiedName(true); ?> $xw - * @param null|getFullyQualifiedName(true); ?> $config - * @return getFullyQualifiedName(true); ?> - - */ - public function xmlSerialize(null| $xw = null, - null| $config = null): ; - - /** - * @param string|array|\stdClass $json Raw or already un-encoded JSON - * @param null|static $type Instance of this class to unserialize into. If left null, a new instance will be created. - * @param null|getFullyQualifiedName(true); ?> $config - * @return static - */ - public static function jsonUnserialize(string|array|\stdClass $json, - null| $type = null, - null| $config = null): self; - /** * @return string */ diff --git a/template/versions/types/class_default.php b/template/versions/types/class_default.php index 2a4f8cbd..64f88b5c 100644 --- a/template/versions/types/class_default.php +++ b/template/versions/types/class_default.php @@ -58,7 +58,31 @@ + + /* */ + private static array $_validationRules = [hasPropertiesWithValidations()): ?>]; +getAllPropertiesIndexedIterator() as $property) : + $validationMap = $property->buildValidationMap($type); + if ([] !== $validationMap) : ?> + + self::getFieldConstantName(); ?> => [ + $v) : ?> + :: => , + + ], + ]; +isPrimitiveOrListType() && !$type->hasPrimitiveOrListParent()) : // -- start xml location array definition @@ -67,21 +91,21 @@ /* */ private array $_valueXMLLocations = [ getAllPropertiesIndexedIterator() as $property) : - if (!$property->requiresXMLLocation()) { + if (!$property->isSerializableAsXMLAttribute()) { continue; } ?> - self::getFieldConstantName(); ?> => getEntityName(); ?>::defaultXMLLocationEnumValue(); ?>, + self::getFieldConstantName(); ?> => getEntityName(); ?>::ATTRIBUTE, ]; - /* */ -getProperties()->getIterator() as $property) : +if ($type->hasLocalProperties()) : ?> + + /* */ +getProperties()->getIterator() as $property) : $documentation = DocumentationUtils::compilePropertyDocumentation($property, 5, true); ?> /** @@ -95,29 +119,6 @@ - - /* */ - /** Default validation map for fields in type getFHIRName(); ?> */ - private const _DEFAULT_VALIDATION_RULES = [hasPropertiesWithValidations()): ?>]; -getAllPropertiesIndexedIterator() as $property) : - $validationMap = $property->buildValidationMap($type); - if ([] !== $validationMap) : ?> - - self::getFieldConstantName(); ?> => [ - $v) : ?> - :: => , - - ], - - ]; - */ getKind()->isOneOf(TypeKindEnum::PRIMITIVE, TypeKindEnum::LIST)) : + // primitive types are different enough to warrant their own template. + if ($type->isPrimitiveOrListType()) : echo require_with( PHPFHIR_TEMPLATE_VERSION_TYPES_PROPERTIES_DIR . '/methods/primitive.php', [ @@ -183,10 +184,9 @@ public function _getResourceType(): string endif; if (!$type->isAbstract()) : ?> + /* */ $type, ] ); -endif; ?> +endif; + +if ($type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) : ?> + + /* */ + public function _nonValueFieldDefined(): bool + { + return getAllPropertiesIndexedIterator() as $i => $property) : + if ($property->isValueProperty()) { continue; } + if ($i > 0) : ?> + + || isset($this->getName(); ?>); + } + /* */ Iterator(): iterable * @param isCollection(), true); ?> $ -requiresXMLLocation()) : ?> +isSerializableAsXMLAttribute()) : ?> * @param getFullyQualifiedName(true); ?> $valueXMLLocation * @return static */ - public function getSetterName(); ?>(isCollection(), true); ?> $requiresXMLLocation()) : ?>, - getSetterName())); echo $valueXMLLocationEnum->getEntityName(); ?> $valueXMLLocation = getEntityName(); ?>::defaultXMLLocationEnumValue(); endif ?>): self + public function getSetterName(); ?>(isCollection(), true); ?> $isSerializableAsXMLAttribute()) : ?>, + getSetterName())); echo $valueXMLLocationEnum->getEntityName(); ?> $valueXMLLocation = getEntityName(); ?>::ATTRIBUTE): self { isCollection()) : ?> if (null === $) { @@ -125,7 +125,7 @@ public function getSetterName(); ?>( $this-> = $; -requiresXMLLocation()) : ?> +isSerializableAsXMLAttribute()) : ?> $this->_valueXMLLocations[self::getFieldConstantName(); ?>] = $valueXMLLocation; return $this; @@ -158,7 +158,7 @@ public function set(requiresXMLLocation()) : ?> +if ($property->isSerializableAsXMLAttribute()) : ?> /** * Return the current location the "value" field of the getName(); ?> element will be placed @@ -188,4 +188,22 @@ public function _setValueXMLLocation(isPrimitiveContainer() && !$type->hasPrimitiveContainerParent()) : + $valueProp = $type->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME); + ?> + + /** + * Return the formatted value of this type's contained primitive type. + * + * @see getValueFHIRType()->getFullyQualifiedClassName(true); ?> + + * + * @return string + */ + public function _getFormattedValue(): string + { + return (string)($this->getValue()?->_getFormattedValue()); + } +getConfig(); -$coreFiles = $config->getCoreFiles(); +$coreFiles = $config->getCoreFiles(); +$constantsClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_CLASSNAME_CONSTANTS); $unserializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG); +if ($type->isResourceType() || $type->hasResourceTypeParent()) { + $typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE); +} else { + $typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE); +} + +$versionCoreFiles = $version->getCoreFiles(); +$versionClass = $versionCoreFiles->getCoreFileByEntityName(PHPFHIR_VERSION_CLASSNAME_VERSION); + ob_start(); ?> /** * @param string|array|\stdClass $json @@ -34,8 +44,8 @@ * @throws \Exception */ public static function jsonUnserialize(string|array|\stdClass $json, - null| $type = null, - null| $config = null): self + null|getEntityName(); ?> $type = null, + null|getEntityName() ?> $config = null): self { isAbstract()) : // abstract types may not be instantiated directly ?> if (null === $type) { @@ -52,7 +62,7 @@ public static function jsonUnserialize(string|array|\stdClass $json, )); } if (null === $config) { - $config = (new ())->getConfig()->getUnserializeConfig(); + $config = (new getEntityName(); ?>())->getConfig()->getUnserializeConfig(); } if (is_string($json)) { $json = json_decode(json: $json, associative: true, depth: $config->getJSONDecodeMaxDepth()); @@ -61,8 +71,8 @@ public static function jsonUnserialize(string|array|\stdClass $json, } hasConcreteParent()) : ?> parent::jsonUnserialize($json, $type, $config);hasCommentContainerParent() && $type->isCommentContainer()) : ?> - if (isset($data[::JSON_FIELD_FHIR_COMMENTS])) { - $type->_setFHIRComments((array)$data[::JSON_FIELD_FHIR_COMMENTS]); + if (isset($data[getEntityName(); ?>::JSON_FIELD_FHIR_COMMENTS])) { + $type->_setFHIRComments((array)$data[getEntityName(); ?>::JSON_FIELD_FHIR_COMMENTS]); } getConfig()->getCoreFiles(); + +$xmlLocationEnum = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); + ob_start(); // first, marshal attribute values foreach ($type->getProperties()->getIterator() as $property) : - $propType = $property->getValueFHIRType(); + if (!$property->isSerializableAsXMLAttribute()) { + continue; + } - $propTypeKind = $propType->getKind(); + $propType = $property->getValueFHIRType(); - if ($propType->hasPrimitiveOrListParent() || $propType->isPrimitiveOrListType()) : - if ($property->isCollection()) : ?> - if (isset($this->getName(); ?>)) { - foreach($this->getName(); ?> as $v) { - $xw->writeAttribute(self::getFieldConstantName(); ?>, $v->_getFormattedValue()); - break; - } - } - - if (isset($this->getName(); ?>) && $this->getName(); ?>->_getValueXMLLocation() === ::ATTRIBUTE) { + // if this is the "value" property on a primitive container, the value may be serialized to the parent's root node, + // to the local node's attributes, or as an element on the local node. + if ($type->isPrimitiveContainer() && $property->isValueProperty()) : ?> + if (isset($this->getName(); ?>) + && (getEntityName(); ?>::LOCAL_ATTRIBUTE === $valueLocation + || (null === $valueLocation && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::LOCAL_ATTRIBUTE))) { $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); } -isPrimitiveContainer()) : - if ($property->isCollection()) : ?> - if (isset($this->getName(); ?>)) { - foreach($this->getName(); ?> as $v) { - if ($v->_getValueXMLLocation() === ::ATTRIBUTE) { - $xw->writeAttribute(self::getFieldConstantName(); ?>, $v->getValue()?->_getFormattedValue()); - break; - } - } +hasPrimitiveOrListParent() || $propType->isPrimitiveOrListType()) : ?> + if (isset($this->getName(); ?>) && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::PARENT_ATTRIBUTE) { + $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); } - - if (isset($this->getName(); ?>) && $this->getName(); ?>->_getValueXMLLocation() === ::ATTRIBUTE) { +isValueContainer()) : ?> + if (isset($this->getName(); ?>) && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::PARENT_ATTRIBUTE) { $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->getValue()?->_getFormattedValue()); } -hasConcreteParent()) : ?> - parent::xmlSerialize($xw, $config); + parent::xmlSerialize($xw, $confighasPrimitiveContainerParent()) : ?>, $valueLocation); getValueFHIRType(); $propTypeKind = $propType->getKind(); - if ($propTypeKind->isResourceContainer($version)) : + // value property start + if (!$property->isCollection() && $property->isValueProperty() && $type->isPrimitiveContainer()) : ?> + if (isset($this->getName(); ?>) + && (getEntityName(); ?>::ELEMENT === $valueLocation + || (null === $valueLocation + && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::ELEMENT))) { + $xw->startElement(self::getFieldConstantName(); ?>); + $xw->writeAttribute($this->getName(); ?>::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); + $xw->endElement(); + } +isResourceContainer($version)) : if ($property->isCollection()) : ?> - if (isset($this->getName(); ?>)) { + if (isset($this->getName(); ?>) && [] !== $this->getName(); ?>) { foreach($this->getName(); ?> as $v) { $xw->startElement(self::getFieldConstantName(); ?>); $xw->startElement($v->_getFHIRTypeName()); @@ -90,42 +105,49 @@ $xw->endElement(); } hasPrimitiveOrListParent() || $propType->isPrimitiveOrListType()) : ?> isCollection()) : ?> - if (isset($this->getName(); ?>)) { + if (isset($this->getName(); ?>) && [] !== $this->getName(); ?>) { foreach($this->getName(); ?> as $v) { - if ($v->_getValueXMLLocation() === ::ELEMENT) { - $xw->startElement(self::getFieldConstantName(); ?>); - $xw->writeAttribute($v::FIELD_VALUE, $v->_getFormattedValue()); - $xw->endElement(); - } + $xw->startElement(self::getFieldConstantName(); ?>); + $xw->writeAttribute($v::getFieldConstantName(); ?>, $v->_getFormattedValue()); + $xw->endElement(); } } - if (isset($this->getName(); ?>) && $this->getName(); ?>->_getValueXMLLocation() === ::ELEMENT) { + if (isset($this->getName(); ?>) && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::ELEMENT) { $xw->startElement(self::getFieldConstantName(); ?>); - $xw->writeAttribute($this->getName(); ?>::FIELD_VALUE, $this->getName(); ?>->_getFormattedValue()); + $xw->writeAttribute($this->getName(); ?>::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); $xw->endElement(); } + // primitive type end + + // primitive container start + elseif ($propType->isPrimitiveContainer()) : ?> isCollection()) : ?> - if (isset($this->getName(); ?>)) { + if (isset($this->getName(); ?>) && [] !== $this->getName(); ?>) { foreach($this->getName(); ?> as $v) { - if ($v->_getValueXMLLocation() === ::ELEMENT) { - $xw->startElement(self::getFieldConstantName(); ?>); - $v->xmlSerialize($xw, $config); - $xw->endElement(); - } + $xw->startElement(self::getFieldConstantName(); ?>); + $v->xmlSerialize($xw, $config); + $xw->endElement(); } } - if (isset($this->getName(); ?>) && $this->getName(); ?>->_getValueXMLLocation() === ::ELEMENT) { + if (isset($this->getName(); ?>) + && ($this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::ELEMENT + || $this->getName(); ?>->_nonValueFieldDefined())) { $xw->startElement(self::getFieldConstantName(); ?>); - $this->getName(); ?>->xmlSerialize($xw, $config); + $this->getName(); ?>->xmlSerialize($xw, $config, $this->_valueXMLLocations[self::getFieldConstantName(); ?>]); $xw->endElement(); } if (isset($this->getName(); ?>)) { $xw->startElement(self::getFieldConstantName(); ?>); @@ -138,7 +160,11 @@ } $xw->endElement(); } -isCollection()) : ?> +isCollection()) : ?> if (isset($this->getName(); ?>)) { foreach ($this->getName(); ?> as $v) { $xw->startElement(self::getFieldConstantName(); ?>); @@ -153,6 +179,7 @@ $xw->endElement(); } getConfig(); -$coreFiles = $config->getCoreFiles(); +$coreFiles = $config->getCoreFiles(); $xmlWriterClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_XML_WRITER); $serializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG); +$xmlLocationEnum = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); + +$versionCoreFiles = $version->getCoreFiles(); +$versionClass = $versionCoreFiles->getCoreFileByEntityName(PHPFHIR_VERSION_CLASSNAME_VERSION); ob_start(); ?> /** * @param null|getFullyQualifiedName(true); ?> $xw * @param null|getFullyQualifiedName(true); ?> $config +isValueContainer() || $type->hasValueContainerParent()) : ?> + * @param null|getFullyQualifiedName(true); ?> $valueLocation + * @return getFullyQualifiedName(true); ?> */ - public function xmlSerialize(null| $xw = null, null| $config = null): + public function xmlSerialize(null|getEntityName(); ?> $xw = null, + null|getEntityName(); ?> $config = nullisPrimitiveContainer() || $type->hasPrimitiveContainerParent()) : ?>, + null|getEntityName(); ?> $valueLocation = null): getEntityName(); ?> { if (null === $config) { - $config = (new ())->getConfig()->getSerializeConfig(); + $config = (new getEntityName(); ?>())->getConfig()->getSerializeConfig(); } if (null === $xw) { - $xw = new ($config); + $xw = new getEntityName(); ?>($config); } if (!$xw->isOpen()) { $xw->openMemory(); diff --git a/template/versions/types/serialization/xml/unserialize/body.php b/template/versions/types/serialization/xml/unserialize/body.php index 42e68f05..01690ca0 100644 --- a/template/versions/types/serialization/xml/unserialize/body.php +++ b/template/versions/types/serialization/xml/unserialize/body.php @@ -57,7 +57,7 @@ $type->($n); getMemberOf()->getImports()->getImportByType($propType); ?> - $type->(getName(); ?>: ::xmlUnserialize($n, null, $config)requiresXMLLocation()) : ?>, valueXMLLocation: getEntityName(); ?>::ELEMENT); + $type->(getName(); ?>: ::xmlUnserialize($n, null, $config)isSerializableAsXMLAttribute()) : ?>, valueXMLLocation: getEntityName(); ?>::ELEMENT); } @@ -84,7 +84,7 @@ } else { $type->(getName(); ?>: (string)$attributes[self::]); } -requiresXMLLocation()) : ?> +isSerializableAsXMLAttribute()) : ?> $type->_setgetName()); ?>ValueXMLLocation(getEntityName(); ?>::ATTRIBUTE); diff --git a/template/versions/types/serialization/xml/unserialize/header.php b/template/versions/types/serialization/xml/unserialize/header.php index c25b8cdf..8279ff83 100644 --- a/template/versions/types/serialization/xml/unserialize/header.php +++ b/template/versions/types/serialization/xml/unserialize/header.php @@ -19,13 +19,20 @@ /** @var \DCarbone\PHPFHIR\Version $version */ /** @var \DCarbone\PHPFHIR\Version\Definition\Type $type */ -use DCarbone\PHPFHIR\Enum\TypeKindEnum; - $config = $version->getConfig(); -$coreFiles = $config->getCoreFiles(); +$coreFiles = $config->getCoreFiles(); $unserializeConfigClass = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG); +if ($type->isResourceType() || $type->hasResourceTypeParent()) { + $typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE); +} else { + $typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE); +} + +$versionCoreFiles = $version->getCoreFiles(); +$versionClass = $versionCoreFiles->getCoreFileByEntityName(PHPFHIR_VERSION_CLASSNAME_VERSION); + ob_start(); ?> /** * @param string|\SimpleXMLElement $element @@ -36,8 +43,8 @@ * @throws \Exception */ public static function xmlUnserialize(string|\SimpleXMLElement $element, - null| $type = null, - null| $config = null): self + null|getEntityName(); ?> $type = null, + null|getEntityName() ?> $config = null): self { isAbstract()) : // abstract types may not be instantiated directly ?> if (null === $type) { @@ -54,7 +61,7 @@ public static function xmlUnserialize(string|\SimpleXMLElement $element, )); } if (null === $config) { - $config = (new ())->getConfig()->getUnserializeConfig(); + $config = (new getEntityName(); ?>())->getConfig()->getUnserializeConfig(); } if (is_string($element)) { $element = new \SimpleXMLElement($element, $config->getLibxmlOpts()); diff --git a/template/versions/types/validation/methods.php b/template/versions/types/validation/methods.php index 6f6e4360..b37ab00a 100644 --- a/template/versions/types/validation/methods.php +++ b/template/versions/types/validation/methods.php @@ -37,7 +37,7 @@ */ public function _getValidationRules(): array { - return self::_DEFAULT_VALIDATION_RULES; + return self::$_validationRules; } /**