mnapoli / assembly

[EXPERIMENTAL] Implementation of container-interop/definition-interop
MIT License
7 stars 5 forks source link

Assembly

This repository is experimental

Assembly provides an implementation for definition-interop definitions as well as a compatible container.

Build Status

Installation

composer require mnapoli/assembly@dev

Usage

While you can implement Interop\Container\Definition\DefinitionProviderInterface and return an array of definition objects built manually, Assembly provides a natural API to create definitions more easily.

To take advantage of this, simply extend Assembly\ArrayDefinitionProvider and fill the getArrayDefinitions method:

class MyModuleDefinitionProvider extend \Assembly\ArrayDefinitionProvider
{
    public function getArrayDefinitions()
    {
        return [
            'logger.destination' => '/var/log/myapp.log',

            'logger' => \Assembly\object('MyLogger')
                ->setConstructorArguments('warning', \Assembly\get('logger.destination'))
                ->addMethodCall('setDebug', true),

            'super_mailer' => \Assembly\factory('MailerFactory', 'create'),

            'mailer' => \Assembly\get('super_mailer'),
        ];
    }
}

If you are using PHP 5.6 or above, you can import namespaced functions:

use function \Assembly\object;
use function \Assembly\get;

class MyModuleDefinitionProvider extend \Assembly\ArrayDefinitionProvider
{
    public function getArrayDefinitions()
    {
        return [
            'logger' => object(MyLogger::class),
            'logger_alias' => get('logger'),
        ];
    }
}

If you do not want to write a new class, you can also instantiate a new provider directly:

$provider = new ArrayDefinitionProvider([
    // add definitions here
]);

Definition classes

If you do not want to use the function helpers, you can also create definition instances directly.

ParameterDefinition

return [
    'db.port' => new ParameterDefinition(3306),
];

This definition will define a container entry "db.port". That means get('db.port') will return 3306.

Reference

return [
    'logger' => new Reference('monolog'),
];

This definition will alias the entry "logger" to the entry "monolog". That means that get('logger') will return the result of get('monolog').

ObjectDefinition

$definition = new ObjectDefinition('PDO');
$definition->addConstructorArgument('mysql:host=localhost;dbname=test');
$definition->addConstructorArgument('user');
$definition->addConstructorArgument('password');

The definition above will return the result of new PDO('mysql:host=localhost;dbname=test', 'user', 'password').

References can also be used:

$definition = new ObjectDefinition('PDO');
$definition->addConstructorArgument(new Reference('db.connection_string'));
$definition->addConstructorArgument('user');
$definition->addConstructorArgument('password');

The definition above will return the result of new PDO($container->get('db.connection_string'), 'user', 'password').

FactoryCallDefinition

The definition below will call the create() method on the db.factory container entry and return its result:

$definition = new FactoryCallDefinition(new Reference('db.factory'), 'create');
$definition->setArguments(new Reference('db.connection_string'), 'user', 'password');

The definition below will call the static Acme\DbFactory::create() method:

$definition = new FactoryCallDefinition('Acme\DbFactory', 'create');

Container

Assembly ships with a simple container that is compatible with the standard definitions. The goal of this container is to provide a very easy way to get started for those wanting to consume definitions.

Here is how to use it:

// List the definition providers to load
$definitionProviders = [
    new Module1DefinitionProvider(),
    new Module2DefinitionProvider(),
];

// Define here container entries for the application
$entries = [
    'abc' => 'def',
    'router' => new Router(...),
];

$container = new Container($entries, $definitionProviders);

For simplicity's sake, the container is immutable and its API is very limited. You are encouraged to use any other compatible container if you are left unsatisfied.

Definition resolver

The "definition resolver" of the container is written in a separate Assembly\Container\DefinitionResolver class. This class is meant to be reused in any other container that wishes to support definition-interop. Using it is very simple:

$resolver = new \Assembly\Container\DefinitionResolver($container);
$value = $resolver->resolve($definition);