Test Failed
Pull Request — master (#37)
by Divine Niiquaye
11:51
created

SealedContainer::doGet()   C

Complexity

Conditions 13
Paths 11

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 22
c 3
b 0
f 0
dl 0
loc 38
rs 6.6166
cc 13
nc 11
nop 2

How to fix   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
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2021 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Rade\DI;
19
20
use Psr\Container\ContainerInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Rade\DI\ContainerInterface. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
21
use Rade\DI\Exceptions\{CircularReferenceException, ContainerResolutionException, NotFoundServiceException};
22
23
/**
24
 * A fully strict PSR-11 Container Implementation.
25
 *
26
 * This class is meant to be used as parent class for container's builder
27
 * compiled container class.
28
 *
29
 * Again, all services declared, should be autowired. Lazy services are not supported.
30
 *
31
 * @author Divine Niiquaye Ibok <[email protected]>
32
 */
33
class SealedContainer implements ContainerInterface
34
{
35
    protected array $loading = [], $services = [], $privates = [], $methodsMap = [], $resolvers = [], $aliases = [], $types = [], $tags = [];
36
37
    public function __construct()
38
    {
39
        $this->services[AbstractContainer::SERVICE_CONTAINER] = $this;
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45
    public function has(string $id): bool
46
    {
47
        return \array_key_exists($id = $this->aliases[$id] ?? $id, $this->methodsMap) || isset($this->types[$id]);
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function get(string $id)
54
    {
55
        if ($nullOnInvalid = '?' === $id[0]) {
56
            $id = \substr($id, 1);
57
        }
58
59
        if (isset($this->services[$id])) {
60
            return $this->services[$id];
61
        }
62
63
        if (\array_key_exists($id, $this->methodsMap)) {
64
            if (isset($this->loading[$id])) {
65
                throw new CircularReferenceException($id, [...\array_keys($this->loading), $id]);
66
            }
67
68
            $this->loading[$id] = true;
69
70
            try {
71
                return $this->{$this->methodsMap[$id]}();
72
            } finally {
73
                unset($this->loading[$id]);
74
            }
75
        }
76
77
        if (\array_key_exists($id, $this->aliases)) {
78
            return $this->services[$id = $this->aliases[$id]] ?? $this->get($id);
79
        }
80
81
        return $this->doGet($id, $nullOnInvalid);
82
    }
83
84
    /**
85
     * Returns a set of service definition's belonging to a tag.
86
     *
87
     * @param string $tagName
88
     * @param string|null $serviceId If provided, tag value will return instead
89
     *
90
     * @return mixed
91
     */
92
    public function tagged(string $tagName, ?string $serviceId = null)
93
    {
94
        $tags = $this->tags[$tagName] ?? [];
95
96
        return null !== $serviceId ? $tags[$serviceId] ?? [] : $tags;
97
    }
98
99
    /**
100
     * Return the resolved service of an entry.
101
     *
102
     * @return mixed
103
     */
104
    protected function doGet(string $id, bool $nullOnInvalid)
105
    {
106
        if (\preg_match('/\[(.*?)?\]$/', $id, $matches, \PREG_UNMATCHED_AS_NULL)) {
107
            $autowired = $this->types[\str_replace($matches[0], '', $oldId = $id)] ?? [];
108
109
            if (!empty($autowired)) {
110
                if (isset($matches[1])) {
111
                    return $this->services[$oldId] = \array_map([$this, 'get'], $autowired);
112
                }
113
114
                foreach ($autowired as $serviceId) {
115
                    if ($serviceId === $matches[1]) {
116
                        return $this->get($this->aliases[$oldId] = $serviceId);
117
                    }
118
                }
119
            }
120
        } elseif (!empty($autowired = $this->types[$id] ?? [])) {
121
            if (\count($autowired) > 1) {
122
                \natsort($autowired);
123
                $autowired = \count($autowired) <= 3 ? \implode(', ', $autowired) : $autowired[0] . ', ...' . \end($autowired);
124
125
                throw new ContainerResolutionException(\sprintf('Multiple services of type %s found: %s.', $id, $autowired));
126
            }
127
128
            if (!isset($this->aliases[$id])) {
129
                $this->aliases[$id] = $autowired[0];
130
            }
131
132
            return $this->services[$autowired[0]] ?? $this->get($autowired[0]);
133
        } elseif (\array_key_exists($id, $this->resolvers)) {
134
            [$resolver, $inline] = $this->resolvers[$id];
135
136
            return \call_user_func_array($resolver, $inline ? [$id] : []);
137
        } elseif ($nullOnInvalid) {
138
            return null;
139
        }
140
141
        throw new NotFoundServiceException(\sprintf('The "%s" requested service is not defined in container.', $id));
142
    }
143
144
    private function __clone()
145
    {
146
    }
147
}
148