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

nette / schema / 3615460175

pending completion
3615460175

push

github

David
constants are PascalCase

26 of 26 new or added lines in 5 files covered. (100.0%)

439 of 450 relevant lines covered (97.56%)

0.98 hits per line

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

96.94
/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;
13
use Nette\Schema\Context;
14
use Nette\Schema\DynamicParameter;
15
use Nette\Schema\Helpers;
16
use Nette\Schema\Schema;
17

18

19
final class Type implements Schema
20
{
21
        use Base;
22
        use Nette\SmartObject;
23

24
        /** @var string */
25
        private $type;
26

27
        /** @var Schema|null for arrays */
28
        private $itemsValue;
29

30
        /** @var Schema|null for arrays */
31
        private $itemsKey;
32

33
        /** @var array{?float, ?float} */
34
        private $range = [null, null];
35

36
        /** @var string|null */
37
        private $pattern;
38

39
        /** @var bool */
40
        private $merge = true;
41

42

43
        public function __construct(string $type)
1✔
44
        {
45
                $defaults = ['list' => [], 'array' => []];
1✔
46
                $this->type = $type;
1✔
47
                $this->default = strpos($type, '[]') ? [] : $defaults[$type] ?? null;
1✔
48
        }
1✔
49

50

51
        public function nullable(): self
52
        {
53
                $this->type = 'null|' . $this->type;
1✔
54
                return $this;
1✔
55
        }
56

57

58
        public function mergeDefaults(bool $state = true): self
1✔
59
        {
60
                $this->merge = $state;
1✔
61
                return $this;
1✔
62
        }
63

64

65
        public function dynamic(): self
66
        {
67
                $this->type = DynamicParameter::class . '|' . $this->type;
1✔
68
                return $this;
1✔
69
        }
70

71

72
        public function min(?float $min): self
1✔
73
        {
74
                $this->range[0] = $min;
1✔
75
                return $this;
1✔
76
        }
77

78

79
        public function max(?float $max): self
1✔
80
        {
81
                $this->range[1] = $max;
1✔
82
                return $this;
1✔
83
        }
84

85

86
        /**
87
         * @param  string|Schema  $valueType
88
         * @param  string|Schema|null  $keyType
89
         * @internal  use arrayOf() or listOf()
90
         */
91
        public function items($valueType = 'mixed', $keyType = null): self
1✔
92
        {
93
                $this->itemsValue = $valueType instanceof Schema
1✔
94
                        ? $valueType
1✔
95
                        : new self($valueType);
1✔
96
                $this->itemsKey = $keyType instanceof Schema || $keyType === null
1✔
97
                        ? $keyType
1✔
98
                        : new self($keyType);
×
99
                return $this;
1✔
100
        }
101

102

103
        public function pattern(?string $pattern): self
1✔
104
        {
105
                $this->pattern = $pattern;
1✔
106
                return $this;
1✔
107
        }
108

109

110
        /********************* processing ****************d*g**/
111

112

113
        public function normalize($value, Context $context)
1✔
114
        {
115
                if ($prevent = (is_array($value) && isset($value[Helpers::PreventMerging]))) {
1✔
116
                        unset($value[Helpers::PreventMerging]);
1✔
117
                }
118

119
                $value = $this->doNormalize($value, $context);
1✔
120
                if (is_array($value) && $this->itemsValue) {
1✔
121
                        $res = [];
1✔
122
                        foreach ($value as $key => $val) {
1✔
123
                                $context->path[] = $key;
1✔
124
                                $context->isKey = true;
1✔
125
                                $key = $this->itemsKey
1✔
126
                                        ? $this->itemsKey->normalize($key, $context)
1✔
127
                                        : $key;
1✔
128
                                $context->isKey = false;
1✔
129
                                $res[$key] = $this->itemsValue->normalize($val, $context);
1✔
130
                                array_pop($context->path);
1✔
131
                        }
132

133
                        $value = $res;
1✔
134
                }
135

136
                if ($prevent && is_array($value)) {
1✔
137
                        $value[Helpers::PreventMerging] = true;
1✔
138
                }
139

140
                return $value;
1✔
141
        }
142

143

144
        public function merge($value, $base)
145
        {
146
                if (is_array($value) && isset($value[Helpers::PreventMerging])) {
1✔
147
                        unset($value[Helpers::PreventMerging]);
×
148
                        return $value;
×
149
                }
150

151
                if (is_array($value) && is_array($base) && $this->itemsValue) {
1✔
152
                        $index = 0;
1✔
153
                        foreach ($value as $key => $val) {
1✔
154
                                if ($key === $index) {
1✔
155
                                        $base[] = $val;
1✔
156
                                        $index++;
1✔
157
                                } else {
158
                                        $base[$key] = array_key_exists($key, $base)
1✔
159
                                                ? $this->itemsValue->merge($val, $base[$key])
1✔
160
                                                : $val;
1✔
161
                                }
162
                        }
163

164
                        return $base;
1✔
165
                }
166

167
                return Helpers::merge($value, $base);
1✔
168
        }
169

170

171
        public function complete($value, Context $context)
1✔
172
        {
173
                $merge = $this->merge;
1✔
174
                if (is_array($value) && isset($value[Helpers::PreventMerging])) {
1✔
175
                        unset($value[Helpers::PreventMerging]);
1✔
176
                        $merge = false;
1✔
177
                }
178

179
                if ($value === null && is_array($this->default)) {
1✔
180
                        $value = []; // is unable to distinguish null from array in NEON
1✔
181
                }
182

183
                $this->doDeprecation($context);
1✔
184

185
                if (!$this->doValidate($value, $this->type, $context)
1✔
186
                        || !$this->doValidateRange($value, $this->range, $context, $this->type)
1✔
187
                ) {
188
                        return;
1✔
189
                }
190

191
                if ($value !== null && $this->pattern !== null && !preg_match("\x01^(?:$this->pattern)$\x01Du", $value)) {
1✔
192
                        $context->addError(
1✔
193
                                "The %label% %path% expects to match pattern '%pattern%', %value% given.",
1✔
194
                                Nette\Schema\Message::PatternMismatch,
1✔
195
                                ['value' => $value, 'pattern' => $this->pattern]
1✔
196
                        );
197
                        return;
1✔
198
                }
199

200
                if ($value instanceof DynamicParameter) {
1✔
201
                        $expected = $this->type . ($this->range === [null, null] ? '' : ':' . implode('..', $this->range));
1✔
202
                        $context->dynamics[] = [$value, str_replace(DynamicParameter::class . '|', '', $expected)];
1✔
203
                }
204

205
                if ($this->itemsValue) {
1✔
206
                        $errCount = count($context->errors);
1✔
207
                        $res = [];
1✔
208
                        foreach ($value as $key => $val) {
1✔
209
                                $context->path[] = $key;
1✔
210
                                $context->isKey = true;
1✔
211
                                $key = $this->itemsKey ? $this->itemsKey->complete($key, $context) : $key;
1✔
212
                                $context->isKey = false;
1✔
213
                                $res[$key] = $this->itemsValue->complete($val, $context);
1✔
214
                                array_pop($context->path);
1✔
215
                        }
216

217
                        if (count($context->errors) > $errCount) {
1✔
218
                                return null;
1✔
219
                        }
220

221
                        $value = $res;
1✔
222
                }
223

224
                if ($merge) {
1✔
225
                        $value = Helpers::merge($value, $this->default);
1✔
226
                }
227

228
                return $this->doFinalize($value, $context);
1✔
229
        }
230
}
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