System Configuration

Before loading Resonance, your application should set a few PHP constants, preferably in the autoloaded file. Those constants are more system-related than application-related. They define hard-coded values that should not be changed in the app configuration maliciously or by accident.

The application loads those constants before it parses any other configuration file.

Those are the required constants:

<?php // Root directory of your application define('DM_APP_ROOT', __DIR__.'/app'); // Root directory of the Resonance framework define('DM_RESONANCE_ROOT', __DIR__.'/vendor/distantmagic/resonance'); // Directory with publicly accessible files (like assets, images etc) define('DM_PUBLIC_ROOT', __DIR__.'/public'); // Project root directory define('DM_ROOT', __DIR__); // Coroutine timeouts define('DM_BATCH_PROMISE_TIMEOUT', 0.3); define('DM_GRAPHQL_PROMISE_TIMEOUT', 0.2); define('DM_POOL_CONNECTION_TIMEOUT', 0.1);
{ "require": {}, "autoload": { "files": [ "constants.php" ] } }

You should never use constants.php to handle application-specific (domain specific) configuration variables (like the database connection parameters or such).

Application Configuration

You can configure Resonance's services by editing the config.ini file. Each section contains a configuration for a specific service.

Default Configuration

Sections are lazy-loaded and will only be loaded and validated if your code uses a specific feature. For example, if your application does not use Sessions (and does not use Redis anywhere else), then the [redis] section won't be loaded.

This is the default configuration file:

[app] env = development esbuild_metafile = %DM_ROOT%/esbuild-meta-app.json scheme = https url = http://localhost:9501 [database] default[driver] = mysql default[host] = default[port] = 3306 default[database] = distantmagic default[username] = distantmagic default[password] = distantmagic default[log_queries] = false default[pool_prefill] = false default[pool_size] = 8 [grpc] grpc_php_plugin_bin = %DM_ROOT%/grpc_php_plugin protoc_bin = /usr/bin/protoc [llamacpp] host = port = 8081 [mailer] default[transport_dsn] = smtp://localhost ; default[dkim_domain_name] = ; default[dkim_selector] = resonance1 ; default[dkim_signing_key_passphrase] = yourpassphrase ; default[dkim_signing_key_private] = dkim/private.key ; default[dkim_signing_key_public] = dkim/public.key [manifest] background_color = "#ffffff" theme_color = "#ffffff" [oauth2] encryption_key = %DM_ROOT%/oauth2/defuse.key jwt_signing_key_passphrase = yourpassphrase jwt_signing_key_private = %DM_ROOT%/oauth2/private.key jwt_signing_key_public = %DM_ROOT%/oauth2/public.key session_key_authorization_request = oauth2.authorization_request session_key_pkce = oauth2.pkce session_key_state = oauth2.state [openapi] description = description title = title version = 0.0.0 [redis] default[db_index] = 0 default[host] = default[password] = null default[port] = 6379 default[prefix] = dm: default[timeout] = 1 default[pool_prefill] = false default[pool_size] = 8 [session] cookie_lifespan = 86400 cookie_name = dmsession redis_connection_pool = default [sqlite-vss] extension_vector0 = %DM_ROOT%/ extension_vss0 = %DM_ROOT%/ [static] base_url = esbuild_metafile = %DM_ROOT%/esbuild-meta-docs.json input_directory = docs output_directory = %DM_ROOT%/docs/build sitemap = %DM_ROOT%/docs/build/sitemap.xml [swoole] host = port = 9501 log_level = SWOOLE_LOG_DEBUG ssl_cert_file = %DM_ROOT%/ssl/origin.crt ssl_key_file = %DM_ROOT%/ssl/origin.key [translator] base_directory = %DM_APP_ROOT%/lang default_primary_language = en [websocket] max_connections = 10000

Environment Variables

You can follow the parse_ini_file interpolation rules. For example:

; Interpolate the PATH environment variable path = ${PATH}

File Paths

For the sake of consistency, all file paths in the configuration file are absolute.

Interpolatable Constants

You can use DM_APP_ROOT, DM_PUBLIC_ROOT, DM_RESONANCE_ROOT and DM_ROOT constants in your configuration file by inserting them with %% delimiters, for example: %DM_APP_ROOT%.

Configuration Providers

You can extend config.ini by adding your configuration sections. Let's say you want to add a new [manifest] section that configures some values that the Web App Manifest will use.

For your config file to be able to have a section like this:

; ... [manifest] background_color = "#000000" theme_color = "#000000" ; ...

First, you need to define your configuration model:

<?php namespace App; readonly class ManifestConfiguration { public function __construct( public string $backgroundColor, public string $themeColor, ) {} }

Then you need to define the configuration provider. Constraints schema is used for config validation:

<?php namespace App\SingletonProvider\ConfigurationProvider; use App\ManifestConfiguration; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\Constraint; use Distantmagic\Resonance\Constraint\ObjectConstraint; use Distantmagic\Resonance\Constraint\StringConstraint; use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider; /** * @template-extends ConfigurationProvider<ManifestConfiguration, array{ * background_color: string, * theme_color: string, * }> */ #[Singleton(provides: ManifestConfiguration::class)] final readonly class ManifestConfigurationProvider extends ConfigurationProvider { public function getConstraint(): Constraint { return new ObjectConstraint( properties: [ 'background_color' => new StringConstraint(), 'theme_color' => new StringConstraint(), ], ); } protected function getConfigurationKey(): string { return 'manifest'; } protected function provideConfiguration($validatedData): ManifestConfiguration { return new ManifestConfiguration( backgroundColor: $validatedData['background_color'], themeColor: $validatedData['theme_color'], ); } }

Then you can use your configuration file in other services, for example:

<?php namespace App\HttpResponder; use App\HttpRouteSymbol; use App\ManifestConfiguration; use Distantmagic\Resonance\Attribute\RespondsToHttp; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\ContentType; use Distantmagic\Resonance\HttpResponder; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\RequestMethod; use Distantmagic\Resonance\SingletonCollection; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; #[RespondsToHttp( method: RequestMethod::GET, pattern: '/manifest.webmanifest', routeSymbol: HttpRouteSymbol::Manifest, )] #[Singleton(collection: SingletonCollection::HttpResponder)] final readonly class Manifest extends HttpResponder { private string $manifest; public function __construct(ManifestConfiguration $manifestConfiguration) { $this->manifest = json_encode([ 'background_color' => $manifestConfiguration->backgroundColor, 'display' => 'standalone', 'id' => '/?source=pwa', 'name' => 'Resonance', 'scope' => '/', 'short_name' => 'Resonance', 'start_url' => '/?source=pwa', 'theme_color' => $manifestConfiguration->themeColor, ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } public function respond( ServerRequestInterface $request, ResponseInterface $response, ): ResponseInterface { return $response ->withHeader('content-type', ContentType::ApplicationJson->value) ->withBody($this->createStream($this->manifest)) ; } }

This configuration is going to be loaded only if the ManifestConfiguration is used as a constructor parameter in a Singleton. See more at Dependency Injection.

Edit on GitHub