Passed
Push — feature/container-factory ( 5aed48 )
by Chema
09:15
created

Container::factory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
ccs 4
cts 5
cp 0.8
crap 2.032
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Framework\Container;
6
7
use Closure;
8
use Gacela\Framework\Container\Exception\ContainerException;
9
use Gacela\Framework\Container\Exception\ContainerKeyNotFoundException;
10
use SplObjectStorage;
11
12
use function is_object;
13
14
final class Container implements ContainerInterface
15
{
16
    /** @var array<string,mixed> */
17
    private array $raw = [];
18
19
    /** @var array<string,mixed> */
20
    private array $services = [];
21
22
    private SplObjectStorage $factoryServices;
23
24 16
    public function __construct()
25
    {
26 16
        $this->factoryServices = new SplObjectStorage();
27
    }
28
29 1
    public function getLocator(): Locator
30
    {
31 1
        return Locator::getInstance();
32
    }
33
34 13
    public function set(string $id, $service): void
35
    {
36 13
        $this->services[$id] = $service;
37
    }
38
39 24
    public function has(string $id): bool
40
    {
41 24
        return isset($this->services[$id]);
42
    }
43
44
    /**
45
     * @throws ContainerKeyNotFoundException
46
     *
47
     * @return mixed
48
     */
49 23
    public function get(string $id)
50
    {
51 23
        if (!$this->has($id)) {
52 4
            throw new ContainerKeyNotFoundException($this, $id);
53
        }
54
55
        if (
56 19
            isset($this->raw[$id])
57 10
            || !is_object($this->services[$id])
58 19
            || !method_exists($this->services[$id], '__invoke')
59
        ) {
60 17
            return $this->services[$id];
61
        }
62
63 5
        if (isset($this->factoryServices[$this->services[$id]])) {
64 1
            return $this->services[$id]($this);
65
        }
66
67 4
        $rawService = $this->services[$id];
68
69
        /** @psalm-suppress InvalidFunctionCall */
70 4
        $this->services[$id] = $rawService($this);
71
72
        /** @var mixed $resolvedService */
73 4
        $resolvedService = $this->services[$id];
74 4
        $this->raw[$id] = $rawService;
75
76 4
        return $resolvedService;
77
    }
78
79
    /**
80
     * @param Closure|object $service
81
     *
82
     * @return Closure|object
83
     */
84 1
    public function factory(object $service): object
85
    {
86 1
        if (!method_exists($service, '__invoke')) {
87
            throw ContainerException::serviceNotInvokable();
88
        }
89
90 1
        $this->factoryServices->attach($service);
91
92 1
        return $service;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $service returns the type object which is incompatible with the type-hinted return object.
Loading history...
93
    }
94
95 2
    public function remove(string $id): void
96
    {
97
        unset(
98 2
            $this->raw[$id],
99 2
            $this->services[$id]
100
        );
101
    }
102
}
103