xref: /web-bugs/docs/container.md (revision 5cd2630a)
1# Dependency injection container
2
3The PHP bug tracker application ships with a simplistic dependency injection
4container which can create services and retrieves configuration values.
5
6Services are one of the more frequently used objects everywhere across the
7application. For example, service for database access, utility service for
8uploading files, data generators, API clients, and similar.
9
10## Dependency injection
11
12Dependencies between classes are injected using either constructor, or via a
13method call such as setter.
14
15```php
16class Repository
17{
18    private $pdo;
19
20    public function __construct(\PDO $pdo)
21    {
22        $this->pdo = $pdo;
23    }
24
25    public function getData(): array
26    {
27        return $this->pdo->query("SELECT * FROM table")->fetchAll();
28    }
29}
30
31$pdo = new \PDO(
32    'mysql:host=localhost;dbname=bugs;charset=utf8', 'nobody', 'password',
33    [
34        \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
35        \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
36        \PDO::ATTR_EMULATE_PREPARES   => false,
37    ]
38);
39
40$repository = new Repository($pdo);
41$data = $repository->getData();
42```
43
44The `$pdo` object in the example is a dependency which is injected via the
45constructor.
46
47Dependency injection container further provides a more efficient creation of
48such dependencies and services:
49
50```php
51$container = require_once __DIR__.'/../config/container.php';
52
53$data = $container->get(Repository::class)->getData();
54```
55
56## Configuration
57
58Configuration parameters include infrastructure configuration (database
59credentials...) and application level configuration (directories locations...).
60
61```php
62// config/parameters.php
63
64return [
65    'parameter_key' => 'value',
66
67    // ...
68];
69```
70
71Which can be retrieved by the container:
72
73```php
74$value = $container->get('parameter_key');
75```
76
77## Container definitions
78
79Each service class is manually defined:
80
81```php
82// config/container.php
83
84// New container initialization with configuration parameters defined in a file.
85$container = new Container(include __DIR__.'/parameters.php');
86
87// Services are then defined using callables with a container argument $c.
88
89// Service with constructor arguments
90$container->set(App\Foo::class, function ($c) {
91    return new App\Foo($c->get(App\Dependency::class));
92});
93
94// Service with a setter method
95$container->set(App\Foo\Bar::class, function ($c) {
96    $object = new App\Foo\Bar($c->get(App\Dependency::class));
97    $object->setFoobar('argument');
98
99    return $object;
100});
101
102// Dependencies can be service classes or configuration parameters
103$container->set(App\Foo\Bar::class, function ($c) {
104    return new App\Foo\Bar(
105        // Configuration parameter
106        $c->get('parameter_key'));
107
108        // Calling method from another service
109        $c->get(App\Dependency::class)->methodName();
110    );
111});
112
113// Service with no dependencies
114$container->set(App\Dependency::class, function ($c) {
115    return new App\Dependency();
116});
117
118return $container;
119```
120