Passed
Branch develop (e0de4e)
by Baptiste
01:53
created

Service::decorate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

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