Configuration
Before this section, review Setup — bootstrap and paths.php.
Concept Core collects settings from PHP files in config/, applies environment overrides
(APP_ENV), and variables from .env. Loading is performed by
ConfigServiceProvider::boot() on the first access to ConfigInterface.
Access in code is through DI (ConfigInterface).
Loading order
Implemented in ConfigServiceProvider. Each subsequent step overrides the previous one
for matching keys (except step 2 — .env is only read; merging happens at step 4).
flowchart LR
A["1. config/*.php"]
B["2. .env is read"]
C["3. config/APP_ENV/*.php"]
D["4. .env → config"]
E["app.timezone"]
A --> B --> C --> D --> E
- Base
config/— all PHP files are merged with Noodlehaus Config. .env— loaded via vlucas/phpdotenv;APP_ENVdetermines the override folder.config/{APP_ENV}/— if the directory exists (dev,production…), its files are merged on top of the base config..envvariables — written into config (highest priority).- Timezone —
date_default_timezone_set()fromapp.timezone.
APP_ENV is read from .env at step 2 and is used only to select
config/{APP_ENV}/. In the final config it appears as app.env at step 4.
.env → config mapping
Each environment variable is converted to a config key using the “first underscore” rule:
the name is split into two parts (limit explode('_', ..., 2)), lowercased,
then joined with a dot.
APP_DEBUG=true → app.debug
DB_HOST=127.0.0.1 → db.host
LOG_MAX_FILES=14 → log.max_files
Nesting deeper than the first level is not supported via .env: APP_FOO_BAR_BAZ becomes
app.foo_bar_baz, not a nested array. Complex structures belong in config/ PHP files.
Boolean values in .env (true, false, 0, 1)
are read correctly via getBool().
.env file
Copy .env.example to .env in the application root.
Do not commit .env to the repository — only the example file.
| .env variable | Config key | Description |
|---|---|---|
APP_NAME | app.name | Application name (console, logs) |
APP_TIMEZONE | app.timezone | PHP timezone (Europe/Kyiv, UTC) |
APP_ENV | app.env | Environment: dev, production, etc.; determines override folder |
APP_DEBUG | app.debug | Debug mode: Whoops, Twig cache off, Valinor FileWatchingCache |
LOG_LEVEL | log.level | Monolog level: debug, info, error… |
LOG_MAX_FILES | log.max_files | Number of rotated log files |
LOG_DB_QUERIES | log.db_queries | Log SQL queries to storage/logs/query.log |
LOG_VALIDATION_DATA | log.validation_data | Log FormRequest validation payload (with masking) |
DB_DRIVER | db.driver | DB driver (mysql) |
DB_HOST | db.host | DB host |
DB_PORT | db.port | Port (in config file; connection core does not read it yet) |
DB_DATABASE | db.database | Database name |
DB_USERNAME | db.username | DB user |
DB_PASSWORD | db.password | DB password |
Override by APP_ENV
If the directory config/{APP_ENV value}/ exists, all PHP files from it are merged on top of
the base config/. File names and array structure are the same; only the required keys change.
In skeleton by default:
config/dev/app.php—app.debug = trueconfig/dev/telemetry.php—telemetry.enabled = trueconfig/production/app.php—app.debug = falseconfig/*/components.php— component registration per environment
config/
├── app.php
├── telemetry.php
├── dev/
│ ├── app.php
│ ├── telemetry.php
│ └── components.php
└── production/
├── app.php
└── components.php
config/ files
Each file returns an array; the root key usually matches the file name (without .php).
app.php
| Key | Type | Default | Purpose |
|---|---|---|---|
app.name | string | App | Application name (console, logs) |
app.version | string | 1.0.0 | Application version in Symfony Console |
app.timezone | string | UTC | PHP timezone (date_default_timezone_set) |
app.env | string | — | Environment from APP_ENV (loading step 4); determines config/{APP_ENV}/ |
app.locale | string | en | Application locale |
app.fallback_locale | string | en | Fallback for validator translations |
app.locale_resolver | class-string|null | null | Custom LocaleResolverInterface |
app.debug | bool | false | Whoops (web), Twig cache off, Valinor FileWatchingCache |
db.php
| Key | Type | Purpose |
|---|---|---|
db.driver | string | Illuminate DB driver |
db.host | string | Host |
db.port | string | Port (reserved in config) |
db.database | string | Database |
db.username | string | User |
db.password | string | Password |
db.charset | string | Encoding (utf8mb4) |
log.php
| Key | Type | Default | Purpose |
|---|---|---|---|
log.name | string | app | Monolog channel name |
log.level | string | ERROR | Minimum level (ERROR, debug…) |
log.max_files | int | 7 | Files on rotation (.env.example: 14) |
log.db_queries | bool | false | Log SQL via QueryLogger (ConfigKey::LOG_DB_QUERIES) |
log.validation_data | bool | false | Log validation data in FormRequest (with masking) |
session.php
PHP session parameters (SessionServiceProvider → Symfony HttpFoundation → session_start()).
Keys correspond to ConfigKey::SESSION_* constants.
| Key | Type | Default | Description |
|---|---|---|---|
session.cookie_lifetime | int | 0 | Cookie lifetime (0 — until browser closes) |
session.cookie_path | string | / | Cookie path |
session.cookie_secure | bool | false | HTTPS only |
session.cookie_httponly | bool | true | HttpOnly |
session.use_only_cookies | bool | true | No session id in URL |
session.cookie_domain | string | '' | Cookie domain (SESSION_COOKIE_DOMAIN in .env) |
session.cookie_samesite | string | Lax | Lax, Strict, None (SESSION_COOKIE_SAMESITE) |
session.use_strict_mode | bool | true | Strict session id mode |
view.php
| Key | Type | Purpose |
|---|---|---|
view.default_extension | string | Template extension (.twig or .php for Plates) |
view.extensions | array<class-string> | Twig / Plates extension classes |
view.paths | array | Namespace → path from app root (frontend → resources/views/frontend) |
view.contexts | array | URL prefix → view namespace (/ → frontend) |
view.cache_dir | string | Subdirectory under storage/cache/ for compiled Twig |
routes.php
The routes key is a list of route files and route interceptors (see Routing, Route interceptors).
return [
'routes' => [
'interceptors' => [
// RouteInterceptorInterface::class,
],
'list' => [
dirname(__DIR__) . '/routes/web.php',
],
],
];
components.php
components is a list of FQCN classes implementing ComponentInterface.
The environment may have MyComponent::class => MyComponent::class —
the core iterates over array values. Components add routes, migration paths, seeders, views, and CLI commands via ComponentInterface methods.
return [
'components' => [
// AuthAdminComponent::class,
],
];
telemetry.php
| Key | Type | Purpose |
|---|---|---|
telemetry.enabled | bool | Master switch for TelemetryCollector (ConfigKey::TELEMETRY_ENABLED) |
telemetry.db_queries | bool | Record DB_QUERY_EXECUTED events (independent of log.db_queries) |
telemetry.logs | bool | Mirror Monolog records as LOG_RECORDED via TelemetryLogHandler |
masking.php
Masking sensitive data before writing to logs and debug panels.
Read by DataMaskerServiceProvider → DataMaskerInterface.
Full description — Data masking.
| Key | ConfigKey | Purpose |
|---|---|---|
masking.patterns | MASKING_PATTERNS | Array of regex → replacement for strings (RegexDataMaskerRule::apply) |
masking.key_patterns | MASKING_KEY_PATTERNS | Regex for key names in arrays (password, token…) |
masking.rules | MASKING_RULES | List of DataMaskerRuleInterface classes (DI) |
// config/masking.php (skeleton fragment)
'masking' => [
'patterns' => [
'/[a-z0-9_\-\+\.]+@[a-z0-9\-]+\.[a-z]{2,}/i' => '***@***.***',
],
'key_patterns' => [
'/.*password.*/i',
'/.*token.*/i',
],
'rules' => [],
],
validator.php
validator.rules — custom validation rules (unique, exists, etc.).
caster.php
caster.transformers — list of custom transformer classes for Valinor DTO mapping.
Mapped to ConfigKey::CASTER_TRANSFORMERS.
pagination.php
pagination.per_page — convenient default for application code (in skeleton: 10).
The core does not read this key automatically; HttpServiceProvider only configures
Paginator::currentPageResolver and currentPathResolver for Illuminate Pagination.
migrations.php
| Key | Purpose |
|---|---|
migrations.table | Migration tracking table |
migrations.paths | Directories with migration classes |
seeders.php
seeders.list — array of seeder classes for db:seed (all at once).
Single seeder: db:seed -c "Fully\Qualified\SeederClass" — full FQCN required.
commands.php
commands — list of Symfony Console command classes from core and application.
Skeleton already registers route:list, db:migrate, view:clear, etc.
ConfigKey constants
Canonical keys read by the core are collected in
Concept\Core\Foundation\ConfigKey. In your own code, prefer these constants
over string literals:
use Concept\Core\Foundation\ConfigKey;
$debug = $config->getBool(ConfigKey::APP_DEBUG);
$routes = $config->get(ConfigKey::ROUTES_LIST, []);
Full list of constants — in source code code/core/src/Foundation/ConfigKey.php
and in the core README (Configuration section).
Access in code
Inject Concept\Core\Services\Config\Contracts\ConfigInterface:
public function __construct(
private readonly ConfigInterface $config,
) {}
$debug = $this->config->getBool('app.debug');
$name = $this->config->getString('app.name');
$routes = $this->config->get('routes', []);
Methods: get(), has(), set(), all(),
getString(), getInt(), getBool().
Development tips
- Locally set
APP_ENV=devandAPP_DEBUG=truein.env. - Secrets (passwords, API keys) — only in
.env, not inconfig/*.php. - Shared defaults — in
config/; environment differences — inconfig/dev/orconfig/production/. - For new environment variables, follow the
GROUP_NAME→group.nameconvention. - Clear Twig cache after template changes:
php bin/console.php view:clear.