Configuration

_Global

All global configuration values are static properties of the _Global class, which extends BaseGlobal.

<?php
// application/_Global.php
use _Flexagon\Base\BaseGlobal;

class _Global extends BaseGlobal {
    // Add application-specific globals here
    public static ?\Session\SessionUserModel $SESSION_USER_MODEL = null;
}

Key configuration options:

Property Default Description
$SITE_TITLE 'Flexagon' Site title
$TIMEZONE 'Asia/Seoul' Passed to date_default_timezone_set()
$DATA_SOURCES [] Data-source map (see below)
$DATA_SOURCE_ID 'default' Default data-source ID
$USE_COMPOSER true vendor/autoload.php auto-load
$USE_OUTPUT_BUFFER true Wrap the entire request with ob_start()
$DB_STATEMENT_CACHE_SIZE 64 Number of prepared statements cached per connection. 0 prepares every time
$DB_CONNECT_FAILURE_FATAL true Throw _Flexagon\DB\ConnectionException on DB connection failure (from the DAO constructor). If false, connect() returns false
$ENABLE_EXTENSION_PHP false If true, URLs must explicitly include .php
$USE_AUTO_CREATED_AT_TIMESTAMP true @db_auto_timestamp insert automatic timestamping
$USE_AUTO_UPDATED_AT_TIMESTAMP true @db_auto_timestamp update automatic timestamping
$RUNNING_MODE FLEXAGON_CONST::RUNNING_MODE_PRODUCTION Runtime mode. The framework does not interpret this value; applications may use it for branching
$DEBUG_ON false Debug flag for application use
$DEBUG_QUERY_BREAKPOINT false after each query Mysql::debugQueryAfter() call (for debugger breakpoints)
$SITE_CONFIG['web']['header'] — HTTP headers added to every response
$SESSION_AUTO_START false Restore session automatically during bootstrap
$SESSION_NAME 'session_data' Session cookie name
$SESSION_DOMAIN '' Cookie domain (.example.com)
$SESSION_COOKIE_SECURE null Cookie Secure flag. null enables it automatically for HTTPS requests
$SESSION_COOKIE_HTTPONLY true Cookie HttpOnly flag
$SESSION_COOKIE_SAMESITE 'Lax' 'Lax' · 'Strict' · 'None'. 'None'automatically enables Secure
$SESSION_MODEL_CLASSES [] Classes allowed in session cookies. If empty, only BaseModel inheritance is checked
$SESSION_TIMEOUT_SECONDS 86400 Session lifetime (seconds)
$SESSION_REQUIRE_EXPIRY false Reject legacy cookies without exp. Set to true after the migration period
$SESSION_NOT_BEFORE 0 Invalidate all sessions issued before this timestamp (stateless forced logout)
$SESSION_ENCRYPTION_STRING '' Session encryption key (10characters or more)
$CLASS_PROPERTY_ENCRYPTION_PASSPHRASE '' @encrypt property encryption key (10characters or more)

Data Sources

new DataSourceModel(
    string $host,
    int    $port,
    string $username,
    string $password,
    string $dbName,
    ?string $charset = 'utf8mb4',
    ?bool   $usePrepareStatement = true,
    array   $pdoOptions = []
);

You can register multiple data sources.

_Global::$DATA_SOURCES['default']   = new DataSourceModel('db-master', 3306, 'app', '****', 'service');
_Global::$DATA_SOURCES['analytics'] = new DataSourceModel('db-replica', 3306, 'ro',  '****', 'stats');

Each data source receives a unique ID based on sha1(username@host/dbName), and DataSourceManager reuses connections by that ID. Multiple DAOs pointing to the same database therefore share a single connection within the request.

pdoOptions is passed to new PDO() as is. It is where values the framework does not set go: TLS, timeouts and the like. The options the driver depends on (error mode, fetch mode, emulated prepares, connection charset) are the driver's and win.

// MySQL that requires TLS (RDS, Azure, PlanetScale and others)
_Global::$DATA_SOURCES['default'] = new DataSourceModel(
    Env::get('DB_HOST'), Env::int('DB_PORT', 3306), Env::get('DB_USER'), Env::get('DB_PASSWORD'), Env::get('DB_NAME'),
    pdoOptions: [PDO::MYSQL_ATTR_SSL_CA => '/etc/ssl/certs/rds-ca.pem'],
);

Without an SSL option, MySQL connects in plain text even when the server offers TLS, and a server that requires TLS refuses the connection. With a CA, the certificate and host name are verified. PostgreSQL defaults to sslmode=prefer: TLS when the server offers it, but the certificate is not verified. To verify it, set the environment variables PGSSLMODE=verify-full and PGSSLROOTCERT=/path/ca.pem (read by libpq).

Stage-specific Configuration

Place stage-specific configuration in application/_Config/<stage>/_Config.php and select it from the CLI with the runtimeStage argument.

php script/batch.php runtimeStage=production

The default stage directories are alpha, beta, and production. A Docker image built with the target of the same name (--target production and so on) gets that stage directory's files copied into application/ (see Docker). To deploy without containers, ant production (or alpha, beta) builds what goes on the server in build/deploy/<stage>: secret and development files left out, the stage's files copied over, and vendor/ installed from composer.lock with --no-dev. How a stage is applied, and how to keep secrets apart with Env, is written up in application/_Config/README.md.