Installation
composer require ardenexal/fhir-metadata
Ensure your composer.json targets PHP 8.1+ and Laravel 10+.
First Use Case: Define a FHIR Resource
use Ardenexal\FhirMetadata\Interfaces\FhirResourceInterface;
class Patient implements FhirResourceInterface {
public function getResourceType(): string { return 'Patient'; }
public function getId(): ?string { return $this->id; }
}
FhirResourceInterface to leverage shared validation and utilities.Where to Look First
Interfaces/FhirResourceInterface.php (core contract).Traits/HasId.php, Traits/HasMeta.php (shared logic).Utilities/FhirValidator.php, Utilities/FhirSerializer.php (helpers).Pattern: Use traits to standardize FHIR resources.
use Ardenexal\FhirMetadata\Traits\{HasId, HasMeta, HasExtension};
class Observation implements FhirResourceInterface {
use HasId, HasMeta, HasExtension;
public string $status;
public array $code;
}
id, meta, extension).Pattern: Validate resources before serialization.
use Ardenexal\FhirMetadata\Utilities\FhirValidator;
$validator = new FhirValidator();
$errors = $validator->validate($patient);
if ($errors) {
throw new \InvalidArgumentException("FHIR validation failed: " . implode(', ', $errors));
}
use Illuminate\Validation\Rule;
Rule::make(function ($attribute, $value, $fail) {
$validator = new FhirValidator();
$errors = $validator->validate($value);
if ($errors) $fail(__('FHIR validation failed'));
});
Pattern: Standardize FHIR JSON responses.
use Ardenexal\FhirMetadata\Utilities\FhirSerializer;
$serializer = new FhirSerializer();
return response()->json($serializer->serialize($resource));
JsonResource to include FHIR metadata:
public function toArray($request) {
return [
'data' => (new FhirSerializer())->serialize($this->resource),
'meta' => $this->resource->getMeta(),
];
}
Pattern: Store FHIR resources as JSON or normalize critical fields.
// Option 1: JSON Column
protected $casts = ['fhir_data' => 'array'];
// Option 2: Normalized Fields
protected $fillable = ['id', 'resource_type', 'status', 'code'];
json casting for dynamic FHIR attributes.Pattern: Transform incoming FHIR payloads.
namespace App\Http\Middleware;
use Ardenexal\FhirMetadata\Utilities\FhirDeserializer;
use Closure;
class ParseFhirPayload {
public function handle($request, Closure $next) {
$deserializer = new FhirDeserializer();
$request->merge(['fhir_resource' => $deserializer->deserialize($request->getContent())]);
return $next($request);
}
}
app/Http/Kernel.php for FHIR endpoints.Undocumented Interfaces
FhirResourceInterface may lack PHPDoc or examples.src/Interfaces/ and test with minimal implementations:
class TestResource implements FhirResourceInterface {
public function getResourceType(): string { return 'Test'; }
public function getId(): ?string { return null; }
}
FHIR Version Mismatches
Utilities/ and validate against a FHIR validator (e.g., fhir-validator).Performance with Large Resources
Composition) may cause memory issues during serialization.StreamedResponse:
return response()->stream(function () {
echo (new FhirSerializer())->serialize($resource);
});
Trait Conflicts
HasId may conflict with Laravel’s HasUuids or HasFactory.use Ardenexal\FhirMetadata\Traits\HasId as FhirHasId;
FhirValidator in unit tests to catch schema issues:
public function testPatientValidation() {
$patient = new Patient(['id' => '1', 'name' => []]); // Missing required 'name'
$this->assertTrue($validator->validate($patient)->has('name'));
}
\Log::debug('FHIR Request', ['payload' => $request->getContent()]);
php artisan tinker
>>> $resource = new Patient(['id' => '1']);
>>> $resource->getMeta()
laravel-debugbar to display FHIR metadata.Custom Validation Rules
FhirValidator to add domain-specific rules:
class CustomFhirValidator extends FhirValidator {
protected function rules(): array {
return array_merge(parent::rules(), [
'Patient.name' => ['required', 'array', 'min:1'],
]);
}
}
New Resource Types
abstract class BaseFhirResource implements FhirResourceInterface {
use HasId, HasMeta;
abstract public function getResourceType(): string;
}
Integration with FHIR Servers
class FhirServerClient {
public function fetchResource(string $type, string $id) {
$response = Http::get("https://fhir-server/fhir/$type/$id");
return (new FhirDeserializer())->deserialize($response->body());
}
}
$this->app->singleton(FhirValidator::class, function ($app) {
return new FhirValidator(config('fhir.validation_rules'));
});
$validator = new FhirValidator();
$validator->setProfile('http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient');
FhirResourceInterface to test utilities:
$mockResource = $this->createMock(FhirResourceInterface::class);
$mockResource->method('getResourceType')->willReturn('Patient');
$mockResource->method('getId')->willReturn('123');
$response = $this->postJson('/fhir/Patient', $validPatientJson);
$response->assertStatus(201);
$this->assertFhirValid($response->json());
public function assertFhirValid(array $json) {
$validator = new FhirValidator();
$resource = (new FhirDeserializer())->deserialize(json_encode($json));
$this->assertEmpty($validator->validate($resource));
}
How can I help you explore Laravel packages today?