@vituum/vite-plugin-latte 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/vendor/autoload.php +1 -1
- package/vendor/composer/autoload_classmap.php +49 -0
- package/vendor/composer/autoload_real.php +4 -4
- package/vendor/composer/autoload_static.php +51 -2
- package/vendor/composer/installed.json +102 -12
- package/vendor/composer/installed.php +14 -5
- package/vendor/latte/latte/composer.json +6 -5
- package/vendor/latte/latte/readme.md +27 -9
- package/vendor/latte/latte/src/Bridges/Tracy/templates/LattePanel.panel.phtml +4 -1
- package/vendor/latte/latte/src/Latte/Compiler/TagLexer.php +1 -1
- package/vendor/latte/latte/src/Latte/Compiler/TagParserData.php +129 -129
- package/vendor/latte/latte/src/Latte/Compiler/TemplateGenerator.php +1 -1
- package/vendor/latte/latte/src/Latte/Compiler/TemplateParser.php +1 -1
- package/vendor/latte/latte/src/Latte/Engine.php +22 -2
- package/vendor/latte/latte/src/Latte/Essential/CachingIterator.php +2 -3
- package/vendor/latte/latte/src/Latte/Essential/CoreExtension.php +9 -1
- package/vendor/latte/latte/src/Latte/Essential/Filters.php +110 -10
- package/vendor/latte/latte/src/Latte/Essential/Nodes/ImportNode.php +8 -2
- package/vendor/latte/latte/src/Latte/Essential/Nodes/VarNode.php +14 -18
- package/vendor/latte/latte/src/Latte/Essential/TranslatorExtension.php +1 -1
- package/vendor/latte/latte/src/Latte/Loaders/FileLoader.php +5 -4
- package/vendor/latte/latte/src/Latte/Runtime/Template.php +1 -1
- package/vendor/latte/latte/src/Latte/Sandbox/Nodes/FunctionCallNode.php +0 -1
- package/vendor/nette/utils/.phpstorm.meta.php +13 -0
- package/vendor/nette/utils/composer.json +51 -0
- package/vendor/nette/utils/license.md +60 -0
- package/vendor/nette/utils/readme.md +55 -0
- package/vendor/nette/utils/src/HtmlStringable.php +22 -0
- package/vendor/nette/utils/src/Iterators/CachingIterator.php +150 -0
- package/vendor/nette/utils/src/Iterators/Mapper.php +33 -0
- package/vendor/nette/utils/src/SmartObject.php +140 -0
- package/vendor/nette/utils/src/StaticClass.php +34 -0
- package/vendor/nette/utils/src/Translator.php +25 -0
- package/vendor/nette/utils/src/Utils/ArrayHash.php +106 -0
- package/vendor/nette/utils/src/Utils/ArrayList.php +136 -0
- package/vendor/nette/utils/src/Utils/Arrays.php +553 -0
- package/vendor/nette/utils/src/Utils/Callback.php +137 -0
- package/vendor/nette/utils/src/Utils/DateTime.php +140 -0
- package/vendor/nette/utils/src/Utils/FileInfo.php +69 -0
- package/vendor/nette/utils/src/Utils/FileSystem.php +326 -0
- package/vendor/nette/utils/src/Utils/Finder.php +510 -0
- package/vendor/nette/utils/src/Utils/Floats.php +107 -0
- package/vendor/nette/utils/src/Utils/Helpers.php +104 -0
- package/vendor/nette/utils/src/Utils/Html.php +839 -0
- package/vendor/nette/utils/src/Utils/Image.php +831 -0
- package/vendor/nette/utils/src/Utils/ImageColor.php +75 -0
- package/vendor/nette/utils/src/Utils/ImageType.php +25 -0
- package/vendor/nette/utils/src/Utils/Iterables.php +238 -0
- package/vendor/nette/utils/src/Utils/Json.php +84 -0
- package/vendor/nette/utils/src/Utils/ObjectHelpers.php +229 -0
- package/vendor/nette/utils/src/Utils/Paginator.php +245 -0
- package/vendor/nette/utils/src/Utils/Random.php +52 -0
- package/vendor/nette/utils/src/Utils/Reflection.php +322 -0
- package/vendor/nette/utils/src/Utils/ReflectionMethod.php +36 -0
- package/vendor/nette/utils/src/Utils/Strings.php +728 -0
- package/vendor/nette/utils/src/Utils/Type.php +267 -0
- package/vendor/nette/utils/src/Utils/Validators.php +416 -0
- package/vendor/nette/utils/src/Utils/exceptions.php +50 -0
- package/vendor/nette/utils/src/compatibility.php +32 -0
- package/vendor/nette/utils/src/exceptions.php +109 -0
|
@@ -0,0 +1,75 @@
|
|
|
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\Utils;
|
|
11
|
+
|
|
12
|
+
use Nette;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Represent RGB color (0..255) with opacity (0..1).
|
|
17
|
+
*/
|
|
18
|
+
class ImageColor
|
|
19
|
+
{
|
|
20
|
+
public static function rgb(int $red, int $green, int $blue, float $opacity = 1): self
|
|
21
|
+
{
|
|
22
|
+
return new self($red, $green, $blue, $opacity);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Accepts formats #RRGGBB, #RRGGBBAA, #RGB, #RGBA
|
|
28
|
+
*/
|
|
29
|
+
public static function hex(string $hex): self
|
|
30
|
+
{
|
|
31
|
+
$hex = ltrim($hex, '#');
|
|
32
|
+
$len = strlen($hex);
|
|
33
|
+
if ($len === 3 || $len === 4) {
|
|
34
|
+
return new self(
|
|
35
|
+
(int) hexdec($hex[0]) * 17,
|
|
36
|
+
(int) hexdec($hex[1]) * 17,
|
|
37
|
+
(int) hexdec($hex[2]) * 17,
|
|
38
|
+
(int) hexdec($hex[3] ?? 'F') * 17 / 255,
|
|
39
|
+
);
|
|
40
|
+
} elseif ($len === 6 || $len === 8) {
|
|
41
|
+
return new self(
|
|
42
|
+
(int) hexdec($hex[0] . $hex[1]),
|
|
43
|
+
(int) hexdec($hex[2] . $hex[3]),
|
|
44
|
+
(int) hexdec($hex[4] . $hex[5]),
|
|
45
|
+
(int) hexdec(($hex[6] ?? 'F') . ($hex[7] ?? 'F')) / 255,
|
|
46
|
+
);
|
|
47
|
+
} else {
|
|
48
|
+
throw new Nette\InvalidArgumentException('Invalid hex color format.');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
private function __construct(
|
|
54
|
+
public int $red,
|
|
55
|
+
public int $green,
|
|
56
|
+
public int $blue,
|
|
57
|
+
public float $opacity = 1,
|
|
58
|
+
) {
|
|
59
|
+
$this->red = max(0, min(255, $red));
|
|
60
|
+
$this->green = max(0, min(255, $green));
|
|
61
|
+
$this->blue = max(0, min(255, $blue));
|
|
62
|
+
$this->opacity = max(0, min(1, $opacity));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
public function toRGBA(): array
|
|
67
|
+
{
|
|
68
|
+
return [
|
|
69
|
+
max(0, min(255, $this->red)),
|
|
70
|
+
max(0, min(255, $this->green)),
|
|
71
|
+
max(0, min(255, $this->blue)),
|
|
72
|
+
max(0, min(127, (int) round(127 - $this->opacity * 127))),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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\Utils;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Type of image file.
|
|
15
|
+
*/
|
|
16
|
+
/*enum*/ final class ImageType
|
|
17
|
+
{
|
|
18
|
+
public const
|
|
19
|
+
JPEG = IMAGETYPE_JPEG,
|
|
20
|
+
PNG = IMAGETYPE_PNG,
|
|
21
|
+
GIF = IMAGETYPE_GIF,
|
|
22
|
+
WEBP = IMAGETYPE_WEBP,
|
|
23
|
+
AVIF = 19, // IMAGETYPE_AVIF,
|
|
24
|
+
BMP = IMAGETYPE_BMP;
|
|
25
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
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\Utils;
|
|
11
|
+
|
|
12
|
+
use Nette;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Utilities for iterables.
|
|
17
|
+
*/
|
|
18
|
+
final class Iterables
|
|
19
|
+
{
|
|
20
|
+
use Nette\StaticClass;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tests for the presence of value.
|
|
24
|
+
*/
|
|
25
|
+
public static function contains(iterable $iterable, mixed $value): bool
|
|
26
|
+
{
|
|
27
|
+
foreach ($iterable as $v) {
|
|
28
|
+
if ($v === $value) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Tests for the presence of key.
|
|
38
|
+
*/
|
|
39
|
+
public static function containsKey(iterable $iterable, mixed $key): bool
|
|
40
|
+
{
|
|
41
|
+
foreach ($iterable as $k => $v) {
|
|
42
|
+
if ($k === $key) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
|
52
|
+
* @template K
|
|
53
|
+
* @template V
|
|
54
|
+
* @param iterable<K, V> $iterable
|
|
55
|
+
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
|
56
|
+
* @return ?V
|
|
57
|
+
*/
|
|
58
|
+
public static function first(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
|
59
|
+
{
|
|
60
|
+
foreach ($iterable as $k => $v) {
|
|
61
|
+
if (!$predicate || $predicate($v, $k, $iterable)) {
|
|
62
|
+
return $v;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return $else ? $else() : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns the key of first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
|
71
|
+
* @template K
|
|
72
|
+
* @template V
|
|
73
|
+
* @param iterable<K, V> $iterable
|
|
74
|
+
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
|
75
|
+
* @return ?K
|
|
76
|
+
*/
|
|
77
|
+
public static function firstKey(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
|
78
|
+
{
|
|
79
|
+
foreach ($iterable as $k => $v) {
|
|
80
|
+
if (!$predicate || $predicate($v, $k, $iterable)) {
|
|
81
|
+
return $k;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return $else ? $else() : null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Tests whether at least one element in the iterator passes the test implemented by the provided function.
|
|
90
|
+
* @template K
|
|
91
|
+
* @template V
|
|
92
|
+
* @param iterable<K, V> $iterable
|
|
93
|
+
* @param callable(V, K, iterable<K, V>): bool $predicate
|
|
94
|
+
*/
|
|
95
|
+
public static function some(iterable $iterable, callable $predicate): bool
|
|
96
|
+
{
|
|
97
|
+
foreach ($iterable as $k => $v) {
|
|
98
|
+
if ($predicate($v, $k, $iterable)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Tests whether all elements in the iterator pass the test implemented by the provided function.
|
|
108
|
+
* @template K
|
|
109
|
+
* @template V
|
|
110
|
+
* @param iterable<K, V> $iterable
|
|
111
|
+
* @param callable(V, K, iterable<K, V>): bool $predicate
|
|
112
|
+
*/
|
|
113
|
+
public static function every(iterable $iterable, callable $predicate): bool
|
|
114
|
+
{
|
|
115
|
+
foreach ($iterable as $k => $v) {
|
|
116
|
+
if (!$predicate($v, $k, $iterable)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Iterator that filters elements according to a given $predicate. Maintains original keys.
|
|
126
|
+
* @template K
|
|
127
|
+
* @template V
|
|
128
|
+
* @param iterable<K, V> $iterable
|
|
129
|
+
* @param callable(V, K, iterable<K, V>): bool $predicate
|
|
130
|
+
* @return \Generator<K, V>
|
|
131
|
+
*/
|
|
132
|
+
public static function filter(iterable $iterable, callable $predicate): \Generator
|
|
133
|
+
{
|
|
134
|
+
foreach ($iterable as $k => $v) {
|
|
135
|
+
if ($predicate($v, $k, $iterable)) {
|
|
136
|
+
yield $k => $v;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Iterator that transforms values by calling $transformer. Maintains original keys.
|
|
144
|
+
* @template K
|
|
145
|
+
* @template V
|
|
146
|
+
* @template R
|
|
147
|
+
* @param iterable<K, V> $iterable
|
|
148
|
+
* @param callable(V, K, iterable<K, V>): R $transformer
|
|
149
|
+
* @return \Generator<K, R>
|
|
150
|
+
*/
|
|
151
|
+
public static function map(iterable $iterable, callable $transformer): \Generator
|
|
152
|
+
{
|
|
153
|
+
foreach ($iterable as $k => $v) {
|
|
154
|
+
yield $k => $transformer($v, $k, $iterable);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Iterator that transforms keys and values by calling $transformer. If it returns null, the element is skipped.
|
|
161
|
+
* @template K
|
|
162
|
+
* @template V
|
|
163
|
+
* @template ResV
|
|
164
|
+
* @template ResK
|
|
165
|
+
* @param iterable<K, V> $iterable
|
|
166
|
+
* @param callable(V, K, iterable<K, V>): ?array{ResV, ResK} $transformer
|
|
167
|
+
* @return \Generator<ResV, ResK>
|
|
168
|
+
*/
|
|
169
|
+
public static function mapWithKeys(iterable $iterable, callable $transformer): \Generator
|
|
170
|
+
{
|
|
171
|
+
foreach ($iterable as $k => $v) {
|
|
172
|
+
$pair = $transformer($v, $k, $iterable);
|
|
173
|
+
if ($pair) {
|
|
174
|
+
yield $pair[0] => $pair[1];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Wraps around iterator and caches its keys and values during iteration.
|
|
182
|
+
* This allows the data to be re-iterated multiple times.
|
|
183
|
+
* @template K
|
|
184
|
+
* @template V
|
|
185
|
+
* @param iterable<K, V> $iterable
|
|
186
|
+
* @return \IteratorAggregate<K, V>
|
|
187
|
+
*/
|
|
188
|
+
public static function memoize(iterable $iterable): iterable
|
|
189
|
+
{
|
|
190
|
+
return new class (self::toIterator($iterable)) implements \IteratorAggregate {
|
|
191
|
+
public function __construct(
|
|
192
|
+
private \Iterator $iterator,
|
|
193
|
+
private array $cache = [],
|
|
194
|
+
) {
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
public function getIterator(): \Generator
|
|
199
|
+
{
|
|
200
|
+
if (!$this->cache) {
|
|
201
|
+
$this->iterator->rewind();
|
|
202
|
+
}
|
|
203
|
+
$i = 0;
|
|
204
|
+
while (true) {
|
|
205
|
+
if (isset($this->cache[$i])) {
|
|
206
|
+
[$k, $v] = $this->cache[$i];
|
|
207
|
+
} elseif ($this->iterator->valid()) {
|
|
208
|
+
$k = $this->iterator->key();
|
|
209
|
+
$v = $this->iterator->current();
|
|
210
|
+
$this->iterator->next();
|
|
211
|
+
$this->cache[$i] = [$k, $v];
|
|
212
|
+
} else {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
yield $k => $v;
|
|
216
|
+
$i++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Creates an iterator from anything that is iterable.
|
|
225
|
+
* @template K
|
|
226
|
+
* @template V
|
|
227
|
+
* @param iterable<K, V> $iterable
|
|
228
|
+
* @return \Iterator<K, V>
|
|
229
|
+
*/
|
|
230
|
+
public static function toIterator(iterable $iterable): \Iterator
|
|
231
|
+
{
|
|
232
|
+
return match (true) {
|
|
233
|
+
$iterable instanceof \Iterator => $iterable,
|
|
234
|
+
$iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()),
|
|
235
|
+
is_array($iterable) => new \ArrayIterator($iterable),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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\Utils;
|
|
11
|
+
|
|
12
|
+
use Nette;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* JSON encoder and decoder.
|
|
17
|
+
*/
|
|
18
|
+
final class Json
|
|
19
|
+
{
|
|
20
|
+
use Nette\StaticClass;
|
|
21
|
+
|
|
22
|
+
/** @deprecated use Json::decode(..., forceArrays: true) */
|
|
23
|
+
public const FORCE_ARRAY = JSON_OBJECT_AS_ARRAY;
|
|
24
|
+
|
|
25
|
+
/** @deprecated use Json::encode(..., pretty: true) */
|
|
26
|
+
public const PRETTY = JSON_PRETTY_PRINT;
|
|
27
|
+
|
|
28
|
+
/** @deprecated use Json::encode(..., asciiSafe: true) */
|
|
29
|
+
public const ESCAPE_UNICODE = 1 << 19;
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Converts value to JSON format. Use $pretty for easier reading and clarity, $asciiSafe for ASCII output
|
|
34
|
+
* and $htmlSafe for HTML escaping, $forceObjects enforces the encoding of non-associateve arrays as objects.
|
|
35
|
+
* @throws JsonException
|
|
36
|
+
*/
|
|
37
|
+
public static function encode(
|
|
38
|
+
mixed $value,
|
|
39
|
+
bool|int $pretty = false,
|
|
40
|
+
bool $asciiSafe = false,
|
|
41
|
+
bool $htmlSafe = false,
|
|
42
|
+
bool $forceObjects = false,
|
|
43
|
+
): string
|
|
44
|
+
{
|
|
45
|
+
if (is_int($pretty)) { // back compatibility
|
|
46
|
+
$flags = ($pretty & self::ESCAPE_UNICODE ? 0 : JSON_UNESCAPED_UNICODE) | ($pretty & ~self::ESCAPE_UNICODE);
|
|
47
|
+
} else {
|
|
48
|
+
$flags = ($asciiSafe ? 0 : JSON_UNESCAPED_UNICODE)
|
|
49
|
+
| ($pretty ? JSON_PRETTY_PRINT : 0)
|
|
50
|
+
| ($forceObjects ? JSON_FORCE_OBJECT : 0)
|
|
51
|
+
| ($htmlSafe ? JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG : 0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$flags |= JSON_UNESCAPED_SLASHES
|
|
55
|
+
| (defined('JSON_PRESERVE_ZERO_FRACTION') ? JSON_PRESERVE_ZERO_FRACTION : 0); // since PHP 5.6.6 & PECL JSON-C 1.3.7
|
|
56
|
+
|
|
57
|
+
$json = json_encode($value, $flags);
|
|
58
|
+
if ($error = json_last_error()) {
|
|
59
|
+
throw new JsonException(json_last_error_msg(), $error);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return $json;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Parses JSON to PHP value. The $forceArrays enforces the decoding of objects as arrays.
|
|
68
|
+
* @throws JsonException
|
|
69
|
+
*/
|
|
70
|
+
public static function decode(string $json, bool|int $forceArrays = false): mixed
|
|
71
|
+
{
|
|
72
|
+
$flags = is_int($forceArrays) // back compatibility
|
|
73
|
+
? $forceArrays
|
|
74
|
+
: ($forceArrays ? JSON_OBJECT_AS_ARRAY : 0);
|
|
75
|
+
$flags |= JSON_BIGINT_AS_STRING;
|
|
76
|
+
|
|
77
|
+
$value = json_decode($json, flags: $flags);
|
|
78
|
+
if ($error = json_last_error()) {
|
|
79
|
+
throw new JsonException(json_last_error_msg(), $error);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return $value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
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\Utils;
|
|
11
|
+
|
|
12
|
+
use Nette;
|
|
13
|
+
use Nette\MemberAccessException;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Nette\SmartObject helpers.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
final class ObjectHelpers
|
|
21
|
+
{
|
|
22
|
+
use Nette\StaticClass;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @return never
|
|
26
|
+
* @throws MemberAccessException
|
|
27
|
+
*/
|
|
28
|
+
public static function strictGet(string $class, string $name): void
|
|
29
|
+
{
|
|
30
|
+
$rc = new \ReflectionClass($class);
|
|
31
|
+
$hint = self::getSuggestion(array_merge(
|
|
32
|
+
array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()),
|
|
33
|
+
self::parseFullDoc($rc, '~^[ \t*]*@property(?:-read)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'),
|
|
34
|
+
), $name);
|
|
35
|
+
throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.'));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @return never
|
|
41
|
+
* @throws MemberAccessException
|
|
42
|
+
*/
|
|
43
|
+
public static function strictSet(string $class, string $name): void
|
|
44
|
+
{
|
|
45
|
+
$rc = new \ReflectionClass($class);
|
|
46
|
+
$hint = self::getSuggestion(array_merge(
|
|
47
|
+
array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()),
|
|
48
|
+
self::parseFullDoc($rc, '~^[ \t*]*@property(?:-write)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'),
|
|
49
|
+
), $name);
|
|
50
|
+
throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.'));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @return never
|
|
56
|
+
* @throws MemberAccessException
|
|
57
|
+
*/
|
|
58
|
+
public static function strictCall(string $class, string $method, array $additionalMethods = []): void
|
|
59
|
+
{
|
|
60
|
+
$trace = debug_backtrace(0, 3); // suppose this method is called from __call()
|
|
61
|
+
$context = ($trace[1]['function'] ?? null) === '__call'
|
|
62
|
+
? ($trace[2]['class'] ?? null)
|
|
63
|
+
: null;
|
|
64
|
+
|
|
65
|
+
if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
|
|
66
|
+
$class = get_parent_class($context);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (method_exists($class, $method)) { // insufficient visibility
|
|
70
|
+
$rm = new \ReflectionMethod($class, $method);
|
|
71
|
+
$visibility = $rm->isPrivate()
|
|
72
|
+
? 'private '
|
|
73
|
+
: ($rm->isProtected() ? 'protected ' : '');
|
|
74
|
+
throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
|
|
75
|
+
|
|
76
|
+
} else {
|
|
77
|
+
$hint = self::getSuggestion(array_merge(
|
|
78
|
+
get_class_methods($class),
|
|
79
|
+
self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:static[ \t]+)?(?:\S+[ \t]+)??(\w+)\(~m'),
|
|
80
|
+
$additionalMethods,
|
|
81
|
+
), $method);
|
|
82
|
+
throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @return never
|
|
89
|
+
* @throws MemberAccessException
|
|
90
|
+
*/
|
|
91
|
+
public static function strictStaticCall(string $class, string $method): void
|
|
92
|
+
{
|
|
93
|
+
$trace = debug_backtrace(0, 3); // suppose this method is called from __callStatic()
|
|
94
|
+
$context = ($trace[1]['function'] ?? null) === '__callStatic'
|
|
95
|
+
? ($trace[2]['class'] ?? null)
|
|
96
|
+
: null;
|
|
97
|
+
|
|
98
|
+
if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method()
|
|
99
|
+
$class = get_parent_class($context);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (method_exists($class, $method)) { // insufficient visibility
|
|
103
|
+
$rm = new \ReflectionMethod($class, $method);
|
|
104
|
+
$visibility = $rm->isPrivate()
|
|
105
|
+
? 'private '
|
|
106
|
+
: ($rm->isProtected() ? 'protected ' : '');
|
|
107
|
+
throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.'));
|
|
108
|
+
|
|
109
|
+
} else {
|
|
110
|
+
$hint = self::getSuggestion(
|
|
111
|
+
array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), fn($m) => $m->isStatic()),
|
|
112
|
+
$method,
|
|
113
|
+
);
|
|
114
|
+
throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.'));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns array of magic properties defined by annotation @property.
|
|
121
|
+
* @return array of [name => bit mask]
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
public static function getMagicProperties(string $class): array
|
|
125
|
+
{
|
|
126
|
+
static $cache;
|
|
127
|
+
$props = &$cache[$class];
|
|
128
|
+
if ($props !== null) {
|
|
129
|
+
return $props;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
$rc = new \ReflectionClass($class);
|
|
133
|
+
preg_match_all(
|
|
134
|
+
'~^ [ \t*]* @property(|-read|-write|-deprecated) [ \t]+ [^\s$]+ [ \t]+ \$ (\w+) ()~mx',
|
|
135
|
+
(string) $rc->getDocComment(),
|
|
136
|
+
$matches,
|
|
137
|
+
PREG_SET_ORDER,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
$props = [];
|
|
141
|
+
foreach ($matches as [, $type, $name]) {
|
|
142
|
+
$uname = ucfirst($name);
|
|
143
|
+
$write = $type !== '-read'
|
|
144
|
+
&& $rc->hasMethod($nm = 'set' . $uname)
|
|
145
|
+
&& ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
|
|
146
|
+
$read = $type !== '-write'
|
|
147
|
+
&& ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname))
|
|
148
|
+
&& ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic();
|
|
149
|
+
|
|
150
|
+
if ($read || $write) {
|
|
151
|
+
$props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3 | ($type === '-deprecated') << 4;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
foreach ($rc->getTraits() as $trait) {
|
|
156
|
+
$props += self::getMagicProperties($trait->name);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if ($parent = get_parent_class($class)) {
|
|
160
|
+
$props += self::getMagicProperties($parent);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return $props;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Finds the best suggestion (for 8-bit encoding).
|
|
169
|
+
* @param (\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionClass|\ReflectionProperty|string)[] $possibilities
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
public static function getSuggestion(array $possibilities, string $value): ?string
|
|
173
|
+
{
|
|
174
|
+
$norm = preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '+', $value);
|
|
175
|
+
$best = null;
|
|
176
|
+
$min = (strlen($value) / 4 + 1) * 10 + .1;
|
|
177
|
+
foreach (array_unique($possibilities, SORT_REGULAR) as $item) {
|
|
178
|
+
$item = $item instanceof \Reflector ? $item->name : $item;
|
|
179
|
+
if ($item !== $value && (
|
|
180
|
+
($len = levenshtein($item, $value, 10, 11, 10)) < $min
|
|
181
|
+
|| ($len = levenshtein(preg_replace($re, '*', $item), $norm, 10, 11, 10)) < $min
|
|
182
|
+
)) {
|
|
183
|
+
$min = $len;
|
|
184
|
+
$best = $item;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return $best;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
private static function parseFullDoc(\ReflectionClass $rc, string $pattern): array
|
|
193
|
+
{
|
|
194
|
+
do {
|
|
195
|
+
$doc[] = $rc->getDocComment();
|
|
196
|
+
$traits = $rc->getTraits();
|
|
197
|
+
while ($trait = array_pop($traits)) {
|
|
198
|
+
$doc[] = $trait->getDocComment();
|
|
199
|
+
$traits += $trait->getTraits();
|
|
200
|
+
}
|
|
201
|
+
} while ($rc = $rc->getParentClass());
|
|
202
|
+
|
|
203
|
+
return preg_match_all($pattern, implode('', $doc), $m) ? $m[1] : [];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Checks if the public non-static property exists.
|
|
209
|
+
* Returns 'event' if the property exists and has event like name
|
|
210
|
+
* @internal
|
|
211
|
+
*/
|
|
212
|
+
public static function hasProperty(string $class, string $name): bool|string
|
|
213
|
+
{
|
|
214
|
+
static $cache;
|
|
215
|
+
$prop = &$cache[$class][$name];
|
|
216
|
+
if ($prop === null) {
|
|
217
|
+
$prop = false;
|
|
218
|
+
try {
|
|
219
|
+
$rp = new \ReflectionProperty($class, $name);
|
|
220
|
+
if ($rp->isPublic() && !$rp->isStatic()) {
|
|
221
|
+
$prop = $name >= 'onA' && $name < 'on_' ? 'event' : true;
|
|
222
|
+
}
|
|
223
|
+
} catch (\ReflectionException $e) {
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return $prop;
|
|
228
|
+
}
|
|
229
|
+
}
|