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
  1. Base config/ — all PHP files are merged with Noodlehaus Config.
  2. .env — loaded via vlucas/phpdotenv; APP_ENV determines the override folder.
  3. config/{APP_ENV}/ — if the directory exists (dev, production…), its files are merged on top of the base config.
  4. .env variables — written into config (highest priority).
  5. Timezonedate_default_timezone_set() from app.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_NAMEapp.nameApplication name (console, logs)
APP_TIMEZONEapp.timezonePHP timezone (Europe/Kyiv, UTC)
APP_ENVapp.envEnvironment: dev, production, etc.; determines override folder
APP_DEBUGapp.debugDebug mode: Whoops, Twig cache off, Valinor FileWatchingCache
LOG_LEVELlog.levelMonolog level: debug, info, error
LOG_MAX_FILESlog.max_filesNumber of rotated log files
LOG_DB_QUERIESlog.db_queriesLog SQL queries to storage/logs/query.log
LOG_VALIDATION_DATAlog.validation_dataLog FormRequest validation payload (with masking)
DB_DRIVERdb.driverDB driver (mysql)
DB_HOSTdb.hostDB host
DB_PORTdb.portPort (in config file; connection core does not read it yet)
DB_DATABASEdb.databaseDatabase name
DB_USERNAMEdb.usernameDB user
DB_PASSWORDdb.passwordDB 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.phpapp.debug = true
  • config/dev/telemetry.phptelemetry.enabled = true
  • config/production/app.phpapp.debug = false
  • config/*/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

KeyTypeDefaultPurpose
app.namestringAppApplication name (console, logs)
app.versionstring1.0.0Application version in Symfony Console
app.timezonestringUTCPHP timezone (date_default_timezone_set)
app.envstringEnvironment from APP_ENV (loading step 4); determines config/{APP_ENV}/
app.localestringenApplication locale
app.fallback_localestringenFallback for validator translations
app.locale_resolverclass-string|nullnullCustom LocaleResolverInterface
app.debugboolfalseWhoops (web), Twig cache off, Valinor FileWatchingCache

db.php

KeyTypePurpose
db.driverstringIlluminate DB driver
db.hoststringHost
db.portstringPort (reserved in config)
db.databasestringDatabase
db.usernamestringUser
db.passwordstringPassword
db.charsetstringEncoding (utf8mb4)

log.php

KeyTypeDefaultPurpose
log.namestringappMonolog channel name
log.levelstringERRORMinimum level (ERROR, debug…)
log.max_filesint7Files on rotation (.env.example: 14)
log.db_queriesboolfalseLog SQL via QueryLogger (ConfigKey::LOG_DB_QUERIES)
log.validation_databoolfalseLog validation data in FormRequest (with masking)

session.php

PHP session parameters (SessionServiceProvider → Symfony HttpFoundation → session_start()). Keys correspond to ConfigKey::SESSION_* constants.

KeyTypeDefaultDescription
session.cookie_lifetimeint0Cookie lifetime (0 — until browser closes)
session.cookie_pathstring/Cookie path
session.cookie_secureboolfalseHTTPS only
session.cookie_httponlybooltrueHttpOnly
session.use_only_cookiesbooltrueNo session id in URL
session.cookie_domainstring''Cookie domain (SESSION_COOKIE_DOMAIN in .env)
session.cookie_samesitestringLaxLax, Strict, None (SESSION_COOKIE_SAMESITE)
session.use_strict_modebooltrueStrict session id mode

view.php

KeyTypePurpose
view.default_extensionstringTemplate extension (.twig or .php for Plates)
view.extensionsarray<class-string>Twig / Plates extension classes
view.pathsarrayNamespace → path from app root (frontendresources/views/frontend)
view.contextsarrayURL prefix → view namespace (/frontend)
view.cache_dirstringSubdirectory 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

KeyTypePurpose
telemetry.enabledboolMaster switch for TelemetryCollector (ConfigKey::TELEMETRY_ENABLED)
telemetry.db_queriesboolRecord DB_QUERY_EXECUTED events (independent of log.db_queries)
telemetry.logsboolMirror Monolog records as LOG_RECORDED via TelemetryLogHandler

masking.php

Masking sensitive data before writing to logs and debug panels. Read by DataMaskerServiceProviderDataMaskerInterface. Full description — Data masking.

KeyConfigKeyPurpose
masking.patternsMASKING_PATTERNSArray of regex → replacement for strings (RegexDataMaskerRule::apply)
masking.key_patternsMASKING_KEY_PATTERNSRegex for key names in arrays (password, token…)
masking.rulesMASKING_RULESList 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

KeyPurpose
migrations.tableMigration tracking table
migrations.pathsDirectories 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=dev and APP_DEBUG=true in .env.
  • Secrets (passwords, API keys) — only in .env, not in config/*.php.
  • Shared defaults — in config/; environment differences — in config/dev/ or config/production/.
  • For new environment variables, follow the GROUP_NAMEgroup.name convention.
  • Clear Twig cache after template changes: php bin/console.php view:clear.