Last update: 09 Dec 2024

Config

Load configuration files the easy way. This configuration loader supports PHP, INI, JSON, XML, YAML and NEON file extensions.

Installation

To get started, install the config repository via the Composer package manager:

composer require zaphyr-org/config

Loading configuration files

There are several ways to load configuration files. We will take a closer look at these in the following.

Direct instantiation

The easiest way to load configuration files, is by direct instantiation:

new Zaphyr\Config\Config(['/config/path/file.yml']);

Via load() method

Another way is to include configuration files using the load() method:

$config = new Zaphyr\Config\Config();
$config->load(['/config/path/file.yml']);
Caution

Please do not include untrusted configuration files with php extension. It could contain and execute malicious code!

Loading configuration files from a directory

It is also possible to load complete configuration file directories. This can be done in two ways.

The easiest way to do this, is to pass the configuration directory path to the constructor:

$config = new Zaphyr\Config\Config(['./config/path']);

You can also use the load() method to load configuration file directories:

$config = new Zaphyr\Config\Config();
$config->load(['./config/path']);
Note

Files are parsed and loaded depending on the file extension. When loading a directory, the path is globed and files are loaded in by name alphabetically.

Available since v2.3.0

Since v2.3.0 it is also possible to load configuration files from a directory recursively. Let's say you have the following directory structure:

/config/path
    /subdir
        file.yml
        /subsubdir
            file.yml
    app.yml

You can load all configuration files from the /config/path directory recursively like this:

$config = new Zaphyr\Config\Config(['./config/path']);
// or
$config->load(['./config/path']);

The configuration files are now loaded as follows:

$config->get('app'); // app.yml
$config->get('subdir.file'); // subdir/file.yml
$config->get('subdir.subsubdir.file'); // subdir/subsubdir/file.yml

As you can see, the subdirectory name acts as the "namespace" for calling the configuration values.

Get configuration values

Getting configuration values can be done via the get() method.

Let's say you have an app.yml configuration file in your /config/path directory and the contents of your file looks like this:

# /config/path/app.yml
name: "My awesome app"

Now you load the configuration file as described above and use the get() method to get the name of your application:

$config = new Zaphyr\Config\Config(['/config/path']);
$config->get('app.name'); // My awesome app

As you can see, the name of the configuration file, in your example app.yml, acts as the "namespace" for calling the configuration value.

The get() method also provides the ability to pass default values if a variable is not present in your configuration files. To do this, simply pass a second parameter to the get() method:

$config->get('app.version', '1.0.0'); // 1.0.0

If a configuration value could not be found, the get() method automatically returns null.

Determine whether a configuration value exists

If you want to know if a configuration value exists, just use the has() method:

$config->has('app.name'); // true

Get all configuration values

You might also want to get all available configuration values as an array. This is possible with the getItems() method:

$config->getItems(); // ['app' => 'name']

Configuration value replacers

You might want to store critical data, such as your database credentials, in your configuration files. It would be fatal to write this directly into the configuration file and then commit it to your Git instance, for example. So you put your critical credentials in a .env file and exclude them from your git commits. This repository now offers you a way to access stored env values within your configuration file.

Let's imagine a scenario where your database credentials are stored in a .env file somewhere in your project:

DB_USER=user
DB_PASS=secret

Now you want to access the env values in your database.yml inside your /config/path directory. This works as follows:

# /config/path/database.yml
mysql:
  user: '%env:DB_USER%'
  password: '%env:DB_PASS%'

With the indicators % and the keyword env: the configuration loader knows to use a replacer. In this case the Zaphyr\Config\Replacers\EnvReplacer. The corresponding replacer now takes over the resolution of your env value for you.

Create a custom replacer

You may also want to use your own replacers in your configuration files. This is also possible and is described below.

First you should create your own replacer class, which implements the Zaphyr\Config\Contracts\ReplacerInterface and includes the replace method:

class MySuperCustomReplacer implements Zaphyr\Config\Contracts\ReplacerInterface
{
    /**
     * {@inheritdoc}
     */
    public function replace(string $value): string
    {
        // Your custom replacer logic
    }
}

Now you need to pass your previously created replacer in the constructor of your Zaphyr\Config\Config instance:

$replacers = ['custom' => MySuperCustomReplacer::class];

$config = new Zaphyr\Config\Config(['/config/paths'], null, $replacers);

Alternatively, you can also pass your own replacer to the addReplacer() method:

$config->addReplacer('custom', MySuperCustomReplacer::class);

You can now use your custom replacer in your configuration files:

config: '%custom:value%'
Note

New replacer instances must always be added before the first use of the load() method. Otherwise, the load() method throws an error because it does not yet know the new replacer!

Custom configuration readers

Even if this repository is already equipped with a lot of configurations file extension readers, it is still possible to create your custom configuration readers. To do this, proceed as follows.

First you should create your own reader instance, which implements the Zaphyr\Config\Contracts\ReaderInterface and contains a read method:

class MySuperCustomReader implements Zaphyr\Config\Contracts\ReaderInterface
{
    /**
     * {@inheritdoc}
     */
    public function read(): array
    {
        // Your custom reader logic
    }
}

Secondly, you register your custom reader in the config class:

$readers = ['custom' => MySuperCustomReader::class];

$config = new Zaphyr\Config\Config(['/config/paths'], $readers);

Alternatively, you can also use the addReader() method:

$config->addReader('custom', MySuperCustomReader::class);

Now you can use configuration files with your own file extension.

Note

New reader instances must always be added before the first use of the load() method. Otherwise, the load() method throws an error because it does not yet know the new reader!

Dependency Injection

Available since v2.2.0

The config repository supports dependency injection, by using any PSR-11 compatible DI container. The PSR-11 container instance can be set using the setContainer method:

$container = new Container();
$container->set(ServiceInterface::class, new Service());

$config->setContainer($container);

Now your constructor parameters for custom readers or replacers are automatically resolved by the DI container:

class MySuperCustomReplacer implements Zaphyr\Config\Contracts\ReplacerInterface
{
    /**
     * @var ServiceInterface
     */
     public function __construct(ServiceInterface $service)
     {
     }

    /**
     * {@inheritdoc}
     */
    public function replace(string $value): string
    {
        // Your custom replacer logic
    }
}
Note

This repository does NOT come with a PSR-11 implementation out of the box. For a PSR-11 implementation, check out the Container repository.