Settings and configuration
CPalius has two separate "configuration" concepts and they must not be confused:
| Settings | Configuration sync (config sync) | |
|---|---|---|
| Where | In the database (cp_settings) |
In cp-content/config/sync/*.yaml files |
| Who changes it | The administrator, from the panel | The developer, with Git |
| What for | Site name, SMTP, security modes… | Roles, workflows, path patterns, field definitions |
| Moving | Backup/restore or with cp:config |
Git |
The two are bridged with cp:config: settings and fields are exported to YAML and imported from YAML.
Defining a setting: #[CpSetting]
Each setting is an attribute collected at build time. By convention they are piled onto an empty carrier class:
#[CpSetting(key: 'shop.currency', label: 'shop.setting.currency', type: 'select',
default: 'TRY', variants: ['TRY' => 'Turkish Lira', 'EUR' => 'Euro'],
module: 'shop', group: 'shop_general')]
#[CpSetting(key: 'shop.notice', label: 'shop.setting.notice', type: 'textarea',
translatable: true, module: 'shop', group: 'shop_general')]
#[CpSetting(key: 'shop.api_secret', label: 'shop.setting.api_secret', type: 'password', module: 'shop')]
final class ShopSettings
{
}
| Parameter | Meaning |
|---|---|
key |
Unique id: module.name |
label |
Label shown on screen (can be a translation key) |
type |
text, checkbox, select, textarea, integer, password |
default |
Value returned if there is no row in the database |
variants |
select options (value => label) |
module |
Owning module/plugin id; core for the core |
group |
Which section it is gathered under on screen |
translatable |
The value is stored as a {"tr": "...", "en": "..."} map (only text and textarea) |
scope |
Settings tab: core, module or plugin. If empty, it is found automatically from the module field |
Settings appear as tabs under AACP → System → System Settings; adding the definition also creates the screen by itself.
Reading
$currency = $settings->get('shop.currency'); // default 'TRY'
$notice = $settings->getForLocale('shop.notice', 'en'); // by language
$all = $settings->getTranslations('shop.notice'); // ['tr' => '…', 'en' => '…']
For a translatable setting the reading order is: request language → default language → first filled value → $default.
Values are kept in memory per request and cached in cache.app (loaded with a single query). If you write a setting in code, call clearCache('shop.currency') afterwards; the panel does this itself.
Encrypted settings
type: 'password' settings (SMTP password, CAPTCHA secret key, API credentials) are stored encrypted in the database (SettingSecretCodec). A read-only SQL injection or a shared database backup does not hand these values out as plain text. An encoded value carries a distinct marker, so plain-text values written before encryption was added are not mistaken for a "corrupt cipher" but are recognized as "old plain text".
Core setting keys
The main settings with their defaults. (All security settings are on the Security page.)
Site
| Key | Default | |
|---|---|---|
core.site_name |
CPalius CMF |
Site name |
core.site_description |
empty | Site description |
core.maintenance_mode |
off | Maintenance mode |
core.maintenance_message |
empty | Maintenance page message |
core.default_locale |
tr |
Default language |
core.timezone |
Europe/Istanbul |
Time zone |
core.permalink_structure |
postname |
Permalink structure |
core.default_meta_title_format |
%%title%% – %%site_name%% |
Default title format |
homepage.mode |
portal |
Home page mode (portal or simple home page) |
| Key | Default |
|---|---|
mail.enabled |
off |
mail.smtp_host, mail.smtp_port |
empty, 587 |
mail.smtp_encryption |
tls |
mail.smtp_user, mail.smtp_password |
empty (the password is stored encrypted) |
mail.from_email, mail.from_name |
empty |
mail.log_retention_days |
90 |
Account registration
| Key | Default |
|---|---|
account.registration_enabled |
on |
account.require_email_verification |
off |
account.require_admin_approval |
off |
account.username_required |
on |
account.require_terms |
on |
Content
| Key | Default |
|---|---|
content.revisions.enabled |
on |
content.revisions.max_per_node |
25 |
content.moderation.enabled_types |
empty (no type enters the workflow) |
content.moderation.workflow |
editorial |
Notification, logging, audit
| Key | Default |
|---|---|
notification.enabled, notification.digest.enabled |
on, on |
logging.min_level |
warning |
logging.retention_days |
30 |
audit.enabled, audit.retention_days |
on, 365 |
Cookie consent (Consent)
consent.enabled is off by default. When turned on, separate consent categories for analytics and marketing cookies (consent.analytics_enabled, consent.marketing_enabled) and all button/message texts are customized with settings.
Performance and storage settings are on the Cache and performance and Media and storage pages.
Configuration sync (config sync)
php cp-core/bin/console cp:config export # write the live configuration to YAML
php cp-core/bin/console cp:config status # is there drift?
php cp-core/bin/console cp:config import # apply the YAML (default: dry run)
php cp-core/bin/console cp:config import -f # actually apply
php cp-core/bin/console cp:config import --only=settings
Design properties:
- Deterministic: keys are sorted recursively; if two environments have the same configuration, the YAML files come out byte for byte identical. A Git diff shows only the real change.
- Portable: the export contains no ids or timestamps.
- Transactional: the import runs in a single database transaction; providers persist but do not flush.
- Provider-based: each configuration type implements a
ConfigProviderInterfaceand owns one or more "documents". The core's providers: settings (settings), fields (field.<bundle>), taxonomy, text formats, path patterns, entity display.
If a module wants to add its own configuration, it implements ConfigProviderInterface: documents(), exportDocument(), diffDocument(), importDocument() and afterImport().
In development add a field → cp:config export → commit to Git → update the files on production → see the difference with cp:config status → cp:config import -f.
Roles (user.role.*.yaml) and workflows (workflow/*.yaml) are files directly; they have no counterpart in the database, so they do not need an export. Edit the file, clear the cache.