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

throwInvalidArrayDefinitionKey()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 12
c 0
b 0
f 0
dl 0
loc 19
ccs 9
cts 9
cp 1
rs 9.8666
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory\Definition;
6
7
use Yiisoft\Factory\Exception\InvalidConfigException;
8
9
use function get_class;
10
use function gettype;
11
use function is_array;
12
use function is_callable;
13
use function is_object;
14
use function is_string;
15
16
final class DefinitionValidator
17
{
18
    /**
19
     * @param mixed $definition
20
     *
21
     * @throws InvalidConfigException
22
     */
23 33
    public static function validate($definition, ?string $id = null): void
24
    {
25
        // Reference or ready object
26 33
        if (is_object($definition)) {
27 2
            return;
28
        }
29
30
        // Class
31 33
        if (is_string($definition) && $definition !== '') {
32 19
            return;
33
        }
34
35
        // Callable definition
36 19
        if (is_callable($definition, true)) {
37
            return;
38
        }
39
40
        // Array definition
41 19
        if (is_array($definition)) {
42 19
            self::validateArrayDefinition($definition, $id);
43 8
            return;
44
        }
45
46
        throw new InvalidConfigException('Invalid definition:' . var_export($definition, true));
47
    }
48
49
    /**
50
     * @throws InvalidConfigException
51
     */
52 19
    private static function validateArrayDefinition(array $definition, ?string $id): void
53
    {
54 19
        foreach ($definition as $key => $value) {
55 18
            if (!is_string($key)) {
56 1
                throw new InvalidConfigException(
57 1
                    sprintf(
58 1
                        'Invalid definition: invalid key in array definition. Allow only string keys, got %d.',
59
                        $key,
60
                    ),
61
                );
62
            }
63
64
            // Class
65 18
            if ($key === ArrayDefinition::CLASS_NAME) {
66 17
                if (!is_string($value)) {
67 1
                    throw new InvalidConfigException(
68 1
                        sprintf(
69 1
                            'Invalid definition: invalid class name. Expected string, got %s.',
70 1
                            self::getType($value),
71
                        ),
72
                    );
73
                }
74 16
                if ($value === '') {
75 1
                    throw new InvalidConfigException('Invalid definition: empty class name.');
76
                }
77 15
                continue;
78
            }
79
80
            // Constructor arguments
81 15
            if ($key === ArrayDefinition::CONSTRUCTOR) {
82 4
                if (!is_array($value)) {
83 1
                    throw new InvalidConfigException(
84 1
                        sprintf(
85 1
                            'Invalid definition: incorrect constructor arguments. Expected array, got %s.',
86 1
                            self::getType($value)
87
                        )
88
                    );
89
                }
90 3
                continue;
91
            }
92
93
            // Methods and properties
94 11
            if (substr($key, -2) === '()') {
95 6
                if (!is_array($value)) {
96 1
                    throw new InvalidConfigException(
97 1
                        sprintf(
98 1
                            'Invalid definition: incorrect method arguments. Expected array, got %s.',
99 1
                            self::getType($value)
100
                        )
101
                    );
102
                }
103 5
                continue;
104
            }
105 6
            if (strncmp($key, '$', 1) === 0) {
106 1
                continue;
107
            }
108
109 5
            self::throwInvalidArrayDefinitionKey($key);
110
        }
111
112 9
        if ($id === null && !isset($definition[ArrayDefinition::CLASS_NAME])) {
113 1
            throw new InvalidConfigException('Invalid definition: no class name specified.');
114
        }
115 8
    }
116
117
    /**
118
     * @throws InvalidConfigException
119
     */
120 5
    private static function throwInvalidArrayDefinitionKey(string $key): void
121
    {
122 5
        $preparedKey = trim(strtr($key, [
123 5
            '()' => '',
124
            '$' => '',
125
        ]));
126
127 5
        if ($preparedKey === '' || !preg_match('/^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/', $preparedKey)) {
128 1
            throw new InvalidConfigException(
129 1
                sprintf('Invalid definition: key "%s" is not allowed.', $key)
130
            );
131
        }
132
133 4
        throw new InvalidConfigException(
134 4
            sprintf(
135 4
                'Invalid definition: key "%s" is not allowed. Did you mean "%s()" or "$%s"?',
136
                $key,
137
                $preparedKey,
138
                $preparedKey
139
            )
140
        );
141
    }
142
143
    /**
144
     * @param mixed $value
145
     */
146 3
    private static function getType($value): string
147
    {
148 3
        return is_object($value) ? get_class($value) : gettype($value);
149
    }
150
}
151