Passed
Push — develop ( efe27a...afc25d )
by Baptiste
01:56
created

Dependencies::feed()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 1
rs 9.6666
c 0
b 0
f 0
1
<?php
2
declare(strict_types = 1);
3
4
namespace Innmind\Compose;
5
6
use Innmind\Compose\{
7
    Definition\Dependency,
8
    Definition\Name,
9
    Exception\ReferenceNotFound,
10
    Exception\NameNotNamespaced,
11
    Exception\CircularDependency,
12
    Exception\LogicException
13
};
14
use Innmind\Immutable\{
15
    Sequence,
16
    Map
17
};
18
19
final class Dependencies
20
{
21
    private $dependencies;
22
23 163
    public function __construct(Dependency ...$dependencies)
24
    {
25 163
        $this->dependencies = Sequence::of(...$dependencies)->reduce(
26 163
            new Map('string', Dependency::class),
27 163
            static function(Map $dependencies, Dependency $dependency): Map {
28 18
                return $dependencies->put(
29 18
                    (string) $dependency->name(),
30 18
                    $dependency
31
                );
32 163
            }
33
        );
34 163
        $this->assertNoCircularDependency();
35 163
    }
36
37 5
    public function feed(Name $name, Services $services): self
38
    {
39 5
        $self = clone $this;
40 5
        $self->dependencies = $self->dependencies->put(
41 5
            (string) $name,
42 5
            $self->dependencies->get((string) $name)->bind($services)
43
        );
44
45 5
        return $self;
46
    }
47
48 35
    public function bind(Services $services): Services
49
    {
50
        return $this
51 35
            ->dependencies
52 35
            ->values()
53 35
            ->sort(static function(Dependency $a, Dependency $b): bool {
54 1
                return $a->dependsOn($b);
55 35
            })
56 35
            ->reduce(
57 35
                $services,
58 35
                static function(Services $services, Dependency $dependency): Services {
59 3
                    return $services->feed($dependency->name());
60 35
                }
61
            );
62
    }
63
64 29
    public function lazy(Name $name): Lazy
65
    {
66
        try {
67 29
            $root = $name->root();
68 16
        } catch (NameNotNamespaced $e) {
69 16
            throw new ReferenceNotFound((string) $name);
70
        }
71
72 18
        if (!$this->dependencies->contains((string) $root)) {
73 5
            throw new ReferenceNotFound((string) $name);
74
        }
75
76
        try {
77
            return $this
78 13
                ->dependencies
79 13
                ->get((string) $root)
80 13
                ->lazy($name->withoutRoot());
81 3
        } catch (ReferenceNotFound $e) {
82 3
            throw new ReferenceNotFound((string) $name, 0, $e);
83
        }
84
    }
85
86 13
    public function build(Name $name): object
87
    {
88 13
        return $this->lazy($name)->load();
89
    }
90
91
    private function assertNoCircularDependency(): void
92
    {
93 163
        $this->dependencies->foreach(function(string $name, Dependency $dependency): void {
94
            $this
95 18
                ->dependencies
96 18
                ->remove($name)
97 18
                ->foreach(static function(string $name, Dependency $other) use ($dependency): void {
98 4
                    if (!$dependency->dependsOn($other)) {
99 4
                        return;
100
                    }
101
102 2
                    if (!$other->dependsOn($dependency)) {
103 1
                        return;
104
                    }
105
106 1
                    throw new CircularDependency(sprintf(
107 1
                        '%s -> %s -> %s',
108 1
                        $dependency->name(),
109 1
                        $other->name(),
110 1
                        $dependency->name()
111
                    ));
112 18
                });
113 163
        });
114 163
    }
115
}
116