Demographic Improvement Project - Multiple Addresses


I am sponsoring a series of projects to improve the demographic section of OpenEMR.

The long-term goal of what I would like to do is outlined in the following post:

My intermediate goal is to normalize database tables to allow one-to-many relationships of contact information.

This will allow multiple entries for different types of contact information:
Telephone Numbers
Email Addresses
Secondary Contacts

It will also more easily allow tracking of old contact information.

My first project is to add the ability to store multiple addresses.

I have created this forum to not only describe the project, but also for us to get guidance & feedback in regards to implementation, application architecture, and general programming approach.


Based upon discussion with Brady Miller, Stephen Nielson, and Jerry Padgett during the weekly conference calls, the following is an outline of the steps of this project:

Add Line & Data type to Layout Editor
Location: Administrator → Forms → Layouts
Edit layout: Core - Demographics
Add Field: “Addresses”

Create Tables
Create table to store addresses.
Table to have one-to-many relationship with patient_data
File Locations:

  • sql/6_0_0-to-6_1_0_upgrade.sql
  • sql/database.sql

Create Code To Display & Save the Address Table
Create Data type for multiple addresses.

Create code that displays from and saves information to the address table.
Location of code:

  • /library/
  • /library/options.js.php
  • /interface/patient_file/summary/demographics_full.php
  • /interface/patient_file/summary/demographics_save.php

Existing Code that Creates Similar Data types:
(1) Commit “Previous Name”
It creates a data type that displays/edit columns in the table ‘patient_history’.
The tables ‘patient_data’ and ‘patient_history’ have a one-to-many relationship.

(2) Commit “Add Encounter to Transaction Form”

Create Code for Database Queries
Centralized Location for Queries is in Services:

  • /src/Services/PatientService.php
  • /src/Services/AddressService.php

This is where the code will be written to query the new tables.
Unfortunately, this is newer and most existing queries do not use it.

PatientService returns query results in variable $processingResult.
$processingResult is of type class PatientValidator

  • /src/Validators/BaseValidator
  • /src/Validators/PatientValidator

Changing Queries that Query Address Info from patient_data (Street, City, etc)
This will be the most work intensive step, since there are a lot of queries.
Queries should be modified to get info from classes/functions created in:

  • PatientService.php
  • AddressService.php.

Migrate Data
From patient_data to our normalized address tables.

Remove Address Related Columns From patient_data
This will be the final step.


Hi @psoas @raroldan17

I have been giving this some thought and have some insights I’d like to share.

While I am one of LBF’s biggest fan, we are finding it more difficult to expand Demographics with one to many type relationship inputs. One hold back is that demographics is hard wired to the patient_data table which over time has expanded greatly. What is needed is the ability in LBF Groups to define what the primary table for storage will be for the groups content. So diverging away from the patient_data table is just a first step.

Next is dealing with a more complicated form than just collecting data in static fields where over time the screen will become tiresome to view. In the case of additional addresses then four or five static fields times say three address datasets makes for rapidly expanding lost of screen space. So the natural pattern is to slide/popup the addition data which is fine however, LBF doesn’t currently have that mechanism.

This is where I’d purpose adding additional data types for handling sub forms or templates. The template could be another LBF with it’s own groups/sub groups where tables are defined or a custom HTML form called as a plug in. In this case the HTML plug in can handle the data distribution to storage. I also wouldn’t rule out using twig templates so data types would need to consider this as well. Remember that LBF groups can have sub groups. For example:

This would mean developing data types with pointer to templates and a display type(slide/dialog).
The data type and supporting items could be something like:

  • data type: pop_template title Additional Addresses
  • List would be a list created in Lists for template by LBF name or path to HTML template.

There are numerous examples of using dialogs(dlgopen) throughout core. Dialog’s can be called as iframes, passed in content or fetched content via ajax. Dialogs can also return a promise for several events(all the normal modal events plus) which is how I recommend using or at least allowing for when implemented as promises become very useful in many form sceneries.

