Passed
Push — upgrade-psr ( 5ae291...cd93d9 )
by Sergei
22:00 queued 19:21
created

CompositeContainer::get()   C

Complexity

Conditions 14
Paths 27

Size

Total Lines 70
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 14

Importance

Changes 0
Metric Value
cc 14
eloc 39
nc 27
nop 1
dl 0
loc 70
ccs 36
cts 36
cp 1
crap 14
rs 6.2666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Di;
6
7
use InvalidArgumentException;
8
use Psr\Container\ContainerInterface;
9
use RuntimeException;
10
use Throwable;
11
use Yiisoft\Di\Helpers\TagHelper;
12
13
use function get_class;
14
use function gettype;
15
use function is_object;
16
use function is_string;
17
18
/**
19
 * A composite container for use with containers that support the delegate lookup feature.
20
 */
21
final class CompositeContainer implements ContainerInterface
22
{
23
    /**
24
     * Containers to look into starting from the beginning of the array.
25
     *
26
     * @var ContainerInterface[] The list of containers.
27
     */
28
    private array $containers = [];
29
30
    /**
31
     * @psalm-template T
32
     * @psalm-param string|class-string<T> $id
33
     * @psalm-return ($id is class-string ? T : mixed)
34
     */
35 34
    public function get($id)
36
    {
37
        /** @psalm-suppress TypeDoesNotContainType */
38 34
        if (!is_string($id)) {
39 1
            throw new InvalidArgumentException(
40 1
                sprintf(
41
                    'ID must be a string, %s given.',
42 1
                    $this->getVariableType($id)
43
                )
44
            );
45
        }
46
47 33
        if ($id === StateResetter::class) {
48 4
            $resetters = [];
49 4
            foreach ($this->containers as $container) {
50 4
                if ($container->has(StateResetter::class)) {
51 4
                    $resetters[] = $container->get(StateResetter::class);
52
                }
53
            }
54 4
            $stateResetter = new StateResetter($this);
55 4
            $stateResetter->setResetters($resetters);
56
57 4
            return $stateResetter;
58
        }
59
60 33
        if (TagHelper::isTagAlias($id)) {
61 3
            $tags = [];
62 3
            foreach ($this->containers as $container) {
63 3
                if (!$container instanceof Container) {
64 1
                    continue;
65
                }
66 3
                if ($container->has($id)) {
67
                    /** @psalm-suppress MixedArgument Container::get() always return array for tag */
68 3
                    array_unshift($tags, $container->get($id));
69
                }
70
            }
71
72
            /** @psalm-suppress MixedArgument Container::get() always return array for tag */
73 3
            return array_merge(...$tags);
74
        }
75
76 30
        foreach ($this->containers as $container) {
77 30
            if ($container->has($id)) {
78
                /** @psalm-suppress MixedReturnStatement */
79 24
                return $container->get($id);
80
            }
81
        }
82
83
        // Collect details from containers
84 8
        $exceptions = [];
85 8
        foreach ($this->containers as $container) {
86 6
            $hasException = false;
87
            try {
88 6
                $container->get($id);
89 5
            } catch (Throwable $t) {
90 5
                $hasException = true;
91 5
                $exceptions[] = [$t, $container];
92 6
            } finally {
93 6
                if (!$hasException) {
94 1
                    $exceptions[] = [
95 1
                        new RuntimeException(
96
                            'Container "has()" returned false, but no exception was thrown from "get()".'
97
                        ),
98
                        $container,
99
                    ];
100
                }
101
            }
102
        }
103
104 8
        throw new CompositeNotFoundException($exceptions);
105
    }
106
107 31
    public function has($id): bool
108
    {
109 31
        foreach ($this->containers as $container) {
110 7
            if ($container->has($id)) {
111 7
                return true;
112
            }
113
        }
114 26
        return false;
115
    }
116
117
    /**
118
     * Attaches a container to the composite container.
119
     */
120 35
    public function attach(ContainerInterface $container): void
121
    {
122 35
        $this->containers[] = $container;
123
    }
124
125
    /**
126
     * Removes a container from the list of containers.
127
     */
128 2
    public function detach(ContainerInterface $container): void
129
    {
130 2
        foreach ($this->containers as $i => $c) {
131 2
            if ($container === $c) {
132 2
                unset($this->containers[$i]);
133
            }
134
        }
135
    }
136
137
    /**
138
     * @param mixed $variable
139
     */
140 1
    private function getVariableType($variable): string
141
    {
142 1
        return is_object($variable) ? get_class($variable) : gettype($variable);
143
    }
144
}
145