Test Failed
Pull Request — master (#212)
by Sergei
04:51 queued 02:31
created

DefinitionParser::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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