Application Configuration

Rhapsody keeps all configuration in the config/ directory and the .env file. You should never modify files inside the /vendor directory. This ensures that framework updates won't overwrite your customisations. Rhapsody is built with extensibility in mind; consult the documentation to learn how to extend or create custom functionality.

Configuration Files

  • .env – environment‑specific variables (database, mail, caching driver, etc.).
  • config.php – general settings (middleware, theme, logging paths, etc.).

Golden Rule: If you need to change behaviour, look for a configuration file first. Only extend or replace classes – never edit core files directly.

Adding New Configuration

You can create additional config files in the config/ folder and load them in your controllers or services as needed. This is useful for tasks like defining constants or paths, or for custom modules you create. Your custom config files will never be touched when updating the framework.


Environment Variables (.env)

The .env file contains sensitive or environment‑specific data. Never commit it to version control. Use .env.example as a template.

Reading Environment Values

Environment variables are always strings, and PHP types $_ENV loosely. The Rhapsody\Core\Support\Env class reads a variable and converts it to the type you want, falling back to a default when the variable is unset (or can't be converted):

use Rhapsody\Core\Support\Env;

$name    = Env::string('APP_NAME', 'Rhapsody');   // string
$timeout = Env::int('GEMINI_TIMEOUT', 60);        // int; non-numeric values fall back to the default
$debug   = Env::bool('APP_DEBUG', false);         // bool
$raw     = Env::get('SOME_KEY');                  // ?string, null when unset

Env::bool() treats true, 1, yes and on as true, and false, 0, no and off as false (case-insensitive). Any other value returns the default.


Reading Config Values

Values from config.php can be read through Rhapsody\Core\Support\Config, a typed reader with dot notation. It does for the config array what Env does for environment variables, with one big difference: it fails loudly. A missing key or a value of the wrong type throws a RuntimeException at the point of use, instead of letting a bad value travel through your code.

use Rhapsody\Core\Support\Config;

$config = $container->get(Config::class);

$host  = $config->string('mail.host');          // throws if 'mail.host' is missing
$port  = $config->int('mail.port', 587);        // 587 when the key is missing
$debug = $config->bool('app.debug', false);
$items = $config->array('cache.stores', []);

$raw = $config->get('app.name', 'Rhapsody');    // any type; the default when missing

if ($config->has('mail.host')) {
    // the key exists
}

The keys above are examples; use the keys defined in your own config.php.

Dot Notation

'mail.host' reads $config['mail']['host'], and you can go as deep as your config array does. An exact top-level key is tried first, so a key that literally contains a dot still works.

Typed Getters

Method Accepts Missing key
string($key, $default = null)Strings, ints and floatsThrows, unless you pass a default
int($key, $default = null)Ints and whole-number strings such as '587'Throws, unless you pass a default
bool($key, $default = null)Bools, and the values true, false, 1, 0, on, off, yes, noThrows, unless you pass a default
array($key, $default = null)ArraysThrows, unless you pass a default
get($key, $default = null)Anything (no type check)Returns the default
has($key)Returns true if the key exists, even when its value is nullReturns false
all()Returns the whole config array–

Because config values often come from .env (where everything is a string), the scalar getters are forgiving about format: '587' reads as the integer 587, and 'true' or 'on' reads as true. A value of null counts as missing for the typed getters, so the default applies, or they throw if you gave none.

Errors

The exception messages name the key, so a misconfiguration is easy to track down:

Missing config key 'mail.host'.
Config key 'mail.port' must be int, string given.

Config, Env, or Request?

  • Config throws on a missing or wrongly-typed key, because a broken setting is a bug in your application.
  • Env falls back to the default you supply, so an unset variable is never fatal.
  • Request accessors (string(), int(), bool(), array()) also fall back to a default, because user input is expected to be messy. See The Request Object.

In tests you can build a reader directly from an array: new Config(['mail' => ['host' => 'smtp.test']]). More on these helpers is on the Support Helpers page.


View File Hierarchy & Theme System

Rhapsody uses Twig for templating. The framework looks for view files in a specific order, making it easy to override core templates or build custom themes.

Directory Structure

The default view directories are:

views/
├── themes/
│   ├── default/                ← Fallback theme (always available)
│   │   
│   └── my_custom_theme/        ← Your active theme (if set)
│       ├── layouts/
│       └── home/
└── vendor/arout/rhapsody-core/resources/views/themes/       ← Core framework views (default, but overridable.)
    ├── default/
    ├── docs/
    └── ...

Theme Resolution Order

When you render a view from your controller (e.g., $this->view('home/index.twig')), the framework searches in this order:

  1. Active theme – views/themes/modern/ ← this is what you currently have set in .env
  2. Default theme – views/themes/default/
  3. Core views – /vendor/arout/rhapsody-core/resources/views/themes/default/
Danger: - Never - modify or add view files in the /vendor directory. It is only listed above for informational purposes. Instead, if you want to use the framework's styling/theme, create a new `default` directory in /views/themes/ if it does not already exist.

If a template exists in your active theme, it is used. Otherwise, the framework falls back to the default theme, and finally to the core view. The application will throw a fatal error if it cannot find your template in one of the above directories.

Setting the Active Theme

Define the theme in your .env file:

APP_THEME=my_custom_theme

If not set, the default theme is used.

Overriding Core Templates

To override a core template (e.g., the main layout), simply create a file with the same path inside your active theme. For example, to override views/core/layouts/main.twig, create views/themes/my_custom_theme/layouts/main.twig.

You can also extend core templates using Twig’s {% extends %} tag with the @core namespace:

{% extends "@core/layouts/main.twig" %}

Custom View Namespaces

If you need additional view directories (e.g., for reusable modules), you can add them to the Twig loader in bootstrap.php:

$loader->addPath(__DIR__ . '/modules/blog/views', 'blog');

Then render a view using the namespace: $this->view('@blog/index.twig').

Error Pages

Custom error pages (404, 500, etc.) can be placed in themes/modern/errors/. The framework will automatically use the theme’s error template if it exists, falling back to the default theme.


Middleware Configuration

See the Middleware documentation for details on setting up middleware.


Cache Driver

Switch between file and redis drivers in .env:

CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379

Logging

Configure log paths in config.php under the logging key.