Skip to content

Commit

Permalink
redefining "value container" concept, as it sucked before.
Browse files Browse the repository at this point in the history
  • Loading branch information
dcarbone committed Feb 1, 2025
1 parent 7b35c13 commit 14672fa
Show file tree
Hide file tree
Showing 19 changed files with 181 additions and 170 deletions.
2 changes: 2 additions & 0 deletions files/constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@

// Core types entities
const PHPFHIR_TYPES_INTERFACE_TYPE = 'TypeInterface';
const PHPFHIR_TYPES_INTERFACE_DSTU1_TYPE = 'DSTU1TypeInterface';
const PHPFHIR_TYPES_INTERFACE_PRIMITIVE_TYPE = 'PrimitiveTypeInterface';
const PHPFHIR_TYPES_INTERFACE_ELEMENT_TYPE = 'ElementTypeInterface';
const PHPFHIR_TYPES_INTERFACE_PRIMITIVE_CONTAINER_TYPE = 'PrimitiveContainerTypeInterface';
Expand All @@ -115,6 +116,7 @@
const PHPFHIR_TYPES_INTERFACE_CONTAINED_TYPE = 'ContainedTypeInterface';
const PHPFHIR_TYPES_INTERFACE_COMMENT_CONTAINER = 'CommentContainerInterface';
const PHPFHIR_TYPES_TRAIT_COMMENT_CONTAINER = 'CommentContainerTrait';
const PHPFHIR_TYPES_TRAIT_VALUE_CONTAINER = 'ValueContainerTrait';


// Core encoding entities
Expand Down
10 changes: 2 additions & 8 deletions src/Utilities/ImportUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo
);
}

if ($type->isValueContainer() || $type->hasValueContainerParent()) {
$imports->addCoreFileImportsByName(
PHPFHIR_ENCODING_ENUM_VALUE_XML_LOCATION,
);
}

$imports->addVersionCoreFileImportsByName(
$type->getVersion(),
PHPFHIR_VERSION_CLASSNAME_VERSION,
Expand Down Expand Up @@ -188,8 +182,8 @@ public static function buildVersionTypeImports(Version $version, Type $type): vo
$imports->addVersionCoreFileImportsByName($type->getVersion(), PHPFHIR_VERSION_CLASSNAME_VERSION);
} else {
$valProp = match(true) {
$propertyType->isPrimitiveContainer() || $propertyType->isValueContainer() => $propertyType->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$propertyType->hasPrimitiveContainerParent() || $propertyType->hasValueContainerParent() => $propertyType->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$propertyType->isPrimitiveContainer() => $propertyType->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$propertyType->hasPrimitiveContainerParent() => $propertyType->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME),
default => null,
};

