Completed
Push — develop ( f49312...f8d1c0 )
by Baptiste
01:54
created

Definitions::build()   B

Complexity

Conditions 3
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 13
cts 13
cp 1
rs 8.9713
c 0
b 0
f 0
cc 3
eloc 14
nc 6
nop 1
crap 3
1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Compose;
5
6
use Innmind\Compose\{
7
    Definition\Name,
8
    Definition\Service,
9
    Definition\Service\Argument,
10
    Exception\ArgumentNotProvided,
11
    Exception\ArgumentNotDefined,
12
    Exception\AtLeastOneServiceMustBeExposed,
13
    Exception\CircularDependency
14
};
15
use Innmind\Immutable\{
16
    Sequence,
17
    MapInterface,
18
    Map,
19
    Pair,
20
    Stream
21
};
22
23
final class Definitions
24
{
25
    private $definitions;
26
    private $exposed;
27
    private $arguments;
28
    private $building;
29
30 25
    public function __construct(Arguments $arguments, Service ...$definitions)
31
    {
32 25
        $this->arguments = $arguments;
33 25
        $this->definitions = Sequence::of(...$definitions)->reduce(
34 25
            new Map('string', Service::class),
35 25
            static function(Map $definitions, Service $definition): Map {
36 24
                return $definitions->put(
37 24
                    (string) $definition->name(),
38 24
                    $definition
39
                );
40 25
            }
41
        );
42 25
        $this->exposed = $this
43 25
            ->definitions
44 25
            ->filter(static function(string $name, Service $definition): bool {
45 24
                return $definition->exposed();
46 25
            })
47 25
            ->map(static function(string $name, Service $definition): Pair {
48 24
                return new Pair(
49 24
                    (string) $definition->exposedAs(),
50 24
                    $definition
51
                );
52 25
            });
53
54 25
        if ($this->exposed->size() === 0) {
55 1
            throw new AtLeastOneServiceMustBeExposed;
56
        }
57
58 24
        $this->building = Stream::of('string');
59 24
    }
60
61
    /**
62
     * @param MapInterface<string, mixed> $arguments
63
     */
64 15
    public function inject(MapInterface $arguments): self
65
    {
66 15
        $self = clone $this;
67 15
        $self->arguments = $self->arguments->bind($arguments);
68 15
        $self->building = $self->building->clear();
69
70 15
        return $self;
71
    }
72
73 11
    public function build(Name $name): object
74
    {
75
        try {
76 11
            if ($this->building->contains((string) $name)) {
77 2
                throw new CircularDependency(
78
                    (string) $this
79 2
                        ->building
80 2
                        ->add((string) $name)
81 2
                        ->join(' -> ')
82
                );
83
            }
84
85 11
            $this->building = $this->building->add((string) $name);
86
87 11
            $service = $this->get($name)->build($this);
88
89 10
            $this->building = $this->building->dropEnd(1);
90 2
        } catch (\Throwable $e) {
91 2
            $this->building = $this->building->clear();
92
93 2
            throw $e;
94
        }
95
96 10
        return $service;
97
    }
98
99 16
    public function arguments(): Arguments
100
    {
101 16
        return $this->arguments;
102
    }
103
104 6
    public function has(Name $name): bool
105
    {
106 6
        if ($this->definitions->contains((string) $name)) {
107 4
            return true;
108
        }
109
110 4
        return $this->exposed->contains((string) $name);
111
    }
112
113 15
    public function get(Name $name): Service
114
    {
115
        try {
116 15
            return $this->definitions->get((string) $name);
117 5
        } catch (\Exception $e) {
118 5
            return $this->exposed->get((string) $name);
119
        }
120
    }
121
}
122