Framework
Introduction

Config Files

Beyond the environment, your app is wired up with PHP *.config.php files that register access roles, settings, file paths, languages and migrations. The build collects the registrations and generates typed code from them.

How they load

Any file whose name ends in .config.php is discovered and included from your app at startup — the vendor directory is skipped and the location otherwise does not matter, so a config/ folder is only a convention. The framework ships an example of each file: copy the ones you need into your app and extend them. Register nothing and the framework falls back to its own defaults.

By convention they live together in a config/ folder — one file per concern:

config/
├── Access.config.php            # access roles
├── Settings.config.php          # typed settings
├── File.config.php              # extra storage paths
├── Intl.config.php              # languages & copy dirs
├── Migration.config.php         # migrations folder & last applied
├── MigrationTables.config.php   # table renames
└── MigrationColumns.config.php  # column renames
Config that feeds generated code — access roles and settings especially — takes effect after the next ./framework build.

Access roles

Register the access levels your app uses and group them:

config/Access.config.php
use Framework\Core\AccessRole;

AccessRole::register("General", "General");
AccessRole::register("Admin", "Admin");
AccessRole::register("API", "API");

If you provide no Access.config.php at all, the framework falls back to exactly this configuration — so the General, Admin and API roles always exist. The build turns whichever roles are registered into a typed Access enum — see how it is generated and how routes use it in Authentication.

Settings

Declare typed settings; the build generates a typed getter for each and a migration stores them in the database. See Settings for the types, storage and generated class.

config/Settings.config.php
use Framework\Core\SettingConfig;
use Framework\Core\VariableType;

SettingConfig::register("siteName", "General", VariableType::String);
SettingConfig::register("maxItems", "General", VariableType::Integer);

File paths

Register extra storage paths and sub-directories on top of the built-in ones (source, thumbs, avatars, temp). The build generates a typed Path class for them, and the directories can be created by a migration. See Files & Storage.

config/File.config.php
use Framework\File\FilePath;

FilePath::register("exports");
FilePath::registerDirectory("archive");

Languages

Set the default language and point the internationalization layer at your copy directories — strings, emails and notifications, each holding one JSON file per language:

config/Intl.config.php
use Framework\Intl\IntlConfig;

IntlConfig::setDefaultLanguage("en");
IntlConfig::setStringsDir("nls/strings");
IntlConfig::setEmailsDir("nls/emails");
IntlConfig::setNotificationsDir("nls/notifications");

Each directory holds one JSON file per language, named by its code (en.json, es.json). The framework loads the file that matches the active language and falls back to the default you set above — so a typical nls/ tree looks like this:

nls/
├── strings/         # UI strings, one file per language
│   ├── en.json
│   └── es.json
├── emails/          # email copy, loaded per language
│   ├── en.json
│   └── es.json
└── notifications/   # notification copy, per language
    ├── en.json
    └── es.json

Migrations

The migration config is split across three files. The main one points the runner at your migrations folder and, when adopting it on an existing database, sets the last migration already applied:

config/Migration.config.php
use Framework\Database\Migration;

Migration::setPath("migrations");
Migration::setLastApplied("2024_01_initial");

A second file lists the table renames and a third the column renames. Both run before the schema is synced, so the sync matches your models against the new names instead of dropping and recreating. Table names may be snake_case or PascalCase, ID columns SNAKE_CASE:

config/MigrationTables.config.php
use Framework\Database\Migration;

Migration::renameTable("old_table", "new_table");
Migration::renameTable("Client", "Customer");
config/MigrationColumns.config.php
use Framework\Database\Migration;

Migration::renameColumn("TableName", "oldColumn", "newColumn");
Migration::renameColumn("Customer", "CLIENT_ID", "CUSTOMER_ID");