Expand Down
10 changes: 5 additions & 5 deletions src/Utilities/TypeHintUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ public static function buildBaseHintParts(Version $version, Type $type, bool $fu

if ($type->isPrimitiveOrListType() || $type->hasPrimitiveOrListParent()) {
$hintTypes = $type->getPrimitiveType()->getPHPReceiveValueTypeHints();
} else if ($type->isValueContainer() || $type->hasValueContainerParent() || $type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) {
} else if ($type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) {
$valProp = match (true) {
$type->isValueContainer() || $type->isPrimitiveContainer() => $type->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$type->hasValueContainerParent() || $type->hasPrimitiveContainerParent() => $type->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$type->isPrimitiveContainer() => $type->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME),
$type->hasPrimitiveContainerParent() => $type->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME),
default => null,
};
$ptp = $valProp->getValueFHIRType();
Expand Down Expand Up @@ -268,7 +268,7 @@ public static function buildSetterParameterDocHint(Version $version,

$hintTypes = self::buildBaseHintParts($version, $pt, true);

if ($pt->isValueContainer() || $pt->hasValueContainerParent() || $pt->isPrimitiveContainer() || $pt->hasPrimitiveContainerParent()) {
if ($pt->isPrimitiveContainer() || $pt->hasPrimitiveContainerParent()) {
$vp = $pt->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME) ?? $pt->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME);
array_push(
$hintTypes,
Expand Down Expand Up @@ -314,7 +314,7 @@ public static function buildSetterParameterHint(Version $version,
} else {
$hintTypes = self::buildBaseHintParts($version, $pt, false);

if ($pt->isValueContainer() || $pt->hasValueContainerParent() || $pt->isPrimitiveContainer() || $pt->hasPrimitiveContainerParent()) {
if ($pt->isPrimitiveContainer() || $pt->hasPrimitiveContainerParent()) {
$vp = $pt->getProperties()->getProperty(PHPFHIR_VALUE_PROPERTY_NAME) ?? $pt->getParentProperty(PHPFHIR_VALUE_PROPERTY_NAME);
array_push(
$hintTypes,
Expand Down
3 changes: 0 additions & 3 deletions src/Version/Definition.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@ public function buildDefinition(): void
$log->info('Setting primitive container flags');
TypeDecorator::setPrimitiveContainerFlag($this->_version, $this->_types);

$log->info('Setting value container flags');
TypeDecorator::setValueContainerFlag($this->_version, $this->_types);

$log->info('Setting comment container flags');
TypeDecorator::setCommentContainerFlag($this->_config, $this->_types);

Expand Down
67 changes: 12 additions & 55 deletions src/Version/Definition/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ class Type
/** @var bool */
private bool $_primitiveContainer = false;
/** @var bool */
private bool $_valueContainer = false;
/** @var bool */
private bool $_commentContainer = false;
/** @var \DCarbone\PHPFHIR\Builder\Imports */
private Imports $_imports;
Expand Down Expand Up @@ -354,9 +352,9 @@ public function getProperties(): Properties
return $this->_properties;
}

public function getParentProperty(string $name) : null|Property
public function getParentProperty(string $name): null|Property
{
foreach($this->getParentPropertiesIterator() as $property) {
foreach ($this->getParentPropertiesIterator() as $property) {
if ($property->getName() === $name) {
return $property;;
}
Expand Down Expand Up @@ -570,12 +568,6 @@ public function isPrimitiveContainer(): bool
*/
public function setPrimitiveContainer(bool $primitiveContainer): Type
{
if ($primitiveContainer && $this->_valueContainer) {
throw new \LogicException(sprintf(
'Cannot mark Type "%s" as primitive container as it is already marked as a value container',
$this->getFHIRName()
));
}
$this->_primitiveContainer = $primitiveContainer;
return $this;
}
Expand Down Expand Up @@ -823,43 +815,6 @@ public function hasContainedTypeParent(): bool
return $this->hasParent() && $this->_parentType->isContainedType();
}

/**
* @return bool
*/
public function isValueContainer(): bool
{
return $this->_valueContainer;
}

/**
* @param bool $valueContainer
* @return \DCarbone\PHPFHIR\Version\Definition\Type
*/
public function setValueContainer(bool $valueContainer): Type
{
if ($valueContainer && $this->_primitiveContainer) {
throw new \LogicException(sprintf(
'Cannot mark Type "%s" as value container as it is already marked as a primitive container',
$this->getFHIRName(),
));
}
$this->_valueContainer = $valueContainer;
return $this;
}

/**
* @return bool
*/
public function hasValueContainerParent(): bool
{
foreach ($this->getParentTypes() as $parent) {
if ($parent->isValueContainer()) {
return true;
}
}
return false;
}

/**
* @return bool
*/
Expand Down Expand Up @@ -907,12 +862,6 @@ public function getDirectlyImplementedInterfaces(): array
->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_PRIMITIVE_CONTAINER_TYPE)
->getFullyQualifiedNamespace(false);
}
} else if ($this->isValueContainer()) {
if (!$this->hasValueContainerParent()) {
$interfaces[PHPFHIR_TYPES_INTERFACE_VALUE_CONTAINER_TYPE] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_VALUE_CONTAINER_TYPE)
->getFullyQualifiedNamespace(false);
}
} else if ($this->isResourceType()) {
if (!$this->hasResourceTypeParent()) {
$interfaces[PHPFHIR_TYPES_INTERFACE_RESOURCE_TYPE] = $coreFiles
Expand Down Expand Up @@ -961,18 +910,26 @@ public function getDirectlyUsedTraits(): array
}

// these must only be added if the type has local properties
if ($this->hasLocalProperties() || $this->getFHIRName() === PHPFHIR_XHTML_TYPE_NAME) {
if ($this->isResourceType() && $this->hasLocalProperties()) {
$traits[PHPFHIR_TRAIT_SOURCE_XMLNS] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TRAIT_SOURCE_XMLNS)
->getFullyQualifiedNamespace(false);
}
} else if (!$parentType->hasLocalProperties()) {
} else if ($this->isResourceType() && !$parentType->hasLocalProperties()) {
// if this type _does_ have a parent, only add these traits if the parent does not have local properties
$traits[PHPFHIR_TRAIT_SOURCE_XMLNS] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TRAIT_SOURCE_XMLNS)
->getFullyQualifiedNamespace(false);
}

// we do not apply the value container trait to primitive types, as they have a per-type implementation
// of _getFormattedValue()
if (($this->isPrimitiveContainer() && !$this->hasPrimitiveContainerParent())) {
$traits[PHPFHIR_TYPES_TRAIT_VALUE_CONTAINER] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TYPES_TRAIT_VALUE_CONTAINER)
->getFullyQualifiedNamespace(false);
}

return $traits;
}

Expand Down
32 changes: 0 additions & 32 deletions src/Version/Definition/TypeDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -406,38 +406,6 @@ public static function setPrimitiveContainerFlag(Version $version, Types $types)
}
}