To manage on the backend I’d recommend we create a new controller class and start migrating the procedural parser code( to methods in a new service class or several. There are several ways to go about this but my first thought is an abstract class that could/would be extended.
For an LBF template, most likely the current engine could handle persisting data and an HTML template could have data handled as part of the template form similar to how the majority of our current forms are handled. Still, more thought is required perhaps concerning a generic MVC for such templates. For now I’d keep it simple while getting the entire new pattern in place.

For the purpose of additional address etc. I would not follow my previous name input using select2 which if I had more time when I developed, I’d gone in the direction I’m talking about here.

Now all of this requires more fine tuning of course but, I hope the concept is somewhat clear however if not, please post a question or thoughts. I’m going back to jamming to Alice Cooper.:slight_smile:


@psoas @stephenwaite I just remembered I recently had to fix the insert in InsuranceService because it wasn’t working.
So if the practice insurance is using it may be the issue with addresses.

Also InsuranceCompany does use the generateId from sequence table. Sometime when restoring partial backups the sequence table can create duplicates. Otherwise this should work.

1 Like

would it be ok to have this line return $freshID for ins_search.php?

it’s also not allowing the address to get created for the new insurance company created from that popup while editing demographics

actually not seeing it use the generateID since it’s extending the base service now

Good point. I should have picked that up but I was unsure how api uses. return $freshId

Actually the whole bottom of the method is not right. Address is never created the way it’s written.
Because AddressService will return false on success and not a new id. sqlInsert will always return false on tables that don’t have a auto increment id.

I think it’s returning $GLOBALS['adodb']['db']->Insert_ID() which on my test is evaluating to an integer.

Not on an address insert is it. addresses table has primary but not auto increment unless maria vs mysql changed because in order to return an id, column needs to be an auto increment.
You may be getting back the fresh id for the new address row but not from the global.

shouldn’t this line be if (!$insuranceResults) {

with my test of adding an insurance company while editing demographics with the Search/Add $insuranceResults is an integer value

I created a LBF Form datatype called “Address List”.

I am able to insert it into the LBF Form. However, I am unable to get it to span the entire row.

It looks like the first column of the LBF is reserved for the label. I do not want to have and do not need a label. I would like my datatype “Address List” to span the entire row, but I cannot find a set of LBF options that will allow this.

In “Edit Layout”, I tried to make the label blank and made “Label Cols” = 0. This did not work. Any advice on how I can adjust the LBF settings so that there is no blank area to the left of my address list?

So, I forgot to mention that the the LBF displays properly when in Edit mode.

Therefore, the problem is not with how the form is set up in Admin → Forms → Layouts.

And, the problem occurs with other datatype’s. Not just mine.

The problem must be a bug in the display code.

In the file “”, the two relevant functions are:
—function display_layout_tabs_data, Lines 3725 - 3937
—function display_layout_tabs_data_editable, Lines 3938 - 4229

Apparently, the second function is working correctly, while the first one is not.

It is probably a simple bug. Would someone more experienced than me be able to help with finding it?

Thank you,

David, it’d be best to create a PR so we can pull code to test and offer suggestions.

PR not necessary because problem is not with my code.

The problem is with the display of LBF used by demographics, likely in the function display_layout_tabs_data.

You can recreate my problem with any datatype. For simplicity, try:
–inserting a field of datatype textbox into demographics layout
–leave label blank
–label cols = 0
–data cols = 4
–options = “Jump to next row”
–go to demographics, enter info into new textbox, and click save.

In display mode, the textbox is in column 2 instead of column 1. (wrong)
In edit mode, the textbox is in column 1. (correct)

Please, let me know if you get a different result.

Actually, I should have not brought it up here.

I forgot:
Bugs should be reported as issues on github.

I just reported it.

By the way, I just recreated the problem on the developmental demo.