Passed
Push — feature/container-factory ( 636d71...1da680 )
by Chema
03:33
created

Container::factory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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