Configuration

Preflow uses a combination of environment variables and PHP config files. All configuration lives in the config/ directory and .env at the project root.

Environment Variables

The .env file holds environment-specific values that should not be committed to version control. The skeleton ships a .env.example as a template.

APP_NAME=MyApp
APP_DEBUG=1
APP_KEY=base64:your-random-key-here
APP_ENGINE=twig
APP_URL=http://localhost:8080

DB_PATH=storage/data/database.sqlite

Access environment variables anywhere via getenv() or the #[Env] attribute:

use Preflow\Core\Container\Attributes\Env;

final class Mailer
{
    public function __construct(
        #[Env('MAIL_HOST')]
        private string $host,

        #[Env('MAIL_PORT', default: '587')]
        private string $port,
    ) {}
}

APP_KEY Generation

The APP_KEY is used for HMAC token signing (component actions, CSRF). Generate one with the CLI:

php preflow key:generate

This writes a random base64-encoded key to your .env file. Never share or commit this value.

Config Files

Configuration files return plain PHP arrays. Access values anywhere using dot notation via the Config service or the #[Config] attribute.

config/app.php

Core application settings:

return [
    'name'     => getenv('APP_NAME') ?: 'Preflow',
    'debug'    => (int) getenv('APP_DEBUG'),
    'timezone' => 'UTC',
    'locale'   => 'en',
    'engine'   => getenv('APP_ENGINE') ?: 'twig',
    'url'      => getenv('APP_URL') ?: 'http://localhost:8080',
];

config/data.php

Storage drivers and database paths:

return [
    'default' => 'sqlite',
    'drivers' => [
        'json' => [
            'path' => __DIR__ . '/../storage/data',
        ],
        'sqlite' => [
            'path' => __DIR__ . '/../' . (getenv('DB_PATH') ?: 'storage/data/database.sqlite'),
        ],
    ],
];

config/middleware.php

Global middleware stack (executed on every request):

return [
    Preflow\I18n\LocaleMiddleware::class,
];

config/providers.php

Service providers to register at boot time:

return [
    App\Providers\AppServiceProvider::class,
];

Accessing Config Values

Use dot notation to read nested values:

use Preflow\Core\Container\Attributes\Config;

final class BlogService
{
    public function __construct(
        #[Config('app.name')]
        private string $appName,

        #[Config('data.default', default: 'json')]
        private string $defaultDriver,
    ) {}
}

Or use the Config instance directly:

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

$config->get('app.name');             // 'Preflow'
$config->get('app.missing', 'fallback'); // 'fallback'
$config->has('data.drivers.sqlite');  // true

Debug Modes

The APP_DEBUG environment variable controls error display:

Value Mode Behavior
0 Production Minimal error pages, no stack traces
1 Development Rich HTML error pages with stack traces and request details
2 Verbose Development mode plus detailed query logging and timing

Set APP_DEBUG=0 in production. The error handler automatically switches between a developer-friendly renderer (with file paths, stack traces, and context) and a safe production page that reveals nothing to end users.