majermi4/friendly-config

Provides a friendlier way to define Symfony configuration using plain old PHP objects.

v1.3.0 2022-10-26 15:10 UTC

README

Provides a friendlier way to define Symfony configuration using plain old PHP objects.

Latest Stable Version tests Coverage Status License: MIT

We love the Symfony configuration component! ❤️ It provides schema, validation, documentation and many more features to our bundle configs. However, many of us don't like defining it ... The goal of this project is to change that.

Documentation

  1. Motivation
    1. Code duplication
    2. Writing config definition manually is hard
    3. Negative impact on development and refactoring speed
  2. Usage
    1. Basics
    2. Simple types
    3. Nested types
    4. Other inferred configuration options
      1. Required
      2. Default value
      3. Info
  3. Limitations

Installation

This is installable via Composer as majermi4/friendly-config:

composer require majermi4/friendly-config

Basic usage:

Instead of having to write configuration such as this:

$rootNode
    ->children()
        ->arrayNode('connection')
            ->children()
                ->scalarNode('driver')
                    ->isRequired()
                    ->cannotBeEmpty()
                ->end()
                ->scalarNode('host')
                    ->defaultValue('localhost')
                ->end()
                ->scalarNode('username')->end()
                ->scalarNode('password')->end()
                ->booleanNode('memory')
                    ->defaultFalse()
                ->end()
            ->end()
        ->end()
        ->arrayNode('settings')
            ->addDefaultsIfNotSet()
            ->children()
                ->scalarNode('name')
                    ->isRequired()
                    ->cannotBeEmpty()
                    ->defaultValue('value')
                ->end()
            ->end()
        ->end()
    ->end()
;

Write plain old PHP objects such as:

class MyConfig
{
    public function __construct(Connection $connection, Settings $settings) { /* your code */ }
}

class Connection
{
    public function __construct(
        string $driver,
        string $username,
        string $password,
        string $host = 'localhost',
        bool $memory = false,
    ) { /* your code */ }
}

class Settings
{
    public function __construct(string $name = 'value') { /* your code */ }
}

The following few lines will convert your pure PHP objects into valid Symfony configuration that defines schema of your bundle configuration. On top of that, the processed configuration values are used to initialize your pure PHP objects, so you can easily access the processed values.

You can register the initialised config objects as services which will allow you to easily access the initialised config objects anywhere in your application.

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Majermi4\FriendlyConfig\FriendlyConfiguration;
use Majermi4\FriendlyConfig\InitializeConfigObject;
use Majermi4\FriendlyConfig\RegisterConfigService;

class MyBundleExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function getConfiguration(array $config, ContainerBuilder $container) : ConfigurationInterface
    {
        return FriendlyConfiguration::fromClass(MyConfig::class, 'my_config');
    }
    
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container): void
    {
        $configuration = $this->getConfiguration($configs, $container);
        $config = $this->processConfiguration($configuration, $configs);

        if ($configuration instanceof FriendlyConfiguration) {
            // Register config object with processed values as a service 
            RegisterConfigService::fromProcessedConfig($configuration->getConfigClass(), $config, $container);
    
            // Or ... initialise config object from processed config immediately if needed
            $initialisedConfig = InitializeConfigObject::fromProcessedConfig(MyConfig::class, $config);
        }        
    }
}