Settings & envinfo¶
The eQual framework allows defining a series of parameters used by controllers that can be modified by administrators through the Settings application. These parameters are modeled using the Setting
entity, which provides flexibility and a robust mechanism for contextual configuration.
Configuration Parameters¶
Each parameter is represented by a Setting
entity. A setting can have one or more associated SettingValue
or SettingSequence
objects. These values may include:
- A general value applicable to all users.
- A user-specific or context-specific value (e.g., via
user_id
,organization_id
, etc.). - A counter or sequential value (for sequences).
Example of a Setting object¶
{
"id": 5,
"code": "numbers.decimal_precision",
"title": "Number of decimal digits",
"package": "core",
"form_control": "select",
"section_id": 1,
"description": "Number of decimal digits",
"help": "Number of decimal digits to store for fields of type 'float'.",
"type": "integer"
}
Auto-Generated Interface¶
The framework automatically generates an interface to manage Setting
entities. This ensures:
- Consistency in data types.
- Proper controls for editing (e.g., select, text, etc.).
- Clear separation between parameters and their values.
Interdependencies and Initialization¶
Parameters can include relational fields or computed fields based on references. These relationships can sometimes require certain entities to be created before others. To address this:
- The initialization order is enforced by naming files in the
init/data
directory with numeric prefixes (e.g.,01_file.json
,02_file.json
).
Special Case: SettingValue¶
- Each
SettingValue
is always linked to a specificSetting
. - Direct use of
setting_id
can risk collision between packages, making maintenance complex. - To avoid this:
- During initialization, the framework uses the
name
field set inSettingValue
objects to find the correspondingsetting_id
. - A warning is generated if a
setting_id
is manually specified. - If the
Setting
cannot be resolved, an error is raised.
Automatic Adjustments¶
- Tests and adaptations are performed during the initialization process using files in the
init/data
directory. - The system ensures consistency by identifying missing or misconfigured settings and resolving issues automatically where possible.
Core Concepts¶
A Setting represents a configurable parameter in the system, uniquely identified by a package
, a section
, and a code
. Each setting must be linked to at least one value or sequence to be considered valid.
SettingValues¶
SettingValues hold the actual value of a setting. These values can be scoped to specific contexts using a selector — a set of fields like user_id
, organization_id
, etc.
Examples: - A setting can have a global default value (no selector). - And specific overrides for a user or an organization.
SettingSequences¶
SettingSequences are special settings that manage numeric counters (e.g., invoice numbers). They also support contextual scoping through selectors, allowing, for instance, separate counters per organization.
Selector Hierarchy¶
The selector defines the context of a value or sequence:
- If empty, it targets the most generic (global) value.
- If non-empty, it must match a value with exactly those fields set (and all other discriminant fields must be
null
). - Fields omitted in the selector are considered implicitly
null
.
This strict matching ensures clarity and avoids ambiguity when retrieving values.
The list of discriminant fields (called context keys) is configurable and defines the scoping logic (e.g., per user, org, etc.). You may override the getSelectorKeys()
method in subclasses to adapt this behavior.
Core Entities¶
Setting
¶
- Represents a unique configuration parameter, defined by its
package
,section
, andcode
. - A
Setting
must have at least one associatedSettingValue
orSettingSequence
.
SettingValue
¶
- Stores the actual value for a
Setting
, with optional scoping using discriminant fields (e.g.,user_id
,organization_id
). - Can be multilingual, depending on the
Setting
'sis_multilang
flag.
SettingSequence
¶
- Provides integer-based sequential values for a given
Setting
, used when auto-incrementing or unique numbering is required. - Also supports contextual scoping like
SettingValue
.
Common Method Patterns¶
The following methods are implemented both for SettingValue
and SettingSequence
, using respective suffixes (_value
, _sequence
).
assert_value($selector, $val)
/ assert_sequence($selector, $val)
¶
- Ensures the
Setting
and the relatedSettingValue
orSettingSequence
exist. - If the
Setting
does not exist, it is created. - The target value is then set via
set_value()
orset_sequence()
.
set_value($selector, $val)
/ set_sequence($selector, $val)
¶
- Sets the actual value (mixed for
value
, integer forsequence
) for the specified selector and language (if applicable). - If the targeted entity does not exist, the operation is ignored.
get_value($selector, $default)
/ get_sequence($selector, $default)
¶
- Retrieves the value or sequence.
- Returns the default if the
Setting
or corresponding entity is missing.
create_value($selector)
/ create_sequence($selector)
¶
- Creates a new
SettingValue
orSettingSequence
based on the selector. - Ensures the scoping rules are respected.
fetch_and_add($selector)
(only for SettingSequence)¶
- Retrieves the current integer value and increments it atomically.
- Useful for generating unique sequential values.
Caching¶
- A dedicated cache (
$_equal_core_setting_cache
) is used to store retrieved values. get_cache()
andset_cache()
handle cache access.- Cache index is automatically computed from
package
,section
,code
, selector fields (ingetSelectorKeys()
order), and language. - The method
build_cache_index(...)
is responsible for building the index key.
Examples¶
// Get a setting value for user_id 1
$value = Settings::get_value('billing', 'defaults', 'currency', 'EUR', ['user_id' => 1]);
// Assert a default setting (global)
Settings::assert_value('billing', 'defaults', 'currency', 'EUR');
// Fetch and increment a sequence
$nextNumber = Settings::fetch_and_add('invoicing', 'sequence', 'invoice_number', ['organization_id' => 5]);
Extensibility¶
- You may override the
getSelectorKeys()
method in subclasses to add or modify discriminant fields. - This allows greater flexibility for scoping by team, device, project, etc.
- Ensure database-level unique constraints match your scoping logic (e.g.,
UNIQUE(setting_id, user_id, organization_id)
where relevant).
Notes¶
set_value()
does not create new entries — it only updates existing ones.assert_value()
ensures creation and setting.- Fallback logic (e.g., from user to org to global) is not currently implemented — each selector must match exactly.
This structured and dynamic approach helps maintain a consistent configuration model, while allowing per-context overrides and automated sequence generation — all while preventing ambiguity and ensuring system integrity.