Arguments::bind()   A
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 20
nc 2
nop 1
dl 0
loc 32
ccs 22
cts 22
cp 1
crap 5
rs 9.2888
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\Argument,
8
    Definition\Name,
9
    Exception\MissingArgument,
10
    Exception\ArgumentNotProvided,
11
    Exception\ArgumentNotDefined,
12
    Compilation
13
};
14
use Innmind\Immutable\{
15
    Sequence,
16
    MapInterface,
17
    Map,
18
    SetInterface,
19
    Set
20
};
21
22
final class Arguments
23
{
24
    private $arguments;
25
    private $values;
26
27 230
    public function __construct(Argument ...$arguments)
28
    {
29 230
        $this->arguments = Sequence::of(...$arguments)->reduce(
30 230
            new Map('string', Argument::class),
31 230
            static function(Map $arguments, Argument $argument): Map {
32 64
                return $arguments->put(
33 64
                    (string) $argument->name(),
34 64
                    $argument
35
                );
36 230
            }
37
        );
38 230
        $this->values = new Map('string', 'mixed');
39 230
    }
40
41
    /**
42
     * @param MapInterface<string, mixed> $values
43
     *
44
     * @throws MissingArgument
45
     */
46 44
    public function bind(MapInterface $values): self
47
    {
48
        if (
49 44
            (string) $values->keyType() !== 'string' ||
50 44
            (string) $values->valueType() !== 'mixed'
51
        ) {
52 1
            throw new \TypeError('Argument 1 must be of type MapInterface<string, mixed>');
53
        }
54
55
        $this
56 43
            ->arguments
57 43
            ->filter(static function(string $name, Argument $argument): bool {
58 42
                return !$argument->optional() && !$argument->hasDefault();
59 43
            })
60 43
            ->foreach(static function(string $name) use ($values): void {
61 36
                if (!$values->contains($name)) {
62 1
                    throw new MissingArgument($name);
63
                }
64 43
            });
65
        $this
66 42
            ->arguments
67 42
            ->filter(static function(string $name) use ($values): bool {
68 41
                return $values->contains($name);
69 42
            })
70 42
            ->foreach(static function(string $name, Argument $argument) use ($values): void {
71 35
                $argument->validate($values->get($name));
72 42
            });
73
74 41
        $self = clone $this;
75 41
        $self->values = $values;
76
77 41
        return $self;
78
    }
79
80
    /**
81
     * @throws ArgumentNotProvided
82
     *
83
     * @return mixed
84
     */
85 39
    public function get(Name $name)
86
    {
87 39
        if (!$this->arguments->contains((string) $name)) {
88 22
            throw new ArgumentNotDefined((string) $name);
89
        }
90
91 27
        if (!$this->values->contains((string) $name)) {
92 16
            throw new ArgumentNotProvided($this->arguments->get((string) $name));
93
        }
94
95 16
        return $this->values->get((string) $name);
96
    }
97
98
    /**
99
     * @return SetInterface<Argument>
100
     */
101 23
    public function all(): SetInterface
102
    {
103 23
        return Set::of(Argument::class, ...$this->arguments->values());
104
    }
105
106 8
    public function compile(): Compilation\Arguments
107
    {
108 8
        return new Compilation\Arguments($this);
109
    }
110
}
111