/**
* A "value container" type is any type with a "value" property that isn't a primitive or primitive-container.
*
* @param \DCarbone\PHPFHIR\Version $version
* @param \DCarbone\PHPFHIR\Version\Definition\Types $types
*/
public static function setValueContainerFlag(Version $version, Types $types): void
{
$logger = $version->getConfig()->getLogger();
foreach ($types->getIterator() as $type) {
// primitive types have special handling and must not be marked as "value containers"
if ($type->isPrimitiveOrListType() || $type->hasPrimitiveOrListParent()) {
continue;
}

// skip "primitive container" types.
if ($type->isPrimitiveContainer() || $type->hasPrimitiveContainerParent()) {
continue;
}

// skip xhtml type
if (PHPFHIR_XHTML_TYPE_NAME === $type->getFHIRName()) {
continue;
}

if ($type->getProperties()->hasProperty(PHPFHIR_VALUE_PROPERTY_NAME)) {
$logger->debug(sprintf('Type "%s" has "value" property, marking as Value Container', $type->getFHIRName()));
$type->setValueContainer(true);
}
}
}

/**
* @param \DCarbone\PHPFHIR\Config $config
* @param \DCarbone\PHPFHIR\Version\Definition\Types $types
Expand Down
91 changes: 91 additions & 0 deletions template/core/types/interface_dstu1_type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php declare(strict_types=1);

/*
* Copyright 2025 Daniel Carbone ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use DCarbone\PHPFHIR\Utilities\ImportUtils;

/** @var \DCarbone\PHPFHIR\Config $config */
/** @var \DCarbone\PHPFHIR\CoreFile $coreFile */

$coreFiles = $config->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 '<?php ';?>declare(strict_types=1);

namespace <?php echo $coreFile->getFullyQualifiedNamespace(false); ?>;

<?php echo $config->getBasePHPFHIRCopyrightComment(true); ?>

<?php echo ImportUtils::compileImportStatements($imports); ?>

/**
* <?php echo $coreFile->getEntityName(); ?> Interface
*
* This is a special interface only applied when generating types for versions based on DSTU1. It is necessary
* as Resources in DSTU1 are extensions of Elements. This is unique to DSTU1.
*/
interface <?php echo $coreFile->getEntityName(); ?> extends <?php echo $typeInterface->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|<?php echo $unserializeConfigClass->getFullyQualifiedName(true); ?> $config
* @param null|<?php echo $coreFile->getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created.
* @return static
*/
public static function xmlUnserialize(string|\SimpleXMLElement $element,
null|<?php echo $unserializeConfigClass->getEntityName() ?> $config = null,
null|<?php echo $coreFile->getEntityName(); ?> $type = null): self;

/**
* @param null|<?php echo $xmlWriterClass->getFullyQualifiedName(true); ?> $xw
* @param null|<?php echo $serializeConfigClass->getFullyQualifiedName(true); ?> $config
* @return <?php echo $xmlWriterClass->getFullyQualifiedName(true); ?>

*/
public function xmlSerialize(null|<?php echo $xmlWriterClass->getEntityName(); ?> $xw = null,
null|<?php echo $serializeConfigClass->getEntityName(); ?> $config = null): <?php echo $xmlWriterClass->getEntityName(); ?>;

/**
* @param string|array|\stdClass $json Raw or already un-encoded JSON
* @param null|<?php echo $unserializeConfigClass->getFullyQualifiedName(true); ?> $config
* @param null|<?php echo $coreFile->getFullyQualifiedName(true); ?> $type Instance of this class to unserialize into. If left null, a new instance will be created.
* @return static
*/
public static function jsonUnserialize(string|array|\stdClass $json,
null|<?php echo $unserializeConfigClass->getEntityName(); ?> $config = null,
null|<?php echo $coreFile->getEntityName(); ?> $type = null): self;
}

<?php return ob_get_clean();
14 changes: 3 additions & 11 deletions template/core/types/interface_element_type.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
* limitations under the License.
*/

use DCarbone\PHPFHIR\Utilities\ImportUtils;

/** @var \DCarbone\PHPFHIR\Config $config */
/** @var \DCarbone\PHPFHIR\CoreFile $coreFile */

use DCarbone\PHPFHIR\Utilities\ImportUtils;

$coreFiles = $config->getCoreFiles();

$typeInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_TYPE);
Expand All @@ -41,17 +41,9 @@

<?php echo ImportUtils::compileImportStatements($imports); ?>

interface <?php echo $coreFile->getEntityName(); ?> extends <?php echo $typeInterface->getEntityName(); ?>, \JsonSerializable
interface <?php echo $coreFile->getEntityName(); ?> extends <?php echo $typeInterface->getEntityName(); ?>

{
/**
* 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 \SimpleXMLElement $element Decoded XML
* @param <?php echo $unserializeConfigClass->getFullyQualifiedName(true); ?> $config
Expand Down
4 changes: 2 additions & 2 deletions template/core/types/interface_primitive_container_type.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
* limitations under the License.
*/

use DCarbone\PHPFHIR\Utilities\ImportUtils;

/** @var \DCarbone\PHPFHIR\Config $config */
/** @var \DCarbone\PHPFHIR\CoreFile $coreFile */

use DCarbone\PHPFHIR\Utilities\ImportUtils;

$coreFiles = $config->getCoreFiles();

$valueContainerInterface = $coreFiles->getCoreFileByEntityName(PHPFHIR_TYPES_INTERFACE_VALUE_CONTAINER_TYPE);
Expand Down
Loading

0 comments on commit 14672fa

Please sign in to comment.