Appearance
Are you an LLM? You can read better optimized documentation at /flows/admin/AD-37-metadata-system.md for this page in Markdown format
Metadata / Registry System
Flow ID: AD-37 Module(s): eshop, settings, application Complexity: Medium Last Updated: 2026-04-04
Business Overview
Ecommercen uses two distinct metadata systems that serve different purposes:
Product Metadata (
product_metatable) -- Dynamic, config-driven per-product fields that extend the product entity with arbitrary data types (text, HTML, dates, uploads). Configured per-client viaapplication/config/product_meta_data.php.Registry (
registrytable) -- A global key-value store for application-wide configuration. Acts as a database-backed alternative to config files, supporting grouping, language-specific values, and encrypted storage. Used pervasively for payment gateway credentials, feature flags, email settings, and integration configuration.
Both systems have a legacy model layer for admin CRUD and a modern Domain + REST API layer for programmatic access.
API Reference
REST Endpoints -- Product Metadata
| Method | Path | Action | Auth |
|---|---|---|---|
GET | /rest/product/product-meta | List metadata records (paginated, filterable) | JWT |
GET | /rest/product/product-meta/{id} | Get single meta record by ID | JWT |
GET | /rest/product/product-meta/item | Get single meta by filter | JWT |
POST | /rest/product/product-meta | Create metadata record | JWT |
POST | /rest/product/product-meta/{id} | Update metadata record | JWT |
DELETE | /rest/product/product-meta/{id} | Delete metadata record | JWT |
Filters: filter[id], filter[productId] (exact), filter[metaType] (exact), filter[category] (exact), filter[lang] (exact), filter[value] (partial) Sorts: id, productId, metaType, categoryRelations: include=product (BELONGS_TO)
Registry -- No REST API
The Registry is accessed only via the Registry library and registry_helper.php functions. There is no REST endpoint for registry operations -- all management happens through the admin settings UI (Adv_settings) and programmatic calls.
Code Flow
Product Metadata -- Admin Integration
Adv_products_admin::create() / edit()
|
+--> On save:
+--> updateProductMetaDataFromPost($productId)
| |
| +--> For each field in metaDataFieldConfig():
| ├── Skip 'upload' type fields
| ├── If MUI: loop languages, add/update per (product_id, category, lang)
| └── If non-MUI: add/update per (product_id, category, lang=null)
|
+--> saveProductMetaDataFiles($productId, $filesData)
|
+--> For each 'upload' type field in metaDataFieldConfig():
├── If MUI: save file per language
└── If non-MUI: save file per productProduct Metadata -- Config-Driven Fields
application/config/product_meta_data.php
|
+--> $config['product_meta'] = [
| 'views' => [type => viewName mapping],
| 'categories' => [
| 'fieldName' => [
| 'type' => 'text|html|date|datetime|checkbox|select|upload',
| 'mui' => true|false,
| 'validation' => 'CI form_validation rules',
| 'upload' => ['allowed_types' => ..., 'size' => ...] // for upload type
| ]
| ]
]The categories array is empty by default and is configured per-client to define custom product fields.
Registry -- Read Flow
Registry::__construct()
|
+--> registry_model->all() (via pscache for caching)
+--> parseDb() -- organize into $data[reggroup][regkey][lang] = regval
|
+--> Registry::value($regGroup, $regKey, $langAbbr, $encrypted)
| Returns single value, optionally decrypted
|
+--> Registry::getGroupAsArray($regGroup, $langAbbr, $encryptedKeys)
| Returns all keys in a group as assoc array
|
+--> Registry::getArray($regKey, $regGroup, $langAbbr)
Returns pipe-delimited value as arrayRegistry -- Write Flow
Registry::setValue($regGroup, $regKey, $regVal, $langAbbr, $encrypted)
|
+--> addItem() -- update in-memory cache
+--> registry_model->set_regval() -- upsert to DB
(if row exists: UPDATE, else: INSERT)
Registry::setArray($regKey, $regGroup, $langAbbr, $regVal)
|
+--> implode('|', $regVal) → setValue()
Registry::delete($regGroup, $regKey, $langAbbr)
|
+--> Remove from in-memory cache
+--> registry_model->delete()Domain Layer
Product Metadata -- Modern Domain (src/)
| File | Responsibility |
|---|---|
src/Domains/Product/ProductMeta/Repository/Entity.php | Entity: id, product_id, meta_type, category, value, lang |
src/Domains/Product/ProductMeta/Repository/Repository.php | Read repository (table: product_meta) |
src/Domains/Product/ProductMeta/Repository/RepositoryConfigurator.php | Relations: product (BELONGS_TO) |
src/Domains/Product/ProductMeta/Repository/WriteRepository.php | Write repository |
src/Domains/Product/ProductMeta/Service.php | Read service |
src/Domains/Product/ProductMeta/WriteService.php | Write service |
src/Domains/Product/ProductMeta/WriteData.php | DTO: productId, metaType, category, value, lang |
src/Domains/Product/ProductMeta/ListRequest.php | Filter/sort definitions |
Product Metadata -- REST Layer (src/)
| File | Responsibility |
|---|---|
src/Rest/Product/Controllers/ProductMeta.php | REST controller with OpenAPI annotations |
src/Rest/Product/Resources/ProductMeta/Resource.php | JSON resource: {id, productId, metaType, category, value, lang} |
src/Rest/Product/Resources/ProductMeta/Collection.php | Collection wrapper |
Product Metadata -- Legacy Layer (ecommercen/)
| File | Responsibility |
|---|---|
ecommercen/eshop/models/AdvProductMetaModel.php | Model: CRUD, metaDataFieldConfig(), getMetaDataObject() |
ecommercen/eshop/controllers/Adv_products_admin.php | Product admin: updateProductMetaDataFromPost(), saveProductMetaDataFiles() |
application/config/product_meta_data.php | Field configuration (types, MUI, validation, upload rules) |
Registry Layer
| File | Responsibility |
|---|---|
application/libraries/Registry.php | Main library: value(), setValue(), getGroupAsArray(), getArray(), setArray(), delete() |
application/models/Registry_model.php | DB model: all(), set_regval(), delete() |
ecommercen/helpers/registry_helper.php | Helper functions: getRegistryValue(), getRegistryArrayValue(), payment/integration getters |
Architecture
Product Metadata
Product Admin (Adv_products_admin) REST API (ProductMeta controller)
| |
+--> AdvProductMetaModel +--> ProductMeta\Service
(legacy model) ProductMeta\WriteService
| |
v v
product_meta table <==================> product_meta table
^
|
application/config/product_meta_data.php (field definitions)The config file defines what fields exist; the model/service provides storage. Admin views are generated dynamically based on the views mapping (metaInputText, metaInputHtml, etc.).
Registry
Any controller / library / helper
|
+--> $this->registry->value('GROUP', 'KEY') -- read
+--> $this->registry->setValue('GROUP', 'KEY') -- write
|
+--> In-memory cache (per-request)
+--> pscache (file-based caching layer)
+--> registry_model → DBThe Registry is loaded once per request (cached via pscache) and provides an in-memory lookup for the duration of the request. The live() method forces a cache refresh (used in cron jobs that need current values).
Data Model
product_meta
| Column | Type | Description |
|---|---|---|
id | int(11) | PK, auto-increment |
product_id | int(11) | FK to shop_product |
meta_type | varchar(255) | Field type (text, html, upload, date, etc.) |
category | varchar(255) | Field name/key from config |
value | longtext | Stored value (text, HTML, filename, etc.) |
lang | varchar(2) | Language code (NULL for non-MUI fields) |
Indexes: category, product_category (product_id + category), product_category_lang (product_id + category + lang)
registry
| Column | Type | Description |
|---|---|---|
id | int(11) | PK, auto-increment |
reggroup | varchar(150) | Configuration group (e.g., VIVAWALLET, ESHOP, EMAIL) |
regkey | varchar(150) | Configuration key within the group |
regval | text | Stored value (may be encrypted) |
lang | varchar(2) | Language code (empty string for non-language-specific values) |
Indexes: reggroup, regkey, key_lang, group_key_lang (composite for lookups)
Well-Known Registry Groups
| Group | Purpose | Example Keys |
|---|---|---|
ESHOP | Shop feature flags and settings | IMPORT_PRODUCTS_FROM_EXCEL_ENABLED |
OTHER | Miscellaneous settings | ORDER_TAGS_ENABLED |
GLOBAL | Global shop settings | ADMIN_EMAIL |
VIVAWALLET | Viva Wallet payment config | MERCHANT_ID, API_KEY, SOURCE_CODE |
PIRAEUSBANK | Piraeus Bank payment config | ACQUIRER_ID, MERCHANT_ID, POS_ID |
ETHNIKIBANK | NBG payment config | PUBLIC_KEY, PRIVATE_KEY |
ALPHABANK | Alpha Bank payment config | ID, SSK, SUBMIT |
APCOPAY | ApcoPay payment config | PROFILE_ID, SECRET, MERCHANT_ID |
JCC | JCC payment config | USERNAME, PASSWORD |
IRIS | Iris payment config | USERNAME, PASSWORD, CUSTOMER_CODE |
PAY_BY_BANK | PayByBank config | API_KEY, API_URL, EXPIRATION |
PAYPAL_ADVANCED | PayPal Advanced config | CLIENT_ID, CLIENT_SECRET |
KLARNA_PAYMENTS | Klarna payment config | USERNAME, PASSWORD |
AGORA | Project Agora ad integration | IS_ENABLED, API_URL, API_KEY |
SMARTCART | Skroutz Smart Cart | IS_ENABLED |
PUBLIC_MARKETPLACE | Public marketplace | ENABLED |
SHOPFLIX | ShopFlix marketplace | IS_ENABLED |
EMAIL_CONTACT_FORM | Contact form SMTP | SMTP_HOST, SMTP_USER, SMTP_PASS |
EMAIL_SHOP_MAILER | Shop email SMTP | SMTP_HOST, SMTP_USER, SMTP_PASS |
Configuration
Product Metadata
- Field config:
application/config/product_meta_data.php-- emptycategoriesarray by default; populated per-client - Supported types:
text,html,date,datetime,checkbox,select,upload - MUI support: Each field can be marked as MUI (
'mui' => true), which stores separate values per language - Validation: Uses CI form_validation rules defined per field
- Upload limits: Per-field
allowed_typesandsize(KB) configuration
Registry
- Cache layer:
pscachelibrary provides file-based caching of all registry values - Encryption: Values can be stored encrypted via
$this->registry->setValue(..., $encrypted = true)using CI'sEncryptionlibrary - Live refresh:
$this->registry->live()forces cache bypass and DB reload
Client Extension Points
Product Metadata
- Define custom fields: Populate
application/config/product_meta_data.phpwith client-specific field definitions - Override model: Override
AdvProductMetaModelinapplication/models/for custom behavior - Custom admin views: The view mapping in the config determines which partial is rendered for each field type
Registry
- Add settings: Use
Registry::setValue()from patchers or admin controllers to add new configuration - Custom helper functions: Add to
registry_helper.phpinapplication/helpers/for client-specific settings retrieval - Settings admin: The
Adv_settingscontroller reads/writes registry values for the admin settings UI
Business Rules
Product Metadata
- Config-driven schema: Fields exist only if defined in
product_meta_data.php-- no UI for adding fields dynamically - MUI isolation: MUI fields store one row per (product_id, category, lang); non-MUI fields use
lang = NULL - Upsert pattern:
updateProductMetaDataFromPost()checkshasRecord()before deciding insert vs. update - Upload handling: File uploads are handled separately from text fields via
saveProductMetaDataFiles() - HTML fields: HTML-type fields skip XSS filtering (
$this->input->post($field, false)) to preserve markup
Registry
- Upsert on write:
set_regval()checks if a row exists for (reggroup, regkey, lang) before deciding INSERT vs. UPDATE - Non-language constant: When
langis empty, it is stored as an empty string in DB but mapped to the internal constantBASEin memory - Pipe-delimited arrays: Array values are stored as pipe-separated strings (
val1|val2|val3) and split on read - Encrypted values: Encryption uses CI's
Encryptionlibrary; decryption happens at read time viavalue(..., $encrypted = true) - Cache coherence: In-memory cache is populated once per request;
setValue()updates both memory and DB;live()forces full reload
Related Flows
- AD-02 Product Management -- Product admin integrates metadata via create/edit forms
- AD-28 Order Tags -- Feature-flagged via registry
OTHER.ORDER_TAGS_ENABLED - AD-06 Transporter Admin -- Transporter settings use a similar key-value pattern (separate table)
- SY-19 Config Registry -- Expanded documentation of the Registry system from a system/infrastructure perspective
- AD-13 Settings -- Admin UI for managing registry values
Wiki Guide: Settings in Database -- developer guide for database-backed configuration