🔧
This commit is contained in:
2
vendor/nette/utils/composer.json
vendored
2
vendor/nette/utils/composer.json
vendored
@@ -15,7 +15,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0 <8.4"
|
||||
"php": "8.0 - 8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/tester": "^2.5",
|
||||
|
||||
47
vendor/nette/utils/readme.md
vendored
47
vendor/nette/utils/readme.md
vendored
@@ -1,5 +1,4 @@
|
||||
Nette Utility Classes
|
||||
=====================
|
||||
[](https://doc.nette.org/en/utils)
|
||||
|
||||
[](https://packagist.org/packages/nette/utils)
|
||||
[](https://github.com/nette/utils/actions)
|
||||
@@ -11,25 +10,27 @@ Nette Utility Classes
|
||||
Introduction
|
||||
------------
|
||||
|
||||
In package nette/utils you will find a set of [useful classes](https://doc.nette.org/utils) for everyday use:
|
||||
In package nette/utils you will find a set of useful classes for everyday use:
|
||||
|
||||
- [Arrays](https://doc.nette.org/utils/arrays) - manipulate arrays
|
||||
- [Callback](https://doc.nette.org/utils/callback) - PHP callbacks
|
||||
- [Date and Time](https://doc.nette.org/utils/datetime) - modify times and dates
|
||||
- [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …
|
||||
- [Finder](https://doc.nette.org/utils/finder) - finds files and directories
|
||||
- [Helper Functions](https://doc.nette.org/utils/helpers)
|
||||
- [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML
|
||||
- [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images
|
||||
- [JSON](https://doc.nette.org/utils/json) - encoding and decoding
|
||||
- [Generating Random Strings](https://doc.nette.org/utils/random)
|
||||
- [Paginator](https://doc.nette.org/utils/paginator) - pagination math
|
||||
- [PHP Reflection](https://doc.nette.org/utils/reflection)
|
||||
- [Strings](https://doc.nette.org/utils/strings) - useful text functions
|
||||
- [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements
|
||||
- [Validation](https://doc.nette.org/utils/validators) - validate inputs
|
||||
- [Type](https://doc.nette.org/utils/type) - PHP data type
|
||||
✅ [Arrays](https://doc.nette.org/utils/arrays)<br>
|
||||
✅ [Callback](https://doc.nette.org/utils/callback) - PHP callbacks<br>
|
||||
✅ [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …<br>
|
||||
✅ [Finder](https://doc.nette.org/utils/finder) - finds files and directories<br>
|
||||
✅ [Floats](https://doc.nette.org/utils/floats) - floating point numbers<br>
|
||||
✅ [Helper Functions](https://doc.nette.org/utils/helpers)<br>
|
||||
✅ [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML<br>
|
||||
✅ [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images<br>
|
||||
✅ [Iterables](https://doc.nette.org/utils/iterables) <br>
|
||||
✅ [JSON](https://doc.nette.org/utils/json) - encoding and decoding<br>
|
||||
✅ [Generating Random Strings](https://doc.nette.org/utils/random)<br>
|
||||
✅ [Paginator](https://doc.nette.org/utils/paginator) - pagination math<br>
|
||||
✅ [PHP Reflection](https://doc.nette.org/utils/reflection)<br>
|
||||
✅ [Strings](https://doc.nette.org/utils/strings) - useful text functions<br>
|
||||
✅ [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements<br>
|
||||
✅ [Type](https://doc.nette.org/utils/type) - PHP data type<br>
|
||||
✅ [Validation](https://doc.nette.org/utils/validators) - validate inputs<br>
|
||||
|
||||
<!---->
|
||||
|
||||
Installation
|
||||
------------
|
||||
@@ -40,11 +41,9 @@ The recommended way to install is via Composer:
|
||||
composer require nette/utils
|
||||
```
|
||||
|
||||
- Nette Utils 4.0 is compatible with PHP 8.0 to 8.3
|
||||
- Nette Utils 3.2 is compatible with PHP 7.2 to 8.3
|
||||
- Nette Utils 3.1 is compatible with PHP 7.1 to 8.0
|
||||
- Nette Utils 3.0 is compatible with PHP 7.1 to 8.0
|
||||
- Nette Utils 2.5 is compatible with PHP 5.6 to 8.0
|
||||
Nette Utils 4.0 is compatible with PHP 8.0 to 8.4.
|
||||
|
||||
<!---->
|
||||
|
||||
[Support Me](https://github.com/sponsors/dg)
|
||||
--------------------------------------------
|
||||
|
||||
@@ -31,26 +31,12 @@ class CachingIterator extends \CachingIterator implements \Countable
|
||||
private int $counter = 0;
|
||||
|
||||
|
||||
public function __construct($iterator)
|
||||
public function __construct(iterable|\stdClass $iterable)
|
||||
{
|
||||
if (is_array($iterator) || $iterator instanceof \stdClass) {
|
||||
$iterator = new \ArrayIterator($iterator);
|
||||
|
||||
} elseif ($iterator instanceof \IteratorAggregate) {
|
||||
do {
|
||||
$iterator = $iterator->getIterator();
|
||||
} while ($iterator instanceof \IteratorAggregate);
|
||||
|
||||
assert($iterator instanceof \Iterator);
|
||||
|
||||
} elseif ($iterator instanceof \Iterator) {
|
||||
} elseif ($iterator instanceof \Traversable) {
|
||||
$iterator = new \IteratorIterator($iterator);
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException(sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', self::class, get_debug_type($iterator)));
|
||||
}
|
||||
|
||||
parent::__construct($iterator, 0);
|
||||
$iterable = $iterable instanceof \stdClass
|
||||
? new \ArrayIterator($iterable)
|
||||
: Nette\Utils\Iterables::toIterator($iterable);
|
||||
parent::__construct($iterable, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
3
vendor/nette/utils/src/Iterators/Mapper.php
vendored
3
vendor/nette/utils/src/Iterators/Mapper.php
vendored
@@ -10,9 +10,8 @@ declare(strict_types=1);
|
||||
namespace Nette\Iterators;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Applies the callback to the elements of the inner iterator.
|
||||
* @deprecated use Nette\Utils\Iterables::map()
|
||||
*/
|
||||
class Mapper extends \IteratorIterator
|
||||
{
|
||||
|
||||
90
vendor/nette/utils/src/Utils/Arrays.php
vendored
90
vendor/nette/utils/src/Utils/Arrays.php
vendored
@@ -122,10 +122,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template T
|
||||
* @param array<T> $array
|
||||
* @return ?T
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function first(array $array, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -138,10 +139,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the last item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template T
|
||||
* @param array<T> $array
|
||||
* @return ?T
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function last(array $array, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -154,7 +156,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the key of first item (matching the specified predicate if given) or null if there is no such item.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function firstKey(array $array, ?callable $predicate = null): int|string|null
|
||||
{
|
||||
@@ -172,7 +178,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns the key of last item (matching the specified predicate if given) or null if there is no such item.
|
||||
* The $predicate has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param ?callable(V, K, array<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function lastKey(array $array, ?callable $predicate = null): int|string|null
|
||||
{
|
||||
@@ -267,7 +277,8 @@ class Arrays
|
||||
*/
|
||||
public static function isList(mixed $value): bool
|
||||
{
|
||||
return is_array($value) && (PHP_VERSION_ID < 80100
|
||||
return is_array($value) && (
|
||||
PHP_VERSION_ID < 80100
|
||||
? !$value || array_keys($value) === range(0, count($value) - 1)
|
||||
: array_is_list($value)
|
||||
);
|
||||
@@ -368,12 +379,11 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether at least one element in the array passes the test implemented by the provided function,
|
||||
* which has the signature `function ($value, $key, array $array): bool`.
|
||||
* @template K
|
||||
* Tests whether at least one element in the array passes the test implemented by the provided function.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
*/
|
||||
public static function some(iterable $array, callable $predicate): bool
|
||||
{
|
||||
@@ -388,12 +398,11 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether all elements in the array pass the test implemented by the provided function,
|
||||
* which has the signature `function ($value, $key, array $array): bool`.
|
||||
* @template K
|
||||
* Tests whether all elements in the array pass the test implemented by the provided function.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
*/
|
||||
public static function every(iterable $array, callable $predicate): bool
|
||||
{
|
||||
@@ -409,11 +418,10 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns a new array containing all key-value pairs matching the given $predicate.
|
||||
* The callback has the signature `function (mixed $value, int|string $key, array $array): bool`.
|
||||
* @template K of array-key
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): bool $predicate
|
||||
* @return array<K, V>
|
||||
*/
|
||||
public static function filter(array $array, callable $predicate): array
|
||||
@@ -430,12 +438,11 @@ class Arrays
|
||||
|
||||
/**
|
||||
* Returns an array containing the original keys and results of applying the given transform function to each element.
|
||||
* The function has signature `function ($value, $key, array $array): mixed`.
|
||||
* @template K of array-key
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @template R
|
||||
* @param iterable<K, V> $array
|
||||
* @param callable(V, K, ($array is array ? array<K, V> : iterable<K, V>)): R $transformer
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): R $transformer
|
||||
* @return array<K, R>
|
||||
*/
|
||||
public static function map(iterable $array, callable $transformer): array
|
||||
@@ -449,6 +456,31 @@ class Arrays
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array containing new keys and values generated by applying the given transform function to each element.
|
||||
* If the function returns null, the element is skipped.
|
||||
* @template K of int|string
|
||||
* @template V
|
||||
* @template ResK of int|string
|
||||
* @template ResV
|
||||
* @param array<K, V> $array
|
||||
* @param callable(V, K, array<K, V>): ?array{ResK, ResV} $transformer
|
||||
* @return array<ResK, ResV>
|
||||
*/
|
||||
public static function mapWithKeys(array $array, callable $transformer): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($array as $k => $v) {
|
||||
$pair = $transformer($v, $k, $array);
|
||||
if ($pair) {
|
||||
$res[$pair[0]] = $pair[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invokes all callbacks and returns array of results.
|
||||
* @param callable[] $callbacks
|
||||
|
||||
2
vendor/nette/utils/src/Utils/Callback.php
vendored
2
vendor/nette/utils/src/Utils/Callback.php
vendored
@@ -94,7 +94,7 @@ final class Callback
|
||||
}
|
||||
|
||||
if (is_string($callable) && str_contains($callable, '::')) {
|
||||
return new ReflectionMethod($callable);
|
||||
return new ReflectionMethod(...explode('::', $callable, 2));
|
||||
} elseif (is_array($callable)) {
|
||||
return new ReflectionMethod($callable[0], $callable[1]);
|
||||
} elseif (is_object($callable) && !$callable instanceof \Closure) {
|
||||
|
||||
17
vendor/nette/utils/src/Utils/FileSystem.php
vendored
17
vendor/nette/utils/src/Utils/FileSystem.php
vendored
@@ -271,7 +271,7 @@ final class FileSystem
|
||||
*/
|
||||
public static function isAbsolute(string $path): bool
|
||||
{
|
||||
return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
|
||||
return (bool) preg_match('#([a-z]:)?[/\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
|
||||
}
|
||||
|
||||
|
||||
@@ -280,7 +280,7 @@ final class FileSystem
|
||||
*/
|
||||
public static function normalizePath(string $path): string
|
||||
{
|
||||
$parts = $path === '' ? [] : preg_split('~[/\\\\]+~', $path);
|
||||
$parts = $path === '' ? [] : preg_split('~[/\\\]+~', $path);
|
||||
$res = [];
|
||||
foreach ($parts as $part) {
|
||||
if ($part === '..' && $res && end($res) !== '..' && end($res) !== '') {
|
||||
@@ -305,6 +305,19 @@ final class FileSystem
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a path against a base path. If the path is absolute, returns it directly, if it's relative, joins it with the base path.
|
||||
*/
|
||||
public static function resolvePath(string $basePath, string $path): string
|
||||
{
|
||||
return match (true) {
|
||||
self::isAbsolute($path) => self::platformSlashes($path),
|
||||
$path === '' => self::platformSlashes($basePath),
|
||||
default => self::joinPaths($basePath, $path),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts backslashes to slashes.
|
||||
*/
|
||||
|
||||
2
vendor/nette/utils/src/Utils/Finder.php
vendored
2
vendor/nette/utils/src/Utils/Finder.php
vendored
@@ -505,6 +505,6 @@ class Finder implements \IteratorAggregate
|
||||
'\-' => '-',
|
||||
],
|
||||
);
|
||||
return '#' . $anchor . $pattern . '$#D' . (defined('PHP_WINDOWS_VERSION_BUILD') ? 'i' : '');
|
||||
return '#' . $anchor . $pattern . '$#D' . (Helpers::IsWindows ? 'i' : '');
|
||||
}
|
||||
}
|
||||
|
||||
3
vendor/nette/utils/src/Utils/Helpers.php
vendored
3
vendor/nette/utils/src/Utils/Helpers.php
vendored
@@ -14,6 +14,9 @@ use Nette;
|
||||
|
||||
class Helpers
|
||||
{
|
||||
public const IsWindows = PHP_OS_FAMILY === 'Windows';
|
||||
|
||||
|
||||
/**
|
||||
* Executes a callback and returns the captured output as a string.
|
||||
*/
|
||||
|
||||
77
vendor/nette/utils/src/Utils/Image.php
vendored
77
vendor/nette/utils/src/Utils/Image.php
vendored
@@ -163,10 +163,7 @@ class Image
|
||||
*/
|
||||
public static function fromFile(string $file, ?int &$type = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
$type = self::detectTypeFromFile($file);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
|
||||
@@ -183,10 +180,7 @@ class Image
|
||||
*/
|
||||
public static function fromString(string $s, ?int &$type = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
$type = self::detectTypeFromString($s);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException('Unknown type of image.');
|
||||
@@ -221,10 +215,7 @@ class Image
|
||||
*/
|
||||
public static function fromBlank(int $width, int $height, ImageColor|array|null $color = null): static
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
self::ensureExtension();
|
||||
if ($width < 1 || $height < 1) {
|
||||
throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
|
||||
}
|
||||
@@ -308,6 +299,7 @@ class Image
|
||||
*/
|
||||
public static function isTypeSupported(int $type): bool
|
||||
{
|
||||
self::ensureExtension();
|
||||
return (bool) (imagetypes() & match ($type) {
|
||||
ImageType::JPEG => IMG_JPG,
|
||||
ImageType::PNG => IMG_PNG,
|
||||
@@ -323,6 +315,7 @@ class Image
|
||||
/** @return ImageType[] */
|
||||
public static function getSupportedTypes(): array
|
||||
{
|
||||
self::ensureExtension();
|
||||
$flag = imagetypes();
|
||||
return array_filter([
|
||||
$flag & IMG_GIF ? ImageType::GIF : null,
|
||||
@@ -640,6 +633,7 @@ class Image
|
||||
array $options = [],
|
||||
): array
|
||||
{
|
||||
self::ensureExtension();
|
||||
$box = imagettfbbox($size, $angle, $fontFile, $text, $options);
|
||||
return [
|
||||
'left' => $minX = min([$box[0], $box[2], $box[4], $box[6]]),
|
||||
@@ -724,42 +718,27 @@ class Image
|
||||
*/
|
||||
private function output(int $type, ?int $quality, ?string $file = null): void
|
||||
{
|
||||
switch ($type) {
|
||||
case ImageType::JPEG:
|
||||
$quality = $quality === null ? 85 : max(0, min(100, $quality));
|
||||
$success = @imagejpeg($this->image, $file, $quality); // @ is escalated to exception
|
||||
break;
|
||||
[$defQuality, $min, $max] = match ($type) {
|
||||
ImageType::JPEG => [85, 0, 100],
|
||||
ImageType::PNG => [9, 0, 9],
|
||||
ImageType::GIF => [null, null, null],
|
||||
ImageType::WEBP => [80, 0, 100],
|
||||
ImageType::AVIF => [30, 0, 100],
|
||||
ImageType::BMP => [null, null, null],
|
||||
default => throw new Nette\InvalidArgumentException("Unsupported image type '$type'."),
|
||||
};
|
||||
|
||||
case ImageType::PNG:
|
||||
$quality = $quality === null ? 9 : max(0, min(9, $quality));
|
||||
$success = @imagepng($this->image, $file, $quality); // @ is escalated to exception
|
||||
break;
|
||||
|
||||
case ImageType::GIF:
|
||||
$success = @imagegif($this->image, $file); // @ is escalated to exception
|
||||
break;
|
||||
|
||||
case ImageType::WEBP:
|
||||
$quality = $quality === null ? 80 : max(0, min(100, $quality));
|
||||
$success = @imagewebp($this->image, $file, $quality); // @ is escalated to exception
|
||||
break;
|
||||
|
||||
case ImageType::AVIF:
|
||||
$quality = $quality === null ? 30 : max(0, min(100, $quality));
|
||||
$success = @imageavif($this->image, $file, $quality); // @ is escalated to exception
|
||||
break;
|
||||
|
||||
case ImageType::BMP:
|
||||
$success = @imagebmp($this->image, $file); // @ is escalated to exception
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Nette\InvalidArgumentException("Unsupported image type '$type'.");
|
||||
$args = [$this->image, $file];
|
||||
if ($defQuality !== null) {
|
||||
$args[] = $quality === null ? $defQuality : max($min, min($max, $quality));
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
throw new ImageException(Helpers::getLastError() ?: 'Unknown error');
|
||||
}
|
||||
Callback::invokeSafe('image' . self::Formats[$type], $args, function (string $message) use ($file): void {
|
||||
if ($file !== null) {
|
||||
@unlink($file);
|
||||
}
|
||||
throw new ImageException($message);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -826,4 +805,12 @@ class Image
|
||||
$color = $color instanceof ImageColor ? $color->toRGBA() : array_values($color);
|
||||
return imagecolorallocatealpha($this->image, ...$color) ?: imagecolorresolvealpha($this->image, ...$color);
|
||||
}
|
||||
|
||||
|
||||
private static function ensureExtension(): void
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
120
vendor/nette/utils/src/Utils/Iterables.php
vendored
120
vendor/nette/utils/src/Utils/Iterables.php
vendored
@@ -49,10 +49,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null.
|
||||
* The $predicate has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template T
|
||||
* @param iterable<T> $iterable
|
||||
* @return ?T
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return ?V
|
||||
*/
|
||||
public static function first(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -67,10 +68,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The $predicate has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template T
|
||||
* @param iterable<T, mixed> $iterable
|
||||
* @return ?T
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param ?callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return ?K
|
||||
*/
|
||||
public static function firstKey(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed
|
||||
{
|
||||
@@ -84,11 +86,10 @@ final class Iterables
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether at least one element in the iterator passes the test implemented by the
|
||||
* provided callback with signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* Tests whether at least one element in the iterator passes the test implemented by the provided function.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
*/
|
||||
public static function some(iterable $iterable, callable $predicate): bool
|
||||
@@ -103,11 +104,10 @@ final class Iterables
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether all elements in the iterator pass the test implemented by the provided function,
|
||||
* which has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* Tests whether all elements in the iterator pass the test implemented by the provided function.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
*/
|
||||
public static function every(iterable $iterable, callable $predicate): bool
|
||||
@@ -123,11 +123,10 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Iterator that filters elements according to a given $predicate. Maintains original keys.
|
||||
* The callback has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): bool $predicate
|
||||
* @return \Generator<K, V>
|
||||
*/
|
||||
public static function filter(iterable $iterable, callable $predicate): \Generator
|
||||
@@ -142,12 +141,11 @@ final class Iterables
|
||||
|
||||
/**
|
||||
* Iterator that transforms values by calling $transformer. Maintains original keys.
|
||||
* The callback has the signature `function (mixed $value, mixed $key, iterable $iterable): bool`.
|
||||
* @template K
|
||||
* @template V
|
||||
* @template R
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): R $transformer
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): R $transformer
|
||||
* @return \Generator<K, R>
|
||||
*/
|
||||
public static function map(iterable $iterable, callable $transformer): \Generator
|
||||
@@ -156,4 +154,86 @@ final class Iterables
|
||||
yield $k => $transformer($v, $k, $iterable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterator that transforms keys and values by calling $transformer. If it returns null, the element is skipped.
|
||||
* @template K
|
||||
* @template V
|
||||
* @template ResV
|
||||
* @template ResK
|
||||
* @param iterable<K, V> $iterable
|
||||
* @param callable(V, K, iterable<K, V>): ?array{ResV, ResK} $transformer
|
||||
* @return \Generator<ResV, ResK>
|
||||
*/
|
||||
public static function mapWithKeys(iterable $iterable, callable $transformer): \Generator
|
||||
{
|
||||
foreach ($iterable as $k => $v) {
|
||||
$pair = $transformer($v, $k, $iterable);
|
||||
if ($pair) {
|
||||
yield $pair[0] => $pair[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps around iterator and caches its keys and values during iteration.
|
||||
* This allows the data to be re-iterated multiple times.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @return \IteratorAggregate<K, V>
|
||||
*/
|
||||
public static function memoize(iterable $iterable): iterable
|
||||
{
|
||||
return new class (self::toIterator($iterable)) implements \IteratorAggregate {
|
||||
public function __construct(
|
||||
private \Iterator $iterator,
|
||||
private array $cache = [],
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
public function getIterator(): \Generator
|
||||
{
|
||||
if (!$this->cache) {
|
||||
$this->iterator->rewind();
|
||||
}
|
||||
$i = 0;
|
||||
while (true) {
|
||||
if (isset($this->cache[$i])) {
|
||||
[$k, $v] = $this->cache[$i];
|
||||
} elseif ($this->iterator->valid()) {
|
||||
$k = $this->iterator->key();
|
||||
$v = $this->iterator->current();
|
||||
$this->iterator->next();
|
||||
$this->cache[$i] = [$k, $v];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
yield $k => $v;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an iterator from anything that is iterable.
|
||||
* @template K
|
||||
* @template V
|
||||
* @param iterable<K, V> $iterable
|
||||
* @return \Iterator<K, V>
|
||||
*/
|
||||
public static function toIterator(iterable $iterable): \Iterator
|
||||
{
|
||||
return match (true) {
|
||||
$iterable instanceof \Iterator => $iterable,
|
||||
$iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()),
|
||||
is_array($iterable) => new \ArrayIterator($iterable),
|
||||
default => throw new Nette\ShouldNotHappenException,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
12
vendor/nette/utils/src/Utils/Reflection.php
vendored
12
vendor/nette/utils/src/Utils/Reflection.php
vendored
@@ -19,14 +19,14 @@ final class Reflection
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
/** @deprecated use Nette\Utils\Validator::isBuiltinType() */
|
||||
/** @deprecated use Nette\Utils\Validators::isBuiltinType() */
|
||||
public static function isBuiltinType(string $type): bool
|
||||
{
|
||||
return Validators::isBuiltinType($type);
|
||||
}
|
||||
|
||||
|
||||
/** @deprecated use Nette\Utils\Validator::isClassKeyword() */
|
||||
/** @deprecated use Nette\Utils\Validators::isClassKeyword() */
|
||||
public static function isClassKeyword(string $name): bool
|
||||
{
|
||||
return Validators::isClassKeyword($name);
|
||||
@@ -100,7 +100,7 @@ final class Reflection
|
||||
|
||||
$hash = [$method->getFileName(), $method->getStartLine(), $method->getEndLine()];
|
||||
if (($alias = $decl->getTraitAliases()[$method->name] ?? null)
|
||||
&& ($m = new \ReflectionMethod($alias))
|
||||
&& ($m = new \ReflectionMethod(...explode('::', $alias, 2)))
|
||||
&& $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]
|
||||
) {
|
||||
return self::getMethodDeclaringMethod($m);
|
||||
@@ -125,7 +125,7 @@ final class Reflection
|
||||
public static function areCommentsAvailable(): bool
|
||||
{
|
||||
static $res;
|
||||
return $res ?? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment();
|
||||
return $res ?? $res = (bool) (new \ReflectionMethod(self::class, __FUNCTION__))->getDocComment();
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ final class Reflection
|
||||
} elseif ($ref instanceof \ReflectionMethod) {
|
||||
return $ref->getDeclaringClass()->name . '::' . $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionFunction) {
|
||||
return $ref->name . '()';
|
||||
return PHP_VERSION_ID >= 80200 && $ref->isAnonymous()
|
||||
? '{closure}()'
|
||||
: $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionProperty) {
|
||||
return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name;
|
||||
} elseif ($ref instanceof \ReflectionParameter) {
|
||||
|
||||
35
vendor/nette/utils/src/Utils/Strings.php
vendored
35
vendor/nette/utils/src/Utils/Strings.php
vendored
@@ -28,7 +28,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated use Nette\Utils\Validator::isUnicode()
|
||||
* @deprecated use Nette\Utils\Validators::isUnicode()
|
||||
*/
|
||||
public static function checkEncoding(string $s): bool
|
||||
{
|
||||
@@ -547,7 +547,6 @@ class Strings
|
||||
return $utf8 && $captureOffset
|
||||
? self::bytesToChars($subject, [$m])[0]
|
||||
: $m;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -589,6 +588,7 @@ class Strings
|
||||
/**
|
||||
* Searches the string for all occurrences matching the regular expression and
|
||||
* returns an array of arrays containing the found expression and each subexpression.
|
||||
* @return ($lazy is true ? \Generator<int, array> : array[])
|
||||
*/
|
||||
public static function matchAll(
|
||||
string $subject,
|
||||
@@ -599,21 +599,41 @@ class Strings
|
||||
bool $unmatchedAsNull = false,
|
||||
bool $patternOrder = false,
|
||||
bool $utf8 = false,
|
||||
): array
|
||||
bool $lazy = false,
|
||||
): array|\Generator
|
||||
{
|
||||
$flags = is_int($captureOffset) // back compatibility
|
||||
? $captureOffset
|
||||
: ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0) | ($patternOrder ? PREG_PATTERN_ORDER : 0);
|
||||
|
||||
if ($utf8) {
|
||||
$offset = strlen(self::substring($subject, 0, $offset));
|
||||
$pattern .= 'u';
|
||||
}
|
||||
|
||||
if ($lazy) {
|
||||
$flags = PREG_OFFSET_CAPTURE | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0);
|
||||
return (function () use ($utf8, $captureOffset, $flags, $subject, $pattern, $offset) {
|
||||
$counter = 0;
|
||||
while (
|
||||
$offset <= strlen($subject) - ($counter ? 1 : 0)
|
||||
&& self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset])
|
||||
) {
|
||||
$offset = $m[0][1] + max(1, strlen($m[0][0]));
|
||||
if (!$captureOffset) {
|
||||
$m = array_map(fn($item) => $item[0], $m);
|
||||
} elseif ($utf8) {
|
||||
$m = self::bytesToChars($subject, [$m])[0];
|
||||
}
|
||||
yield $counter++ => $m;
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
if ($offset > strlen($subject)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$flags = is_int($captureOffset) // back compatibility
|
||||
? $captureOffset
|
||||
: ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0) | ($patternOrder ? PREG_PATTERN_ORDER : 0);
|
||||
|
||||
self::pcre('preg_match_all', [
|
||||
$pattern, $subject, &$m,
|
||||
($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER),
|
||||
@@ -622,7 +642,6 @@ class Strings
|
||||
return $utf8 && $captureOffset
|
||||
? self::bytesToChars($subject, $m)
|
||||
: $m;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
4
vendor/nette/utils/src/Utils/Type.php
vendored
4
vendor/nette/utils/src/Utils/Type.php
vendored
@@ -260,8 +260,8 @@ final class Type
|
||||
$subtypes,
|
||||
fn($subtype) => Validators::isBuiltinType($type)
|
||||
? strcasecmp($type, $subtype) === 0
|
||||
: is_a($subtype, $type, allow_string: true)
|
||||
)
|
||||
: is_a($subtype, $type, allow_string: true),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
10
vendor/nette/utils/src/Utils/exceptions.php
vendored
10
vendor/nette/utils/src/Utils/exceptions.php
vendored
@@ -11,7 +11,7 @@ namespace Nette\Utils;
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an image error occurs.
|
||||
* An error occurred while working with the image.
|
||||
*/
|
||||
class ImageException extends \Exception
|
||||
{
|
||||
@@ -19,7 +19,7 @@ class ImageException extends \Exception
|
||||
|
||||
|
||||
/**
|
||||
* The exception that indicates invalid image file.
|
||||
* The image file is invalid or in an unsupported format.
|
||||
*/
|
||||
class UnknownImageFileException extends ImageException
|
||||
{
|
||||
@@ -27,7 +27,7 @@ class UnknownImageFileException extends ImageException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that indicates error of JSON encoding/decoding.
|
||||
* JSON encoding or decoding failed.
|
||||
*/
|
||||
class JsonException extends \JsonException
|
||||
{
|
||||
@@ -35,7 +35,7 @@ class JsonException extends \JsonException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that indicates error of the last Regexp execution.
|
||||
* Regular expression pattern or execution failed.
|
||||
*/
|
||||
class RegexpException extends \Exception
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class RegexpException extends \Exception
|
||||
|
||||
|
||||
/**
|
||||
* The exception that indicates assertion error.
|
||||
* Type validation failed. The value doesn't match the expected type constraints.
|
||||
*/
|
||||
class AssertionException extends \Exception
|
||||
{
|
||||
|
||||
35
vendor/nette/utils/src/exceptions.php
vendored
35
vendor/nette/utils/src/exceptions.php
vendored
@@ -11,8 +11,7 @@ namespace Nette;
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when the value of an argument is
|
||||
* outside the allowable range of values as defined by the invoked method.
|
||||
* The value is outside the allowed range.
|
||||
*/
|
||||
class ArgumentOutOfRangeException extends \InvalidArgumentException
|
||||
{
|
||||
@@ -20,8 +19,7 @@ class ArgumentOutOfRangeException extends \InvalidArgumentException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a method call is invalid for the object's
|
||||
* current state, method has been invoked at an illegal or inappropriate time.
|
||||
* The object is in a state that does not allow the requested operation.
|
||||
*/
|
||||
class InvalidStateException extends \RuntimeException
|
||||
{
|
||||
@@ -29,7 +27,7 @@ class InvalidStateException extends \RuntimeException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is not implemented.
|
||||
* The requested feature is not implemented.
|
||||
*/
|
||||
class NotImplementedException extends \LogicException
|
||||
{
|
||||
@@ -37,8 +35,7 @@ class NotImplementedException extends \LogicException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an invoked method is not supported. For scenarios where
|
||||
* it is sometimes possible to perform the requested operation, see InvalidStateException.
|
||||
* The requested operation is not supported.
|
||||
*/
|
||||
class NotSupportedException extends \LogicException
|
||||
{
|
||||
@@ -46,7 +43,7 @@ class NotSupportedException extends \LogicException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is deprecated.
|
||||
* The requested feature is deprecated and no longer available.
|
||||
*/
|
||||
class DeprecatedException extends NotSupportedException
|
||||
{
|
||||
@@ -54,7 +51,7 @@ class DeprecatedException extends NotSupportedException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a class member (property or method) fails.
|
||||
* Cannot access the requested class property or method.
|
||||
*/
|
||||
class MemberAccessException extends \Error
|
||||
{
|
||||
@@ -62,7 +59,7 @@ class MemberAccessException extends \Error
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an I/O error occurs.
|
||||
* Failed to read from or write to a file or stream.
|
||||
*/
|
||||
class IOException extends \RuntimeException
|
||||
{
|
||||
@@ -70,7 +67,7 @@ class IOException extends \RuntimeException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a file that does not exist on disk.
|
||||
* The requested file does not exist.
|
||||
*/
|
||||
class FileNotFoundException extends IOException
|
||||
{
|
||||
@@ -78,7 +75,7 @@ class FileNotFoundException extends IOException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when part of a file or directory cannot be found.
|
||||
* The requested directory does not exist.
|
||||
*/
|
||||
class DirectoryNotFoundException extends IOException
|
||||
{
|
||||
@@ -86,7 +83,7 @@ class DirectoryNotFoundException extends IOException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an argument does not match with the expected value.
|
||||
* The provided argument has invalid type or format.
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
@@ -94,7 +91,7 @@ class InvalidArgumentException extends \InvalidArgumentException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an illegal index was requested.
|
||||
* The requested array or collection index does not exist.
|
||||
*/
|
||||
class OutOfRangeException extends \OutOfRangeException
|
||||
{
|
||||
@@ -102,8 +99,16 @@ class OutOfRangeException extends \OutOfRangeException
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a value (typically returned by function) does not match with the expected value.
|
||||
* The returned value has unexpected type or format.
|
||||
*/
|
||||
class UnexpectedValueException extends \UnexpectedValueException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Houston, we have a problem.
|
||||
*/
|
||||
class ShouldNotHappenException extends \LogicException
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user