diff --git a/files/constants.php b/files/constants.php index 0ffdb65f..abaf8cf0 100644 --- a/files/constants.php +++ b/files/constants.php @@ -121,7 +121,6 @@ // Core encoding entities const PHPFHIR_ENCODING_CLASSNAME_XML_WRITER = 'XMLWriter'; const PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION = 'ValueXMLLocationEnum'; -const PHPFHIR_ENCODING_TRAIT_VALUE_XML_LOCATION = 'ValueXMLLocationTrait'; const PHPFHIR_ENCODING_CLASSNAME_SERIALIZE_CONFIG = 'SerializeConfig'; const PHPFHIR_ENCODING_CLASSNAME_UNSERIALIZE_CONFIG = 'UnserializeConfig'; diff --git a/src/Enum/TypeKindEnum.php b/src/Enum/TypeKindEnum.php index 282a366f..9ac79801 100644 --- a/src/Enum/TypeKindEnum.php +++ b/src/Enum/TypeKindEnum.php @@ -40,7 +40,6 @@ enum TypeKindEnum: string case RESOURCE = 'Resource'; case RESOURCE_CONTAINER = 'ResourceContainer'; case RESOURCE_INLINE = 'Resource.Inline'; - case QUANTITY = 'Quantity'; // this indicates a type that is an immediate child of a resource and not used elsewhere case RESOURCE_COMPONENT = 'resource_component'; diff --git a/src/Enum/XMLValueLocationUtils.php b/src/Enum/XMLValueLocationUtils.php index 3b5f6f06..4de92852 100644 --- a/src/Enum/XMLValueLocationUtils.php +++ b/src/Enum/XMLValueLocationUtils.php @@ -25,10 +25,20 @@ class XMLValueLocationUtils { public static function determineDefaultLocation(Type $type, Property $property, bool $withClass): string { - $case = match (true) { - $property->isValueProperty() && !$type->isQuantity() && !$type->hasQuantityParent() => 'LOCAL_ATTRIBUTE', - default => 'ELEMENT', - }; + $propType = $property->getValueFHIRType(); + if ($propType->isPrimitiveOrListType() || $propType->hasPrimitiveContainerParent()) { + $case = match(true) { + $type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent() => 'CONTAINER_ATTRIBUTE', + default => 'ELEMENT_ATTRIBUTE', + }; + } else if ($property->isValueProperty()) { + $case = match (true) { + $type->isQuantity() || $type->hasQuantityParent() => 'ELEMENT_ATTRIBUTE', + default => 'CONTAINER_ATTRIBUTE', + }; + } else { + $case = 'ELEMENT_ATTRIBUTE'; + } if ($withClass) { return sprintf('%s::%s', PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION, $case); } diff --git a/src/Version/Definition/Type.php b/src/Version/Definition/Type.php index 6750f9a4..9df2c076 100644 --- a/src/Version/Definition/Type.php +++ b/src/Version/Definition/Type.php @@ -828,7 +828,7 @@ public function hasValueContainerParent(): bool */ public function isQuantity(): bool { - return $this->_kind === TypeKindEnum::QUANTITY; + return $this->_fhirName === 'Quantity'; } /** diff --git a/src/Version/Definition/TypeDecorator.php b/src/Version/Definition/TypeDecorator.php index 419baac0..33ec5483 100644 --- a/src/Version/Definition/TypeDecorator.php +++ b/src/Version/Definition/TypeDecorator.php @@ -396,7 +396,7 @@ public static function setValueContainerFlag(Config $config, Types $types): void } // skip "quantity" types, as their "value" is always applied as an element - if ($type->getKind()->isOneOf(TypeKindEnum::QUANTITY)) { + if ($type->isQuantity()) { continue; } diff --git a/template/core/encoding/enum_value_xml_location.php b/template/core/encoding/enum_value_xml_location.php index a4714729..80e2ed54 100644 --- a/template/core/encoding/enum_value_xml_location.php +++ b/template/core/encoding/enum_value_xml_location.php @@ -30,7 +30,8 @@ enum { case PARENT_ATTRIBUTE; - case LOCAL_ATTRIBUTE; - case ELEMENT; + case CONTAINER_ATTRIBUTE; + case ELEMENT_ATTRIBUTE; + case ELEMENT_VALUE; } getCoreFiles(); - -$valueXMLLocationEnum = $coreFiles->getCoreFileByEntityName(PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION); - -ob_start(); - -echo 'declare(strict_types=1); - -namespace getFullyQualifiedNamespace(false); ?>; - -getBasePHPFHIRCopyrightComment(true); ?> - -trait - -{ - private getEntityName(); ?> $_valueLoc; - - /** - * Set the XML location of this element's value when serializing - * - * @param getFullyQualifiedName(true); ?> $valueXMLLocation - */ - public function _setValueXMLLocation(getEntityName(); ?> $valueXMLLocation): void - { - $this->_valueLoc = $valueXMLLocation; - } - - /** - * @return null|getFullyQualifiedName(true); ?> - - */ - public function _getValueXMLLocation(): null|getEntityName(); ?> - - { - return $this->_valueLoc ?? null; - } -} -getFullyQualifiedName(true); ?> $xw * @param getFullyQualifiedName(true); ?> $config - * @return getFullyQualifiedName(true); ?> - */ public function xmlSerialize(getEntityName(); ?> $xw, - getEntityName(); ?> $config): getEntityName(); ?>; + getEntityName(); ?> $config): void; /** * @param array $json Decoded JSON diff --git a/template/core/types/interface_value_container_type.php b/template/core/types/interface_value_container_type.php index 49d690a7..a43d1e26 100644 --- a/template/core/types/interface_value_container_type.php +++ b/template/core/types/interface_value_container_type.php @@ -68,12 +68,10 @@ public function _nonValueFieldDefined(): bool; * @param getFullyQualifiedName(true); ?> $xw * @param getFullyQualifiedName(true); ?> $config * @param null|getFullyQualifiedName(true); ?> $valueLocation - * @return getFullyQualifiedName(true); ?> - */ public function xmlSerialize(getEntityName(); ?> $xw, getEntityName(); ?> $config, - null|getEntityName(); ?> $valueLocation = null): getEntityName(); ?>; + null|getEntityName(); ?> $valueLocation = null): void; } $type, ] ); - - echo "\n"; endif; if ($type->hasLocalProperties()) : diff --git a/template/versions/types/properties/methods/default.php b/template/versions/types/properties/methods/default.php index f2bac3f9..5886aeee 100644 --- a/template/versions/types/properties/methods/default.php +++ b/template/versions/types/properties/methods/default.php @@ -71,19 +71,22 @@ public function get(): ?? isCollection()) : ?>[]null; } - + /** * @return \ArrayIterator<getFullyQualifiedClassName(true); ?>> */ public function getIterator(): iterable { - if (!isset($this->) || [] === $this->) { + if (!isset($this->)) { return new \EmptyIterator(); } return new \ArrayIterator($this->); } Iterator(): iterable * @param isCollection(), true); ?> $ -isSerializableAsXMLAttribute()) : ?> +isSerializableAsXMLAttribute()) : ?> * @param getFullyQualifiedName(true); ?> $valueXMLLocation - + * @return static */ public function getSetterName(); ?>(isCollection(), true); ?> $isSerializableAsXMLAttribute()) : ?>, getSetterName())); echo $valueXMLLocationEnum->getEntityName(); ?> $valueXMLLocation = ): self { -isCollection()) : ?> +isCollection()) : ?> if (null === $) { unset($this->); return $this; } -isPrimitiveContainer() || $propType->isPrimitiveOrListType()) : ?> +isPrimitiveContainer() || $propType->isPrimitiveOrListType()) : ?> if (!($ instanceof )) { $ = new (value: $); } isResourceContainer($version)) : ?> + elseif ($propTypeKind->isResourceContainer($version)) : ?> if ($ instanceof getClassName(); ?>) { $ = $->getContainedType(); } -isCollection()) : ?> if (!isset($this->)) { $this-> = []; } - + if (!($ instanceof )) { $ = new ($); } - + $this-> = $; -isSerializableAsXMLAttribute()) : ?> - $this->_valueXMLLocations[self::getFieldConstantName(); ?>] = $valueXMLLocation; - +isSerializableAsXMLAttribute()) : ?> + if ($this->_valueXMLLocations[self::getFieldConstantName(); ?>] !== $valueXMLLocation) { + $this->_setgetName()); ?>ValueXMLLocation($valueXMLLocation); + } + return $this; } - + /** @@ -152,7 +168,12 @@ public function getSetterName(); ?>(( ...$): self { -isValueContainer()) : ?> + if ([] === $) { + unset($this->); + return $this; + } +isValueContainer()) : ?> $this-> = []; foreach($ as $v) { if ($v instanceof ) { @@ -161,13 +182,18 @@ public function set([] = new (value: $v); } } - + $this-> = $; - + return $this; } -isSerializableAsXMLAttribute()) : ?> +isSerializableAsXMLAttribute()) : ?> /** * Return the current location the "value" field of the getName(); ?> element will be placed @@ -191,6 +217,21 @@ public function _getValueXMLLocation() : ValueXMLLocation(getEntityName(); ?> $valueXMLLocation) : self { +isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) : ?> + if (getEntityName(); ?>::PARENT_ATTRIBUTE === $valueXMLLocation) { + throw new \InvalidArgumentException(sprintf( + 'Cannot set "%s" as value XML serialize location for property "" on value container type "getFHIRName(); ?>"', + $valueXMLLocation->name, + )); + } +isPrimitiveOrListType() || $propType->hasprimitiveType()) : ?> + if (getEntityName(); ?>::CONTAINER_ATTRIBUTE === $valueXMLLocation) { + throw new \InvalidArgumentException(sprintf( + 'Cannot set "%s" as value XML serialize location for primitive property "" on type "getfhirName(); ?>"', + $valueXMLLocation->name, + )); + } + $this->_valueXMLLocations[self::getFieldConstantName(); ?>] = $valueXMLLocation; return $this; } @@ -211,7 +252,7 @@ public function _setValueXMLLocation(getValue()?->_getFormattedValue()); + return isset($this->getName(); ?>) ? $this->getName(); ?>->_getFormattedValue() : ''; } $type, ] ); -?> + +if ($type->isResourceType() || $type->hasResourceTypeParent()) : ?> if (isset($rootOpened) && $rootOpened) { $xw->endElement(); } @@ -70,5 +71,6 @@ $xw->endDocument(); } return $xw; + } getValueFHIRType(); - // a "value" property may be serialized as an attribute on the containing type's parent node, an attribute on the - // containing type's node, or as a child element of the containing type's node. - // - // this defaults to being controlled by the containing node, unless the parent node explicitly passes the - // "parent_attribute" value enum into the xml serialize func of the containing type. - // - // "value" properties are the only types of properties that respect the "valueLocation" parameter on value - // container xml serialize funcs. if ($property->isValueProperty()) : - // if this is a value container type, we need to only serialize our value as an attribute on our node - // if, and only if, the $valueLocation parameter is == "local_attribute" or is null and our internal - // location map defines it as "local_attribute" if ($type->isValueContainer() || $type->hasValueContainerParent()) : ?> - if (isset($this->getName(); ?>) - && (getEntityName(); ?>::LOCAL_ATTRIBUTE === $valueLocation - || (null === $valueLocation - && getEntityName(); ?>::LOCAL_ATTRIBUTE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]))) { + if (isset($this->getName(); ?>) && getEntityName(); ?>::CONTAINER_ATTRIBUTE === $valueLocation) { $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); } if (isset($this->getName(); ?>) && getEntityName(); ?>::PARENT_ATTRIBUTE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]) { $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); } isPrimitiveOrListType() || $propType->hasPrimitiveOrListParent()) : ?> - if (isset($this->getName(); ?>) && getEntityName(); ?>::LOCAL_ATTRIBUTE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]) { - $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); - } -isValueContainer() || $propType->hasValueContainerParent()) : ?> + elseif ($propType->isValueContainer() || $propType->hasValueContainerParent() || $propType->isPrimitiveOrListType() || $propType->hasPrimitiveOrListParent()) : ?> if (isset($this->getName(); ?>) && getEntityName(); ?>::PARENT_ATTRIBUTE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]) { $xw->writeAttribute(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); } @@ -96,14 +74,15 @@ $propTypeKind = $propType->getKind(); // 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(); + if (!$property->isCollection() && $property->isValueProperty() && ($type->isValueContainer() || $type->hasValueContainerParent())) : ?> + if (isset($this->getName(); ?>)) { + if (getEntityName(); ?>::ELEMENT_ATTRIBUTE === $valueLocation) { + $xw->startElement(self::getFieldConstantName(); ?>); + $xw->writeAttribute(getClassName(); ?>::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); + $xw->endElement(); + } else if (getEntityName(); ?>::ELEMENT_VALUE === $valueLocation) { + $xw->writeElement(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); + } } hasPrimitiveOrListParent() || $propType->isPrimitiveOrListType()) : ?> -isCollection()) : ?> + elseif ($propType->hasPrimitiveOrListParent() || $propType->isPrimitiveOrListType()) : + if ($property->isCollection()) : ?> if (isset($this->getName(); ?>) && [] !== $this->getName(); ?>) { foreach($this->getName(); ?> as $v) { $xw->startElement(self::getFieldConstantName(); ?>); @@ -142,17 +121,21 @@ } } - if (isset($this->getName(); ?>) && $this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::ELEMENT) { - $xw->startElement(self::getFieldConstantName(); ?>); - $xw->writeAttribute($this->getName(); ?>::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); - $xw->endElement(); + if (isset($this->getName(); ?>)) { + if (getEntityName(); ?>::ELEMENT_ATTRIBUTE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]) { + $xw->startElement(self::getFieldConstantName(); ?>); + $xw->writeAttribute(getClassName(); ?>::FIELD_VALUE, $this->getName(); ?>->_getFormattedValue()); + $xw->endElement(); + } else if (getEntityName(); ?>::ELEMENT_VALUE === $this->_valueXMLLocations[self::getFieldConstantName(); ?>]) { + $xw->writeElement(self::getFieldConstantName(); ?>, $this->getName(); ?>->_getFormattedValue()); + } } isPrimitiveContainer()) : ?> -isCollection()) : ?> + elseif ($propType->isValueContainer() || $propType->hasValueContainerParent()) : + if ($property->isCollection()) : ?> if (isset($this->getName(); ?>) && [] !== $this->getName(); ?>) { foreach($this->getName(); ?> as $v) { $xw->startElement(self::getFieldConstantName(); ?>); @@ -162,7 +145,7 @@ } if (isset($this->getName(); ?>) - && ($this->_valueXMLLocations[self::getFieldConstantName(); ?>] === getEntityName(); ?>::ELEMENT + && (getEntityName(); ?>::PARENT_ATTRIBUTE !== $this->_valueXMLLocations[self::getFieldConstantName(); ?>] || $this->getName(); ?>->_nonValueFieldDefined())) { $xw->startElement(self::getFieldConstantName(); ?>); $this->getName(); ?>->xmlSerialize($xw, $config, $this->_valueXMLLocations[self::getFieldConstantName(); ?>]); diff --git a/template/versions/types/serialization/xml/serialize/header.php b/template/versions/types/serialization/xml/serialize/header.php index 4a0544cf..26fd4f8c 100644 --- a/template/versions/types/serialization/xml/serialize/header.php +++ b/template/versions/types/serialization/xml/serialize/header.php @@ -33,19 +33,23 @@ ob_start(); ?> /** - * @param null|getFullyQualifiedName(true); ?> $xw - * @param null|getFullyQualifiedName(true); ?> $config + * @param isResourceType() || $type->hasResourceTypeParent()) : ?>null|getFullyQualifiedName(true); ?> $xw + * @param isResourceType() || $type->hasResourceTypeParent()) : ?>null|getFullyQualifiedName(true); ?> $config isValueContainer() || $type->hasValueContainerParent()) : ?> * @param null|getFullyQualifiedName(true); ?> $valueLocation +isResourceType() || $type->hasResourceTypeParent()) : ?> * @return getFullyQualifiedName(true); ?> + */ - public function xmlSerialize(null|getEntityName(); ?> $xw = null, - null|getEntityName(); ?> $config = nullisValueContainer() || $type->hasValueContainerParent()) : ?>, - null|getEntityName(); ?> $valueLocation = null): getEntityName(); ?> + public function xmlSerialize(isResourceType() || $type->hasResourceTypeParent()) : ?>null|getEntityName(); ?> $xwisResourceType() || $type->hasResourceTypeParent()) : ?> = null, + isResourceType() || $type->hasResourceTypeParent()) : ?>null|getEntityName(); ?> $configisResourceType() || $type->hasResourceTypeParent()) : ?> = nullisValueContainer() || $type->hasValueContainerParent()) : ?>, + null|getEntityName(); ?> $valueLocation = null): isResourceType() || $type->hasResourceTypeParent()) : echo $xmlWriterClass->getEntityName(); else : ?>void { +isResourceType() || $type->hasResourceTypeParent()) : ?> if (null === $config) { $config = (new getEntityName(); ?>())->getConfig()->getSerializeConfig(); } @@ -63,4 +67,8 @@ public function xmlSerialize(null|getEntityName(); ? $rootOpened = true; $xw->openRootNode('', $this->_getSourceXMLNS()); } -isValueContainer() || $type->hasValueContainerParent()) : ?> + $valueLocation = $valueLocation ?? $this->_valueXMLLocations[self::FIELD_VALUE]; +getCoreFiles()->getCoreFileByEntityName(PHPFHIR_VERSION_INTERFACE_VERSION_CONTAINED_TYPE); ob_start(); ?> - foreach ($element->children() as $n) { - $childName = $n->getName(); + foreach ($element->children() as $ce) { + $cen = $ce->getName(); getAllPropertiesIndexedIterator() as $i => $property) : $propType = $property->getValueFHIRType(); $propTypeKind = $propType->getKind(); $setter = $property->getSetterName(); $propConst = $property->getFieldConstantName(); - if ($i > 0) : ?> else if (self:: === $childName) { -isPrimitiveOrListType()) : ?> - $valueAttr = $n->attributes()[getClassName(); ?>::FIELD_VALUE] ?? null; - if (null !== $valueAttr) { - $value = (string)$valueAttr; + if ($i > 0) : ?> else if (self:: === $cen) { +isPrimitiveOrListType() || $propType->hasPrimitiveOrListParent()) : ?> + $va = $ce->attributes()[getClassName(); ?>::FIELD_VALUE] ?? null; + if (null !== $va) { + $type->((string)$va, getEntityName(); ?>::ELEMENT_ATTRIBUTE); } else { - $value = (string)$n; + $type->((string)$ce, getEntityName(); ?>::ELEMENT_VALUE); } - $type->($value, getEntityName(); ?>::ELEMENT); isResourceContainer($version)) : ?> - foreach ($n->children() as $nn) { + foreach ($ce->children() as $cen) { /** @var getFullyQualifiedName(true); ?> $cn */ - $cn = ::getContainedTypeClassNameFromXML($nn); - $type->($cn::xmlUnserialize($nn, $config)); + $cn = ::getContainedTypeClassNameFromXML($cen); + $type->($cn::xmlUnserialize($cen, $config)); } - $type->($n); + $type->($ce); getMemberOf()->getImports()->getImportByType($propType); ?> - $type->(::xmlUnserialize($n, $config)); + $type->(::xmlUnserialize($ce, $config)); } - } $attributes = $element->attributes(); if (isset($attributes[self::])) { - $type->((string)$attributes[self::], getEntityName(); ?>::LOCAL_ATTRIBUTE); + if ($property->isValueProperty() && ($type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent())) : ?> + $type->((string)$attributes[self::], getEntityName(); ?>::CONTAINER_ATTRIBUTE); +isPrimitiveOrListType() || $propType->hasPrimitiveOrListParent()) : ?> + $type->((string)$attributes[self::], getEntityName(); ?>::PARENT_ATTRIBUTE); if (isset($type->getName(); ?>)) { $type->getName(); ?>->setValue((string)$attributes[self::]); + $type->_setgetName()); ?>ValueXMLLocation(getEntityName(); ?>::PARENT_ATTRIBUTE); } else { - $type->((string)$attributes[self::]); + $type->((string)$attributes[self::], getEntityName(); ?>::PARENT_ATTRIBUTE); } -isValueContainer() || $type->hasValueContainerParent()) : ?> - $type->_setgetName()); ?>ValueXMLLocation(getEntityName(); ?>::LOCAL_ATTRIBUTE); - - $type->_setgetName()); ?>ValueXMLLocation(getEntityName(); ?>::PARENT_ATTRIBUTE);