Skip to content

Commit

Permalink
Merge pull request #59 from lcobucci/improve-documentation
Browse files Browse the repository at this point in the history
Improve documentation
  • Loading branch information
lcobucci authored Sep 6, 2020
2 parents f3ac1cb + e42b6d0 commit 9b72cc6
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 99 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/.github export-ignore
/docs export-ignore
/test export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
Expand All @@ -8,3 +9,4 @@
/composer.lock export-ignore
/Dockerfile export-ignore
/.dockerignore export-ignore
/mkdocs.yml export-ignore
122 changes: 23 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,114 +1,38 @@
# di-builder
# DI Builder

[![Total Downloads](https://img.shields.io/packagist/dt/lcobucci/di-builder.svg?style=flat-square)](https://packagist.org/packages/lcobucci/di-builder)
[![Latest Stable Version](https://img.shields.io/packagist/v/lcobucci/di-builder.svg?style=flat-square)](https://packagist.org/packages/lcobucci/di-builder)
[![Total Downloads]](https://packagist.org/packages/lcobucci/di-builder)
[![Latest Stable Version]](https://packagist.org/packages/lcobucci/di-builder)
[![Unstable Version]](https://packagist.org/packages/lcobucci/di-builder)

[![Build Status](https://img.shields.io/travis/com/lcobucci/di-builder.svg?style=flat-square)](http://travis-ci.com/lcobucci/di-builder)
[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/lcobucci/di-builder/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/lcobucci/di-builder/?branch=master)
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/lcobucci/di-builder/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/lcobucci/di-builder/?branch=master)
[![Build Status]](http://travis-ci.com/lcobucci/di-builder)
[![Scrutinizer Code Quality]](https://scrutinizer-ci.com/g/lcobucci/di-builder/?branch=master)
[![Code Coverage]](https://scrutinizer-ci.com/g/lcobucci/di-builder/?branch=master)

This library tries to help the usage of the
[Symfony dependecy injection Component](http://symfony.com/doc/current/components/dependency_injection/introduction.html)
by offering an easy interface to build and load your dependency injection container.

## Features

- Multiple container files or paths: you can create the container from one or
more files and paths, this is useful when dealing with modules;
- Multiple file loader: you can select if you want to create your container from
XML (default), YAML, PHP or mixed mode (delegates the loading by the extension of file);
- Usage of your own container base class: sometimes you may use a different class
to inherit your container (rather than ```Symfony\Component\DependencyInjection\Container```;
- Automatic dump creation: instead of building your container for all requests you
will do that only when things change (development mode only);
- Configuration handlers: you are able to inject handlers to be executed before
the container compilation process (to change the services definitions);
- Dynamic parameters: if you need to configure parameters that may change according
with the environment automatically (like base project directory using ```__DIR__```).
Library that makes easier the creation of compiled containers using the [Symfony DI Component].

## Installation

This package is available on [Packagist](http://packagist.org/packages/lcobucci/di-builder),
you can install it using [Composer](http://getcomposer.org).
This package is available on [Packagist], you can install it using [Composer].

```shell
composer require lcobucci/di-builder
```

### PHP Configuration

In order to make sure that we're dealing with the correct data, we're using `assert()`,
which is a very interesting feature in PHP but not often used. The nice thing
about `assert()` is that we can (and should) disable it in production mode so
that we don't have useless statements.

So, for production mode, we recommend you to set `zend.assertions` to `-1` in your `php.ini`.
For development you should leave `zend.assertions` as `1` and set `assert.exception` to `1`, which
will make PHP throw an [`AssertionError`](https://secure.php.net/manual/en/class.assertionerror.php)
when things go wrong.

Check the documentation for more information: https://secure.php.net/manual/en/function.assert.php

## Basic usage

The usage is really simple, just trust the ```Lcobucci\DependencyInjection\Builder``` interface and
all should be good =)

Take a look:

```php
<?php
/* Composer autoloader was required before this */

use Your\Own\Compiler\DoSomethingPass;
use Lcobucci\DependencyInjection\ContainerBuilder;
use Lcobucci\DependencyInjection\Generators\Php as PhpGenerator;

$container = ContainerBuilder::default(__FILE__)
->setGenerator(new PhpGenerator(__FILE__)) // Changes the generator
->addFile(__DIR__ . '/config/services.php') // Appends a file to create the container
->addPath(__DIR__ . '/src/Users/config') // Appends a new path to locate files
->addFile('services.php') // Appends a file to create the container (to be used with the configured paths)
->useDevelopmentMode() // Enables the development mode (production is the default)
->setDumpDir(__DIR__ . '/tmp') // Changes the dump directory
->setParameter('app.basedir', __DIR__) // Configures a dynamic parameter
->addPass(new DoSomethingPass()) // Appends a new compiler pass
->addDelayedPass(DoSomethingPass::class) // Appends a new compiler pass that will only be initialised while building the container
->addPackage(MyPackage::class) // Appends a new package that might provide files and compiler passes to be added to the the container
->getContainer(); // Retrieves the container =)
```

## Compiler Pass
## Usage

The handlers are very great to change your container __before__ dumping a container. And
you can create your own handler by just implementing the ```Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface```
interface (so you can also use compiler pass from symfony bundles). Like this:
Please read our documentation at <https://lcobucci-di-builder.readthedocs.io>.

```php
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
## License

final class EventListenerInjector implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$dispatcher = $container->getDefinition('event.dispatcher');

foreach ($container->findTaggedServiceIds('event.listener') as $service => $tags) {
foreach ($tags as $tag) {
$dispatcher->addMethodCall(
'addListener',
[$tag['event'], new Reference($service), $tag['priority']]
);
}
}
}
}
```
The project is licensed under the BSD-3-Clause license, see [LICENSE] file.

Happy coding ;)
[Total Downloads]: https://img.shields.io/packagist/dt/lcobucci/di-builder.svg?style=flat-square
[Latest Stable Version]: https://img.shields.io/packagist/v/lcobucci/di-builder.svg?style=flat-square
[Unstable Version]: https://img.shields.io/packagist/vpre/lcobucci/di-builder.svg?style=flat-square
[Build Status]: https://img.shields.io/travis/com/lcobucci/di-builder.svg?style=flat-square
[Scrutinizer Code Quality]: https://img.shields.io/scrutinizer/g/lcobucci/di-builder/master.svg?style=flat-square
[Code Coverage]: https://img.shields.io/scrutinizer/coverage/g/lcobucci/di-builder/master.svg?style=flat-square
[Symfony DI Component]: http://symfony.com/doc/current/components/dependency_injection/introduction.html
[Packagist]: http://packagist.org/packages/lcobucci/di-builder
[Composer]: http://getcomposer.org
[LICENSE]: LICENSE
54 changes: 54 additions & 0 deletions docs/compiler-passes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Compiler Passes

Compiler passes are components that hook into the container compilation process and add/modify service definitions.
They're extremely handy to dynamically configure your services.

For example, if you want to automatically register all services tagged with `event.listener` to the event dispatcher, you may use the follow compiler pass:

```php
<?php
declare(strict_types=1);

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

final class EventListenerInjector implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$dispatcher = $container->getDefinition(EventDispatcherInterface::class);

foreach ($container->findTaggedServiceIds('event.listener') as $service => $tags) {
foreach ($tags as $tag) {
$dispatcher->addMethodCall(
'addListener',
[$tag['event'], new Reference($service), $tag['priority']]
);
}
}
}
}
```

## Type and priority

There are different types of compiler passes.
You can see the available types on the [`PassConfig`] class.

You may also configure different priorities for the compiler passes.

## Configuration

When setting up your container, you can call `ContainerBuilder#addPass()` or `ContainerBuilder#addDelayedPass()`.

The type and priority are configured via these methods as well.
The default values are `PassConfig::TYPE_BEFORE_OPTIMIZATION` as type and `0` as priority.

!!! Important
The method `ContainerBuilder#addDelayedPass()` was introduced on [v5.2.0], to avoid the creation of **unnecessary instances**.
It's recommended to use it because it (possibly) makes your application faster by reducing the number of loaded classes and instantiated objects during the bootstrap.

[`PassConfig`]: https://github.com/symfony/dependency-injection/blob/6152c7f22d9d2f367534144a75a54e27f51e6f44/Compiler/PassConfig.php#L25-L29
[v5.2.0]: https://github.com/lcobucci/di-builder/releases/tag/5.2.0
68 changes: 68 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Configuration

Setting up the container can be a complicated task.
In order to make the it easier, we provide a builder.

The builder is initialised via a named constructor using XML as the default format.
Once everything is configured, the builder gives you a fully functional container:

```php
<?php
declare(strict_types=1);

use Lcobucci\DependencyInjection\ContainerBuilder;

// The path to the current file is passed so we can track changes
// to it and refresh the cache (for development mode)
$builder = ContainerBuilder::default(__FILE__);

$container = $builder->getContainer();

// Alternatively, you may use the method `ContainerBuilder#getTestContainer()`,
// so it can be use for tests that need a real container:
$testContainer = $builder->getTestContainer();
```

## Available methods

* `ContainerBuilder#setGenerator()`: Modifies the generator to be used.
We support the `XML`, `Yaml`, `PHP`, and `Delegating` generators (the latter allows to use all formats together)
* `ContainerBuilder#addPath()`: Add a base path to find files
* `ContainerBuilder#addFile()`: Adds a container source file
* `ContainerBuilder#addPass()`: Adds an instance of a [Compiler Pass](compiler-passes.md) to be processed
* `ContainerBuilder#addDelayedPass()`: Adds a reference (class name and constructor arguments) of a [Compiler Pass](compiler-passes.md) to be processed
* `ContainerBuilder#addPackage()`: Adds a reference (class name and constructor arguments) of a [Package](packages.md) to be processed
* `ContainerBuilder#useDevelopmentMode()`: Optimises the generate container for development purposes (configures the compiler to track file changes and update the cache)
* `ContainerBuilder#setDumpDir()`: Configures the directory to be used to dump the cache files
* `ContainerBuilder#setParameter()`: Configures a dynamic parameter
* `ContainerBuilder#setBaseClass()`: Modifies which class should be used as base class for the container

## Configuration file example

You may use the following configuration file as inspiration for your projects (usually placed in the `/config` folder):

```php
<?php
declare(strict_types=1);

namespace Me\MyApplication;

use Lcobucci\DependencyInjection\ContainerBuilder;

use function dirname;
use function getenv;

require __DIR__ . '/../vendor/autoload.php';

$builder = ContainerBuilder::default(__FILE__);
$projectRoot = dirname(__DIR__);

if (getenv('APPLICATION_MODE', true) === 'development') {
$builder->useDevelopmentMode();
}

return $builder->setDumpDir($projectRoot . '/var/tmp')
->setParameter('app.basedir', $projectRoot)
->addFile(__DIR__ . '/container.xml')
->getContainer();
```
24 changes: 24 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Overview

`lcobucci/di-builder` is a library that provides a powerful way to create compiled DI containers.
We rely on the [Symfony DI component] to perform such task.

## Motivation

The underlying component is just brilliant.
However, it doesn't provide a self-contained solution to be used **outside the Symfony ecosystem**.
The logic you see in this library is essentially present in the Symfony HTTP Kernel (or micro kernel).

The goal here is to reliably produce compiled DI containers that don't harm developer experience.

## Support

If you're having any issue to use the library, please [create a GH issue].

## License

The project is licensed under the BSD-3-Clause license, see [LICENSE file].

[Symfony DI component]: http://symfony.com/doc/current/components/dependency_injection/introduction.html
[create a GH issue]: https://github.com/lcobucci/di-builder/issues/new
[LICENSE file]: https://github.com/lcobucci/di-builder/blob/master/LICENSE
44 changes: 44 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Installation

This package is available on [Packagist] and you can install it using [Composer].

By running the following command you'll add `lcobucci/di-builder` as a dependency to your project:

```sh
composer require lcobucci/di-builder
```

## Autoloading

!!! Note
We'll be omitting the autoloader from the code samples to simplify the documentation.

In order to be able to use the classes provided by this library you're also required to include [Composer]'s autoloader in your application:

```php
require 'vendor/bin/autoload.php';
```

!!! Tip
If you're not familiar with how [composer] works, we highly recommend you to take some time to read it's documentation - especially the [autoloading section].

## PHP configuration

In order to make sure that we're dealing with the correct data, we're using the function `assert()`.

The nice thing about `assert()` is that we can (and should) disable it on production.
That would avoid creating and executing _opcodes_ which are relevant only for development.

Check the documentation for more information: <https://secure.php.net/manual/en/function.assert.php>

### Production mode

We recommend you to set `zend.assertions` to `-1` in your `php.ini`.

### Development

You should leave `zend.assertions` as `1` and set `assert.exception` to `1`, which will make PHP throw an `AssertionError` when things go wrong.

[Packagist]: https://packagist.org/packages/lcobucci/di-builder
[Composer]: https://getcomposer.org
[autoloading section]: https://getcomposer.org/doc/01-basic-usage.md#autoloading
41 changes: 41 additions & 0 deletions docs/packages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Packages

Packages are reusable piece of code that can be plugged into your dependency injection container.
You're likely to use them when creating or consuming libraries.

A package can be a `CompilerPassListProvider` and/or a `FileListProvider`.
The former provides a list of compiler passes (with types and priorities) to be added to the container compilation.
The latter provides a list of files to be loaded for the container.

An example:

```php
<?php
declare(strict_types=1);

namespace MyAwesomeLib\DependencyInjection;

use Generator;
use Lcobucci\DependencyInjection\CompilerPassListProvider;
use Lcobucci\DependencyInjection\FileListProvider;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;

final class MyAwesomeLib implements CompilerPassListProvider, FileListProvider
{
/** @inheritDoc */
public function getCompilerPasses(): Generator
{
yield [new MyCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5];
}

/** @inheritDoc */
public function getFiles() : Generator
{
yield dirname(__DIR__) . '/../config/my-awesome-lib.xml';
}
}
```

## Configuration

When setting up your container, you can call `ContainerBuilder#addPackage()` to register a package - also providing the necessary constructor arguments.
14 changes: 14 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
site_name: lcobucci/di-builder
theme: readthedocs

nav:
- Intro:
- 'index.md'
- 'installation.md'
- Usage:
- 'configuration.md'
- 'compiler-passes.md'
- 'packages.md'

markdown_extensions:
- admonition

0 comments on commit 9b72cc6

Please sign in to comment.