Skip to content

Commit 1124c16

Browse files
committed
chore: release 0.3.0
1 parent cdf6f08 commit 1124c16

9 files changed

Lines changed: 44 additions & 71 deletions

File tree

.phpbench/7ea/5/6/135269a570308183f5e3c64aad44f6d4eb810a43.xml

Lines changed: 2 additions & 0 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
## [0.3] - 2026-03-30
10+
## [0.3.0] - 2026-05-06
1111

1212
### Added
13-
- implement FHIR metadata cache warmer and configuration support
13+
- [IG Generation] `fhir:generate-ig` command for generating typed PHP classes from FHIR Implementation Guide StructureDefinitions
14+
- [IG Generation] `FHIRExtensionGenerator` for simple (single value type) and complex (sub-extension slices) typed extension classes
15+
- [IG Generation] `FHIRProfileGenerator` for profile subclasses with multi-level inheritance support
16+
- [IG Generation] `FHIRExtensionDefinition` and `FHIRProfile` metadata attributes for runtime introspection
17+
- [IG Generation] Transitive IG dependency package auto-loading into `BuilderContext` for cross-package type resolution
18+
- [IG Generation] FHIR R4B/R5 extension classes and FHIR R5 enums for various value sets
19+
- [IG Generation] Slice discriminator support
20+
- [Serialization] `FHIRIGTypeRegistry` for URL-to-class mapping of typed IG extension and profile subclasses
21+
- [Serialization] `FHIRIGRegistryCompilerPass` to scan the IG output directory and wire up the registry at compile time
22+
- [Serialization] `FHIRComplexExtensionInterface` with `fromSubExtensions()` factory for complex extension deserialization
23+
- [Serialization] `PropertyMetadataProvider` now walks the full class hierarchy so typed extension subclasses inherit `FhirProperty` metadata from parent classes
24+
- [Bundle] `fhir.ig.*` configuration keys (`namespace`, `output_directory`, `offline`, `packages`) in `config/packages/fhir.yaml`
25+
- [Bundle] FHIR metadata cache warmer with configurable `enable_cache_warmer` option
26+
- [Metadata] `FHIRExtensionInterface` providing a common `getExtensionUrl()` typing point across R4/R4B/R5
27+
- [Metadata] `FHIRExtensionsTrait` with lookup helpers: `findExtension`, `findExtensions`, `hasExtension`, `findExtensionByUrl`, `findExtensionsByUrl`
28+
- [FHIRPath] Benchmarks for FHIRPath evaluation and parsing
29+
- [Infrastructure] Deployment workflow and documentation for the demo app
30+
31+
### Changed
32+
- [Serialization] Null checks and type casting added for primitives
33+
- [Serialization] Extensions and normalizers updated for versioning and deprecation handling
34+
- [Docs] `fhir:generate-ig` command, IG bundle configuration, and component guides documented in README
1435

1536
### Fixed
16-
- standardize formatting and indentation across multiple PHP files
37+
- [IG Generation] Base constraint profiles (vitalsigns, bp, bodyheight, etc.) now generated so IG profiles that extend them resolve correctly
38+
- [IG Generation] Slice parameter names conflicting with parent `Extension` properties now suffixed with `Slice` to avoid PHP property invariance compile errors
39+
- [Serialization] Base extensions registered in `FHIRIGTypeRegistry` so deserializer uses typed subclasses instead of falling back to `Extension`
40+
- [Serialization] Complex extension deserialization now uses `fromSubExtensions()` to correctly populate typed promoted properties
41+
- [Serialization] PHPStan and PHPUnit notice issues in serialization layer
42+
- [Infrastructure] Dockerfile updated with zip extension for Composer dist downloads
43+
- [Infrastructure] Demo `composer.lock` constrained to PHP 8.3 compatible packages
44+
- [FHIRPath] PHPDoc type hints improved in `FHIRPathEvaluator`
1745

18-
[Unreleased]: https://github.com/Ardenexal/php-fhir-tools/compare/0.3...HEAD
19-
[0.3]: https://github.com/Ardenexal/php-fhir-tools/compare/0.2...0.3
46+
[Unreleased]: https://github.com/Ardenexal/FHIR-Structure-Definition-php-generator/compare/v0.3.0...HEAD
47+
[0.3.0]: https://github.com/Ardenexal/FHIR-Structure-Definition-php-generator/compare/0.2...v0.3.0
48+
[0.2]: https://github.com/Ardenexal/FHIR-Structure-Definition-php-generator/releases/tag/0.2

