Configuration Management
Orkestra provides a robust configuration system that allows you to define, validate, and manage application settings. This guide covers all aspects of the configuration system.
Configuration Basics
The Configuration
class is the central component of Orkestra's configuration system:
use Orkestra\Configuration;
// Create a new configuration instance
$config = new Configuration([
'key' => 'value',
'anotherKey' => 'anotherValue'
]);
Setting and Getting Values
// Set a value
$config->set('key', 'value');
// Get a value
$value = $config->get('key'); // Returns 'value'
// Check if a key exists
if ($config->has('key')) {
// Key exists
}
Configuration Definitions
Definitions provide structure and documentation for your configuration values:
$config = new Configuration([
'definition' => [
'db_host' => ['Database hostname', 'localhost'],
'db_port' => ['Database port', 3306],
'api_key' => ['API key for external service', null], // Required value
]
]);
Each definition consists of:
- A descriptive label explaining the purpose of the configuration
- A default value (or
null
for required values)
Important: Orkestra's current implementation only supports flat configuration definitions. Nested definitions (definitions for nested arrays or objects) are not directly supported.
Accessing Default Values
When retrieving a value, if the key doesn't exist but has a definition with a default, the default is returned:
// Even if 'db_host' isn't explicitly set, it will return 'localhost'
$dbHost = $config->get('db_host');
Required Values
If a configuration key is defined with a null
default, it's considered required. Attempting to retrieve a required value without setting it first will throw an exception:
// This will throw an InvalidArgumentException if 'api_key' isn't set
$apiKey = $config->get('api_key');
Working with Complex Values
While definitions are flat, the configuration values themselves can be complex objects or arrays:
// Set a complex value
$config->set('database', [
'host' => 'localhost',
'port' => 3306,
'credentials' => [
'username' => 'user',
'password' => 'password'
]
]);
// Get the complex value
$database = $config->get('database');
$host = $database['host'];
$username = $database['credentials']['username'];
To define and validate complex values, use a flat definition with a validation function:
$config = new Configuration([
'definition' => [
'database' => ['Database configuration', []], // Default is empty array
],
'validation' => [
'database' => function ($value) {
// Validate database configuration
if (!is_array($value)) return false;
// Check required fields
if (!isset($value['host']) || !isset($value['credentials'])) {
return false;
}
// Check credentials
if (!isset($value['credentials']['username']) ||
!isset($value['credentials']['password'])) {
return false;
}
return true;
}
]
]);
Configuration Validation
Orkestra's configuration system includes powerful validation capabilities:
$config = new Configuration([
'db_port' => 3306,
'definition' => [
'db_port' => ['Database port', 3306],
],
'validation' => [
'db_port' => fn ($value) => is_int($value) && $value > 0,
]
]);
// Validates all configuration values
$config->validate(); // Returns true if all validations pass
Custom Validators
You can define custom validation functions for your configuration values:
$config = new Configuration([]);
$config->set('validation', [
'api_url' => function ($value) {
return filter_var($value, FILTER_VALIDATE_URL) !== false;
},
'email' => function ($value) {
return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
}
]);
$config->set('api_url', 'https://api.example.com');
$config->set('email', 'user@example.com');
$config->validate(); // Returns true
Validation on Boot
Configuration validation typically happens during the application boot process:
// In a service provider
public function register(App $app): void
{
$app->config()->set('api_key', '1234567890');
}
// In App::boot()
$app->config()->validate(); // Will throw if any validations fail
Advanced Configuration Patterns
Environment-Specific Configuration
You can load different configuration values based on the environment:
$env = $_ENV['APP_ENV'] ?? 'development';
// Load base config
$config = new Configuration([
// Common configuration
]);
// Load environment-specific config
$envConfig = require "config/{$env}.php";
foreach ($envConfig as $key => $value) {
$config->set($key, $value);
}
Organization of Complex Configuration
Since nested definitions aren't supported, it's recommended to organize complex configurations using distinct top-level keys:
// Instead of nested definitions for database configuration
// Use separate keys for different components
// config/database.php
return [
'db_driver' => $_ENV['DB_DRIVER'] ?? 'mysql',
'db_host' => $_ENV['DB_HOST'] ?? 'localhost',
'db_port' => (int)($_ENV['DB_PORT'] ?? 3306),
'db_name' => $_ENV['DB_NAME'],
'db_user' => $_ENV['DB_USER'],
'db_password' => $_ENV['DB_PASSWORD'],
];
// In bootstrap file
$app->config()->set('database', require __DIR__ . '/config/database.php');
// Define validation for the entire database config
$app->config()->set('validation', [
'database' => function ($value) {
return isset($value['db_host']) && isset($value['db_name']);
}
]);
// Or use an array of values for more complex structures
$app->config()->set('services', [
'email' => [
'driver' => 'smtp',
'host' => 'smtp.example.com'
],
'payment' => [
'provider' => 'stripe',
'key' => 'sk_test_123'
]
]);
Common Error Cases and Troubleshooting
Undefined Configuration Keys
Attempting to get an undefined configuration key will throw an exception:
$config = new Configuration([]);
$config->get('undefinedKey'); // Throws InvalidArgumentException
Solution: Always check if a key exists before attempting to get its value:
if ($config->has('key')) {
$value = $config->get('key');
}
Invalid Validation Handlers
Setting invalid validation handlers will throw an exception:
$config = new Configuration([]);
// These will all throw InvalidArgumentException
$config->set('validation', 'invalidValidator');
$config->set('validation', ['key' => 'invalidValidator']);
$config->set('validation', [fn () => true]); // Missing key
Solution: Ensure validation handlers are arrays of key-function pairs:
$config->set('validation', [
'key' => fn ($value) => true // Valid validator
]);
Invalid Definitions
Setting invalid definitions will throw an exception:
$config = new Configuration([]);
// These will all throw InvalidArgumentException
$config->set('definition', 'invalidDefinition');
$config->set('definition', ['key' => []]); // Empty definition
$config->set('definition', ['key' => ['description', 'default', 'extraValue']]); // Too many elements
Solution: Ensure definitions follow the correct format:
$config->set('definition', [
'key' => ['Description', 'default'] // Valid definition
]);
Best Practices
-
Use Descriptive Keys: Use descriptive keys that indicate both the category and the specific setting (e.g.,
db_host
instead of justhost
). -
Validate Critical Values: Use validation for all critical configuration values to catch issues early.
-
Group Related Settings: Use arrays for complex values but keep the definitions at the top level.
-
Use Environment Variables: Load sensitive values from environment variables or secrets managers rather than hardcoding them.
-
Document Validation Rules: Include clear documentation about validation rules in your definitions.
Related Topics
- Application Lifecycle - How configuration integrates into the application lifecycle