Container::get()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 10
c 1
b 0
f 1
nc 4
nop 1
dl 0
loc 16
ccs 10
cts 10
cp 1
crap 4
rs 9.9332
1
<?php
2
/**
3
 * @author PhileCMS
4
 * @link https://github.com/PhileCMS/Phile
5
 * @license http://opensource.org/licenses/MIT
6
 */
7
8
namespace Phile\Core;
9
10
use Psr\Container\ContainerInterface;
11
use Phile\Exception\ContainerNotFoundException as NotFoundException;
12
13
/**
14
 * Implements a simple PSR-11 container
15
 */
16
class Container implements ContainerInterface
17
{
18
    /** @var array Container configuration */
19
    protected $config = [];
20
21
    /** @var Container */
22
    protected static $instance;
23
24
    /** @var array raw items */
25
    protected $raw = [];
26
27
    /** @var array evaluated items */
28
    protected $build = [];
29
30
    /**
31
     * Constructor
32
     *
33
     * @param array $config Container configuration
34
     *  - `types` array with <item id> => <required item type>
35
     */
36 38
    public function __construct(array $config = [])
37
    {
38 38
        $this->config = $config;
39
    }
40
41
    /**
42
     * Sets instance for static usage
43
     *
44
     * @param Container $instance
45
     * @return void
46
     */
47 35
    public static function setInstance(Container $instance): void
48
    {
49 35
        self::$instance = $instance;
50
    }
51
52
    /**
53
     * Gets instance for static usage
54
     *
55
     * @return self
56
     */
57 56
    public static function getInstance(): self
58
    {
59 56
        return self::$instance;
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65 58
    public function has($id)
66
    {
67 58
        return array_key_exists($id, $this->raw);
68
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 52
    public function get($id)
74
    {
75 52
        if (!$this->has($id)) {
76 1
            throw new NotFoundException(
77 1
                sprintf('Item "%s" not found in Container.', $id),
78
                1519111836
79
            );
80
        }
81 51
        if (!is_callable($this->raw[$id])) {
82 48
            return $this->raw[$id];
83
        }
84 35
        if (!isset($this->build[$id])) {
85 35
            $this->build[$id] = call_user_func($this->raw[$id], $this);
86 35
            $this->typeCheck($id, $this->build[$id]);
87
        }
88 35
        return $this->build[$id];
89
    }
90
91
    /**
92
     * Set an object
93
     *
94
     * @param string $id Identifier for the object to set
95
     * @param mixed $object Object to set
96
     * @return self
97
     */
98 43
    public function set(string $id, $object): self
99
    {
100 43
        if (!is_callable($object)) {
101 42
            $this->typeCheck($id, $object);
102
        }
103 42
        $this->raw[$id] = $object;
104 42
        return $this;
105
    }
106
107
    /**
108
     * Check object-type matches required type for that ID
109
     *
110
     * @param string $id
111
     * @param mixed $object
112
     * @return void
113
     * @throws \Phile\Exception\ContainerException
114
     */
115 43
    protected function typeCheck(string $id, $object)
116
    {
117 43
        if (!isset($this->config['types'][$id])) {
118 12
            return;
119
        }
120 42
        $requirement = $this->config['types'][$id];
121 42
        if (get_class($object) === $requirement || is_subclass_of($object, $requirement)) {
122 41
            return;
123
        }
124 1
        $msg = sprintf('The Container-item "%s" must implement the interface: "%s"', $id, $requirement);
125 1
        throw new \Phile\Exception\ContainerException($msg, 1398536617);
126
    }
127
}
128