Passed
Pull Request — master (#85)
by Sergei
02:04
created

Factory   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Test Coverage

Coverage 96.97%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 25
c 2
b 0
f 0
dl 0
loc 127
ccs 32
cts 33
cp 0.9697
rs 10
wmc 16

8 Methods

Rating   Name   Duplication   Size   Complexity  
A merge() 0 3 2
A create() 0 12 4
A __construct() 0 4 1
A setMultiple() 0 5 2
A set() 0 3 1
A get() 0 13 3
A getDefinition() 0 9 2
A has() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory;
6
7
use Psr\Container\ContainerInterface;
8
use Yiisoft\Factory\Definition\ArrayDefinition;
9
use Yiisoft\Factory\Definition\DefinitionInterface;
10
use Yiisoft\Factory\Definition\Normalizer;
11
use Yiisoft\Factory\Exception\InvalidConfigException;
12
use Yiisoft\Factory\Exception\NotInstantiableException;
13
14
use function is_string;
15
16
class Factory implements FactoryInterface
17
{
18
    /**
19
     * @var ContainerInterface|null Parent container.
20
     */
21
    private ?ContainerInterface $container = null;
22
23
    /**
24
     * @var DefinitionInterface[] object definitions indexed by their types
25
     * @psalm-var array<string, DefinitionInterface>
26
     */
27
    private array $definitions = [];
28
29
    /**
30
     * Factory constructor.
31
     *
32
     * @psalm-param array<string, mixed> $definitions
33
     *
34
     * @throws InvalidConfigException
35
     * @throws NotInstantiableException
36
     */
37 27
    public function __construct(ContainerInterface $container = null, array $definitions = [])
38
    {
39 27
        $this->container = $container;
40 27
        $this->setMultiple($definitions);
41 27
    }
42
43 17
    public function create($config, array $constructorArguments = [])
44
    {
45 17
        $definition = Normalizer::normalize($config, null, $constructorArguments);
46 17
        if ($definition instanceof ArrayDefinition && $this->has($definition->getClass())) {
47 2
            $definition = $this->merge($this->getDefinition($definition->getClass()), $definition);
48
        }
49
50 17
        if ($definition instanceof ArrayDefinition) {
51 7
            return $definition->resolve($this->container ?? $this);
52
        }
53
54 10
        return $definition->resolve($this);
55
    }
56
57 2
    private function merge(DefinitionInterface $one, ArrayDefinition $two): DefinitionInterface
58
    {
59 2
        return $one instanceof ArrayDefinition ? $one->merge($two) : $two;
60
    }
61
62
    /**
63
     * @param string $id
64
     *
65
     * @throws NotInstantiableException
66
     *
67
     * @return mixed|object
68
     */
69 20
    public function get($id)
70
    {
71
        try {
72 20
            $definition = $this->getDefinition($id);
73 5
        } catch (InvalidConfigException $e) {
74 5
            throw new NotInstantiableException($id);
75
        }
76
77 17
        if ($definition instanceof ArrayDefinition) {
0 ignored issues
show
introduced by
$definition is always a sub-type of Yiisoft\Factory\Definition\ArrayDefinition.
Loading history...
78 16
            return $definition->resolve($this->container ?? $this);
79
        }
80
81 5
        return $definition->resolve($this);
82
    }
83
84
    /**
85
     * @param mixed $id
86
     *
87
     * @throws InvalidConfigException
88
     */
89 22
    public function getDefinition($id): DefinitionInterface
90
    {
91 22
        if (is_string($id)) {
92
            // prevent infinite loop when Reference definition points to string but not to a class
93
            /** @psalm-suppress ArgumentTypeCoercion */
94 22
            return $this->definitions[$id] ?? new ArrayDefinition([ArrayDefinition::CLASS_NAME => $id]);
95
        }
96
97
        return Normalizer::normalize($id);
98
    }
99
100
    /**
101
     * Sets a definition to the factory.
102
     *
103
     * @param mixed $definition
104
     *
105
     * @throws InvalidConfigException
106
     *
107
     * @see `Normalizer::normalize()`
108
     */
109 12
    public function set(string $id, $definition): void
110
    {
111 12
        $this->definitions[$id] = Normalizer::normalize($definition, $id);
112 12
    }
113
114
    /**
115
     * Sets multiple definitions at once.
116
     *
117
     * @param array $definitions definitions indexed by their ids
118
     *
119
     * @psalm-param array<string, mixed> $definitions
120
     *
121
     * @throws InvalidConfigException
122
     */
123 27
    public function setMultiple(array $definitions): void
124
    {
125
        /** @var mixed $definition */
126 27
        foreach ($definitions as $id => $definition) {
127 11
            $this->set($id, $definition);
128
        }
129 27
    }
130
131
    /**
132
     * Returns a value indicating whether the container has the definition of the specified name.
133
     *
134
     * @param string $id class name, interface name or alias name
135
     *
136
     * @return bool whether the container is able to provide instance of class specified.
137
     *
138
     * @see set()
139
     */
140 7
    public function has($id): bool
141
    {
142 7
        return isset($this->definitions[$id]);
143
    }
144
}
145