OpenEyes provides a comprehensive settings system that allows administrators to customize behavior at multiple levels, from installation-wide defaults to user-specific preferences.
Settings Architecture
The settings system uses a hierarchical approach with multiple levels of specificity:
User Settings (highest priority)
↓
Firm Settings
↓
Institution + Subspecialty Settings
↓
Subspecialty Settings
↓
Specialty Settings
↓
Site Settings
↓
Institution Settings
↓
Installation Settings (lowest priority, system defaults)
When retrieving a setting, the system checks each level in order (most specific first) until a value is found.
Settings Database Schema
The system uses 9 related tables:
Table: setting_metadata
Defines available settings and their properties:
Unique setting key (used in code)
Display name for admin interface
Type of input field (text, dropdown, checkbox, HTML, etc.)
Serialized data for field configuration (e.g., dropdown options)
Default value when no override exists
Optional: Link to specific element type if setting is element-specific
Help text for administrators
Setting group for organization in admin UI
Minimum level at which this setting can be overridden
Setting Instance Tables
Each level has its own table for storing setting values:
setting_installation - System-wide defaults
setting_institution - Institution-specific values
setting_site - Site-specific values
setting_specialty - Specialty-specific values
setting_subspecialty - Subspecialty-specific values
setting_institution_subspecialty - Institution + subspecialty combination
setting_firm - Firm/context-specific values
setting_user - User-specific values
All instance tables share this structure:
CREATE TABLE setting_ [level] (
id INT PRIMARY KEY AUTO_INCREMENT,
key VARCHAR ( 64 ) NOT NULL ,
value TEXT ,
element_type_id INT ,
[level]_id INT NOT NULL ,
last_modified_date DATETIME ,
created_date DATETIME ,
UNIQUE KEY ( key , element_type_id, [level]_id)
);
Accessing Settings
In PHP Code
// Get a setting value
$value = SettingMetadata :: model () -> getSetting ( 'setting_key' );
// Get setting with element type context
$value = SettingMetadata :: model () -> getSetting (
'examination_view_mode' ,
ElementType :: model () -> findByAttributes ([ 'class_name' => 'Element_OphCiExamination_History' ])
);
// Get setting display name (applies data mapping)
$displayValue = SettingMetadata :: model () -> getSettingName ( 'setting_key' );
// Get setting for specific institution (e.g., in admin)
$value = SettingMetadata :: model () -> getSetting (
'setting_key' ,
$element_type = null ,
$return_object = false ,
$allowed_classes = [ 'SettingInstitution' , 'SettingInstallation' ],
$institution_id = 123 ,
$is_setting_page = true
);
// Check if setting has specific value
if ( SettingMetadata :: checkSetting ( 'feature_enabled' , 'on' )) {
// Feature is enabled
}
Setting Context
The system automatically determines context from the current session:
File: protected/models/SettingMetadata.php:219
public function getSetting ( $key = null , $element_type = null , ...)
{
// Gather context from session
$user_id = Yii :: app () -> session [ 'user' ] -> id ?? null ;
$firm_id = $firm ? $firm -> id : null ;
$subspecialty_id = /* from firm */ ;
$specialty_id = /* from subspecialty */ ;
$site_id = /* from session */ ;
$institution_id = $site -> institution_id ?? null ;
// Check each level in order
foreach ( self :: $CONTEXT_CLASSES as $class => $field ) {
if ( $setting = $this -> getSettingValue ( $class , $key , ... )) {
return $this -> parseSetting ( $setting , $metadata );
}
}
// Return default if no override found
return $metadata -> default_value ;
}
Setting Field Types
Available Field Types
Table: setting_field_type
Text
Textarea
Checkbox
Dropdown
Radio
HTML
Simple text input field. array (
'field_type_id' => 1 , // Text
'default_value' => 'Default text'
)
Multi-line text area. array (
'field_type_id' => 2 , // Textarea
'default_value' => 'Multi-line\ndefault text'
)
Boolean on/off toggle. array (
'field_type_id' => 3 , // Checkbox
'default_value' => 'on' // or 'off'
)
Select from predefined options. array (
'field_type_id' => 4 , // Dropdown
'data' => serialize ( array (
'option1' => 'Display Label 1' ,
'option2' => 'Display Label 2' ,
'option3' => 'Display Label 3'
)),
'default_value' => 'option1'
)
Radio button group. array (
'field_type_id' => 5 , // Radio
'data' => serialize ( array (
'yes' => 'Yes' ,
'no' => 'No'
)),
'default_value' => 'no'
)
Rich text editor with HTML support. array (
'field_type_id' => 6 , // HTML
'default_value' => '<p>Default HTML content</p>'
)
Supports substitution placeholders for dynamic content.
HTML Settings with Substitutions
HTML field types can include dynamic substitutions:
Available Substitutions
Session Substitutions (user/firm/site context):
[user_name] - Current user’s full name
[user_title] - User’s professional title
[firm_name] - Current firm name
[site_name] - Current site name
[site_address] - Site address
[site_phone] - Site phone number
[site_fax] - Site fax number
[site_email] - Site email
[current_date] - Today’s date
[primary_logo] - Institution primary logo
[secondary_logo] - Institution secondary logo
Patient Substitutions:
[patient_full_name]
[patient_first_name]
[patient_last_name]
[patient_date_of_birth]
[patient_gender]
[patient_nhs_num]
[patient_hos_num]
[patient_last_exam_date]
Using Substitutions
// In setting metadata
array (
'key' => 'correspondence_footer' ,
'field_type_id' => 6 , // HTML
'data' => serialize ( array (
'substitutions' => array (
'site_name' ,
'site_address' ,
'site_phone'
)
)),
'default_value' => '<p><span data-substitution="site_name">[site_name]</span><br>
<span data-substitution="site_address">[site_address]</span><br>
Tel: <span data-substitution="site_phone">[site_phone]</span></p>'
)
// Performing substitutions at runtime
$html = SettingMetadata :: model () -> getSetting ( 'correspondence_footer' );
// Substitutions are automatically applied when retrieved
Substitutions are processed automatically by the parseSetting() method in SettingMetadata.php:384.
Managing Settings in Admin Interface
Accessing System Settings
Navigate to: Admin → System Settings
Settings are organized into groups:
Core - Essential system settings
User Interface - Display and behavior settings
Clinical - Clinical workflow settings
Correspondence - Letter and document settings
Examination - Examination module settings
Module-specific - Settings for each active module
Setting Groups
Table: setting_group
class SettingGroup extends BaseActiveRecord
{
public $id ;
public $name ; // Display name
public $description ; // Help text
public $display_order ; // Sort order
}
Editing Settings
Select Setting Group
Choose the group containing the setting to edit
Choose Setting Level
Select whether to edit at:
Installation (system default)
Institution
Site
Subspecialty
etc.
Modify Value
Change the setting value using the appropriate input field
Save Changes
Click “Save” to apply the new value
Changing installation-level settings affects all institutions and users unless overridden at a more specific level.
Common System Settings
Core Settings
hos_num_label
string
default: "Hospital Number"
Label for hospital number field
nhs_num_label
string
default: "NHS Number"
Label for NHS number field
Display version number in footer
Email address for helpdesk/support
Phone number for helpdesk/support
User Interface Settings
recent_context_firm_limit
Number of recent firms to show in context menu
Default pagination size for lists
patient_summary_id_widgets
Configure which ID numbers to display in patient summary
Clinical Settings
Default site for new events
Automatically generate event descriptions
Method for printing events: pdf or html
Correspondence Settings
correspondence_sort_order
Default sort order for correspondence list
Default address type for letters
Default letter footer content (supports substitutions)
Custom Text Settings
OpenEyes allows customizing display text for event types and element types:
Event Type Custom Text
// protected/controllers/AdminController.php:307
public function actionEditEventTypeCustomText ()
{
foreach ( $_POST [ 'EventType' ] as $event_type_form ) {
$event_type = EventType :: model () -> findByPk ( $event_type_form [ 'id' ]);
$event_type -> custom_event_name = $form [ 'custom_event_name' ];
$event_type -> save ();
}
}
Element Type Custom Text
// protected/controllers/AdminController.php:334
public function actionEditElementTypeCustomText ()
{
foreach ( $_POST [ 'ElementType' ] as $element_type_form ) {
$element_type = ElementType :: model () -> findByPk (
$element_type_form [ 'id' ]
);
$element_type -> custom_hint_text = $form [ 'custom_hint_text' ];
$element_type -> save ();
}
}
Caching
The settings system implements aggressive caching for performance:
File: protected/models/SettingMetadata.php:250-270
// Check for settings table updates
$debounce_val = Yii :: app () -> settingCache -> get ( 'SettingMetaDebounce' );
if ( $debounce_val === false ) {
// Query last update time of all setting tables
$dependency_sql = " SELECT sha1(GROUP_CONCAT(UPDATE_TIME))
FROM information_schema . tables
WHERE TABLE_NAME IN (
'setting_metadata',
'setting_installation',
'setting_institution',
...
)" ;
$debounce_val = Yii :: app () -> db -> createCommand ( $dependency_sql )
-> queryScalar ();
// Cache for 5 seconds to prevent excessive queries
Yii :: app () -> settingCache -> set ( 'SettingMetaDebounce' , $debounce_val , 5 );
}
Cache Management
// Clear settings cache
SettingMetadata :: resetCache ();
// or via CLI
. / yiic cache flush settingCache
// Clear all caches
. / yiic cache flush all
Settings are cached with a dependency on the last update time of setting tables. The cache automatically invalidates when settings are modified.
Creating New Settings
Via Database Migration
class m240101_120000_add_new_setting extends OEMigration
{
public function up ()
{
// Get or create setting group
$group_id = $this -> getIdOfSettingGroupByName ( 'Core' );
// Get field type
$field_type_id = $this -> getIdOfSettingFieldTypeByName ( 'Checkbox' );
// Insert setting metadata
$this -> insert ( 'setting_metadata' , [
'element_type_id' => null ,
'display_order' => 10 ,
'field_type_id' => $field_type_id ,
'key' => 'my_new_setting' ,
'name' => 'My New Setting' ,
'data' => null ,
'default_value' => 'off' ,
'description' => 'Description of what this setting does' ,
'group_id' => $group_id ,
'lowest_setting_level' => 'INSTALLATION' ,
]);
// Optionally set installation-level value
$this -> insert ( 'setting_installation' , [
'key' => 'my_new_setting' ,
'value' => 'on' ,
]);
}
public function down ()
{
$this -> delete ( 'setting_installation' ,
"`key` = 'my_new_setting'" );
$this -> delete ( 'setting_metadata' ,
"`key` = 'my_new_setting'" );
}
}
Via Admin SQL
-- Insert setting metadata
INSERT INTO setting_metadata (
element_type_id,
display_order,
field_type_id,
`key` ,
name ,
data ,
default_value,
description ,
group_id
) VALUES (
NULL ,
10 ,
( SELECT id FROM setting_field_type WHERE name = 'Checkbox' ),
'feature_enabled' ,
'Enable Feature' ,
NULL ,
'off' ,
'Enable the new feature functionality' ,
( SELECT id FROM setting_group WHERE name = 'Core' )
);
-- Set installation default
INSERT INTO setting_installation ( `key` , value )
VALUES ( 'feature_enabled' , 'on' );
API Reference
File: protected/models/SettingMetadata.php
getSetting($key, $element_type, $return_object, $allowed_classes, $institution_id, $is_setting_page) - Retrieve setting value
getSettingName($key, $allowed_classes, $institution_id, $is_setting_page) - Get display name with data mapping
checkSetting($key, $value) - Check if setting has specific value
parseSetting($setting, $metadata) - Process setting value (apply substitutions, etc.)
performSubstitutions($html, $substitutions, $preserve_empty) - Apply substitutions to HTML
getSessionSubstitutions() - Get available session-based substitutions
getPatientSubstitutions($patient, $event) - Get patient-specific substitutions
resetCache() - Clear settings cache
AdminController Settings Methods
File: protected/controllers/AdminController.php
actionEditEventTypeCustomText() - Line 307
actionEditElementTypeCustomText() - Line 334
Best Practices
Use Appropriate Levels Set settings at the most appropriate level for your use case
Document Custom Settings Add clear descriptions to help future administrators
Test Before Production Test setting changes in a development environment first
Version Control Migrations Use database migrations for new settings in code