src/Bundle/FHIRBundle/src/DependencyInjection/Compiler/FHIRIGRegistryCompilerPass.php

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Ardenexal\FHIRTools\Component\Metadata\Attribute\FHIRProfile;
99
use Ardenexal\FHIRTools\Component\Metadata\Attribute\FHIRSliceDiscriminator;
1010
use Ardenexal\FHIRTools\Component\Serialization\FHIRIGTypeRegistry;
11+
use Ardenexal\FHIRTools\Component\Serialization\FHIRIGTypeRegistryFactory;
1112
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1213
use Symfony\Component\DependencyInjection\ContainerBuilder;
1314
use Symfony\Component\Finder\Finder;
@@ -34,21 +35,6 @@
3435
*/
3536
class FHIRIGRegistryCompilerPass implements CompilerPassInterface
3637
{
37-
/**
38-
* Known base FHIR versions and the sentinel DataType\Extension class used to locate
39-
* each version's Extension directory via reflection.
40-
*
41-
* The sentinel is the DataType\Extension class (not a namespace). Its file path is used
42-
* to compute the sibling Extension/ directory: DataType/Extension.php → ../Extension/.
43-
*
44-
* @var array<string, class-string>
45-
*/
46-
private const array BASE_VERSION_SENTINELS = [
47-
'R4' => 'Ardenexal\\FHIRTools\\Component\\Models\\R4\\DataType\\Extension',
48-
'R4B' => 'Ardenexal\\FHIRTools\\Component\\Models\\R4B\\DataType\\Extension',
49-
'R5' => 'Ardenexal\\FHIRTools\\Component\\Models\\R5\\DataType\\Extension',
50-
];
51-
5238
public function process(ContainerBuilder $container): void
5339
{
5440
if (!$container->hasDefinition(FHIRIGTypeRegistry::class)) {
@@ -71,7 +57,7 @@ public function process(ContainerBuilder $container): void
7157
// Base extension classes (e.g. PGenderIdentityExtension) live here and also
7258
// carry #[FHIRExtensionDefinition] attributes that must be registered so the
7359
// deserializer can resolve them to their typed classes.
74-
foreach ($this->resolveBaseExtensionDirectories() as $dir => $ns) {
60+
foreach (FHIRIGTypeRegistryFactory::resolveBaseExtensionDirectories() as $dir => $ns) {
7561
$this->scanDirectoryIntoMappings($dir, $ns, $extensionMappings, $profileMappings, $sliceDiscriminatorMappings);
7662
}
7763

@@ -90,11 +76,6 @@ public function process(ContainerBuilder $container): void
9076
* object instances. FHIRIGTypeRegistry hydrates them to SliceDiscriminator objects
9177
* in its constructor.
9278
*
93-
* @param array<string, class-string> $extensionMappings
94-
* @param array<string, class-string> $profileMappings
95-
* @param array<string, list<array{type: string, path: string, value: mixed, targetClass: class-string}>> $sliceDiscriminatorMappings
96-
*/
97-
/**
9879
* @param array<string, array<string, class-string>> $extensionMappings
9980
* @param array<string, class-string> $profileMappings
10081
* @param array<string, list<array{type: string, path: string, value: mixed, targetClass: class-string}>> $sliceDiscriminatorMappings
@@ -173,43 +154,4 @@ private function scanDirectoryIntoMappings(
173154
}
174155
}
175156
}
176-
177-
/**
178-
* Auto-detect base models Extension directories for each supported FHIR version.
179-
*
180-
* Uses reflection on known sentinel DataType\Extension classes to find their source
181-
* files, then resolves the sibling Extension/ directory. This works in both the
182-
* monorepo and consumer apps where the Models component is installed via Composer.
183-
*
184-
* @return array<string, string> directory path → namespace root
185-
*/
186-
private function resolveBaseExtensionDirectories(): array
187-
{
188-
$dirs = [];
189-
190-
foreach (self::BASE_VERSION_SENTINELS as $version => $sentinelClass) {
191-
if (!class_exists($sentinelClass)) {
192-
continue; // Models for this version not installed — skip.
193-
}
194-
195-
$sentinelFile = (new \ReflectionClass($sentinelClass))->getFileName();
196-
197-
if ($sentinelFile === false) {
198-
continue;
199-
}
200-
201-
// sentinel is in …/Models/src/{version}/DataType/Extension.php
202-
// Extension classes are in …/Models/src/{version}/Extension/
203-
$extensionDir = dirname(dirname($sentinelFile)) . DIRECTORY_SEPARATOR . 'Extension';
204-
205-
if (!is_dir($extensionDir)) {
206-
continue;
207-
}
208-
209-
$namespace = "Ardenexal\\FHIRTools\\Component\\Models\\{$version}\\Extension";
210-
$dirs[$extensionDir] = $namespace;
211-
}
212-
213-
return $dirs;
214-
}
215157
}

src/Component/Serialization/src/FHIRIGTypeRegistryFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private static function registerPsr4Autoloader(string $directory, string $namesp
172172
*
173173
* @return array<string, string> directory path → namespace root
174174
*/
175-
private static function resolveBaseExtensionDirectories(): array
175+
public static function resolveBaseExtensionDirectories(): array
176176
{
177177
$dirs = [];
178178

src/Component/Serialization/src/Normalizer/AbstractFHIRNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(
4444
protected readonly FHIRMetadataExtractorInterface $metadataExtractor,
4545
?NormalizerInterface $normalizer = null,
4646
?DenormalizerInterface $denormalizer = null,
47-
string $fhirVersion = 'R4B',
47+
string $fhirVersion = 'R4',
4848
protected ?FHIRIGTypeRegistry $igTypeRegistry = null,
4949
) {
5050
$this->normalizer = $normalizer;

src/Component/Serialization/src/Normalizer/FHIRBackboneElementNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function __construct(
2929
FHIRMetadataExtractorInterface $metadataExtractor,
3030
?NormalizerInterface $normalizer = null,
3131
?DenormalizerInterface $denormalizer = null,
32-
string $fhirVersion = 'R4B',
32+
string $fhirVersion = 'R4',
3333
?FHIRIGTypeRegistry $igTypeRegistry = null,
3434
) {
3535
parent::__construct($metadataExtractor, $normalizer, $denormalizer, $fhirVersion, $igTypeRegistry);

src/Component/Serialization/src/Normalizer/FHIRComplexTypeNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function __construct(
3535
private readonly FHIRTypeResolverInterface $typeResolver,
3636
?NormalizerInterface $normalizer = null,
3737
?DenormalizerInterface $denormalizer = null,
38-
string $fhirVersion = 'R4B',
38+
string $fhirVersion = 'R4',
3939
?FHIRIGTypeRegistry $igTypeRegistry = null,
4040
) {
4141
parent::__construct($metadataExtractor, $normalizer, $denormalizer, $fhirVersion, $igTypeRegistry);

src/Component/Serialization/src/Normalizer/FHIRPrimitiveTypeNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function __construct(
3434
FHIRMetadataExtractorInterface $metadataExtractor,
3535
?NormalizerInterface $normalizer = null,
3636
?DenormalizerInterface $denormalizer = null,
37-
string $fhirVersion = 'R4B',
37+
string $fhirVersion = 'R4',
3838
?FHIRIGTypeRegistry $igTypeRegistry = null,
3939
) {
4040
parent::__construct($metadataExtractor, $normalizer, $denormalizer, $fhirVersion, $igTypeRegistry);

src/Component/Serialization/src/Normalizer/FHIRResourceNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function __construct(
3232
private readonly FHIRTypeResolverInterface $typeResolver,
3333
?NormalizerInterface $normalizer = null,
3434
?DenormalizerInterface $denormalizer = null,
35-
string $fhirVersion = 'R4B',
35+
string $fhirVersion = 'R4',
3636
?FHIRIGTypeRegistry $igTypeRegistry = null,
3737
) {
3838
parent::__construct($metadataExtractor, $normalizer, $denormalizer, $fhirVersion, $igTypeRegistry);

0 commit comments

Comments
 (0)