• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / schema / 11205893850

06 Oct 2024 11:00PM UTC coverage: 96.559% (-0.9%) from 97.421%
11205893850

push

github

dg
Expect::array(shape) returns Structure

4 of 4 new or added lines in 1 file covered. (100.0%)

7 existing lines in 2 files now uncovered.

477 of 494 relevant lines covered (96.56%)

0.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.91
/src/Schema/Elements/Type.php
1
<?php
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
declare(strict_types=1);
9

10
namespace Nette\Schema\Elements;
11

12
use Nette\Schema\Context;
13
use Nette\Schema\DynamicParameter;
14
use Nette\Schema\Helpers;
15
use Nette\Schema\Schema;
16

17

18
final class Type implements Schema
19
{
20
        use Base;
21

22
        private string $type;
23
        private ?Schema $itemsValue = null;
24
        private ?Schema $itemsKey = null;
25

26
        /** @var array{?float, ?float} */
27
        private array $range = [null, null];
28
        private ?string $pattern = null;
29
        private bool $merge = true;
30

31

32
        public function __construct(string $type)
1✔
33
        {
34
                $defaults = ['list' => [], 'array' => []];
1✔
35
                $this->type = $type;
1✔
36
                $this->default = strpos($type, '[]') ? [] : $defaults[$type] ?? null;
1✔
37
        }
1✔
38

39

40
        public function nullable(): self
41
        {
42
                $this->type = 'null|' . $this->type;
1✔
43
                return $this;
1✔
44
        }
45

46

47
        public function mergeDefaults(bool $state = true): self
1✔
48
        {
49
                $this->merge = $state;
1✔
50
                return $this;
1✔
51
        }
52

53

54
        public function dynamic(): self
55
        {
56
                $this->type = DynamicParameter::class . '|' . $this->type;
1✔
57
                return $this;
1✔
58
        }
59

60

61
        public function min(?float $min): self
1✔
62
        {
63
                $this->range[0] = $min;
1✔
64
                return $this;
1✔
65
        }
66

67

68
        public function max(?float $max): self
1✔
69
        {
70
                $this->range[1] = $max;
1✔
71
                return $this;
1✔
72
        }
73

74

75
        /**
76
         * @internal  use arrayOf() or listOf()
77
         */
78
        public function items(string|Schema $valueType = 'mixed', string|Schema|null $keyType = null): self
1✔
79
        {
80
                $this->itemsValue = $valueType instanceof Schema
1✔
81
                        ? $valueType
1✔
82
                        : new self($valueType);
1✔
83
                $this->itemsKey = $keyType instanceof Schema || $keyType === null
1✔
84
                        ? $keyType
1✔
UNCOV
85
                        : new self($keyType);
×
86
                return $this;
1✔
87
        }
88

89

90
        public function pattern(?string $pattern): self
1✔
91
        {
92
                $this->pattern = $pattern;
1✔
93
                return $this;
1✔
94
        }
95

96

97
        /********************* processing ****************d*g**/
98

99

100
        public function normalize(mixed $value, Context $context): mixed
1✔
101
        {
102
                if ($prevent = (is_array($value) && isset($value[Helpers::PreventMerging]))) {
1✔
103
                        unset($value[Helpers::PreventMerging]);
1✔
104
                }
105

106
                $value = $this->doNormalize($value, $context);
1✔
107
                if (is_array($value) && $this->itemsValue) {
1✔
108
                        $res = [];
1✔
109
                        foreach ($value as $key => $val) {
1✔
110
                                $context->path[] = $key;
1✔
111
                                $context->isKey = true;
1✔
112
                                $key = $this->itemsKey
1✔
113
                                        ? $this->itemsKey->normalize($key, $context)
1✔
114
                                        : $key;
1✔
115
                                $context->isKey = false;
1✔
116
                                $res[$key] = $this->itemsValue->normalize($val, $context);
1✔
117
                                array_pop($context->path);
1✔
118
                        }
119

120
                        $value = $res;
1✔
121
                }
122

123
                if ($prevent && is_array($value)) {
1✔
124
                        $value[Helpers::PreventMerging] = true;
1✔
125
                }
126

127
                return $value;
1✔
128
        }
129

130

131
        public function merge(mixed $value, mixed $base): mixed
1✔
132
        {
133
                if (is_array($value) && isset($value[Helpers::PreventMerging])) {
1✔
UNCOV
134
                        unset($value[Helpers::PreventMerging]);
×
UNCOV
135
                        return $value;
×
136
                }
137

138
                if (is_array($value) && is_array($base) && $this->itemsValue) {
1✔
139
                        $index = 0;
1✔
140
                        foreach ($value as $key => $val) {
1✔
141
                                if ($key === $index) {
1✔
142
                                        $base[] = $val;
1✔
143
                                        $index++;
1✔
144
                                } else {
145
                                        $base[$key] = array_key_exists($key, $base)
1✔
146
                                                ? $this->itemsValue->merge($val, $base[$key])
1✔
147
                                                : $val;
1✔
148
                                }
149
                        }
150

151
                        return $base;
1✔
152
                }
153

154
                return Helpers::merge($value, $base);
1✔
155
        }
156

157

158
        public function complete(mixed $value, Context $context): mixed
1✔
159
        {
160
                $merge = $this->merge;
1✔
161
                if (is_array($value) && isset($value[Helpers::PreventMerging])) {
1✔
162
                        unset($value[Helpers::PreventMerging]);
1✔
163
                        $merge = false;
1✔
164
                }
165

166
                if ($value === null && is_array($this->default)) {
1✔
167
                        $value = []; // is unable to distinguish null from array in NEON
1✔
168
                }
169

170
                $this->doDeprecation($context);
1✔
171

172
                $isOk = $context->createChecker();
1✔
173
                Helpers::validateType($value, $this->type, $context);
1✔
174
                $isOk() && Helpers::validateRange($value, $this->range, $context, $this->type);
1✔
175
                $isOk() && $value !== null && $this->pattern !== null && Helpers::validatePattern($value, $this->pattern, $context);
1✔
176
                $isOk() && is_array($value) && $this->validateItems($value, $context);
1✔
177
                $isOk() && $merge && $value = Helpers::merge($value, $this->default);
1✔
178
                $isOk() && $value = $this->doTransform($value, $context);
1✔
179
                if (!$isOk()) {
1✔
180
                        return null;
1✔
181
                }
182

183
                if ($value instanceof DynamicParameter) {
1✔
184
                        $expected = $this->type . ($this->range === [null, null] ? '' : ':' . implode('..', $this->range));
1✔
185
                        $context->dynamics[] = [$value, str_replace(DynamicParameter::class . '|', '', $expected), $context->path];
1✔
186
                }
187
                return $value;
1✔
188
        }
189

190

191
        private function validateItems(array &$value, Context $context): void
1✔
192
        {
193
                if (!$this->itemsValue) {
1✔
194
                        return;
1✔
195
                }
196

197
                $res = [];
1✔
198
                foreach ($value as $key => $val) {
1✔
199
                        $context->path[] = $key;
1✔
200
                        $context->isKey = true;
1✔
201
                        $key = $this->itemsKey ? $this->itemsKey->complete($key, $context) : $key;
1✔
202
                        $context->isKey = false;
1✔
203
                        $res[$key] = $this->itemsValue->complete($val, $context);
1✔
204
                        array_pop($context->path);
1✔
205
                }
206
                $value = $res;
1✔
207
        }
1✔
208
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc