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

nette / schema / 6399713247

04 Oct 2023 12:00AM UTC coverage: 96.115%. Remained the same
6399713247

push

github

dg
castTo() allows you to create objects [Closes #44][Closes #47][Closes #58][Closes #46]

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

470 of 489 relevant lines covered (96.11%)

0.96 hits per line

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

96.88
/src/Schema/Helpers.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;
11

12
use Nette;
13
use Nette\Utils\Reflection;
14

15

16
/**
17
 * @internal
18
 */
19
final class Helpers
20
{
21
        use Nette\StaticClass;
22

23
        public const PreventMerging = '_prevent_merging';
24
        public const PREVENT_MERGING = self::PreventMerging;
25

26

27
        /**
28
         * Merges dataset. Left has higher priority than right one.
29
         * @return array|string
30
         */
31
        public static function merge($value, $base)
32
        {
33
                if (is_array($value) && isset($value[self::PreventMerging])) {
1✔
34
                        unset($value[self::PreventMerging]);
1✔
35
                        return $value;
1✔
36
                }
37

38
                if (is_array($value) && is_array($base)) {
1✔
39
                        $index = 0;
1✔
40
                        foreach ($value as $key => $val) {
1✔
41
                                if ($key === $index) {
1✔
42
                                        $base[] = $val;
1✔
43
                                        $index++;
1✔
44
                                } else {
45
                                        $base[$key] = static::merge($val, $base[$key] ?? null);
1✔
46
                                }
47
                        }
48

49
                        return $base;
1✔
50

51
                } elseif ($value === null && is_array($base)) {
1✔
52
                        return $base;
1✔
53

54
                } else {
55
                        return $value;
1✔
56
                }
57
        }
58

59

60
        public static function getPropertyType(\ReflectionProperty $prop): ?string
1✔
61
        {
62
                if (!class_exists(Nette\Utils\Type::class)) {
1✔
63
                        throw new Nette\NotSupportedException('Expect::from() requires nette/utils 3.x');
×
64
                } elseif ($type = Nette\Utils\Type::fromReflection($prop)) {
1✔
65
                        return (string) $type;
1✔
66
                } elseif ($type = preg_replace('#\s.*#', '', (string) self::parseAnnotation($prop, 'var'))) {
1✔
67
                        $class = Reflection::getPropertyDeclaringClass($prop);
1✔
68
                        return preg_replace_callback('#[\w\\\\]+#', function ($m) use ($class) {
1✔
69
                                return Reflection::expandClassName($m[0], $class);
1✔
70
                        }, $type);
1✔
71
                }
72

73
                return null;
1✔
74
        }
75

76

77
        /**
78
         * Returns an annotation value.
79
         * @param  \ReflectionProperty  $ref
80
         */
81
        public static function parseAnnotation(\Reflector $ref, string $name): ?string
1✔
82
        {
83
                if (!Reflection::areCommentsAvailable()) {
1✔
84
                        throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
×
85
                }
86

87
                $re = '#[\s*]@' . preg_quote($name, '#') . '(?=\s|$)(?:[ \t]+([^@\s]\S*))?#';
1✔
88
                if ($ref->getDocComment() && preg_match($re, trim($ref->getDocComment(), '/*'), $m)) {
1✔
89
                        return $m[1] ?? '';
1✔
90
                }
91

92
                return null;
1✔
93
        }
94

95

96
        /**
97
         * @param  mixed  $value
98
         */
99
        public static function formatValue($value): string
100
        {
101
                if (is_object($value)) {
1✔
102
                        return 'object ' . get_class($value);
1✔
103
                } elseif (is_string($value)) {
1✔
104
                        return "'" . Nette\Utils\Strings::truncate($value, 15, '...') . "'";
1✔
105
                } elseif (is_scalar($value)) {
1✔
106
                        return var_export($value, true);
1✔
107
                } else {
108
                        return strtolower(gettype($value));
1✔
109
                }
110
        }
111

112

113
        public static function validateType($value, string $expected, Context $context): void
1✔
114
        {
115
                if (!Nette\Utils\Validators::is($value, $expected)) {
1✔
116
                        $expected = str_replace(DynamicParameter::class . '|', '', $expected);
1✔
117
                        $expected = str_replace(['|', ':'], [' or ', ' in range '], $expected);
1✔
118
                        $context->addError(
1✔
119
                                'The %label% %path% expects to be %expected%, %value% given.',
1✔
120
                                Message::TypeMismatch,
1✔
121
                                ['value' => $value, 'expected' => $expected]
1✔
122
                        );
123
                }
124
        }
1✔
125

126

127
        public static function validateRange($value, array $range, Context $context, string $types = ''): void
1✔
128
        {
129
                if (is_array($value) || is_string($value)) {
1✔
130
                        [$length, $label] = is_array($value)
1✔
131
                                ? [count($value), 'items']
1✔
132
                                : (in_array('unicode', explode('|', $types), true)
1✔
133
                                        ? [Nette\Utils\Strings::length($value), 'characters']
1✔
134
                                        : [strlen($value), 'bytes']);
1✔
135

136
                        if (!self::isInRange($length, $range)) {
1✔
137
                                $context->addError(
1✔
138
                                        "The length of %label% %path% expects to be in range %expected%, %length% $label given.",
1✔
139
                                        Message::LengthOutOfRange,
1✔
140
                                        ['value' => $value, 'length' => $length, 'expected' => implode('..', $range)]
1✔
141
                                );
142
                        }
143
                } elseif ((is_int($value) || is_float($value)) && !self::isInRange($value, $range)) {
1✔
144
                        $context->addError(
1✔
145
                                'The %label% %path% expects to be in range %expected%, %value% given.',
1✔
146
                                Message::ValueOutOfRange,
1✔
147
                                ['value' => $value, 'expected' => implode('..', $range)]
1✔
148
                        );
149
                }
150
        }
1✔
151

152

153
        public static function isInRange($value, array $range): bool
1✔
154
        {
155
                return ($range[0] === null || $value >= $range[0])
1✔
156
                        && ($range[1] === null || $value <= $range[1]);
1✔
157
        }
158

159

160
        public static function validatePattern(string $value, string $pattern, Context $context): void
1✔
161
        {
162
                if (!preg_match("\x01^(?:$pattern)$\x01Du", $value)) {
1✔
163
                        $context->addError(
1✔
164
                                "The %label% %path% expects to match pattern '%pattern%', %value% given.",
1✔
165
                                Message::PatternMismatch,
1✔
166
                                ['value' => $value, 'pattern' => $pattern]
1✔
167
                        );
168
                }
169
        }
1✔
170

171

172
        public static function getCastStrategy(string $type): \Closure
1✔
173
        {
174
                if (Nette\Utils\Reflection::isBuiltinType($type)) {
1✔
175
                        return static function ($value) use ($type) {
1✔
176
                                settype($value, $type);
1✔
177
                                return $value;
1✔
178
                        };
1✔
179
                } elseif (method_exists($type, '__construct')) {
1✔
180
                        return static function ($value) use ($type) {
1✔
181
                                if (PHP_VERSION_ID < 80000 && is_array($value)) {
1✔
182
                                        throw new Nette\NotSupportedException("Creating $type objects is supported since PHP 8.0");
×
183
                                }
184
                                return is_array($value)
1✔
185
                                        ? new $type(...$value)
1✔
186
                                        : new $type($value);
1✔
187
                        };
1✔
188
                } else {
189
                        return static function ($value) use ($type) {
1✔
190
                                $object = new $type;
1✔
191
                                foreach ($value as $k => $v) {
1✔
192
                                        $object->$k = $v;
1✔
193
                                }
194
                                return $object;
1✔
195
                        };
1✔
196
                }
197
        }
198
}
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