Builder::build()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 4
c 1
b 0
f 1
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 2
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antidot\Container;
6
7
use InvalidArgumentException;
8
use Psr\Container\ContainerInterface;
9
use ReflectionMethod;
10
11
use function array_key_exists;
12
use function array_merge;
13
use function sprintf;
14
15
class Builder
16
{
17
    /**
18
     * @param array<mixed> $dependencies
19
     */
20 10
    public static function build(array $dependencies, bool $autowire = false): ContainerInterface
21
    {
22 10
        $self = new self();
23
24 10
        return new Container(
25 10
            $self->parseConfigFor($dependencies),
26
            $autowire
27
        );
28
    }
29
30
    /**
31
     * @param array<mixed> $dependencies
32
     */
33 10
    private function parseConfigFor(array $dependencies): ContainerConfig
34
    {
35
        $containerConfig = [
36 10
            'config' => $dependencies,
37
            'parameters' => [],
38 10
            'delegators' => $dependencies['delegators'] ?? [],
39
        ];
40
41 10
        $factories = array_merge(
42 10
            $dependencies['factories'] ?? [],
43 10
            $dependencies['dependencies']['factories'] ?? []
44
        );
45
46 10
        foreach ($factories as $name => $factory) {
47 3
            $containerConfig[$name] = static function (ContainerInterface $container) use ($factory) {
48 3
                if (is_array($factory)) {
49 1
                    $class = array_shift($factory);
50 1
                    $instance = new $class();
51 1
                    $method = new ReflectionMethod($class, '__invoke');
52 1
                    return $method->invokeArgs($instance, array_merge([$container], $factory));
53
                }
54
55 2
                if (is_callable($factory)) {
56 1
                    return $factory($container);
57
                }
58
59 1
                if (class_exists($factory)) {
60 1
                    return (new $factory())($container);
61
                }
62
63
                throw new InvalidArgumentException('Invalid factory type given.');
64
            };
65
        }
66
67 10
        $services = array_merge(
68 10
            $dependencies['services'] ?? [],
69 10
            $dependencies['dependencies']['invokables'] ?? []
70
        );
71
72 10
        foreach ($services as $name => $service) {
73 6
            $this->assertValidService($service);
74 3
            if (is_array($service)) {
75 1
                $containerConfig['parameters'][$name] = $service['arguments'] ?? [];
76 1
                $containerConfig[$name] = $service['class'];
77
            }
78
79 3
            if (is_string($service)) {
80 2
                $containerConfig[$name] = $service;
81
            }
82
        }
83
84 7
        $aliases = array_merge(
85 7
            $dependencies['aliases'] ?? [],
86 7
            $dependencies['dependencies']['aliases'] ?? []
87
        );
88 7
        foreach ($aliases as $alias => $service) {
89
            $this->assertValidAlias($service, $containerConfig);
90
            $containerConfig[$alias] = $service;
91
        }
92
93 7
        return new ContainerConfig($containerConfig);
94
    }
95
96
    /**
97
     * @param mixed $service
98
     */
99 6
    private function assertValidService($service): void
100
    {
101 6
        if (is_array($service)) {
102 3
            if (false === array_key_exists('class', $service)) {
103 1
                throw new InvalidArgumentException(
104 1
                    'Invalid Container Configuration, "class" parameter is required for configurable dependencies.'
105
                );
106
            }
107
108 2
            $service = $service['class'];
109
        }
110
111 5
        if (false === is_string($service)) {
112 2
            throw new InvalidArgumentException(
113
                'Invalid Container Configuration, Service "class", Simple or autowired dependencies must have'
114 2
                . ' a string value.'
115
            );
116
        }
117 3
    }
118
119
    /**
120
     * @param string $service
121
     * @param array<string, string> $containerConfig
122
     */
123
    private function assertValidAlias(string $service, array $containerConfig): void
124
    {
125
        if (false === array_key_exists($service, $containerConfig)) {
126
            throw new InvalidArgumentException(sprintf(
127
                'Invalid Alias "%s" given, be sure that the service already exists.',
128
                $service
129
            ));
130
        }
131
    }
132
}
133