Test Failed
Push — refactoring ( b23161...e32e17 )
by Sergei
05:17 queued 02:54
created

DefinitionParser::prepareDefinitionFromArray()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 45
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 26
nc 8
nop 2
dl 0
loc 45
ccs 7
cts 7
cp 1
crap 8
rs 8.4444
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Di;
6
7
use League\Container\Definition\DefinitionInterface;
8
use Yiisoft\Factory\Definition\ArrayDefinition;
9
use Yiisoft\Factory\Definition\ArrayDefinitionValidator;
0 ignored issues
show
Bug introduced by
The type Yiisoft\Factory\Definiti...rrayDefinitionValidator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
10
use Yiisoft\Factory\Exception\InvalidConfigException;
11
12
use function get_class;
13
use function gettype;
14
use function in_array;
15
use function is_array;
16
use function is_object;
17
use function is_string;
18
19
/**
20
 * @internal Splits metadata and definition.
21
 *
22
 * Supports the following configuration:
23
 *
24
 * 1) With a dedicated definition:
25
 *
26
 * ```php
27
 * Engine::class => [
28
 *     'definition' => [
29
 *         '__class' => BigEngine::class,
30
 *         'setNumber()' => [42],
31
 *     ],
32
 *     'tags' => ['a', 'b'],
33
 *     'reset' => function () {
34
 *         $this->number = 42;
35
 *      },
36
 * ]
37
 * ```
38
 *
39
 * 2) Mixed in array definition:
40
 *
41
 * ```php
42
 * Engine::class => [
43
 *     '__class' => BigEngine::class,
44
 *     'setNumber()' => [42],
45
 *     'tags' => ['a', 'b'],
46
 *     'reset' => function () {
47
 *         $this->number = 42;
48
 *      },
49
 * ]
50
 * ```
51
 */
52
final class DefinitionParser
53 99
{
54
    private const DEFINITION_META = 'definition';
55 99
56 99
    private array $allowedMeta;
57
58
    public function __construct(array $allowedMeta)
59
    {
60
        $this->allowedMeta = $allowedMeta;
61
    }
62
63 99
    /**
64
     * @param mixed $definition
65 99
     *
66 93
     * @throws InvalidConfigException
67
     */
68
    public function parse($definition): array
69
    {
70 41
        if (!is_array($definition)) {
71 3
            $this->checkNotPhpArrayDefinition($definition);
72 3
            return [$definition, []];
73 3
        }
74 3
75
        // Dedicated definition
76 3
        if (isset($definition[self::DEFINITION_META])) {
77
            $newDefinition = $definition[self::DEFINITION_META];
78
            unset($definition[self::DEFINITION_META]);
79 38
80 38
            foreach ($definition as $key => $_value) {
81
                $this->checkMetaKey($key);
82 38
            }
83 3
84
            if (is_array($newDefinition)) {
85
                $this->prepareDefinitionFromArray($newDefinition);
86
            } else {
87
                $this->checkNotPhpArrayDefinition($newDefinition);
88 35
            }
89 32
90 24
            return [$newDefinition, $definition];
91 35
        }
92
93 35
        $meta = [];
94
        $this->prepareDefinitionFromArray($definition, $meta);
95
        return [$definition, $meta];
96 16
    }
97
98 14
    /**
99 14
     * @throws InvalidConfigException
100
     */
101
    private function prepareDefinitionFromArray(array &$definition, array &$meta = null): void
102 35
    {
103
        $result = [
104
            ArrayDefinition::IS_PREPARED_CONFIG => true,
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Factory\Definiti...ion::IS_PREPARED_CONFIG was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
105
            ArrayDefinition::METHODS_AND_PROPERTIES => [],
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Factory\Definiti...:METHODS_AND_PROPERTIES was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
106
        ];
107
        foreach ($definition as $key => $value) {
108 19
            // It is not array definition
109
            if (!is_string($key)) {
110 19
                $this->checkNotPhpArrayDefinition($definition);
111 3
                return;
112 3
            }
113 3
114
            // Class
115
            if ($key === ArrayDefinition::CLASS_NAME) {
116
                ArrayDefinitionValidator::validateClassName($value);
117
                $result[$key] = $value;
118
                continue;
119
            }
120 17
121
            // Constructor arguments
122
            if ($key === ArrayDefinition::CONSTRUCTOR) {
123
                ArrayDefinitionValidator::validateConstructorArguments($value);
124
                $result[$key] = $value;
125
                continue;
126
            }
127
128
            // Methods and properties
129
            if (substr($key, -2) === '()') {
130
                ArrayDefinitionValidator::validateMethodArguments($value);
131
                $result[ArrayDefinition::METHODS_AND_PROPERTIES][$key] = [ArrayDefinition::FLAG_METHOD, $key, $value];
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Factory\Definiti...Definition::FLAG_METHOD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
132
                continue;
133
            }
134
            if (strncmp($key, '$', 1) === 0) {
135
                $result[ArrayDefinition::METHODS_AND_PROPERTIES][$key] = [ArrayDefinition::FLAG_PROPERTY, $key, $value];
0 ignored issues
show
Bug introduced by
The constant Yiisoft\Factory\Definiti...finition::FLAG_PROPERTY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
136
                continue;
137
            }
138
139
            $this->checkMetaKey($key);
140
141
            if ($meta !== null) {
142
                $meta[$key] = $value;
143
            }
144
        }
145
        $definition = $result;
146
    }
147
148
    /**
149
     * @param mixed $definition
150
     *
151
     * @throws InvalidConfigException
152
     */
153
    private function checkNotPhpArrayDefinition($definition): void
154
    {
155
        if ($definition instanceof DefinitionInterface) {
156
            return;
157
        }
158
159
        if (is_array($definition)) {
160
            return;
161
        }
162
163
        if (is_string($definition) && !empty($definition)) {
164
            return;
165
        }
166
167
        if (is_object($definition)) {
168
            return;
169
        }
170
171
        throw new InvalidConfigException('Invalid definition:' . var_export($definition, true));
172
    }
173
174
    /**
175
     * @throws InvalidConfigException
176
     */
177
    private function checkMetaKey(string $key): void
178
    {
179
        if (!in_array($key, $this->allowedMeta, true)) {
180
            throw new InvalidConfigException(
181
                sprintf(
182
                    'Invalid definition: metadata "%s" is not allowed. Did you mean "%s()" or "$%s"?',
183
                    $key,
184
                    $key,
185
                    $key,
186
                )
187
            );
188
        }
189
    }
190
}
191