From 964836c2230a26a9b5bdc4d7e970717af9bbbbbb Mon Sep 17 00:00:00 2001 From: "Luis M. Santos" Date: Fri, 27 Mar 2026 11:25:16 -0400 Subject: [PATCH 1/3] feature(docker) Added OPENEMR_GIT arg in Dockerfile to allow pulling from test forks if specified otherwise pull from OpenEMR's repo. Signed-off-by: Luis M. Santos --- docker/openemr/8.0.1/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/openemr/8.0.1/Dockerfile b/docker/openemr/8.0.1/Dockerfile index 55c5c21f..6d19f170 100644 --- a/docker/openemr/8.0.1/Dockerfile +++ b/docker/openemr/8.0.1/Dockerfile @@ -156,8 +156,9 @@ RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin - # - Branch: --build-arg OPENEMR_VERSION=master # - Tag: --build-arg OPENEMR_VERSION=v7.0.5 ARG OPENEMR_VERSION=master +ARG OPENEMR_GIT=https://github.com/openemr/openemr.git FROM base AS openemr-source -RUN git clone https://github.com/openemr/openemr.git --branch "${OPENEMR_VERSION}" --depth 1 \ +RUN git clone "${OPENEMR_GIT}" --branch "${OPENEMR_VERSION}" --depth 1 \ && rm -rf openemr/.git # Stage 2: Install PHP dependencies (Composer) From 188c2d20a68b991d90bf33c0c77033c923fc642a Mon Sep 17 00:00:00 2001 From: "Luis M. Santos" Date: Fri, 27 Mar 2026 11:39:08 -0400 Subject: [PATCH 2/3] chore(readme) Added OPENEMR_GIT to README Signed-off-by: Luis M. Santos --- docker/openemr/binary/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker/openemr/binary/README.md b/docker/openemr/binary/README.md index 57a8c9b6..7f100fa6 100644 --- a/docker/openemr/binary/README.md +++ b/docker/openemr/binary/README.md @@ -25,6 +25,7 @@ docker build -t openemr-binary:latest . ### Build Arguments - `OPENEMR_VERSION`: OpenEMR version (default: `7_0_4`) +- `OPENEMR_GIT`: OpenEMR git repository to build from (default: `https://github.com/openemr/openemr.git`) - `BINARY_RELEASE_DATE`: Release date for binary package (default: `12282025`) - `PHP_VERSION`: PHP version used in binaries (default: `8.5`) - `ALPINE_VERSION`: Alpine Linux version (default: `3.22`) @@ -37,6 +38,14 @@ docker build \ -t openemr-binary:latest . ``` +```bash +docker build \ + --build-arg OPENEMR_GIT=https://github.com/myuser/openemr.git \ + --build-arg OPENEMR_VERSION=7_0_4 \ + --build-arg BINARY_RELEASE_DATE=12292025 \ + -t openemr-binary:latest . +``` + ## Usage ### Basic Usage with docker-compose From ad77857ce723b147347530cfbd0d9466d52b2b19 Mon Sep 17 00:00:00 2001 From: "Luis M. Santos" Date: Thu, 2 Apr 2026 20:11:49 -0400 Subject: [PATCH 3/3] feature(auto-import-codes) Added script for automatically importing any code databases available at target directory. The default directory is the contrib directory. Signed-off-by: Luis M. Santos --- docker/openemr/8.0.1/auto_import_codes.php | 120 +++++++++++++++++++++ docker/openemr/flex/auto_import_codes.php | 120 +++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 docker/openemr/8.0.1/auto_import_codes.php create mode 100644 docker/openemr/flex/auto_import_codes.php diff --git a/docker/openemr/8.0.1/auto_import_codes.php b/docker/openemr/8.0.1/auto_import_codes.php new file mode 100644 index 00000000..ee9059d6 --- /dev/null +++ b/docker/openemr/8.0.1/auto_import_codes.php @@ -0,0 +1,120 @@ +#!/usr/bin/env php + + * @copyright Copyright (c) 2026 Luis M. Santos, MD + * @copyright Copyright (c) 2026 MedicalMasses L.L.C. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + */ +$sitePath = '/var/www/localhost/htdocs/openemr'; +$_GET['site'] = 'default'; +$ignoreAuth = true; +$sessionAllowWrite = true; +chdir($sitePath); + +// Load OpenEMR's Composer autoloader +// This gives us access to all OpenEMR classes, including the Installer class +require_once 'interface/globals.php'; +require_once 'library/standard_tables_capture.inc.php'; + +function import_dir(string $type, $importFunction): void { + foreach (glob("*.zip") as $file) { + # Copy to temp + echo " [" . $type . "] Copying file => " . $file . "!\n"; + if (!temp_copy($file, $type)) { + error_log("Failed to copy " . $file . " of type " . $type); + return; + } + + # Unpack + echo " [" . $type . "] Uncompressing file => " . $file . "!\n"; + if (!temp_unarchive($file, $type)) { + error_log("Failed to unzip " . $file . " of type " . $type); + } + + # Import data + echo " [" . $type . "] Importing file => " . $file . "!\n"; + $importFunction($type); + + # Cleanup + echo " [" . $type . "] Cleaning up import for file => " . $file . "!\n"; + temp_dir_cleanup($type); + } +} + +function import_snomed(string $path): void { + // TODO: Consider including auto detection in OpenEMR at a later date. + try { + snomedRF2_import(); + } catch (Exception $e) { + try { + snomed_import(true); + } catch (Exception $e) { + snomed_import(); + } + } +} + +function import(string $path): void { + # Change to import directory + chdir($path); + + # Scan directory + $dirs = scandir('./'); + echo "Available directories => ". $dirs . "\n"; + foreach ($dirs as $dir) { + if ($dir == "." || $dir == "..") { + continue; + } + + if(is_dir($dir)) { + # Go into directory + echo "Entering directory => ". $dir . "\n"; + chdir($dir); + + match ($dir) { + "icd9" => import_dir("ICD9", function ($type) {icd_import($type);}), + "icd10" => import_dir("ICD10", function ($type) {icd_import($type);}), + "rxnorm" => import_dir("RXNORM", function () {rxnorm_import(false);}), + "snomed" => import_dir("SNOMED", function ($file) {import_snomed($file);}), + "cqm", "cqm_valueset" => import_dir("CQM_VALUESET", function ($type) {valueset_import($type);}), + default => import_dir("VALUESET", function ($type) {valueset_import($type);}), + }; + + # Restore parent path for the next iteration + echo "Exiting directory => ". $dir . " back to ". $path . "\n"; + chdir($path); + } + } +} + +// Ensure we're running from CLI +if (php_sapi_name() !== 'cli') { + throw RuntimeException('This tool can only be run from the command line'); +} + +$contribPath = realpath($sitePath . '/contrib'); +if ($argc > 1) { + if (strlen($argv[1])) { + $contribPath = realpath($argv[1]); + } +} + +import($contribPath); diff --git a/docker/openemr/flex/auto_import_codes.php b/docker/openemr/flex/auto_import_codes.php new file mode 100644 index 00000000..ee9059d6 --- /dev/null +++ b/docker/openemr/flex/auto_import_codes.php @@ -0,0 +1,120 @@ +#!/usr/bin/env php + + * @copyright Copyright (c) 2026 Luis M. Santos, MD + * @copyright Copyright (c) 2026 MedicalMasses L.L.C. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + */ +$sitePath = '/var/www/localhost/htdocs/openemr'; +$_GET['site'] = 'default'; +$ignoreAuth = true; +$sessionAllowWrite = true; +chdir($sitePath); + +// Load OpenEMR's Composer autoloader +// This gives us access to all OpenEMR classes, including the Installer class +require_once 'interface/globals.php'; +require_once 'library/standard_tables_capture.inc.php'; + +function import_dir(string $type, $importFunction): void { + foreach (glob("*.zip") as $file) { + # Copy to temp + echo " [" . $type . "] Copying file => " . $file . "!\n"; + if (!temp_copy($file, $type)) { + error_log("Failed to copy " . $file . " of type " . $type); + return; + } + + # Unpack + echo " [" . $type . "] Uncompressing file => " . $file . "!\n"; + if (!temp_unarchive($file, $type)) { + error_log("Failed to unzip " . $file . " of type " . $type); + } + + # Import data + echo " [" . $type . "] Importing file => " . $file . "!\n"; + $importFunction($type); + + # Cleanup + echo " [" . $type . "] Cleaning up import for file => " . $file . "!\n"; + temp_dir_cleanup($type); + } +} + +function import_snomed(string $path): void { + // TODO: Consider including auto detection in OpenEMR at a later date. + try { + snomedRF2_import(); + } catch (Exception $e) { + try { + snomed_import(true); + } catch (Exception $e) { + snomed_import(); + } + } +} + +function import(string $path): void { + # Change to import directory + chdir($path); + + # Scan directory + $dirs = scandir('./'); + echo "Available directories => ". $dirs . "\n"; + foreach ($dirs as $dir) { + if ($dir == "." || $dir == "..") { + continue; + } + + if(is_dir($dir)) { + # Go into directory + echo "Entering directory => ". $dir . "\n"; + chdir($dir); + + match ($dir) { + "icd9" => import_dir("ICD9", function ($type) {icd_import($type);}), + "icd10" => import_dir("ICD10", function ($type) {icd_import($type);}), + "rxnorm" => import_dir("RXNORM", function () {rxnorm_import(false);}), + "snomed" => import_dir("SNOMED", function ($file) {import_snomed($file);}), + "cqm", "cqm_valueset" => import_dir("CQM_VALUESET", function ($type) {valueset_import($type);}), + default => import_dir("VALUESET", function ($type) {valueset_import($type);}), + }; + + # Restore parent path for the next iteration + echo "Exiting directory => ". $dir . " back to ". $path . "\n"; + chdir($path); + } + } +} + +// Ensure we're running from CLI +if (php_sapi_name() !== 'cli') { + throw RuntimeException('This tool can only be run from the command line'); +} + +$contribPath = realpath($sitePath . '/contrib'); +if ($argc > 1) { + if (strlen($argv[1])) { + $contribPath = realpath($argv[1]); + } +} + +import($contribPath);