diff --git a/README.md b/README.md index 2ccbf4ac..a6da378d 100644 --- a/README.md +++ b/README.md @@ -4,108 +4,9 @@ Tools for creating PHP classes from the HL7 FHIR Specification If you're looking to use the classes generated by this library, you may want the [php-fhir-generated](https://github.com/dcarbone/php-fhir-generated) repo instead. - -* [php-fhir](#php-fhir) -* [Install as Standalone Generator](#install-as-standalone-generator) -* [Install as Library](#install-as-library) -* [Version Table](#version-table) -* [Basic Usage](#basic-usage) - * [Class Generation](#class-generation) - * [Generation Example](#generation-example) - * [Data Querying](#data-querying) - * [Response Parsing](#response-parsing) - * [Parsing Example](#parsing-example) -* [Serialization](#serialization) - * [JSON Serialization](#json-serialization) - * [XML Serialization](#xml-serialization) -* [Testing](#testing) - * [TODO](#todo) - * [Suggestions and help](#suggestions-and-help) - - -# Install as Standalone Generator -If you wish to use this package as a standalone generator: - -1. Check out the desired branch or tag -2. Execute `composer install` from root of project directory -3. Execute `./bin/generate.sh` -4. Answer all prompts - * If no custom configuration file is defined, definitions will be downloaded to `./input` and -classes will be generated under `./output` - * You can execute `./bin/generate.sh --help` for details on how to utilize this script - * You can configure various aspects of this script by altering the values in [./bin/config.php](./bin/config.php) - -This script will download configured major versions of FHIR into the `input` folder and -generate classes for every version in the `output` folder. - -# Install as Library -If you wish to use the generator as part of a project, you can include it as a composer -dependency: - -```shell -composer require dcarbone/php-fhir -``` - -From there, you can reference the [Example](#generation-example) block for a quick example on how to -configure and execute the generator. - -# Version Table - -| PHPFHIR Version | PHP Versions | FHIR Versions | -|-----------------|--------------|----------------------------------| -| v2 | 5.4-7.4 | DSTU1, DSTU2, STU3, R4 (setVersionsToGenerate(['DSTU2', 'STU3']); - -// next, iterate through all configured versions and render code: -foreach ($config->getVersionsIterator() as $versionConfig) { - $versionConfig->getDefinition()->getBuilder()->render(); -} -``` - -## Data Querying - -Currently only a very simple client intended for debugging use is generated. A future goal is to generate a more -fully-featured client. - -## Response Parsing - -As part of the class generation above, a response parsing class called `PHPFHIRResponseParser` will be created -and added into the root namespace directory. It currently supports JSON and XML response types. +# Documentation -The parser class takes a single optional boolean argument that will determine if it should -attempt to load up the generated Autoloader class. By default it will do so, but you are free to configure your -own autoloader and not use the generated one if you wish. +Please refer to our wiki for the latest documentation: https://github.com/dcarbone/php-fhir/wiki ## Parsing Example diff --git a/src/Version/DefaultConfig.php b/src/Version/DefaultConfig.php index ff5ff377..24b72799 100644 --- a/src/Version/DefaultConfig.php +++ b/src/Version/DefaultConfig.php @@ -57,13 +57,28 @@ public function setUnserializeConfig(array $config): self if ([] === $config) { return $this; } - if (isset($config['libxmlOpts']) && isset($config['libxmlOptMask'])) { + if (array_key_exists('libxmlOpts', $config) && array_key_exists('libxmlOptMask', $config)) { throw new \DomainException('Cannot specify both "libxmlOpts" and "libxmlOptMask" keys.'); } foreach (self::_UNSERIALIZE_CONFIG_KEYS as $k) { - if (isset($config[$k]) || array_key_exists($k, $config)) { - $this->_unserializeConfig[$k] = $config[$k]; + if (!array_key_exists($k, $config)) { + continue; } + $this->_unserializeConfig[$k] = match ($k) { + 'libxmlOpts' => intval($config[$k]), + 'libxmlOptMask' => is_string($config[$k]) && preg_match('{^[A-Z0-9_\s|]+}$}', $config[$k]) + ? $config[$k] + : throw new \InvalidArgumentException(sprintf( + 'Value provided to "libxmlOptMask" is either not a string or is an invalid options mask: %s', + $config[$k], + )), + 'jsonDecodeMaxDepth' => intval($config[$k]), + + default => throw new \UnexpectedValueException(sprintf( + 'Unknown unserialize config key "%s"', + $k, + )) + }; } return $this; } @@ -87,8 +102,22 @@ public function setSerializeConfig(array $config): self return $this; } foreach (self::_SERIALIZE_CONFIG_KEYS as $k) { - if (isset($config[$k]) || array_key_exists($k, $config)) { - $this->_serializeConfig[$k] = $config[$k]; + if (!array_key_exists($k, $config)) { + continue; + } + $this->_serializeConfig[$k] = match ($k) { + 'overrideSourceXMLNS' => (bool)$config[$k], + 'rootXMLNS' => null === $config[$k] ? null : (string)$config[$k], + + default => throw new \UnexpectedValueException(sprintf( + 'Unknown serialize config key "%s"', + $k, + )) + }; + if ($this->_serializeConfig['overrideSourceXMLNS'] ?? false) { + if (!isset($this->_serializeConfig['rootXMLNS']) || '' === $this->_serializeConfig['rootXMLNS']) { + throw new \DomainException('Must specify rootXMLNS if overrideSourceXMLNS is true'); + } } } return $this; diff --git a/template/core/class_autoloader.php b/template/core/class_autoloader.php index 0329ccda..cb85ee14 100644 --- a/template/core/class_autoloader.php +++ b/template/core/class_autoloader.php @@ -36,6 +36,19 @@ abstract class { private const _ROOT_NAMESPACE = 'getFullyQualifiedName(false); ?>\\'; + private const _VERSION_AUTOLOADER_MAP = [ +getVersionsIterator() as $i => $version): ?> + => [ + 'getFullyQualifiedName(false); ?>\\', + 'getFullyQualifiedName(false, PHPFHIR_CLASSNAME_AUTOLOADER); ?>', + getFullyQualifiedName(false), + $version->getFullyQualifiedName(false, PHPFHIR_CLASSNAME_AUTOLOADER), + ); ?>, + ], + + ]; + private const _CORE_CLASS_MAP = [ // core types getCoreFiles()->getIterator() as $coreFile): if ($coreFile->isAutoloader() || $coreFile->isTest()) { continue; } ?> @@ -47,10 +60,16 @@ abstract class private static bool $_registered = false; + private static array $_versionRegistered = [ +getVersionsIterator() as $i => $version) : ?> + => false, + + ]; + public static function register(): bool { if (!self::$_registered) { - self::$_registered = spl_autoload_register(__CLASS__ . '::loadClass', true); + self::$_registered = spl_autoload_register(__CLASS__ . '::loadClass'); } return self::$_registered; } @@ -72,22 +91,18 @@ public static function loadClass(string $class): null|bool return (bool)require self::_CORE_CLASS_MAP[$class]; } else if (!str_starts_with($class, self::_ROOT_NAMESPACE)) { return null; - }getVersionsIterator() as $version): ?> else if (str_starts_with($class, 'getFullyQualifiedName(false); ?>\\')) { - if (!class_exists('getFullyQualifiedName(true, PHPFHIR_CLASSNAME_AUTOLOADER); ?>', false)) { - if (((bool)require getFullyQualifiedName(false), - $version->getFullyQualifiedName(false, PHPFHIR_CLASSNAME_AUTOLOADER), - ); ?>) && getFullyQualifiedName(true, PHPFHIR_CLASSNAME_AUTOLOADER); ?>::register()) { - if ($class !== 'getFullyQualifiedName(false, PHPFHIR_CLASSNAME_AUTOLOADER); ?>') { - return getFullyQualifiedName(true, PHPFHIR_CLASSNAME_AUTOLOADER); ?>::loadClass($class); - } else { - return true; - } - } else { - return false; - } + }getVersionsIterator() as $i => $version): ?> else if (str_starts_with($class, self::_VERSION_AUTOLOADER_MAP[][0])) { + if (self::$_versionRegistered[]) { + return null; + } + require self::_VERSION_AUTOLOADER_MAP[][2]; + getFullyQualifiedName(true, PHPFHIR_CLASSNAME_AUTOLOADER); ?>::register(); + self::$_versionRegistered[] = true; + if ($class !== self::_VERSION_AUTOLOADER_MAP[][1]) { + return getFullyQualifiedName(true, PHPFHIR_CLASSNAME_AUTOLOADER); ?>::loadClass($class); + } else { + return true; } - return null; } else { return null; }