@@ -35,6 +35,8 @@ class Imports implements \Countable
3535
3636 /** @var \DCarbone\PHPFHIR\Builder\Import[] */
3737 private array $ _imports = [];
38+ /** @var bool */
39+ private bool $ _sorted = false ;
3840
3941 /** @var int */
4042 private int $ _requiredImportCount = 0 ;
@@ -54,59 +56,87 @@ public function __construct(Config $config, string $localNamespace, string $loca
5456 /**
5557 * @param string $namespace Namespace of referenced entity
5658 * @param string $name Name of referenced entity
57- * @return \DCarbone\PHPFHIR\Builder\Imports
59+ * @param null|string $alias Explicit alias to use
60+ * @return \DCarbone\PHPFHIR\Builder\Import
5861 */
59- public function addImport (string $ namespace , string $ name ): self
62+ public function addImport (string $ namespace , string $ name, null | string $ alias = null ): Import
6063 {
6164 // ensure clean namespace value
6265 $ namespace = trim ($ namespace , PHPFHIR_NAMESPACE_SEPARATOR );
6366
64- // do not need to import sibling entities.
67+ // do not need to explicitly import same-namespace entities.
6568 $ requiresImport = ($ namespace !== $ this ->_localNamespace );
69+ if ($ requiresImport ) {
70+ $ this ->_requiredImportCount ++;
71+ }
72+
73+ // check if one with the same name or explicit alias already exists.
74+ $ current = match ($ alias ) {
75+ null => $ this ->_imports [$ name ] ?? null ,
76+ default => $ this ->_imports [$ alias ] ?? null ,
77+ };
6678
67- if (isset ($ this ->_imports [$ name ])) {
68- // if we have already seen this type, move on.
69- if ($ this ->_imports [$ name ]->getNamespace () === $ namespace ) {
70- return $ this ;
79+ // if match found...
80+ if ($ current ) {
81+ // ...and is an exact match, return it
82+ if ($ current ->getNamespace () === $ namespace ) {
83+ return $ current ;
7184 }
72- // if there is a conflicting imported type here...
73- $ aliasName = $ this ->_findNextAliasName ($ name );
74- $ this ->_imports [$ aliasName ] = new Import ($ name , $ namespace , $ aliasName , $ requiresImport );
85+
86+ // otherwise, if alias was explicitly provided, bail out now as this indicates faulty logic somewhere
87+ // along the line.
88+ if (null !== $ alias ) {
89+ throw new \LogicException (sprintf (
90+ 'Explicit alias "%s" for type "%s" at namespace "%s" collides with alias for type "%s" at namespace "%s". ' ,
91+ $ alias ,
92+ $ name ,
93+ $ namespace ,
94+ $ current ->getName (),
95+ $ current ->getNamespace (),
96+ ));
97+ }
98+
99+ // otherwise, find next available alias and create import
100+ $ import = new Import ($ name , $ namespace , $ this ->_findNextAliasName ($ name ), $ requiresImport );
75101 } else if ($ name === $ this ->_localName && $ namespace != $ this ->_localNamespace ) {
76102 // if the referenced type has the same name but exists in a different namespace, alias it.
77- $ aliasName = $ this ->_findNextAliasName ($ name );
78- $ this ->_imports [$ aliasName ] = new Import ($ name , $ namespace , $ aliasName , $ requiresImport );
103+ $ import = new Import ($ name , $ namespace , $ alias ?? $ this ->_findNextAliasName ($ name ), $ requiresImport );
79104 } else {
80105 // otherwise, go ahead and add to map.
81- $ this -> _imports [ $ name ] = new Import ($ name , $ namespace , '' , $ requiresImport );
106+ $ import = new Import ($ name , $ namespace , $ alias ?? '' , $ requiresImport );
82107 }
83108
84- if ( $ requiresImport ) {
85- $ this ->_requiredImportCount ++ ;
86- }
109+ // add new import to local map
110+ $ this ->_sorted = false ;
111+ $ this -> _imports [ $ import -> getImportedName ()] = $ import ;
87112
88- uasort (
89- $ this ->_imports ,
90- function (Import $ a , Import $ b ) {
91- return strnatcasecmp ($ a ->getFullyQualifiedName (false ), $ b ->getFullyQualifiedName (false ));
92- }
93- );
113+ return $ import ;
114+ }
94115
95- return $ this ;
116+ /**
117+ * Add specific core file to imported list with optional explicit alias.
118+ *
119+ * @param \DCarbone\PHPFHIR\CoreFile $coreFile
120+ * @param string|null $alias
121+ * @return \DCarbone\PHPFHIR\Builder\Import
122+ */
123+ public function addCoreFileImport (CoreFile $ coreFile , null |string $ alias = null ): Import
124+ {
125+ return $ this ->addImport ($ coreFile ->getFullyQualifiedNamespace (false ), $ coreFile ->getEntityName (), $ alias );
96126 }
97127
98- public function addCoreFileImports (CoreFile ...$ coreFile ): self
128+ public function addCoreFileImports (CoreFile ...$ coreFiles ): self
99129 {
100- foreach ($ coreFile as $ cf ) {
101- $ this ->addImport ($ cf-> getFullyQualifiedNamespace ( false ), $ cf -> getEntityName () );
130+ foreach ($ coreFiles as $ cf ) {
131+ $ this ->addCoreFileImport ($ cf );
102132 }
103133 return $ this ;
104134 }
105135
106136 public function addCoreFileImportsByName (string ...$ entityNames ): self
107137 {
108138 foreach ($ entityNames as $ en ) {
109- $ this ->addCoreFileImports (
139+ $ this ->addCoreFileImport (
110140 $ this ->_config ->getCoreFiles ()->getCoreFileByEntityName ($ en ),
111141 );
112142 }
@@ -116,7 +146,7 @@ public function addCoreFileImportsByName(string ...$entityNames): self
116146 public function addVersionCoreFileImportsByName (Version $ version , string ...$ entityNames ): self
117147 {
118148 foreach ($ entityNames as $ en ) {
119- $ coreFile = $ version ->getCoreFiles ()->getCoreFileByEntityName ($ en );
149+ $ coreFile = $ version ->getVersionCoreFiles ()->getCoreFileByEntityName ($ en );
120150 $ this ->addImport ($ coreFile ->getNamespace (), $ coreFile ->getEntityName ());
121151 }
122152 return $ this ;
@@ -135,6 +165,7 @@ public function addVersionTypeImports(Type ...$types): self
135165 */
136166 public function getIterator (): iterable
137167 {
168+ $ this ->_sort ();
138169 return new \ArrayIterator ($ this ->_imports );
139170 }
140171
@@ -168,8 +199,9 @@ public function getImportByType(Type $type): Import
168199 */
169200 public function getImportByClassAndNamespace (string $ classname , string $ namespace ): null |Import
170201 {
202+ $ this ->_sort ();
171203 foreach ($ this ->_imports as $ import ) {
172- if ($ import ->getNamespace () === $ namespace && $ import ->getClassname () === $ classname ) {
204+ if ($ import ->getNamespace () === $ namespace && $ import ->getName () === $ classname ) {
173205 return $ import ;
174206 }
175207 }
@@ -208,4 +240,18 @@ private function _findNextAliasName(string $classname): string
208240 }
209241 return $ aliasName ;
210242 }
243+
244+ private function _sort (): void
245+ {
246+ if ($ this ->_sorted ) {
247+ return ;
248+ }
249+ uasort (
250+ $ this ->_imports ,
251+ function (Import $ a , Import $ b ) {
252+ return strnatcasecmp ($ a ->getFullyQualifiedName (false ), $ b ->getFullyQualifiedName (false ));
253+ }
254+ );
255+ $ this ->_sorted = true ;
256+ }
211257}
0 commit comments