Skip to content

Commit

Permalink
more template merging, too many dang files.
Browse files Browse the repository at this point in the history
  • Loading branch information
dcarbone committed Jan 3, 2025
1 parent ac42030 commit 191e94b
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 773 deletions.
4 changes: 3 additions & 1 deletion src/Utilities/TypeHintUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ public static function primitivePHPValueTypeSetterDoc(Version $version, Primitiv
$hintTypes = $primitiveType->getPHPReceiveValueTypeHints();

if ($asCollection) {
$hintTypes[] = array_map(function(string $v) { return sprintf('%s[]', $v); }, $hintTypes);
$hintTypes[] = array_map(function (string $v) {
return sprintf('%s[]', $v);
}, $hintTypes);
} else if ($nullable) {
array_unshift($hintTypes, 'null');
}
Expand Down
27 changes: 16 additions & 11 deletions src/Version/Definition/Property.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,11 @@

use DCarbone\PHPFHIR\Enum\PropertyUseEnum;
use DCarbone\PHPFHIR\Utilities\NameUtils;
use InvalidArgumentException;
use SimpleXMLElement;

/**
* Class Property
* @package DCarbone\PHPFHIR\Definition
*/
class Property
{
use DocumentationTrait;
use SourceTrait;
use DocumentationTrait,
SourceTrait;

/** @var \DCarbone\PHPFHIR\Version\Definition\Type */
private Type $memberOf;
Expand Down Expand Up @@ -76,7 +70,7 @@ class Property
* @param \SimpleXMLElement $sxe
* @param string $sourceFilename
*/
public function __construct(Type $memberOf, SimpleXMLElement $sxe, string $sourceFilename)
public function __construct(Type $memberOf, \SimpleXMLElement $sxe, string $sourceFilename)
{
$this->memberOf = $memberOf;
$this->sourceSXE = $sxe;
Expand Down Expand Up @@ -121,14 +115,25 @@ public function getName(): null|string
return $this->name;
}

/**
* @return string|null
*/
public function getExtName(): null|string
{
if (null === $this->name) {
return null;
}
return "_{$this->name}";
}

/**
* @param string $name
* @return \DCarbone\PHPFHIR\Version\Definition\Property
*/
public function setName(string $name): Property
{
if ('' === $name) {
throw new InvalidArgumentException(
throw new \InvalidArgumentException(
sprintf(
'Type "%s" Property $name cannot be empty',
$this->valueFHIRType->getFHIRName()
Expand Down Expand Up @@ -302,7 +307,7 @@ public function getRef(): null|string
public function setRef(string $ref): Property
{
if ('' === $ref) {
throw new InvalidArgumentException(
throw new \InvalidArgumentException(
sprintf(
'Type "%s" Property $ref cannot be empty',
$this->valueFHIRType->getFHIRName()
Expand Down
36 changes: 27 additions & 9 deletions src/Version/Definition/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -757,20 +757,32 @@ 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_INTERFACE_COMMENT_CONTAINER] = $this->config->getFullyQualifiedName(false);
$interfaces[PHPFHIR_INTERFACE_COMMENT_CONTAINER] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_INTERFACE_COMMENT_CONTAINER)
->getFullyQualifiedNamespace(false);
}
if ($this->isContainedType()) {
$interfaces[PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE] = $this->version->getFullyQualifiedName(false);
$interfaces[PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE] = $versionCoreFiles
->getCoreFileByEntityName(PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE)
->getFullyQualifiedNamespace(false);
} else if ($this->getKind() === TypeKindEnum::PRIMITIVE) {
$interfaces[PHPFHIR_INTERFACE_PRIMITIVE_TYPE] = $this->config->getFullyQualifiedName(false);
$interfaces[PHPFHIR_INTERFACE_PRIMITIVE_TYPE] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_INTERFACE_PRIMITIVE_TYPE)
->getFullyQualifiedNamespace(false);
} else {
$interfaces[PHPFHIR_INTERFACE_TYPE] = $this->config->getFullyQualifiedName(false);
$interfaces[PHPFHIR_INTERFACE_TYPE] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_INTERFACE_TYPE)
->getFullyQualifiedNamespace(false);
}
} elseif ($this->isContainedType() && !$parentType->isContainedType()) {
$interfaces[PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE] = $this->version->getFullyQualifiedName(false);
$interfaces[PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE] = $versionCoreFiles
->getCoreFileByEntityName(PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE)
->getFullyQualifiedNamespace(false);
}

return $interfaces;
Expand All @@ -783,22 +795,28 @@ public function getDirectlyUsedTraits(): array
{
$traits = [];
$parentType = $this->getParentType();
$coreFiles = $this->version->getConfig()->getCoreFiles();

if (null === $parentType) {
// if this type has no parent(s), try to add all traits

if ($this->isCommentContainer()) {
$traits[] = PHPFHIR_TRAIT_COMMENT_CONTAINER;
$traits[PHPFHIR_TRAIT_COMMENT_CONTAINER] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TRAIT_COMMENT_CONTAINER)
->getFullyQualifiedNamespace(false);
}

// these must only be added if the type has local properties
if ($this->hasLocalProperties()) {
$traits[] = PHPFHIR_TRAIT_SOURCE_XMLNS;
$traits[PHPFHIR_TRAIT_SOURCE_XMLNS] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TRAIT_SOURCE_XMLNS)
->getFullyQualifiedNamespace(false);
}
} else if (!$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;
$traits[PHPFHIR_TRAIT_SOURCE_XMLNS] = $coreFiles
->getCoreFileByEntityName(PHPFHIR_TRAIT_SOURCE_XMLNS)
->getFullyQualifiedNamespace(false);
}

return $traits;
Expand Down
9 changes: 7 additions & 2 deletions src/Version/Definition/TypeDecorationValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ abstract class TypeDecorationValidator
*/
public static function validateDecoration(Config $config, Version $version, Types $types): void
{
$versionName = $version->getName();

$seenClasses = [];
foreach ($types->getGenerator() as $type) {
$typeKind = $type->getKind();
Expand Down Expand Up @@ -78,6 +76,13 @@ public static function validateDecoration(Config $config, Version $version, Type
}
}

if ($typeKind === TypeKindenum::PRIMITIVE_CONTAINER) {
$valueProperty = $type->getLocalProperties()->getProperty('value');
if (null === $valueProperty) {
throw ExceptionUtils::createPrimitiveValuePropertyNotFound($type);
}
}

if ($types->isContainedType($type) !== $type->isContainedType()) {
throw ExceptionUtils::createContainedTypeFlagMismatchException($types->isContainedType($type), $type);
}
Expand Down
146 changes: 69 additions & 77 deletions src/Version/Definition/TypeImports.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,58 @@ public function __construct(Type $type)
$this->type = $type;
}

/**
* @param string $classname
* @param string $namespace
*/
public function addImport(string $classname, string $namespace): void
{
$requiresImport = !str_starts_with($classname, '\\') &&
ltrim($namespace, '\\') !== $this->type->getFullyQualifiedNamespace(false);

if (isset($this->imports[$classname])) {
// if we have already seen this type, move on.
if ($this->imports[$classname]->getNamespace() === $namespace) {
return;
}

// if there is a conflicting imported type here...
$aliasName = $this->findNextAliasName($classname, $namespace);
$this->imports[$aliasName] = new TypeImport($classname, $namespace, true, $aliasName, $requiresImport);
return;
}

if ($classname === $this->type->getClassName() &&
$namespace !== $this->type->getFullyQualifiedNamespace(false)) {
// if the imported type has the same class name as the direct type, but a different namespace
$aliasName = $this->findNextAliasName($classname, $namespace);
$this->imports[$aliasName] = new TypeImport($classname, $namespace, true, $aliasName, $requiresImport);
return;
}

// otherwise, go ahead and add to map.
$this->imports[$classname] = new TypeImport($classname, $namespace, false, '', $requiresImport);
}

public function addCoreFileImport(string $entityName): void
{
$coreFile = $this->type->getVersion()->getConfig()->getCoreFiles()->getCoreFileByEntityName($entityName);
$this->addImport($coreFile->getEntityName(), $coreFile->getNamespace());
}

public function addVersionCoreFileImport(string $entityName): void
{
$coreFile = $this->type->getVersion()->getCoreFiles()->getCoreFileByEntityName($entityName);
$this->addImport($coreFile->getEntityName(), $coreFile->getNamespace());
}

/**
* @return \DCarbone\PHPFHIR\Version\Definition\TypeImport[]
*/
public function getIterator(): \Iterator
public function getIterator(): iterable
{
$this->buildImports();
return new \ArrayIterator($this->imports, \ArrayIterator::STD_PROP_LIST);
return new \ArrayIterator($this->imports);
}

/**
Expand Down Expand Up @@ -120,39 +165,6 @@ private function findNextAliasName(string $classname, string $namespace): string
return $aliasName;
}

/**
* @param string $classname
* @param string $namespace
*/
private function addImport(string $classname, string $namespace): void
{
$requiresImport = !str_starts_with($classname, '\\') &&
ltrim($namespace, '\\') !== $this->type->getFullyQualifiedNamespace(false);

if (isset($this->imports[$classname])) {
// if we have already seen this type, move on.
if ($this->imports[$classname]->getNamespace() === $namespace) {
return;
}

// if there is a conflicting imported type here...
$aliasName = $this->findNextAliasName($classname, $namespace);
$this->imports[$aliasName] = new TypeImport($classname, $namespace, true, $aliasName, $requiresImport);
return;
}

if ($classname === $this->type->getClassName() &&
$namespace !== $this->type->getFullyQualifiedNamespace(false)) {
// if the imported type has the same class name as the direct type, but a different namespace
$aliasName = $this->findNextAliasName($classname, $namespace);
$this->imports[$aliasName] = new TypeImport($classname, $namespace, true, $aliasName, $requiresImport);
return;
}

// otherwise, go ahead and add to map.
$this->imports[$classname] = new TypeImport($classname, $namespace, false, '', $requiresImport);
}

/**
* Attempts to build succinct list of imports used by this type. Currently flawed, results in some unused imports
* to be defined. Will need to be revisited.
Expand All @@ -164,77 +176,58 @@ private function buildImports(): void
if ($this->parsed) {
return;
}

// immediately set to true so we don't recurse ourselves to death.
$this->parsed = true;

// immediately add self
$this->addImport($this->type->getClassName(), $this->type->getFullyQualifiedNamespace(false));

$typeNS = $this->type->getFullyQualifiedNamespace(false);
$configNS = $this->type->getConfig()->getFullyQualifiedName(false);
$versionNS = $this->type->getVersion()->getFullyQualifiedName(false);

$typeKind = $this->type->getKind();

$allProperties = $this->type->getAllPropertiesIterator();

// non-abstract types must import config and xml writer
if (!$this->type->isAbstract()) {
$this->addImport(PHPFHIR_CLASSNAME_XML_WRITER, $configNS);
$this->addImport(PHPFHIR_ENUM_XML_LOCATION, $configNS);
$this->addCoreFileImport(PHPFHIR_CLASSNAME_XML_WRITER);
$this->addCoreFileImport(PHPFHIR_ENUM_XML_LOCATION);
}

// if this type is in a nested namespace, there are a few base interfaces, classes, and traits
// that may need to be imported to ensure function
if ($typeNS !== $configNS) {
$this->addImport(PHPFHIR_CLASSNAME_UNSERIALIZE_CONFIG, $configNS);
$this->addImport(PHPFHIR_CLASSNAME_SERIALIZE_CONFIG, $configNS);
$this->addVersionCoreFileImport(PHPFHIR_CLASSNAME_VERSION);
$this->addVersionCoreFileImport(PHPFHIR_CLASSNAME_VERSION_CONSTANTS);
$this->addCoreFileImport(PHPFHIR_CLASSNAME_UNSERIALIZE_CONFIG);
$this->addCoreFileImport(PHPFHIR_CLASSNAME_SERIALIZE_CONFIG);

// always add the base type interface
$this->addImport(PHPFHIR_INTERFACE_TYPE, $configNS);
$this->addCoreFileImport(PHPFHIR_INTERFACE_TYPE);

// add directly implemented interfaces
foreach ($this->type->getDirectlyImplementedInterfaces() as $interface => $namespace) {
$this->addImport($interface, $namespace);
}
// add directly implemented traits
foreach ($this->type->getDirectlyUsedTraits() as $trait) {
$this->addImport($trait, $configNS);
}
// add root Constants class if this is a comment containing type or has local properties with validations
if (($this->type->isCommentContainer() && !$this->type->hasCommentContainerParent()) ||
$this->type->hasLocalPropertiesWithValidations() ||
($typeKind->isOneOf(TypeKindEnum::PRIMITIVE) && !$this->type->hasPrimitiveParent())) {
$this->addImport(PHPFHIR_CLASSNAME_CONSTANTS, $configNS);
}
foreach ($this->type->getDirectlyImplementedInterfaces() as $interface => $namespace) {
$this->addImport($interface, $namespace);
}

foreach ($this->type->getDirectlyUsedTraits() as $trait => $namespace) {
$this->addImport($trait, $namespace);
}

if ($typeNS !== $versionNS) {
// add a few imports used during unserialization.
$this->addImport(PHPFHIR_CLASSNAME_VERSION, $versionNS);
$this->addImport(PHPFHIR_CLASSNAME_VERSION_CONSTANTS, $versionNS);
if (($this->type->isCommentContainer() && !$this->type->hasCommentContainerParent()) ||
$this->type->hasLocalPropertiesWithValidations() ||
($typeKind->isOneOf(TypeKindEnum::PRIMITIVE) && !$this->type->hasPrimitiveParent())) {
$this->addCoreFileImport(PHPFHIR_CLASSNAME_CONSTANTS);
}

// determine if we need to import our parent type
if ($parentType = $this->type->getParentType()) {
$pns = $parentType->getFullyQualifiedNamespace(false);
$this->addImport($parentType->getClassName(), $pns);
} else {
$this->addImport(PHPFHIR_TRAIT_SOURCE_XMLNS, $configNS);
}

if ($this->type->hasLocalPropertiesWithValidations()) {
$this->addImport(PHPFHIR_CLASSNAME_VALIDATOR, $configNS);
$this->addCoreFileImport(PHPFHIR_CLASSNAME_VALIDATOR);
}

// determine if we need to import a restriction base
if ($restrictionBaseType = $this->type->getRestrictionBaseFHIRType()) {
$rns = $restrictionBaseType->getFullyQualifiedNamespace(false);
$this->addImport($restrictionBaseType->getClassName(), $rns);
}

// add property types to import statement
foreach ($allProperties as $property) {
$propertyType = $property->getValueFHIRType();
if (null === $propertyType) {
Expand All @@ -249,10 +242,10 @@ private function buildImports(): void

if ($ptk->isOneOf(TypeKindEnum::RESOURCE_CONTAINER, TypeKindEnum::RESOURCE_INLINE) &&
$typeNS !== $configNS) {
$this->addImport(PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE, $versionNS);
$this->addImport(PHPFHIR_CLASSNAME_VERSION_TYPE_MAP, $versionNS);
$this->addImport(PHPFHIR_CLASSNAME_CONSTANTS, $configNS);
$this->addImport(PHPFHIR_CLASSNAME_VERSION, $versionNS);
$this->addCoreFileImport(PHPFHIR_CLASSNAME_CONSTANTS);
$this->addVersionCoreFileImport(PHPFHIR_INTERFACE_VERSION_CONTAINED_TYPE);
$this->addVersionCoreFileImport(PHPFHIR_CLASSNAME_VERSION_TYPE_MAP);
$this->addVersionCoreFileImport(PHPFHIR_CLASSNAME_VERSION);
} else {
if ($ptk === TypeKindEnum::PRIMITIVE_CONTAINER) {
$primType = $propertyType->getLocalProperties()->getProperty('value')->getValueFHIRType();
Expand All @@ -264,7 +257,6 @@ private function buildImports(): void
}
}

// sort the imported class list
uasort(
$this->imports,
function (TypeImport $a, TypeImport $b) {
Expand Down
Loading

0 comments on commit 191e94b

Please sign in to comment.