Passed
Pull Request — master (#78)
by Dmitriy
02:32
created

ArrayDefinition::getMeta()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory\Definition;
6
7
use Psr\Container\ContainerInterface;
8
use Yiisoft\Factory\Exception\InvalidConfigException;
9
10
use Yiisoft\Factory\Exception\NotInstantiableException;
11
12
use function array_key_exists;
13
use function get_class;
14
use function gettype;
15
use function is_array;
16
use function is_object;
17
use function is_string;
18
19
/**
20
 * Builds object by array config
21
 */
22
class ArrayDefinition implements DefinitionInterface
23
{
24
    public const CLASS_NAME = 'class';
25
    public const CONSTRUCTOR = '__construct()';
26
27
    /**
28
     * @psalm-var class-string
29
     */
30
    private string $class;
31
    private array $constructorArguments;
32
33
    /**
34
     * @psalm-var array<string, mixed|array>
35
     */
36
    private array $methodsAndProperties;
37
38
    /**
39
     * @psalm-var array<string, mixed>
40
     */
41
    private array $meta = [];
42
43
    /**
44
     * @param array $config Container entry config.
45
     * @param string[] $allowedMeta Allowed metadata keys.
46
     *
47
     * @throws InvalidConfigException
48
     */
49 49
    public function __construct(array $config, array $allowedMeta = [])
50
    {
51 49
        [$config,] = Normalizer::parse($config, $allowedMeta);
52 46
        $this->setClass($config);
53 43
        unset($config[self::CLASS_NAME]);
54 43
        $this->setConstructorArguments($config);
55 42
        unset($config[self::CONSTRUCTOR]);
56 42
        $this->methodsAndProperties = $config;
57 42
    }
58
59
    /**
60
     * @throws InvalidConfigException
61
     */
62 46
    private function setClass(array $config): void
63
    {
64 46
        if (!array_key_exists(self::CLASS_NAME, $config)) {
65 1
            throw new InvalidConfigException('Invalid definition: no class name specified.');
66
        }
67
68
        /** @var mixed */
69 45
        $class = $config[self::CLASS_NAME];
70
71 45
        if (!is_string($class)) {
72 1
            throw new InvalidConfigException(sprintf('Invalid definition: invalid class name "%s".', (string)$class));
73
        }
74
75 44
        if ($class === '') {
76 1
            throw new InvalidConfigException('Invalid definition: empty class name.');
77
        }
78
79 43
        $this->class = $class;
80 43
    }
81
82
    /**
83
     * @throws InvalidConfigException
84
     */
85 43
    private function setConstructorArguments(array $config): void
86
    {
87 43
        $arguments = $config[self::CONSTRUCTOR] ?? [];
88
89 43
        if (!is_array($arguments)) {
90 1
            throw new InvalidConfigException(
91 1
                sprintf(
92 1
                    'Invalid definition: incorrect constructor arguments. Expected array, got %s.',
93 1
                    $this->getType($arguments)
94
                )
95
            );
96
        }
97
98 42
        $this->constructorArguments = $arguments;
99 42
    }
100
101
    /**
102
     * @psalm-return class-string
103
     */
104 42
    public function getClass(): string
105
    {
106 42
        return $this->class;
107
    }
108
109 39
    public function getConstructorArguments(): array
110
    {
111 39
        return $this->constructorArguments;
112
    }
113
114 36
    public function getMethodsAndProperties(): array
115
    {
116 36
        return $this->methodsAndProperties;
117
    }
118
119
    /**
120
     * @throws NotInstantiableException
121
     * @throws InvalidConfigException
122
     */
123 42
    public function resolve(ContainerInterface $container): object
124
    {
125 42
        return ArrayDefinitionBuilder::getInstance()->build($container, $this);
126
    }
127
128 2
    public function merge(self $other): self
129
    {
130 2
        $methodsAndProperties = $this->getMethodsAndProperties();
131
132 2
        foreach ($other->getMethodsAndProperties() as $name => $arguments) {
133 1
            $methodsAndProperties[$name] = isset($methodsAndProperties[$name])
134 1
                ? $this->mergeArguments($methodsAndProperties[$name], $arguments)
135
                : $arguments;
136
        }
137
138 2
        return new self(array_merge([
139 2
            self::CLASS_NAME => $other->getClass(),
140 2
            self::CONSTRUCTOR => $this->mergeArguments(
141 2
                $this->getConstructorArguments(),
142 2
                $other->getConstructorArguments()
143
            ),
144
        ], $methodsAndProperties));
145
    }
146
147 2
    private function mergeArguments(array $selfArguments, array $otherArguments): array
148
    {
149
        /** @var mixed $argument */
150 2
        foreach ($otherArguments as $name => $argument) {
151
            /** @var mixed */
152 1
            $selfArguments[$name] = $argument;
153
        }
154
155 2
        return $selfArguments;
156
    }
157
158
    /**
159
     * @param mixed $value
160
     */
161 1
    private function getType($value): string
162
    {
163 1
        return is_object($value) ? get_class($value) : gettype($value);
164
    }
165
166
    public function getMeta(): array
167
    {
168
        return $this->meta;
169
    }
170
}
171