Skip to content

Architecture

Daniel Carbone edited this page Apr 21, 2026 · 2 revisions

Architecture

This page describes how the php-fhir code-generation pipeline works, from configuration to rendered PHP files.

High-Level Flow

┌───────────────────────────────┐
│  Config (+ VersionConfig[])   │  ← user-supplied settings
└──────────────┬────────────────┘
               ▼
┌───────────────────────────────┐
│          Builder              │  orchestrates the whole process
└──────────────┬────────────────┘
               │
    ┌──────────┴──────────┐
    ▼                     ▼
 Core Files         Per-Version Pipeline
 (shared)           (repeated for each FHIR version)
    │                     │
    │         ┌───────────┼──────────────┐
    │         ▼           ▼              ▼
    │    Definition   Version Core   Type Classes
    │    (XSD parse)  Files          + Test Classes
    │
    └──► output/src   output/tests

Key Classes

Config

Namespace: DCarbone\PHPFHIR\Config

Holds all generation-time settings: output paths, namespace prefix, libxml options, and the list of Version objects. Created by the user (or via Config::fromArray()), then handed to Builder.

Config\VersionConfig

Pure data object carrying per-version settings (name, schemaPath, namespace, defaultConfig). Config wraps each one inside a full Version at construction time.

Version

Namespace: DCarbone\PHPFHIR\Version

Represents a single FHIR version within a generation run. Provides:

  • getDefinition() — lazy-loaded Definition (parses XSDs on first access).
  • getVersionCoreFiles() / getVersionTestCoreFiles()CoreFiles for this version.
  • getSourceMetadata() — FHIR copyright, generation date, and semantic version parsed from fhir-base.xsd.

Version\Definition

Parses a version's XSD schemas and builds a typed model of every FHIR type. The pipeline is:

  1. TypeExtractor::parseTypes() — walks each .xsd and creates raw Type instances.
  2. TypeDecorator (multiple passes) — resolves parent types, restriction bases, component-of relationships, primitive flags, contained-type flags, comment containers, per-version overrides, and import lists.
  3. TypePropertyDecorator — resolves property types, names, and overloaded properties.
  4. TypeDecorationValidator — performs sanity checks on the fully-decorated type graph.

The result is a Types collection accessible via Definition::getTypes().

Version\SourceMetadata

Parses the XML comment block at the top of fhir-base.xsd to extract:

  • The FHIR copyright notice.
  • The FHIR generation date.
  • The FHIR semantic version string (e.g. v4.0.1 or v6.0.0-ballot4).

During parsing the version string is split on the first -:

  • _fhirVersionBase — the clean vX.Y.Z portion, used for all Semver range comparisons.
  • _fhirPreRelease — the suffix after - (e.g. ballot4), or null for GA releases.

This separation is necessary because Composer Semver rejects non-standard pre-release identifiers such as ballot4; by stripping the suffix before calling Semver::satisfies() every range check works correctly regardless of whether the source is a ballot build or a GA release.

Public API:

Method Returns Description
getSemanticVersion(bool) string Full version string, optionally with v prefix stripped.
getShortVersion() string Major.Minor form of the base version (e.g. 6.0).
getVersionInteger() int Integer derived from the base version; pre-release and GA share the same int.
getPreRelease() null|string Pre-release identifier (e.g. ballot4), or null for GA.
isPreRelease() bool true when a pre-release suffix is present.
isDSTU1()isR5() bool Range checks against the base version.
isR6() bool true for >= v6.0.0, < v7.0.0 (catches ballot builds as well as GA).

Builder

Namespace: DCarbone\PHPFHIR\Builder

Orchestrates the entire render pipeline. Builder::render() calls, in order:

  1. writeLibraryCoreEntities() — shared interfaces, traits, enums, the FHIR client, encoding helpers, and validation framework.
  2. writeLibraryTestClasses() — shared test mock classes and core tests.
  3. writeFHIRVersionCoreEntities() — per-version Version, VersionConstants, VersionTypeMap, VersionClient, enums, and interfaces.
  4. writeFHIRVersionTypeClasses() — one PHP class per FHIR type (primitives, elements, resources, resource containers, XHTML).
  5. writeFHIRVersionTestClasses() — per-version test core files.
  6. writeFHIRVersionTypeTestClasses() — one test class per non-abstract FHIR type.

CoreFiles / CoreFile

A CoreFiles instance scans a template directory, pairs each template with an output path and namespace, and wraps them in CoreFile objects. Each CoreFile knows:

  • its template source path,
  • its entity type (class, interface, trait, enum, test, exception),
  • its output filepath,
  • its fully-qualified namespace and class name,
  • its Imports (use-statements).

Render\Templates

Static methods that require a template file and return the rendered PHP string. Templates are plain PHP files that return a string; they receive contextual variables ($config, $version, $type, $coreFile) via extract().


Template Layout

Templates live under the template/ directory:

template/
├── core/                       ← shared core entities
│   ├── class_autoloader.php
│   ├── class_constants.php
│   ├── class_fhir_version.php
│   ├── client/                 ← FHIR REST client
│   ├── encoding/               ← (Un)serialize config, XML writer, resource parser
│   ├── types/                  ← Core interfaces & traits (TypeInterface, etc.)
│   ├── validation/             ← Validator, rules, traits
│   └── versions/               ← VersionConfig, VersionInterface, VersionTypeMapInterface
├── versions/
│   ├── core/                   ← Per-version core (Version, VersionConstants, VersionTypeMap, …)
│   └── types/                  ← Per-type class templates
│       ├── class_default.php
│       ├── class_primitive.php
│       ├── class_resource_container.php
│       ├── class_xhtml.php
│       ├── methods/            ← Getter/setter method fragments
│       ├── primitives/         ← Primitive-specific helpers
│       ├── properties/         ← Property declaration fragments
│       └── serialization/      ← JSON & XML (de)serialization fragments
└── tests/
    ├── core/                   ← Shared test templates (mocks, etc.)
    └── versions/
        ├── core/               ← Per-version test core templates
        └── types/              ← Per-type test class template

Template filenames follow the convention <entity-type>_<name>.php:

Prefix Generated entity
class_ Class
interface_ Interface
trait_ Trait
enum_ Enum
exception_ Exception class
test_ PHPUnit test class

Enum Reference (Generator-Side)

These enums drive decisions during type decoration and rendering:

Enum Purpose
TypeKindEnum Classifies each FHIR type (Primitive, Element, Resource, ResourceContainer, etc.)
PrimitiveTypeEnum Maps FHIR primitive names to PHP scalar types
PropertyUseEnum Indicates how a property is used (required, optional, prohibited)
AttributeNameEnum Standard XSD attribute names encountered during parsing
ElementNameEnum Standard XSD element names encountered during parsing

Next: Generated Code →

Clone this wiki locally