Skip to content

Commit 6e0816d

Browse files
authored
Track XML serialization locations (#111)
Addresses #110
1 parent 0f07854 commit 6e0816d

36 files changed

+461
-749
lines changed

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ jobs:
8585
with:
8686
php-version: ${{ matrix.php-version }}
8787
extensions: libxml simplexml json zip
88-
# https://github.com/mheap/phpunit-github-actions-printer/blob/master/.github/workflows/ci.yml#L32
88+
ini-values: precision=20
8989

9090
- name: 'Install jq'
9191
uses: dcarbone/install-jq-action@v2

README.md

Lines changed: 10 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -75,79 +75,22 @@ There are 2 important things to note with this section:
7575

7676
### Generation Example
7777

78-
```php
79-
require __DIR__.'/vendor/autoload.php';
80-
81-
$schemaPath = 'schema/path';
78+
You can view an example config array here: [bin/config.php](./bin/config.php).
8279

80+
```php
8381
// first, build new configuration class
84-
$config = new \DCarbone\PHPFHIR\Config([
85-
// The path to look look for and optionally download source XSD files to
86-
'schemaPath' => __DIR__ . '/../input',
87-
88-
// The path to place generated type class files
89-
'classesPath' => __DIR__ . '/../output',
90-
91-
// If true, will use a noop null logger
92-
'silent' => false,
93-
94-
// If true, will skip generation of test classes
95-
'skipTests' => false,
96-
97-
// Map of versions and configurations to generate
98-
// Each entry in this map will grab the latest revision of that particular version. If you wish to use a specific
99-
// version, please see https://www.hl7.org/fhir/directory.html
100-
'versions' => [
101-
'DSTU1' => [
102-
// Source URL
103-
'url' => 'https://hl7.org/fhir/DSTU1/fhir-all-xsd.zip',
104-
// Namespace to prefix the generated classes with
105-
'namespace' => '\\HL7\\FHIR\\DSTU1',
106-
],
107-
'DSTU2' => [
108-
'url' => 'https://hl7.org/fhir/DSTU2/fhir-all-xsd.zip',
109-
'namespace' => '\\HL7\\FHIR\\DSTU2',
110-
'testEndpoint' => 'https://hapi.fhir.org/baseDstu2',
111-
],
112-
'STU3' => [
113-
'url' => 'https://hl7.org/fhir/STU3/fhir-all-xsd.zip',
114-
'namespace' => '\\HL7\\FHIR\\STU3',
115-
'testEndpoint' => 'https://hapi.fhir.org/baseDstu3',
116-
],
117-
'R4' => [
118-
'url' => 'https://www.hl7.org/fhir/R4/fhir-all-xsd.zip',
119-
'namespace' => '\\HL7\\FHIR\\R4',
120-
'testEndpoint' => 'https://hapi.fhir.org/baseR4',
121-
],
122-
'R5' => [
123-
'url' => 'https://hl7.org/fhir/R5/fhir-all-xsd.zip',
124-
'namespace' => '\\HL7\\FHIR\\R5',
125-
'testEndpoint' => 'https://hapi.fhir.org/baseR5',
126-
]
127-
],
128-
]);
82+
$config = new \DCarbone\PHPFHIR\Config(require 'config.php');
12983

130-
// next, build definition class
131-
$version_config = new \DCarbone\PHPFHIR\Config\VersionConfig($config, $config->getVersion('R5'));
132-
$definition = new \DCarbone\PHPFHIR\Definition($version_config);
133-
$definition->buildDefinition();
134-
135-
$builder = new \DCarbone\PHPFHIR\Builder($config, $definition);
136-
$builder->render();
84+
// next, iterate through all configured versions and render code:
85+
foreach ($config->getVersions() as $versionConfig) {
86+
$versionConfig->getDefinition()->getBuilder()->render();
87+
}
13788
```
13889

139-
Using the above code will generate class files under the included [output](./output) directory, under the namespace
140-
` HL7\\FHIR\\{version} `
141-
142-
If you wish the files to be placed under a different directory, pass the path in as the 2nd argument in the
143-
generator constructor.
144-
145-
If you wish the classes to have a different base namespace, pass the desired NS name in as the 3rd argument in the
146-
generator constructor.
147-
14890
## Data Querying
14991

150-
There are a plethora of good HTTP clients you can use to get data out of a FHIR server, so I leave that up to you.
92+
Currently only a very simple client intended for debugging use is generated. A future goal is to generate a more
93+
fully-featured client.
15194

15295
## Response Parsing
15396

@@ -166,7 +109,7 @@ require 'path to PHPFHIRResponseParserConfig.php';
166109
require 'path to PHPFHIRResponseParser.php';
167110

168111
// build config
169-
$config = new \YourConfiguredNamespace\PHPFHIRResponseParserConfig([
112+
$config = new \YourConfiguredNamespace\PHPFHIRConfig([
170113
'registerAutoloader' => true, // use if you are not using Composer
171114
'libxmlOpts' => LIBXML_NONET | LIBXML_BIGLINES | LIBXML_PARSEHUGE | LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOXMLDECL // choose different libxml arguments if you want, ymmv.
172115
'rootXmlns' => 'https://hl7.org/fhir', // a specific root xmlns to use, if the source does not return one

bin/config.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
*/
2121
return [
2222
// The path to look look for and optionally download source XSD files to
23-
'schemaPath' => __DIR__ . '/../input/',
23+
'schemaPath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'input/',
2424

2525
// The path to place generated type class files
26-
'classesPath' => __DIR__ . '/../output/',
26+
'classesPath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'output/',
2727

2828
// If true, will use a noop null logger
2929
'silent' => false,
@@ -32,7 +32,7 @@
3232
'skipTests' => false,
3333

3434
// If you wish to specify alternative libxml opts, do so here.
35-
'libxmlOpts' => LIBXML_NONET | LIBXML_PARSEHUGE | LIBXML_COMPACT,
35+
'libxmlOpts' => LIBXML_NONET | LIBXML_BIGLINES | LIBXML_PARSEHUGE | LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOXMLDECL,
3636

3737
// Map of versions and configurations to generate
3838
// Each entry in this map will grab the latest revision of that particular version. If you wish to use a specific
@@ -43,6 +43,8 @@
4343
'url' => 'https://hl7.org/fhir/DSTU1/fhir-all-xsd.zip',
4444
// Namespace to prefix the generated classes with
4545
'namespace' => '\\HL7\\FHIR\\DSTU1',
46+
// if defined, enables integration and validation test generation against the provided endpoint.
47+
'testEndpoint' => '',
4648
],
4749
'DSTU2' => [
4850
'url' => 'https://hl7.org/fhir/DSTU2/fhir-all-xsd.zip',

bin/generate.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,11 @@ function is_dir_empty(string $dir): bool
380380
);
381381

382382
foreach ($versions_to_generate as $version) {
383-
$build_config = new Config\VersionConfig($config, $config->getVersion($version));
384-
385-
$url = $build_config->getUrl();
383+
$version_config = $config->getVersion($version);
384+
$url = $version_config->getUrl();
386385

387386
// build vars
388-
$namespace = $build_config->getFullyQualifiedName(true);
387+
$namespace = $version_config->getFullyQualifiedName(true);
389388
$version = trim($version);
390389
$schema_dir = $config->getSchemaPath() . DIRECTORY_SEPARATOR . $version;
391390

@@ -507,10 +506,10 @@ function is_dir_empty(string $dir): bool
507506
PHP_EOL
508507
);
509508

510-
$definition = new Definition($build_config);
509+
$definition = new Definition($version_config);
511510
$definition->buildDefinition();
512511

513-
$builder = new Builder($build_config, $definition);
512+
$builder = new Builder($version_config, $definition);
514513
if ($only_library) {
515514
$builder->writeFhirTypeFiles();
516515
} elseif ($only_tests) {

files/constants.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
const PHPFHIR_ENUM_CONFIG_KEY = 'PHPFHIRConfigKeyEnum';
104104
const PHPFHIR_ENUM_TYPE = 'PHPFHIRTypeEnum';
105105
const PHPFHIR_ENUM_API_FORMAT = 'PHPFHIRApiFormatEnum';
106+
const PHPFHIR_ENUM_XML_LOCATION_ENUM = 'PHPFHIRXmlLocationEnum';
106107

107108
// validation constants
108109
const PHPFHIR_VALIDATION_ENUM = 'enum';

src/Config.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020

2121
use DCarbone\PHPFHIR\Config\Version;
22+
use DCarbone\PHPFHIR\Config\VersionConfig;
2223
use Psr\Log\LoggerInterface;
2324
use Psr\Log\NullLogger;
2425

@@ -43,7 +44,8 @@ class Config
4344

4445
/** @var string */
4546
private string $classesPath = PHPFHIR_DEFAULT_OUTPUT_DIR;
46-
/** @var \DCarbone\PHPFHIR\Config\Version[] */
47+
48+
/** @var \DCarbone\PHPFHIR\Config\VersionConfig[] */
4749
private array $versions = [];
4850

4951
/** @var bool */
@@ -226,13 +228,13 @@ public function setVersions(array $versions): self
226228
{
227229
$this->versions = [];
228230
foreach ($versions as $name => $version) {
229-
$this->versions[$name] = ($version instanceof Version) ? $version : new Version($name, $version);
231+
$this->versions[$name] = ($version instanceof VersionConfig) ? $version : new VersionConfig($this, new Version($name, $version));
230232
}
231233
return $this;
232234
}
233235

234236
/**
235-
* @return \DCarbone\PHPFHIR\Config\Version[]
237+
* @return \DCarbone\PHPFHIR\Config\VersionConfig[]
236238
*/
237239
public function getVersions(): array
238240
{
@@ -250,9 +252,9 @@ public function hasVersion(string $version): bool
250252

251253
/**
252254
* @param string $version
253-
* @return \DCarbone\PHPFHIR\Config\Version
255+
* @return \DCarbone\PHPFHIR\Config\VersionConfig
254256
*/
255-
public function getVersion(string $version): Version
257+
public function getVersion(string $version): VersionConfig
256258
{
257259
if (!$this->hasVersion($version)) {
258260
throw new \OutOfBoundsException(

src/Config/VersionConfig.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020

2121
use DCarbone\PHPFHIR\Config;
22+
use DCarbone\PHPFHIR\Definition;
2223
use DCarbone\PHPFHIR\Enum\TestType;
2324
use DCarbone\PHPFHIR\Logger;
2425

@@ -33,6 +34,9 @@ class VersionConfig
3334
/** @var \DCarbone\PHPFHIR\Config\Version */
3435
private Version $version;
3536

37+
/** @var \DCarbone\PHPFHIR\Definition */
38+
private Definition $definition;
39+
3640
/**
3741
* BuildConfig constructor.
3842
* @param \DCarbone\PHPFHIR\Config $config
@@ -141,4 +145,15 @@ public function getVersion(): Version
141145
{
142146
return $this->version;
143147
}
148+
149+
/**
150+
* @return \DCarbone\PHPFHIR\Definition
151+
*/
152+
public function getDefinition(): Definition
153+
{
154+
if (!isset($this->definition)) {
155+
$this->definition = new Definition($this);
156+
}
157+
return $this->definition;;
158+
}
144159
}

src/Definition.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ class Definition
3535
private VersionConfig $config;
3636

3737
/** @var \DCarbone\PHPFHIR\Definition\Types|null */
38-
private ?Types $types = null;
38+
private null|Types $types = null;
39+
40+
/** @var \DCarbone\PHPFHIR\Builder */
41+
private Builder $builder;
3942

4043
/**
4144
* Definition constructor.
@@ -132,4 +135,15 @@ public function isDefined(): bool
132135
{
133136
return null !== $this->getTypes();
134137
}
138+
139+
/**
140+
* @return \DCarbone\PHPFHIR\Builder
141+
*/
142+
public function getBuilder(): Builder
143+
{
144+
if (!isset($this->builder)) {
145+
$this->builder = new Builder($this->getConfig(), $this);
146+
}
147+
return $this->builder;
148+
}
135149
}

src/Definition/Properties.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
use Countable;
2222
use DCarbone\PHPFHIR\Config\VersionConfig;
23+
use DCarbone\PHPFHIR\Enum\TypeKind;
2324
use InvalidArgumentException;
2425
use SplFixedArray;
2526

@@ -162,7 +163,7 @@ public function hasProperty(string $name): bool
162163
*/
163164
public function allPropertiesIterator(): iterable
164165
{
165-
return SplFixedArray::fromArray($this->properties, false);
166+
return SplFixedArray::fromArray($this->properties, preserveKeys: false);
166167
}
167168

168169
/**
@@ -173,7 +174,7 @@ public function allPropertiesIterator(): iterable
173174
public function allSortedPropertiesIterator(): iterable
174175
{
175176
$this->_buildLocalCaches();
176-
return SplFixedArray::fromArray($this->_sortedProperties, false);
177+
return SplFixedArray::fromArray($this->_sortedProperties, preserveKeys: false);
177178
}
178179

179180
/**
@@ -184,7 +185,7 @@ public function allSortedPropertiesIterator(): iterable
184185
public function localPropertiesIterator(): iterable
185186
{
186187
$this->_buildLocalCaches();
187-
return SplFixedArray::fromArray($this->_localProperties, false);
188+
return SplFixedArray::fromArray($this->_localProperties, preserveKeys: false);
188189
}
189190

190191
/**
@@ -195,7 +196,26 @@ public function localPropertiesIterator(): iterable
195196
public function localSortedPropertiesIterator(): iterable
196197
{
197198
$this->_buildLocalCaches();
198-
return SplFixedArray::fromArray($this->_localSortedProperties, false);
199+
return SplFixedArray::fromArray($this->_localSortedProperties, preserveKeys: false);
200+
}
201+
202+
/**
203+
* @param \DCarbone\PHPFHIR\Enum\TypeKind|null ...$kinds
204+
* @return \DCarbone\PHPFHIR\Definition\Property[]
205+
*/
206+
public function localPropertiesOfTypeKinds(bool $includeCollections, null|TypeKind... $kinds): iterable
207+
{
208+
$out = [];
209+
foreach ($this->localPropertiesIterator() as $property) {
210+
if (!$includeCollections && $property->isCollection()) {
211+
continue;
212+
}
213+
$pt = $property->getValueFHIRType();
214+
if (in_array($pt?->getKind(), $kinds, true)) {
215+
$out[] = $property;
216+
}
217+
}
218+
return SplFixedArray::fromArray($out, preserveKeys: false);
199219
}
200220

201221
/**

src/Definition/TypeImports.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ private function buildImports(): void
230230
$this->addImport(PHPFHIR_CLASSNAME_CONFIG, $configNS);
231231
$this->addImport(PHPFHIR_CLASSNAME_XML_WRITER, $configNS);
232232
$this->addImport(PHPFHIR_ENUM_CONFIG_KEY, $configNS);
233+
$this->addImport(PHPFHIR_ENUM_XML_LOCATION_ENUM, $configNS);
233234
}
234235

235236
// if this type is in a nested namespace, there are a few base interfaces, classes, and traits

template/core/classes/class_autoloader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@
9090
if (!enum_exists('<?php echo $config->getFullyQualifiedName(true, PHPFHIR_ENUM_API_FORMAT); ?>', false)) {
9191
require __DIR__ . DIRECTORY_SEPARATOR . '<?php echo PHPFHIR_ENUM_API_FORMAT; ?>.php';
9292
}
93+
if (!enum_exists('<?php echo $config->getFullyQualifiedName(true, PHPFHIR_ENUM_XML_LOCATION_ENUM); ?>', false)) {
94+
require __DIR__ . DIRECTORY_SEPARATOR . '<?php echo PHPFHIR_ENUM_XML_LOCATION_ENUM; ?>.php';
95+
}
96+
9397

9498
// parser classes
9599
if (!class_exists('<?php echo $config->getFullyQualifiedName(true, PHPFHIR_CLASSNAME_TYPEMAP); ?>', false)) {

template/core/classes/class_xml_writer.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ public function writeAttribute(string $name, string $value): bool
134134
&& $this->endAttribute();
135135
}
136136

137+
/**
138+
* Write a complete element with a text value
139+
*
140+
* @param string $name Element name
141+
* @param string $value Element text value
142+
* @return bool
143+
*/
144+
public function writeSimpleElement(string $name, string $value): bool
145+
{
146+
return $this->startElement($name)
147+
&& $this->text($value)
148+
&& $this->endElement();
149+
}
150+
137151
/**
138152
* @return bool
139153
*/

0 commit comments

Comments
 (0)