Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [SDC] `$extract` supports version-agnostic definition/template extraction (R4/R4B/R5), `extractAllocateId` cross-resource references, fixed-value + FHIRPath calculated values, and choice slices; observation-based extraction is R4-only (non-R4 runs warn and skip)
- [SDC] `$extract` output is always a `transaction` Bundle — `entry.request` is `POST Type` (no id) or `PUT Type/id` (id present), create/update only; mixed-method Questionnaires merge into one Bundle; empty extraction yields an empty Bundle plus an `information` `OperationOutcome`, and a malformed expression warns and skips that entry
- [SDC] Opt-in `Provenance` generation via `ExtractContext(emitProvenance: true)`: when resources are extracted, the Bundle gains a `Provenance` entry targeting them and referencing the source `QuestionnaireResponse` (default output omits it)
- [SDC] `FHIRQuestionnairePopulateService::populate($questionnaire, new PopulateContext(...))` implements `Questionnaire/$populate`, returning a `PopulateResult` (generated `QuestionnaireResponse` + optional companion `OperationOutcome`); version-agnostic (R4/R4B/R5) and offline-first — the caller supplies launch-context resources up front, bound as FHIRPath external constants (`%patient`, …)
- [SDC] `$populate` supports expression-based population (`launchContext` + `initialExpression`, root/item `variable` chains, and `itemPopulationContext` repeating groups) and observation-based population (`observationLinkPeriod`, via a `PopulationDataProviderInterface`), with canonical-URL `Questionnaire` resolution through an optional `FHIRQuestionnaireResolverInterface`
- [Metadata] New `SafeExtensionReader` for tolerant extension traversal (`url`, `value[x]`, nested `extension[]`, find-by-url) that degrades to absent instead of throwing on constructor-bypassed (deserialized) objects
- [FHIRPath] `EvaluationContext::withResourceNode()`/`getResourceNode()` bind `%resource`/`%rootResource` to a resource distinct from the evaluation focus

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ wires everything for you.
<td><a href="fhirpath/overview.md">FHIRPath</a></td>
</tr>
<tr>
<td>SDC — extract resources from a QuestionnaireResponse (<code>$extract</code>)</td>
<td>SDC — populate (<code>$populate</code>) and extract (<code>$extract</code>) QuestionnaireResponse resources</td>
Comment thread
Copilot marked this conversation as resolved.
Outdated
<td><code>ardenexal/fhir-sdc</code></td>
<td><a href="sdc/overview.md">SDC</a></td>
</tr>
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This is a library monorepo. Each component is published as a standalone Composer
| `ardenexal/fhir-serialization` | Read/write FHIR JSON or XML |
| `ardenexal/fhir-validation` | Validate resources against base and profile constraints |
| `ardenexal/fhir-path` | Evaluate FHIRPath 2.0 expressions |
| `ardenexal/fhir-sdc` | Run SDC `$extract` — turn a completed `QuestionnaireResponse` into a transaction Bundle of FHIR resources |
| `ardenexal/fhir-sdc` | Run SDC `$populate` (pre-fill a `QuestionnaireResponse` from launch context) and `$extract` (turn a completed `QuestionnaireResponse` into a transaction Bundle of FHIR resources) |
| `ardenexal/fhir-models` | Use the pre-generated R4 / R4B / R5 model classes |
| `ardenexal/fhir-metadata` | Shared FHIR attributes and interfaces (a dependency of the others) |

Expand Down
41 changes: 35 additions & 6 deletions docs/sdc/overview.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
---
description: Extract FHIR resources from a completed QuestionnaireResponse.
description: Populate and extract FHIR resources for SDC Questionnaires.
Comment thread
Copilot marked this conversation as resolved.
Outdated
icon: file-export
---

# Overview

The SDC component implements [Structured Data Capture](https://build.fhir.org/ig/HL7/sdc/)
operations for FHIR PHP model objects. Today it delivers
operations for FHIR PHP model objects. Today it delivers two operations:
`QuestionnaireResponse/$extract` — turning a completed `QuestionnaireResponse` into FHIR
resources per the [SDC extraction operation](https://build.fhir.org/ig/HL7/sdc/en/extraction.html).
resources per the [SDC extraction operation](https://build.fhir.org/ig/HL7/sdc/en/extraction.html) —
and `Questionnaire/$populate` — pre-filling a `QuestionnaireResponse` from launch context per the
[SDC populate operation](https://build.fhir.org/ig/HL7/sdc/en/populate.html).
It supports R4, R4B, and R5.

## Quick start
## `$extract` quick start

```php
use Ardenexal\FHIRTools\Component\Sdc\ExtractContext;
Expand All @@ -30,6 +32,27 @@ $bundle = $result->getResource(); // a transaction Bundle (always)
$issues = $result->getIssues(); // an OperationOutcome, or null when nothing to report
```

## `$populate` quick start

```php
use Ardenexal\FHIRTools\Component\Sdc\BundlePopulationDataProvider;
use Ardenexal\FHIRTools\Component\Sdc\FHIRQuestionnairePopulateService;
use Ardenexal\FHIRTools\Component\Sdc\PopulateContext;
use Ardenexal\FHIRTools\Component\Serialization\FhirVersion;

$service = new FHIRQuestionnairePopulateService();

$result = $service->populate($questionnaire, new PopulateContext(
fhirVersion: FhirVersion::R4, // output model namespace (R4 / R4B / R5)
launchContextResources: ['patient' => $patient], // bound as FHIRPath %patient, …
subject: 'Patient/123', // sets QuestionnaireResponse.subject (optional)
dataProvider: new BundlePopulationDataProvider($dataBundle), // observation-based (optional)
));

$response = $result->getResponse(); // a QuestionnaireResponse (status: in-progress)
$issues = $result->getIssues(); // an OperationOutcome, or null when nothing to report
```

## What it does

* **Three extraction methods** — observation-based (R4 only), definition-based
Expand All @@ -44,8 +67,14 @@ $issues = $result->getIssues(); // an OperationOutcome, or null when nothing t
* **Opt-in `Provenance`** — pass `emitProvenance: true` to add a `Provenance` entry linking
the extracted resources back to the source `QuestionnaireResponse`.

`Questionnaire/$populate` is scaffolded (conformance harness in place) but has no public API
yet.
`Questionnaire/$populate` pre-fills a `QuestionnaireResponse` from a `Questionnaire`'s SDC
population directives — expression-based (`launchContext` + `initialExpression`, `variable`
chains, `itemPopulationContext`) and observation-based (`observationLinkPeriod`). Call
`FHIRQuestionnairePopulateService::populate($questionnaire, new PopulateContext(...))`; the
returned `PopulateResult` carries the generated `QuestionnaireResponse` (status
`in-progress`) plus an optional `OperationOutcome`. Population is offline-first and
FHIRPath-only — the component README is canonical for the supported-mechanisms table and
exclusions.

## Reference

Expand Down
Loading