Dep: update
주로 PHAN
This commit is contained in:
+5
-2
@@ -7,13 +7,16 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Utils;
|
||||
namespace Nette;
|
||||
|
||||
|
||||
interface IHtmlString
|
||||
interface HtmlStringable
|
||||
{
|
||||
/**
|
||||
* Returns string in HTML format
|
||||
*/
|
||||
function __toString(): string;
|
||||
}
|
||||
|
||||
|
||||
interface_exists(Utils\IHtmlString::class);
|
||||
+1
-1
@@ -47,7 +47,7 @@ class CachingIterator extends \CachingIterator implements \Countable
|
||||
} 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.', __CLASS__, is_object($iterator) ? get_class($iterator) : gettype($iterator)));
|
||||
throw new Nette\InvalidArgumentException(sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', self::class, is_object($iterator) ? get_class($iterator) : gettype($iterator)));
|
||||
}
|
||||
|
||||
parent::__construct($iterator, 0);
|
||||
|
||||
+10
-11
@@ -22,20 +22,20 @@ use Nette\Utils\ObjectHelpers;
|
||||
trait SmartObject
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
* @throws MemberAccessException
|
||||
*/
|
||||
public function __call(string $name, array $args)
|
||||
{
|
||||
$class = get_class($this);
|
||||
$class = static::class;
|
||||
|
||||
if (ObjectHelpers::hasProperty($class, $name) === 'event') { // calling event handlers
|
||||
if (is_iterable($this->$name)) {
|
||||
foreach ($this->$name as $handler) {
|
||||
$handlers = $this->$name ?? null;
|
||||
if (is_iterable($handlers)) {
|
||||
foreach ($handlers as $handler) {
|
||||
$handler(...$args);
|
||||
}
|
||||
} elseif ($this->$name !== null) {
|
||||
throw new UnexpectedValueException("Property $class::$$name must be iterable or null, " . gettype($this->$name) . ' given.');
|
||||
} elseif ($handlers !== null) {
|
||||
throw new UnexpectedValueException("Property $class::$$name must be iterable or null, " . gettype($handlers) . ' given.');
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -45,7 +45,6 @@ trait SmartObject
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws MemberAccessException
|
||||
*/
|
||||
public static function __callStatic(string $name, array $args)
|
||||
@@ -60,7 +59,7 @@ trait SmartObject
|
||||
*/
|
||||
public function &__get(string $name)
|
||||
{
|
||||
$class = get_class($this);
|
||||
$class = static::class;
|
||||
|
||||
if ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) { // property getter
|
||||
if (!($prop & 0b0001)) {
|
||||
@@ -86,7 +85,7 @@ trait SmartObject
|
||||
*/
|
||||
public function __set(string $name, $value)
|
||||
{
|
||||
$class = get_class($this);
|
||||
$class = static::class;
|
||||
|
||||
if (ObjectHelpers::hasProperty($class, $name)) { // unsetted property
|
||||
$this->$name = $value;
|
||||
@@ -109,7 +108,7 @@ trait SmartObject
|
||||
*/
|
||||
public function __unset(string $name)
|
||||
{
|
||||
$class = get_class($this);
|
||||
$class = static::class;
|
||||
if (!ObjectHelpers::hasProperty($class, $name)) {
|
||||
throw new MemberAccessException("Cannot unset the property $class::\$$name.");
|
||||
}
|
||||
@@ -118,6 +117,6 @@ trait SmartObject
|
||||
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return isset(ObjectHelpers::getMagicProperties(get_class($this))[$name]);
|
||||
return isset(ObjectHelpers::getMagicProperties(static::class)[$name]);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@ trait StaticClass
|
||||
/** @throws \Error */
|
||||
final public function __construct()
|
||||
{
|
||||
throw new \Error('Class ' . get_class($this) . ' is static and cannot be instantiated.');
|
||||
throw new \Error('Class ' . static::class . ' is static and cannot be instantiated.');
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -13,7 +13,7 @@ namespace Nette\Localization;
|
||||
/**
|
||||
* Translator adapter.
|
||||
*/
|
||||
interface ITranslator
|
||||
interface Translator
|
||||
{
|
||||
/**
|
||||
* Translates the given string.
|
||||
@@ -22,3 +22,6 @@ interface ITranslator
|
||||
*/
|
||||
function translate($message, ...$parameters): string;
|
||||
}
|
||||
|
||||
|
||||
interface_exists(Nette\Localization\ITranslator::class);
|
||||
+9
-8
@@ -17,16 +17,17 @@ use Nette;
|
||||
*/
|
||||
class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
{
|
||||
/** @return static */
|
||||
public static function from(array $arr, bool $recursive = true)
|
||||
/**
|
||||
* Transforms array to ArrayHash.
|
||||
* @return static
|
||||
*/
|
||||
public static function from(array $array, bool $recursive = true)
|
||||
{
|
||||
$obj = new static;
|
||||
foreach ($arr as $key => $value) {
|
||||
if ($recursive && is_array($value)) {
|
||||
$obj->$key = static::from($value, true);
|
||||
} else {
|
||||
$obj->$key = $value;
|
||||
}
|
||||
foreach ($array as $key => $value) {
|
||||
$obj->$key = $recursive && is_array($value)
|
||||
? static::from($value, true)
|
||||
: $value;
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
|
||||
+184
-74
@@ -21,17 +21,17 @@ class Arrays
|
||||
use Nette\StaticClass;
|
||||
|
||||
/**
|
||||
* Returns item from array or $default if item is not set.
|
||||
* @param string|int|array $key one or more keys
|
||||
* Returns item from array. If it does not exist, it throws an exception, unless a default value is set.
|
||||
* @param string|int|array $key one or more keys
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
* @throws Nette\InvalidArgumentException if item does not exist and default value is not provided
|
||||
*/
|
||||
public static function get(array $arr, $key, $default = null)
|
||||
public static function get(array $array, $key, $default = null)
|
||||
{
|
||||
foreach (is_array($key) ? $key : [$key] as $k) {
|
||||
if (is_array($arr) && array_key_exists($k, $arr)) {
|
||||
$arr = $arr[$k];
|
||||
if (is_array($array) && array_key_exists($k, $array)) {
|
||||
$array = $array[$k];
|
||||
} else {
|
||||
if (func_num_args() < 3) {
|
||||
throw new Nette\InvalidArgumentException("Missing item '$k'.");
|
||||
@@ -39,38 +39,40 @@ class Arrays
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns reference to array item.
|
||||
* @param string|int|array $key one or more keys
|
||||
* Returns reference to array item. If the index does not exist, new one is created with value null.
|
||||
* @param string|int|array $key one or more keys
|
||||
* @return mixed
|
||||
* @throws Nette\InvalidArgumentException if traversed item is not an array
|
||||
*/
|
||||
public static function &getRef(array &$arr, $key)
|
||||
public static function &getRef(array &$array, $key)
|
||||
{
|
||||
foreach (is_array($key) ? $key : [$key] as $k) {
|
||||
if (is_array($arr) || $arr === null) {
|
||||
$arr = &$arr[$k];
|
||||
if (is_array($array) || $array === null) {
|
||||
$array = &$array[$k];
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException('Traversed item is not an array.');
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Recursively appends elements of remaining keys from the second array to the first.
|
||||
* Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as
|
||||
* the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains
|
||||
* the value from the first array in the case of a key collision.
|
||||
*/
|
||||
public static function mergeTree(array $arr1, array $arr2): array
|
||||
public static function mergeTree(array $array1, array $array2): array
|
||||
{
|
||||
$res = $arr1 + $arr2;
|
||||
foreach (array_intersect_key($arr1, $arr2) as $k => $v) {
|
||||
if (is_array($v) && is_array($arr2[$k])) {
|
||||
$res[$k] = self::mergeTree($v, $arr2[$k]);
|
||||
$res = $array1 + $array2;
|
||||
foreach (array_intersect_key($array1, $array2) as $k => $v) {
|
||||
if (is_array($v) && is_array($array2[$k])) {
|
||||
$res[$k] = self::mergeTree($v, $array2[$k]);
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
@@ -78,37 +80,82 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Searches the array for a given key and returns the offset if successful.
|
||||
* Returns zero-indexed position of given array key. Returns null if key is not found.
|
||||
* @param string|int $key
|
||||
* @return int|null offset if it is found, null otherwise
|
||||
*/
|
||||
public static function searchKey(array $arr, $key): ?int
|
||||
public static function getKeyOffset(array $array, $key): ?int
|
||||
{
|
||||
$foo = [$key => null];
|
||||
return Helpers::falseToNull(array_search(key($foo), array_keys($arr), true));
|
||||
return Helpers::falseToNull(array_search(self::toKey($key), array_keys($array), true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts new array before item specified by key.
|
||||
* @param string|int $key
|
||||
* @deprecated use getKeyOffset()
|
||||
*/
|
||||
public static function insertBefore(array &$arr, $key, array $inserted): void
|
||||
public static function searchKey(array $array, $key): ?int
|
||||
{
|
||||
$offset = (int) self::searchKey($arr, $key);
|
||||
$arr = array_slice($arr, 0, $offset, true) + $inserted + array_slice($arr, $offset, count($arr), true);
|
||||
return self::getKeyOffset($array, $key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts new array after item specified by key.
|
||||
* @param string|int $key
|
||||
* Tests an array for the presence of value.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function insertAfter(array &$arr, $key, array $inserted): void
|
||||
public static function contains(array $array, $value): bool
|
||||
{
|
||||
$offset = self::searchKey($arr, $key);
|
||||
$offset = $offset === null ? count($arr) : $offset + 1;
|
||||
$arr = array_slice($arr, 0, $offset, true) + $inserted + array_slice($arr, $offset, count($arr), true);
|
||||
return in_array($value, $array, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first item from the array or null if array is empty.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function first(array $array)
|
||||
{
|
||||
return count($array) ? reset($array) : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the last item from the array or null if array is empty.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function last(array $array)
|
||||
{
|
||||
return count($array) ? end($array) : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts the contents of the $inserted array into the $array immediately after the $key.
|
||||
* If $key is null (or does not exist), it is inserted at the beginning.
|
||||
* @param string|int|null $key
|
||||
*/
|
||||
public static function insertBefore(array &$array, $key, array $inserted): void
|
||||
{
|
||||
$offset = $key === null ? 0 : (int) self::getKeyOffset($array, $key);
|
||||
$array = array_slice($array, 0, $offset, true)
|
||||
+ $inserted
|
||||
+ array_slice($array, $offset, count($array), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts the contents of the $inserted array into the $array before the $key.
|
||||
* If $key is null (or does not exist), it is inserted at the end.
|
||||
* @param string|int|null $key
|
||||
*/
|
||||
public static function insertAfter(array &$array, $key, array $inserted): void
|
||||
{
|
||||
if ($key === null || ($offset = self::getKeyOffset($array, $key)) === null) {
|
||||
$offset = count($array) - 1;
|
||||
}
|
||||
$array = array_slice($array, 0, $offset + 1, true)
|
||||
+ $inserted
|
||||
+ array_slice($array, $offset + 1, count($array), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,42 +164,47 @@ class Arrays
|
||||
* @param string|int $oldKey
|
||||
* @param string|int $newKey
|
||||
*/
|
||||
public static function renameKey(array &$arr, $oldKey, $newKey): void
|
||||
public static function renameKey(array &$array, $oldKey, $newKey): bool
|
||||
{
|
||||
$offset = self::searchKey($arr, $oldKey);
|
||||
if ($offset !== null) {
|
||||
$keys = array_keys($arr);
|
||||
$keys[$offset] = $newKey;
|
||||
$arr = array_combine($keys, $arr);
|
||||
$offset = self::getKeyOffset($array, $oldKey);
|
||||
if ($offset === null) {
|
||||
return false;
|
||||
}
|
||||
$val = &$array[$oldKey];
|
||||
$keys = array_keys($array);
|
||||
$keys[$offset] = $newKey;
|
||||
$array = array_combine($keys, $array);
|
||||
$array[$newKey] = &$val;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns array entries that match the pattern.
|
||||
* Returns only those array items, which matches a regular expression $pattern.
|
||||
* @throws Nette\RegexpException on compilation or runtime error
|
||||
*/
|
||||
public static function grep(array $arr, string $pattern, int $flags = 0): array
|
||||
public static function grep(array $array, string $pattern, int $flags = 0): array
|
||||
{
|
||||
return Strings::pcre('preg_grep', [$pattern, $arr, $flags]);
|
||||
return Strings::pcre('preg_grep', [$pattern, $array, $flags]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns flattened array.
|
||||
* Transforms multidimensional array to flat array.
|
||||
*/
|
||||
public static function flatten(array $arr, bool $preserveKeys = false): array
|
||||
public static function flatten(array $array, bool $preserveKeys = false): array
|
||||
{
|
||||
$res = [];
|
||||
$cb = $preserveKeys
|
||||
? function ($v, $k) use (&$res): void { $res[$k] = $v; }
|
||||
: function ($v) use (&$res): void { $res[] = $v; };
|
||||
array_walk_recursive($arr, $cb);
|
||||
array_walk_recursive($array, $cb);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a variable is a zero-based integer indexed array.
|
||||
* Checks if the array is indexed in ascending order of numeric keys from zero, a.k.a list.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isList($value): bool
|
||||
@@ -166,7 +218,7 @@ class Arrays
|
||||
* @param string|string[] $path
|
||||
* @return array|\stdClass
|
||||
*/
|
||||
public static function associate(array $arr, $path)
|
||||
public static function associate(array $array, $path)
|
||||
{
|
||||
$parts = is_array($path)
|
||||
? $path
|
||||
@@ -178,7 +230,7 @@ class Arrays
|
||||
|
||||
$res = $parts[0] === '->' ? new \stdClass : [];
|
||||
|
||||
foreach ($arr as $rowOrig) {
|
||||
foreach ($array as $rowOrig) {
|
||||
$row = (array) $rowOrig;
|
||||
$x = &$res;
|
||||
|
||||
@@ -218,13 +270,13 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes to associative array.
|
||||
* Normalizes array to associative array. Replace numeric keys with their values, the new value will be $filling.
|
||||
* @param mixed $filling
|
||||
*/
|
||||
public static function normalize(array $arr, $filling = null): array
|
||||
public static function normalize(array $array, $filling = null): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($arr as $k => $v) {
|
||||
foreach ($array as $k => $v) {
|
||||
$res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v;
|
||||
}
|
||||
return $res;
|
||||
@@ -232,17 +284,18 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Picks element from the array by key and return its value.
|
||||
* Returns and removes the value of an item from an array. If it does not exist, it throws an exception,
|
||||
* or returns $default, if provided.
|
||||
* @param string|int $key
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
* @throws Nette\InvalidArgumentException if item does not exist and default value is not provided
|
||||
*/
|
||||
public static function pick(array &$arr, $key, $default = null)
|
||||
public static function pick(array &$array, $key, $default = null)
|
||||
{
|
||||
if (array_key_exists($key, $arr)) {
|
||||
$value = $arr[$key];
|
||||
unset($arr[$key]);
|
||||
if (array_key_exists($key, $array)) {
|
||||
$value = $array[$key];
|
||||
unset($array[$key]);
|
||||
return $value;
|
||||
|
||||
} elseif (func_num_args() < 3) {
|
||||
@@ -255,12 +308,13 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether some element in the array passes the callback test.
|
||||
* Tests whether at least one element in the array passes the test implemented by the
|
||||
* provided callback with signature `function ($value, $key, array $array): bool`.
|
||||
*/
|
||||
public static function some(array $arr, callable $callback): bool
|
||||
public static function some(iterable $array, callable $callback): bool
|
||||
{
|
||||
foreach ($arr as $k => $v) {
|
||||
if ($callback($v, $k, $arr)) {
|
||||
foreach ($array as $k => $v) {
|
||||
if ($callback($v, $k, $array)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -269,12 +323,13 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether all elements in the array pass the callback test.
|
||||
* 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`.
|
||||
*/
|
||||
public static function every(array $arr, callable $callback): bool
|
||||
public static function every(iterable $array, callable $callback): bool
|
||||
{
|
||||
foreach ($arr as $k => $v) {
|
||||
if (!$callback($v, $k, $arr)) {
|
||||
foreach ($array as $k => $v) {
|
||||
if (!$callback($v, $k, $array)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -283,28 +338,83 @@ class Arrays
|
||||
|
||||
|
||||
/**
|
||||
* Applies the callback to the elements of the array.
|
||||
* Calls $callback on all elements in the array and returns the array of return values.
|
||||
* The callback has the signature `function ($value, $key, array $array): bool`.
|
||||
*/
|
||||
public static function map(array $arr, callable $callback): array
|
||||
public static function map(iterable $array, callable $callback): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($arr as $k => $v) {
|
||||
$res[$k] = $callback($v, $k, $arr);
|
||||
foreach ($array as $k => $v) {
|
||||
$res[$k] = $callback($v, $k, $array);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts array to object
|
||||
* @param object $obj
|
||||
* Invokes all callbacks and returns array of results.
|
||||
* @param callable[] $callbacks
|
||||
*/
|
||||
public static function invoke(iterable $callbacks, ...$args): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($callbacks as $k => $cb) {
|
||||
$res[$k] = $cb(...$args);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invokes method on every object in an array and returns array of results.
|
||||
* @param object[] $objects
|
||||
*/
|
||||
public static function invokeMethod(iterable $objects, string $method, ...$args): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($objects as $k => $obj) {
|
||||
$res[$k] = $obj->$method(...$args);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the elements of the $array array to the $object object and then returns it.
|
||||
* @param object $object
|
||||
* @return object
|
||||
*/
|
||||
public static function toObject(array $arr, $obj)
|
||||
public static function toObject(iterable $array, $object)
|
||||
{
|
||||
foreach ($arr as $k => $v) {
|
||||
$obj->$k = $v;
|
||||
foreach ($array as $k => $v) {
|
||||
$object->$k = $v;
|
||||
}
|
||||
return $obj;
|
||||
return $object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts value to array key.
|
||||
* @param mixed $value
|
||||
* @return int|string
|
||||
*/
|
||||
public static function toKey($value)
|
||||
{
|
||||
return key([$value => null]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns copy of the $array where every item is converted to string
|
||||
* and prefixed by $prefix and suffixed by $suffix.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function wrap(array $array, string $prefix = '', string $suffix = ''): array
|
||||
{
|
||||
$res = [];
|
||||
foreach ($array as $k => $v) {
|
||||
$res[$k] = $prefix . $v . $suffix;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-7
@@ -26,6 +26,7 @@ final class Callback
|
||||
*/
|
||||
public static function closure($callable, string $method = null): \Closure
|
||||
{
|
||||
trigger_error(__METHOD__ . '() is deprecated, use Closure::fromCallable().', E_USER_DEPRECATED);
|
||||
try {
|
||||
return \Closure::fromCallable($method === null ? $callable : [$callable, $method]);
|
||||
} catch (\TypeError $e) {
|
||||
@@ -68,8 +69,10 @@ final class Callback
|
||||
{
|
||||
$prev = set_error_handler(function ($severity, $message, $file) use ($onError, &$prev, $function): ?bool {
|
||||
if ($file === __FILE__) {
|
||||
$msg = ini_get('html_errors') ? Html::htmlToText($message) : $message;
|
||||
$msg = preg_replace("#^$function\(.*?\): #", '', $msg);
|
||||
$msg = ini_get('html_errors')
|
||||
? Html::htmlToText($message)
|
||||
: $message;
|
||||
$msg = preg_replace("#^$function\\(.*?\\): #", '', $msg);
|
||||
if ($onError($msg, $severity) !== false) {
|
||||
return null;
|
||||
}
|
||||
@@ -86,13 +89,17 @@ final class Callback
|
||||
|
||||
|
||||
/**
|
||||
* Checks that $callable is valid PHP callback. Otherwise throws exception. If the $syntax is set to true, only verifies
|
||||
* that $callable has a valid structure to be used as a callback, but does not verify if the class or method actually exists.
|
||||
* @param mixed $callable
|
||||
* @return callable
|
||||
* @throws Nette\InvalidArgumentException
|
||||
*/
|
||||
public static function check($callable, bool $syntax = false)
|
||||
{
|
||||
if (!is_callable($callable, $syntax)) {
|
||||
throw new Nette\InvalidArgumentException($syntax
|
||||
throw new Nette\InvalidArgumentException(
|
||||
$syntax
|
||||
? 'Given value is not a callable type.'
|
||||
: sprintf("Callback '%s' is not callable.", self::toString($callable))
|
||||
);
|
||||
@@ -102,7 +109,8 @@ final class Callback
|
||||
|
||||
|
||||
/**
|
||||
* @param mixed $callable may be syntactically correct but not callable
|
||||
* Converts PHP callback to textual form. Class or method may not exists.
|
||||
* @param mixed $callable
|
||||
*/
|
||||
public static function toString($callable): string
|
||||
{
|
||||
@@ -119,8 +127,10 @@ final class Callback
|
||||
|
||||
|
||||
/**
|
||||
* @param callable $callable is escalated to ReflectionException
|
||||
* Returns reflection for method or function used in PHP callback.
|
||||
* @param callable $callable type check is escalated to ReflectionException
|
||||
* @return \ReflectionMethod|\ReflectionFunction
|
||||
* @throws \ReflectionException if callback is not valid
|
||||
*/
|
||||
public static function toReflection($callable): \ReflectionFunctionAbstract
|
||||
{
|
||||
@@ -140,6 +150,9 @@ final class Callback
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether PHP callback is function or static method.
|
||||
*/
|
||||
public static function isStatic(callable $callable): bool
|
||||
{
|
||||
return is_array($callable) ? is_string($callable[0]) : is_string($callable);
|
||||
@@ -147,8 +160,7 @@ final class Callback
|
||||
|
||||
|
||||
/**
|
||||
* Unwraps closure created by Closure::fromCallable()
|
||||
* @internal
|
||||
* Unwraps closure created by Closure::fromCallable().
|
||||
*/
|
||||
public static function unwrap(\Closure $closure): callable
|
||||
{
|
||||
|
||||
+28
-6
@@ -39,9 +39,10 @@ class DateTime extends \DateTime implements \JsonSerializable
|
||||
|
||||
|
||||
/**
|
||||
* DateTime object factory.
|
||||
* Creates a DateTime object from a string, UNIX timestamp, or other DateTimeInterface object.
|
||||
* @param string|int|\DateTimeInterface $time
|
||||
* @return static
|
||||
* @throws \Exception if the date and time are not valid.
|
||||
*/
|
||||
public static function from($time)
|
||||
{
|
||||
@@ -63,11 +64,26 @@ class DateTime extends \DateTime implements \JsonSerializable
|
||||
/**
|
||||
* Creates DateTime object.
|
||||
* @return static
|
||||
* @throws Nette\InvalidArgumentException if the date and time are not valid.
|
||||
*/
|
||||
public static function fromParts(int $year, int $month, int $day, int $hour = 0, int $minute = 0, float $second = 0.0)
|
||||
{
|
||||
$s = sprintf('%04d-%02d-%02d %02d:%02d:%02.5f', $year, $month, $day, $hour, $minute, $second);
|
||||
if (!checkdate($month, $day, $year) || $hour < 0 || $hour > 23 || $minute < 0 || $minute > 59 || $second < 0 || $second >= 60) {
|
||||
public static function fromParts(
|
||||
int $year,
|
||||
int $month,
|
||||
int $day,
|
||||
int $hour = 0,
|
||||
int $minute = 0,
|
||||
float $second = 0.0
|
||||
) {
|
||||
$s = sprintf('%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second);
|
||||
if (
|
||||
!checkdate($month, $day, $year)
|
||||
|| $hour < 0
|
||||
|| $hour > 23
|
||||
|| $minute < 0
|
||||
|| $minute > 59
|
||||
|| $second < 0
|
||||
|| $second >= 60
|
||||
) {
|
||||
throw new Nette\InvalidArgumentException("Invalid date '$s'");
|
||||
}
|
||||
return new static($s);
|
||||
@@ -107,13 +123,19 @@ class DateTime extends \DateTime implements \JsonSerializable
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the date and time in the format 'Y-m-d H:i:s'.
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
|
||||
/** @return static */
|
||||
/**
|
||||
* Creates a copy with a modified time.
|
||||
* @return static
|
||||
*/
|
||||
public function modifyClone(string $modify = '')
|
||||
{
|
||||
$dolly = clone $this;
|
||||
|
||||
+46
-41
@@ -20,54 +20,59 @@ final class FileSystem
|
||||
use Nette\StaticClass;
|
||||
|
||||
/**
|
||||
* Creates a directory.
|
||||
* @throws Nette\IOException
|
||||
* Creates a directory if it doesn't exist.
|
||||
* @throws Nette\IOException on error occurred
|
||||
*/
|
||||
public static function createDir(string $dir, int $mode = 0777): void
|
||||
{
|
||||
if (!is_dir($dir) && !@mkdir($dir, $mode, true) && !is_dir($dir)) { // @ - dir may already exist
|
||||
throw new Nette\IOException("Unable to create directory '$dir'. " . Helpers::getLastError());
|
||||
throw new Nette\IOException("Unable to create directory '$dir' with mode " . decoct($mode) . '. ' . Helpers::getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies a file or directory.
|
||||
* @throws Nette\IOException
|
||||
* Copies a file or a directory. Overwrites existing files and directories by default.
|
||||
* @throws Nette\IOException on error occurred
|
||||
* @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists
|
||||
*/
|
||||
public static function copy(string $source, string $dest, bool $overwrite = true): void
|
||||
public static function copy(string $origin, string $target, bool $overwrite = true): void
|
||||
{
|
||||
if (stream_is_local($source) && !file_exists($source)) {
|
||||
throw new Nette\IOException("File or directory '$source' not found.");
|
||||
if (stream_is_local($origin) && !file_exists($origin)) {
|
||||
throw new Nette\IOException("File or directory '$origin' not found.");
|
||||
|
||||
} elseif (!$overwrite && file_exists($dest)) {
|
||||
throw new Nette\InvalidStateException("File or directory '$dest' already exists.");
|
||||
} elseif (!$overwrite && file_exists($target)) {
|
||||
throw new Nette\InvalidStateException("File or directory '$target' already exists.");
|
||||
|
||||
} elseif (is_dir($source)) {
|
||||
static::createDir($dest);
|
||||
foreach (new \FilesystemIterator($dest) as $item) {
|
||||
} elseif (is_dir($origin)) {
|
||||
static::createDir($target);
|
||||
foreach (new \FilesystemIterator($target) as $item) {
|
||||
static::delete($item->getPathname());
|
||||
}
|
||||
foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
|
||||
foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($origin, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) {
|
||||
if ($item->isDir()) {
|
||||
static::createDir($dest . '/' . $iterator->getSubPathName());
|
||||
static::createDir($target . '/' . $iterator->getSubPathName());
|
||||
} else {
|
||||
static::copy($item->getPathname(), $dest . '/' . $iterator->getSubPathName());
|
||||
static::copy($item->getPathname(), $target . '/' . $iterator->getSubPathName());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
static::createDir(dirname($dest));
|
||||
if (($s = @fopen($source, 'rb')) && ($d = @fopen($dest, 'wb')) && @stream_copy_to_stream($s, $d) === false) { // @ is escalated to exception
|
||||
throw new Nette\IOException("Unable to copy file '$source' to '$dest'. " . Helpers::getLastError());
|
||||
static::createDir(dirname($target));
|
||||
if (
|
||||
($s = @fopen($origin, 'rb'))
|
||||
&& ($d = @fopen($target, 'wb'))
|
||||
&& @stream_copy_to_stream($s, $d) === false
|
||||
) { // @ is escalated to exception
|
||||
throw new Nette\IOException("Unable to copy file '$origin' to '$target'. " . Helpers::getLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes a file or directory.
|
||||
* @throws Nette\IOException
|
||||
* Deletes a file or directory if exists.
|
||||
* @throws Nette\IOException on error occurred
|
||||
*/
|
||||
public static function delete(string $path): void
|
||||
{
|
||||
@@ -89,33 +94,33 @@ final class FileSystem
|
||||
|
||||
|
||||
/**
|
||||
* Renames a file or directory.
|
||||
* @throws Nette\IOException
|
||||
* @throws Nette\InvalidStateException if the target file or directory already exist
|
||||
* Renames or moves a file or a directory. Overwrites existing files and directories by default.
|
||||
* @throws Nette\IOException on error occurred
|
||||
* @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists
|
||||
*/
|
||||
public static function rename(string $name, string $newName, bool $overwrite = true): void
|
||||
public static function rename(string $origin, string $target, bool $overwrite = true): void
|
||||
{
|
||||
if (!$overwrite && file_exists($newName)) {
|
||||
throw new Nette\InvalidStateException("File or directory '$newName' already exists.");
|
||||
if (!$overwrite && file_exists($target)) {
|
||||
throw new Nette\InvalidStateException("File or directory '$target' already exists.");
|
||||
|
||||
} elseif (!file_exists($name)) {
|
||||
throw new Nette\IOException("File or directory '$name' not found.");
|
||||
} elseif (!file_exists($origin)) {
|
||||
throw new Nette\IOException("File or directory '$origin' not found.");
|
||||
|
||||
} else {
|
||||
static::createDir(dirname($newName));
|
||||
if (realpath($name) !== realpath($newName)) {
|
||||
static::delete($newName);
|
||||
static::createDir(dirname($target));
|
||||
if (realpath($origin) !== realpath($target)) {
|
||||
static::delete($target);
|
||||
}
|
||||
if (!@rename($name, $newName)) { // @ is escalated to exception
|
||||
throw new Nette\IOException("Unable to rename file or directory '$name' to '$newName'. " . Helpers::getLastError());
|
||||
if (!@rename($origin, $target)) { // @ is escalated to exception
|
||||
throw new Nette\IOException("Unable to rename file or directory '$origin' to '$target'. " . Helpers::getLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads file content.
|
||||
* @throws Nette\IOException
|
||||
* Reads the content of a file.
|
||||
* @throws Nette\IOException on error occurred
|
||||
*/
|
||||
public static function read(string $file): string
|
||||
{
|
||||
@@ -128,8 +133,8 @@ final class FileSystem
|
||||
|
||||
|
||||
/**
|
||||
* Writes a string to a file.
|
||||
* @throws Nette\IOException
|
||||
* Writes the string to a file.
|
||||
* @throws Nette\IOException on error occurred
|
||||
*/
|
||||
public static function write(string $file, string $content, ?int $mode = 0666): void
|
||||
{
|
||||
@@ -144,7 +149,7 @@ final class FileSystem
|
||||
|
||||
|
||||
/**
|
||||
* Is path absolute?
|
||||
* Determines if the path is absolute.
|
||||
*/
|
||||
public static function isAbsolute(string $path): bool
|
||||
{
|
||||
@@ -153,7 +158,7 @@ final class FileSystem
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes ../. and directory separators in path.
|
||||
* Normalizes `..` and `.` and directory separators in path.
|
||||
*/
|
||||
public static function normalizePath(string $path): string
|
||||
{
|
||||
@@ -173,7 +178,7 @@ final class FileSystem
|
||||
|
||||
|
||||
/**
|
||||
* Joins all given path segments then normalizes the resulting path.
|
||||
* Joins all segments of the path and normalizes the result.
|
||||
*/
|
||||
public static function joinPaths(string ...$paths): string
|
||||
{
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Utils;
|
||||
|
||||
use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Floating-point numbers comparison.
|
||||
*/
|
||||
class Floats
|
||||
{
|
||||
use Nette\StaticClass;
|
||||
|
||||
private const EPSILON = 1e-10;
|
||||
|
||||
|
||||
public static function isZero(float $value): bool
|
||||
{
|
||||
return abs($value) < self::EPSILON;
|
||||
}
|
||||
|
||||
|
||||
public static function isInteger(float $value): bool
|
||||
{
|
||||
return abs(round($value) - $value) < self::EPSILON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare two floats. If $a < $b it returns -1, if they are equal it returns 0 and if $a > $b it returns 1
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function compare(float $a, float $b): int
|
||||
{
|
||||
if (is_nan($a) || is_nan($b)) {
|
||||
throw new \LogicException('Trying to compare NAN');
|
||||
|
||||
} elseif (!is_finite($a) && !is_finite($b) && $a === $b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$diff = abs($a - $b);
|
||||
if (($diff < self::EPSILON || ($diff / max(abs($a), abs($b)) < self::EPSILON))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $a < $b ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if $a = $b
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function areEqual(float $a, float $b): bool
|
||||
{
|
||||
return self::compare($a, $b) === 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if $a < $b
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function isLessThan(float $a, float $b): bool
|
||||
{
|
||||
return self::compare($a, $b) < 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if $a <= $b
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function isLessThanOrEqualTo(float $a, float $b): bool
|
||||
{
|
||||
return self::compare($a, $b) <= 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if $a > $b
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function isGreaterThan(float $a, float $b): bool
|
||||
{
|
||||
return self::compare($a, $b) > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if $a >= $b
|
||||
* @throws \LogicException if one of parameters is NAN
|
||||
*/
|
||||
public static function isGreaterThanOrEqualTo(float $a, float $b): bool
|
||||
{
|
||||
return self::compare($a, $b) >= 0;
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -13,7 +13,7 @@ namespace Nette\Utils;
|
||||
class Helpers
|
||||
{
|
||||
/**
|
||||
* Captures PHP output into a string.
|
||||
* Executes a callback and returns the captured output as a string.
|
||||
*/
|
||||
public static function capture(callable $func): string
|
||||
{
|
||||
@@ -29,7 +29,8 @@ class Helpers
|
||||
|
||||
|
||||
/**
|
||||
* Returns the last PHP error as plain string.
|
||||
* Returns the last occurred PHP error or an empty string if no error occurred. Unlike error_get_last(),
|
||||
* it is nit affected by the PHP directive html_errors and always returns text, not HTML.
|
||||
*/
|
||||
public static function getLastError(): string
|
||||
{
|
||||
@@ -41,18 +42,18 @@ class Helpers
|
||||
|
||||
|
||||
/**
|
||||
* Converts false to null.
|
||||
* @param mixed $val
|
||||
* Converts false to null, does not change other values.
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function falseToNull($val)
|
||||
public static function falseToNull($value)
|
||||
{
|
||||
return $val === false ? null : $val;
|
||||
return $value === false ? null : $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the best suggestion (for 8-bit encoding).
|
||||
* Looks for a string from possibilities that is most similar to value, but not the same (for 8-bit encoding).
|
||||
* @param string[] $possibilities
|
||||
*/
|
||||
public static function getSuggestion(array $possibilities, string $value): ?string
|
||||
|
||||
+15
-10
@@ -10,6 +10,7 @@ declare(strict_types=1);
|
||||
namespace Nette\Utils;
|
||||
|
||||
use Nette;
|
||||
use Nette\HtmlStringable;
|
||||
use function is_array, is_float, is_object, is_string;
|
||||
|
||||
|
||||
@@ -230,7 +231,7 @@ use function is_array, is_float, is_object, is_string;
|
||||
* @method self width(?int $val)
|
||||
* @method self wrap(?string $val)
|
||||
*/
|
||||
class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
class Html implements \ArrayAccess, \Countable, \IteratorAggregate, HtmlStringable
|
||||
{
|
||||
use Nette\SmartObject;
|
||||
|
||||
@@ -538,7 +539,9 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
if (func_num_args() === 1) {
|
||||
$this->attrs['data'] = $name;
|
||||
} else {
|
||||
$this->attrs["data-$name"] = is_bool($value) ? json_encode($value) : $value;
|
||||
$this->attrs["data-$name"] = is_bool($value)
|
||||
? json_encode($value)
|
||||
: $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@@ -546,7 +549,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
|
||||
/**
|
||||
* Sets element's HTML content.
|
||||
* @param IHtmlString|string $html
|
||||
* @param HtmlStringable|string $html
|
||||
* @return static
|
||||
*/
|
||||
final public function setHtml($html)
|
||||
@@ -567,12 +570,12 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
|
||||
/**
|
||||
* Sets element's textual content.
|
||||
* @param IHtmlString|string|int|float $text
|
||||
* @param HtmlStringable|string|int|float $text
|
||||
* @return static
|
||||
*/
|
||||
final public function setText($text)
|
||||
{
|
||||
if (!$text instanceof IHtmlString) {
|
||||
if (!$text instanceof HtmlStringable) {
|
||||
$text = htmlspecialchars((string) $text, ENT_NOQUOTES, 'UTF-8');
|
||||
}
|
||||
$this->children = [(string) $text];
|
||||
@@ -591,7 +594,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
|
||||
/**
|
||||
* Adds new element's child.
|
||||
* @param IHtmlString|string $child Html node or raw HTML string
|
||||
* @param HtmlStringable|string $child Html node or raw HTML string
|
||||
* @return static
|
||||
*/
|
||||
final public function addHtml($child)
|
||||
@@ -602,12 +605,12 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
|
||||
/**
|
||||
* Appends plain-text string to element content.
|
||||
* @param IHtmlString|string|int|float $text
|
||||
* @param HtmlStringable|string|int|float $text
|
||||
* @return static
|
||||
*/
|
||||
public function addText($text)
|
||||
{
|
||||
if (!$text instanceof IHtmlString) {
|
||||
if (!$text instanceof HtmlStringable) {
|
||||
$text = htmlspecialchars((string) $text, ENT_NOQUOTES, 'UTF-8');
|
||||
}
|
||||
return $this->insert(null, $text);
|
||||
@@ -628,7 +631,7 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
|
||||
/**
|
||||
* Inserts child node.
|
||||
* @param IHtmlString|string $child Html node or raw HTML string
|
||||
* @param HtmlStringable|string $child Html node or raw HTML string
|
||||
* @return static
|
||||
*/
|
||||
public function insert(?int $index, $child, bool $replace = false)
|
||||
@@ -823,7 +826,9 @@ class Html implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
|
||||
foreach ($value as $k => $v) {
|
||||
if ($v != null) { // intentionally ==, skip nulls & empty string
|
||||
// composite 'style' vs. 'others'
|
||||
$tmp[] = $v === true ? $k : (is_string($k) ? $k . ':' . $v : $v);
|
||||
$tmp[] = $v === true
|
||||
? $k
|
||||
: (is_string($k) ? $k . ':' . $v : $v);
|
||||
}
|
||||
}
|
||||
if ($tmp === null) {
|
||||
|
||||
+98
-38
@@ -13,7 +13,7 @@ use Nette;
|
||||
|
||||
|
||||
/**
|
||||
* Basic manipulation with images.
|
||||
* Basic manipulation with images. Supported types are JPEG, PNG, GIF, WEBP and BMP.
|
||||
*
|
||||
* <code>
|
||||
* $image = Image::fromFile('nette.jpg');
|
||||
@@ -22,6 +22,9 @@ use Nette;
|
||||
* $image->send();
|
||||
* </code>
|
||||
*
|
||||
* @method Image affine(array $affine, array $clip = null)
|
||||
* @method array affineMatrixConcat(array $m1, array $m2)
|
||||
* @method array affineMatrixGet(int $type, mixed $options = null)
|
||||
* @method void alphaBlending(bool $on)
|
||||
* @method void antialias(bool $on)
|
||||
* @method void arc($x, $y, $w, $h, $start, $end, $color)
|
||||
@@ -50,7 +53,6 @@ use Nette;
|
||||
* @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
|
||||
* @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
|
||||
* @method Image cropAuto(int $mode = -1, float $threshold = .5, int $color = -1)
|
||||
* @method void dashedLine($x1, $y1, $x2, $y2, $color)
|
||||
* @method void ellipse($cx, $cy, $w, $h, $color)
|
||||
* @method void fill($x, $y, $color)
|
||||
* @method void filledArc($cx, $cy, $w, $h, $s, $e, $color, $style)
|
||||
@@ -79,6 +81,7 @@ use Nette;
|
||||
* @method Image scale(int $newWidth, int $newHeight = -1, int $mode = IMG_BILINEAR_FIXED)
|
||||
* @method void setBrush(Image $brush)
|
||||
* @method void setClip(int $x1, int $y1, int $x2, int $y2)
|
||||
* @method void setInterpolation(int $method = IMG_BILINEAR_FIXED)
|
||||
* @method void setPixel($x, $y, $color)
|
||||
* @method void setStyle(array $style)
|
||||
* @method void setThickness($thickness)
|
||||
@@ -89,7 +92,7 @@ use Nette;
|
||||
* @method array ttfText($size, $angle, $x, $y, $color, string $fontfile, string $text)
|
||||
* @property-read int $width
|
||||
* @property-read int $height
|
||||
* @property-read resource $imageResource
|
||||
* @property-read resource|\GdImage $imageResource
|
||||
*/
|
||||
class Image
|
||||
{
|
||||
@@ -122,7 +125,7 @@ class Image
|
||||
|
||||
private const FORMATS = [self::JPEG => 'jpeg', self::PNG => 'png', self::GIF => 'gif', self::WEBP => 'webp', self::BMP => 'bmp'];
|
||||
|
||||
/** @var resource */
|
||||
/** @var resource|\GdImage */
|
||||
private $image;
|
||||
|
||||
|
||||
@@ -141,42 +144,44 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Opens image from file.
|
||||
* Reads an image from a file and returns its type in $type.
|
||||
* @throws Nette\NotSupportedException if gd extension is not loaded
|
||||
* @throws UnknownImageFileException if file not found or file type is not known
|
||||
* @return static
|
||||
*/
|
||||
public static function fromFile(string $file, int &$detectedFormat = null)
|
||||
public static function fromFile(string $file, int &$type = null)
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
$detectedFormat = @getimagesize($file)[2]; // @ - files smaller than 12 bytes causes read error
|
||||
if (!isset(self::FORMATS[$detectedFormat])) {
|
||||
$detectedFormat = null;
|
||||
$type = self::detectTypeFromFile($file);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
|
||||
}
|
||||
return new static(Callback::invokeSafe('imagecreatefrom' . image_type_to_extension($detectedFormat, false), [$file], function (string $message): void {
|
||||
|
||||
$method = 'imagecreatefrom' . self::FORMATS[$type];
|
||||
return new static(Callback::invokeSafe($method, [$file], function (string $message): void {
|
||||
throw new ImageException($message);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new image from the image stream in the string.
|
||||
* Reads an image from a string and returns its type in $type.
|
||||
* @return static
|
||||
* @throws Nette\NotSupportedException if gd extension is not loaded
|
||||
* @throws ImageException
|
||||
*/
|
||||
public static function fromString(string $s, int &$detectedFormat = null)
|
||||
public static function fromString(string $s, int &$type = null)
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
|
||||
}
|
||||
|
||||
if (func_num_args() > 1) {
|
||||
$tmp = @getimagesizefromstring($s)[2]; // @ - strings smaller than 12 bytes causes read error
|
||||
$detectedFormat = isset(self::FORMATS[$tmp]) ? $tmp : null;
|
||||
$type = self::detectTypeFromString($s);
|
||||
if (!$type) {
|
||||
throw new UnknownImageFileException('Unknown type of image.');
|
||||
}
|
||||
|
||||
return new static(Callback::invokeSafe('imagecreatefromstring', [$s], function (string $message): void {
|
||||
@@ -186,8 +191,9 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Creates blank image.
|
||||
* Creates a new true color image of the given dimensions. The default color is black.
|
||||
* @return static
|
||||
* @throws Nette\NotSupportedException if gd extension is not loaded
|
||||
*/
|
||||
public static function fromBlank(int $width, int $height, array $color = null)
|
||||
{
|
||||
@@ -211,6 +217,29 @@ class Image
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of image from file.
|
||||
*/
|
||||
public static function detectTypeFromFile(string $file): ?int
|
||||
{
|
||||
$type = @getimagesize($file)[2]; // @ - files smaller than 12 bytes causes read error
|
||||
return isset(self::FORMATS[$type]) ? $type : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of image from string.
|
||||
*/
|
||||
public static function detectTypeFromString(string $s): ?int
|
||||
{
|
||||
$type = @getimagesizefromstring($s)[2]; // @ - strings smaller than 12 bytes causes read error
|
||||
return isset(self::FORMATS[$type]) ? $type : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the file extension for the given `Image::XXX` constant.
|
||||
*/
|
||||
public static function typeToExtension(int $type): string
|
||||
{
|
||||
if (!isset(self::FORMATS[$type])) {
|
||||
@@ -220,6 +249,9 @@ class Image
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the mime type for the given `Image::XXX` constant.
|
||||
*/
|
||||
public static function typeToMimeType(int $type): string
|
||||
{
|
||||
return 'image/' . self::typeToExtension($type);
|
||||
@@ -228,7 +260,7 @@ class Image
|
||||
|
||||
/**
|
||||
* Wraps GD image.
|
||||
* @param resource $image
|
||||
* @param resource|\GdImage $image
|
||||
*/
|
||||
public function __construct($image)
|
||||
{
|
||||
@@ -257,12 +289,12 @@ class Image
|
||||
|
||||
/**
|
||||
* Sets image resource.
|
||||
* @param resource $image
|
||||
* @param resource|\GdImage $image
|
||||
* @return static
|
||||
*/
|
||||
protected function setImageResource($image)
|
||||
{
|
||||
if (!is_resource($image) || get_resource_type($image) !== 'gd') {
|
||||
if (!$image instanceof \GdImage && !(is_resource($image) && get_resource_type($image) === 'gd')) {
|
||||
throw new Nette\InvalidArgumentException('Image is not valid.');
|
||||
}
|
||||
$this->image = $image;
|
||||
@@ -272,7 +304,7 @@ class Image
|
||||
|
||||
/**
|
||||
* Returns image GD resource.
|
||||
* @return resource
|
||||
* @return resource|\GdImage
|
||||
*/
|
||||
public function getImageResource()
|
||||
{
|
||||
@@ -281,7 +313,7 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Resizes image.
|
||||
* Scales an image.
|
||||
* @param int|string|null $width in pixels or percent
|
||||
* @param int|string|null $height in pixels or percent
|
||||
* @return static
|
||||
@@ -297,9 +329,16 @@ class Image
|
||||
if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { // resize
|
||||
$newImage = static::fromBlank($newWidth, $newHeight, self::rgb(0, 0, 0, 127))->getImageResource();
|
||||
imagecopyresampled(
|
||||
$newImage, $this->image,
|
||||
0, 0, 0, 0,
|
||||
$newWidth, $newHeight, $this->getWidth(), $this->getHeight()
|
||||
$newImage,
|
||||
$this->image,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
$newWidth,
|
||||
$newHeight,
|
||||
$this->getWidth(),
|
||||
$this->getHeight()
|
||||
);
|
||||
$this->image = $newImage;
|
||||
}
|
||||
@@ -316,16 +355,23 @@ class Image
|
||||
* @param int|string|null $newWidth in pixels or percent
|
||||
* @param int|string|null $newHeight in pixels or percent
|
||||
*/
|
||||
public static function calculateSize(int $srcWidth, int $srcHeight, $newWidth, $newHeight, int $flags = self::FIT): array
|
||||
{
|
||||
if ($newWidth !== null && self::isPercent($newWidth)) {
|
||||
public static function calculateSize(
|
||||
int $srcWidth,
|
||||
int $srcHeight,
|
||||
$newWidth,
|
||||
$newHeight,
|
||||
int $flags = self::FIT
|
||||
): array {
|
||||
if ($newWidth === null) {
|
||||
} elseif (self::isPercent($newWidth)) {
|
||||
$newWidth = (int) round($srcWidth / 100 * abs($newWidth));
|
||||
$percents = true;
|
||||
} else {
|
||||
$newWidth = abs($newWidth);
|
||||
}
|
||||
|
||||
if ($newHeight !== null && self::isPercent($newHeight)) {
|
||||
if ($newHeight === null) {
|
||||
} elseif (self::isPercent($newHeight)) {
|
||||
$newHeight = (int) round($srcHeight / 100 * abs($newHeight));
|
||||
$flags |= empty($percents) ? 0 : self::STRETCH;
|
||||
} else {
|
||||
@@ -433,7 +479,7 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Sharpen image.
|
||||
* Sharpens image a little bit.
|
||||
* @return static
|
||||
*/
|
||||
public function sharpen()
|
||||
@@ -497,15 +543,21 @@ class Image
|
||||
}
|
||||
|
||||
imagecopy(
|
||||
$this->image, $output,
|
||||
$left, $top, 0, 0, $width, $height
|
||||
$this->image,
|
||||
$output,
|
||||
$left,
|
||||
$top,
|
||||
0,
|
||||
0,
|
||||
$width,
|
||||
$height
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Saves image to the file. Quality is 0..100 for JPEG and WEBP, 0..9 for PNG.
|
||||
* Saves image to the file. Quality is in the range 0..100 for JPEG (default 85) and WEBP (default 80) and 0..9 for PNG (default 9).
|
||||
* @throws ImageException
|
||||
*/
|
||||
public function save(string $file, int $quality = null, int $type = null): void
|
||||
@@ -524,7 +576,7 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Outputs image to string. Quality is 0..100 for JPEG and WEBP, 0..9 for PNG.
|
||||
* Outputs image to string. Quality is in the range 0..100 for JPEG (default 85) and WEBP (default 80) and 0..9 for PNG (default 9).
|
||||
*/
|
||||
public function toString(int $type = self::JPEG, int $quality = null): string
|
||||
{
|
||||
@@ -552,7 +604,7 @@ class Image
|
||||
|
||||
|
||||
/**
|
||||
* Outputs image to browser. Quality is 0..100 for JPEG and WEBP, 0..9 for PNG.
|
||||
* Outputs image to browser. Quality is in the range 0..100 for JPEG (default 85) and WEBP (default 80) and 0..9 for PNG (default 9).
|
||||
* @throws ImageException
|
||||
*/
|
||||
public function send(int $type = self::JPEG, int $quality = null): void
|
||||
@@ -610,7 +662,7 @@ class Image
|
||||
{
|
||||
$function = 'image' . $name;
|
||||
if (!function_exists($function)) {
|
||||
ObjectHelpers::strictCall(get_class($this), $name);
|
||||
ObjectHelpers::strictCall(static::class, $name);
|
||||
}
|
||||
|
||||
foreach ($args as $key => $value) {
|
||||
@@ -620,15 +672,23 @@ class Image
|
||||
} elseif (is_array($value) && isset($value['red'])) { // rgb
|
||||
$args[$key] = imagecolorallocatealpha(
|
||||
$this->image,
|
||||
$value['red'], $value['green'], $value['blue'], $value['alpha']
|
||||
$value['red'],
|
||||
$value['green'],
|
||||
$value['blue'],
|
||||
$value['alpha']
|
||||
) ?: imagecolorresolvealpha(
|
||||
$this->image,
|
||||
$value['red'], $value['green'], $value['blue'], $value['alpha']
|
||||
$value['red'],
|
||||
$value['green'],
|
||||
$value['blue'],
|
||||
$value['alpha']
|
||||
);
|
||||
}
|
||||
}
|
||||
$res = $function($this->image, ...$args);
|
||||
return is_resource($res) && get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res;
|
||||
return $res instanceof \GdImage || (is_resource($res) && get_resource_type($res) === 'gd')
|
||||
? $this->setImageResource($res)
|
||||
: $res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+3
-2
@@ -27,7 +27,8 @@ final class Json
|
||||
|
||||
|
||||
/**
|
||||
* Returns the JSON representation of a value. Accepts flag Json::PRETTY.
|
||||
* Converts value to JSON format. The flag can be Json::PRETTY, which formats JSON for easier reading and clarity,
|
||||
* and Json::ESCAPE_UNICODE for ASCII output.
|
||||
* @param mixed $value
|
||||
* @throws JsonException
|
||||
*/
|
||||
@@ -47,7 +48,7 @@ final class Json
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a JSON string. Accepts flag Json::FORCE_ARRAY.
|
||||
* Parses JSON to PHP value. The flag can be Json::FORCE_ARRAY, which forces an array instead of an object as the return value.
|
||||
* @return mixed
|
||||
* @throws JsonException
|
||||
*/
|
||||
|
||||
+3
-1
@@ -87,7 +87,9 @@ final class ObjectHelpers
|
||||
$rc = new \ReflectionClass($class);
|
||||
preg_match_all(
|
||||
'~^ [ \t*]* @property(|-read|-write) [ \t]+ [^\s$]+ [ \t]+ \$ (\w+) ()~mx',
|
||||
(string) $rc->getDocComment(), $matches, PREG_SET_ORDER
|
||||
(string) $rc->getDocComment(),
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
$props = [];
|
||||
|
||||
+12
-4
@@ -79,7 +79,9 @@ class Paginator
|
||||
*/
|
||||
public function getLastPage(): ?int
|
||||
{
|
||||
return $this->itemCount === null ? null : $this->base + max(0, $this->getPageCount() - 1);
|
||||
return $this->itemCount === null
|
||||
? null
|
||||
: $this->base + max(0, $this->getPageCount() - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +111,9 @@ class Paginator
|
||||
protected function getPageIndex(): int
|
||||
{
|
||||
$index = max(0, $this->page - $this->base);
|
||||
return $this->itemCount === null ? $index : min($index, max(0, $this->getPageCount() - 1));
|
||||
return $this->itemCount === null
|
||||
? $index
|
||||
: min($index, max(0, $this->getPageCount() - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +131,9 @@ class Paginator
|
||||
*/
|
||||
public function isLast(): bool
|
||||
{
|
||||
return $this->itemCount === null ? false : $this->getPageIndex() >= $this->getPageCount() - 1;
|
||||
return $this->itemCount === null
|
||||
? false
|
||||
: $this->getPageIndex() >= $this->getPageCount() - 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +142,9 @@ class Paginator
|
||||
*/
|
||||
public function getPageCount(): ?int
|
||||
{
|
||||
return $this->itemCount === null ? null : (int) ceil($this->itemCount / $this->itemsPerPage);
|
||||
return $this->itemCount === null
|
||||
? null
|
||||
: (int) ceil($this->itemCount / $this->itemsPerPage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -20,7 +20,8 @@ final class Random
|
||||
use Nette\StaticClass;
|
||||
|
||||
/**
|
||||
* Generate random string.
|
||||
* Generates a random string of given length from characters specified in second argument.
|
||||
* Supports intervals, such as `0-9` or `A-Z`.
|
||||
*/
|
||||
public static function generate(int $length = 10, string $charlist = '0-9a-z'): string
|
||||
{
|
||||
|
||||
+122
-45
@@ -21,50 +21,122 @@ final class Reflection
|
||||
|
||||
private const BUILTIN_TYPES = [
|
||||
'string' => 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1,
|
||||
'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1,
|
||||
'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1,
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Determines if type is PHP built-in type. Otherwise, it is the class name.
|
||||
*/
|
||||
public static function isBuiltinType(string $type): bool
|
||||
{
|
||||
return isset(self::BUILTIN_TYPES[strtolower($type)]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names.
|
||||
* If the function does not have a return type, it returns null.
|
||||
* If the function has union type, it throws Nette\InvalidStateException.
|
||||
*/
|
||||
public static function getReturnType(\ReflectionFunctionAbstract $func): ?string
|
||||
{
|
||||
$type = $func->getReturnType();
|
||||
return $type instanceof \ReflectionNamedType && $func instanceof \ReflectionMethod
|
||||
? self::normalizeType($type->getName(), $func)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
public static function getParameterType(\ReflectionParameter $param): ?string
|
||||
{
|
||||
$type = $param->getType();
|
||||
return $type instanceof \ReflectionNamedType
|
||||
? self::normalizeType($type->getName(), $param)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
public static function getPropertyType(\ReflectionProperty $prop): ?string
|
||||
{
|
||||
$type = PHP_VERSION_ID >= 70400 ? $prop->getType() : null;
|
||||
return $type instanceof \ReflectionNamedType
|
||||
? self::normalizeType($type->getName(), $prop)
|
||||
: null;
|
||||
return self::getType($func, $func->getReturnType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection
|
||||
* Returns the types of return value of given function or method and normalizes `self`, `static`, and `parent` to actual class names.
|
||||
*/
|
||||
public static function getReturnTypes(\ReflectionFunctionAbstract $func): array
|
||||
{
|
||||
return self::getType($func, $func->getReturnType(), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of given parameter and normalizes `self` and `parent` to the actual class names.
|
||||
* If the parameter does not have a type, it returns null.
|
||||
* If the parameter has union type, it throws Nette\InvalidStateException.
|
||||
*/
|
||||
public static function getParameterType(\ReflectionParameter $param): ?string
|
||||
{
|
||||
return self::getType($param, $param->getType());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the types of given parameter and normalizes `self` and `parent` to the actual class names.
|
||||
*/
|
||||
public static function getParameterTypes(\ReflectionParameter $param): array
|
||||
{
|
||||
return self::getType($param, $param->getType(), true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of given property and normalizes `self` and `parent` to the actual class names.
|
||||
* If the property does not have a type, it returns null.
|
||||
* If the property has union type, it throws Nette\InvalidStateException.
|
||||
*/
|
||||
public static function getPropertyType(\ReflectionProperty $prop): ?string
|
||||
{
|
||||
return self::getType($prop, PHP_VERSION_ID >= 70400 ? $prop->getType() : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the types of given property and normalizes `self` and `parent` to the actual class names.
|
||||
*/
|
||||
public static function getPropertyTypes(\ReflectionProperty $prop): array
|
||||
{
|
||||
return self::getType($prop, PHP_VERSION_ID >= 70400 ? $prop->getType() : null, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection
|
||||
* @return string|array|null
|
||||
*/
|
||||
private static function getType($reflection, ?\ReflectionType $type, bool $asArray = false)
|
||||
{
|
||||
if ($type === null) {
|
||||
return $asArray ? [] : null;
|
||||
|
||||
} elseif ($type instanceof \ReflectionNamedType) {
|
||||
$name = self::normalizeType($type->getName(), $reflection);
|
||||
if ($asArray) {
|
||||
return $type->allowsNull() && $type->getName() !== 'mixed'
|
||||
? [$name, 'null']
|
||||
: [$name];
|
||||
}
|
||||
return $name;
|
||||
|
||||
} elseif ($type instanceof \ReflectionUnionType) {
|
||||
if ($asArray) {
|
||||
$types = [];
|
||||
foreach ($type->getTypes() as $type) {
|
||||
$types[] = self::normalizeType($type->getName(), $reflection);
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union type.');
|
||||
|
||||
} else {
|
||||
throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection
|
||||
*/
|
||||
private static function normalizeType(string $type, $reflection): string
|
||||
{
|
||||
$lower = strtolower($type);
|
||||
if ($lower === 'self') {
|
||||
if ($reflection instanceof \ReflectionFunction) {
|
||||
return $type;
|
||||
} elseif ($lower === 'self' || $lower === 'static') {
|
||||
return $reflection->getDeclaringClass()->name;
|
||||
} elseif ($lower === 'parent' && $reflection->getDeclaringClass()->getParentClass()) {
|
||||
return $reflection->getDeclaringClass()->getParentClass()->name;
|
||||
@@ -75,8 +147,9 @@ final class Reflection
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default value of parameter. If it is a constant, it returns its value.
|
||||
* @return mixed
|
||||
* @throws \ReflectionException when default value is not available or resolvable
|
||||
* @throws \ReflectionException If the parameter does not have a default value or the constant cannot be resolved
|
||||
*/
|
||||
public static function getParameterDefaultValue(\ReflectionParameter $param)
|
||||
{
|
||||
@@ -107,7 +180,7 @@ final class Reflection
|
||||
|
||||
|
||||
/**
|
||||
* Returns declaring class or trait.
|
||||
* Returns a reflection of a class or trait that contains a declaration of given property. Property can also be declared in the trait.
|
||||
*/
|
||||
public static function getPropertyDeclaringClass(\ReflectionProperty $prop): \ReflectionClass
|
||||
{
|
||||
@@ -124,7 +197,8 @@ final class Reflection
|
||||
|
||||
|
||||
/**
|
||||
* Returns declaring method in class or trait.
|
||||
* Returns a reflection of a method that contains a declaration of $method.
|
||||
* Usually, each method is its own declaration, but the body of the method can also be in the trait and under a different name.
|
||||
*/
|
||||
public static function getMethodDeclaringMethod(\ReflectionMethod $method): \ReflectionMethod
|
||||
{
|
||||
@@ -158,14 +232,12 @@ final class Reflection
|
||||
|
||||
|
||||
/**
|
||||
* Are documentation comments available?
|
||||
* Finds out if reflection has access to PHPdoc comments. Comments may not be available due to the opcode cache.
|
||||
*/
|
||||
public static function areCommentsAvailable(): bool
|
||||
{
|
||||
static $res;
|
||||
return $res === null
|
||||
? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment()
|
||||
: $res;
|
||||
return $res ?? $res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment();
|
||||
}
|
||||
|
||||
|
||||
@@ -174,13 +246,13 @@ final class Reflection
|
||||
if ($ref instanceof \ReflectionClass) {
|
||||
return $ref->name;
|
||||
} elseif ($ref instanceof \ReflectionMethod) {
|
||||
return $ref->getDeclaringClass()->name . '::' . $ref->name;
|
||||
return $ref->getDeclaringClass()->name . '::' . $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionFunction) {
|
||||
return $ref->name;
|
||||
return $ref->name . '()';
|
||||
} elseif ($ref instanceof \ReflectionProperty) {
|
||||
return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name;
|
||||
} elseif ($ref instanceof \ReflectionParameter) {
|
||||
return '$' . $ref->name . ' in ' . self::toString($ref->getDeclaringFunction()) . '()';
|
||||
return '$' . $ref->name . ' in ' . self::toString($ref->getDeclaringFunction());
|
||||
} else {
|
||||
throw new Nette\InvalidArgumentException;
|
||||
}
|
||||
@@ -188,10 +260,11 @@ final class Reflection
|
||||
|
||||
|
||||
/**
|
||||
* Expands class name into full name.
|
||||
* Expands the name of the class to full name in the given context of given class.
|
||||
* Thus, it returns how the PHP parser would understand $name if it were written in the body of the class $context.
|
||||
* @throws Nette\InvalidArgumentException
|
||||
*/
|
||||
public static function expandClassName(string $name, \ReflectionClass $rc): string
|
||||
public static function expandClassName(string $name, \ReflectionClass $context): string
|
||||
{
|
||||
$lower = strtolower($name);
|
||||
if (empty($name)) {
|
||||
@@ -200,21 +273,21 @@ final class Reflection
|
||||
} elseif (isset(self::BUILTIN_TYPES[$lower])) {
|
||||
return $lower;
|
||||
|
||||
} elseif ($lower === 'self') {
|
||||
return $rc->name;
|
||||
} elseif ($lower === 'self' || $lower === 'static') {
|
||||
return $context->name;
|
||||
|
||||
} elseif ($name[0] === '\\') { // fully qualified name
|
||||
return ltrim($name, '\\');
|
||||
}
|
||||
|
||||
$uses = self::getUseStatements($rc);
|
||||
$uses = self::getUseStatements($context);
|
||||
$parts = explode('\\', $name, 2);
|
||||
if (isset($uses[$parts[0]])) {
|
||||
$parts[0] = $uses[$parts[0]];
|
||||
return implode('\\', $parts);
|
||||
|
||||
} elseif ($rc->inNamespace()) {
|
||||
return $rc->getNamespaceName() . '\\' . $name;
|
||||
} elseif ($context->inNamespace()) {
|
||||
return $context->getNamespaceName() . '\\' . $name;
|
||||
|
||||
} else {
|
||||
return $name;
|
||||
@@ -255,11 +328,15 @@ final class Reflection
|
||||
$namespace = $class = $classLevel = $level = null;
|
||||
$res = $uses = [];
|
||||
|
||||
$nameTokens = PHP_VERSION_ID < 80000
|
||||
? [T_STRING, T_NS_SEPARATOR]
|
||||
: [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED];
|
||||
|
||||
while ($token = current($tokens)) {
|
||||
next($tokens);
|
||||
switch (is_array($token) ? $token[0] : $token) {
|
||||
case T_NAMESPACE:
|
||||
$namespace = ltrim(self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]) . '\\', '\\');
|
||||
$namespace = ltrim(self::fetch($tokens, $nameTokens) . '\\', '\\');
|
||||
$uses = [];
|
||||
break;
|
||||
|
||||
@@ -277,10 +354,10 @@ final class Reflection
|
||||
break;
|
||||
|
||||
case T_USE:
|
||||
while (!$class && ($name = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR]))) {
|
||||
while (!$class && ($name = self::fetch($tokens, $nameTokens))) {
|
||||
$name = ltrim($name, '\\');
|
||||
if (self::fetch($tokens, '{')) {
|
||||
while ($suffix = self::fetch($tokens, [T_STRING, T_NS_SEPARATOR])) {
|
||||
while ($suffix = self::fetch($tokens, $nameTokens)) {
|
||||
if (self::fetch($tokens, T_AS)) {
|
||||
$uses[self::fetch($tokens, T_STRING)] = $name . $suffix;
|
||||
} else {
|
||||
|
||||
+66
-48
@@ -24,7 +24,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the string is valid for UTF-8 encoding.
|
||||
* Checks if the string is valid in UTF-8 encoding.
|
||||
*/
|
||||
public static function checkEncoding(string $s): bool
|
||||
{
|
||||
@@ -33,7 +33,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Removes invalid code unit sequences from UTF-8 string.
|
||||
* Removes all invalid UTF-8 characters from a string.
|
||||
*/
|
||||
public static function fixEncoding(string $s): string
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns a specific character in UTF-8 from code point (0x0 to 0xD7FF or 0xE000 to 0x10FFFF).
|
||||
* Returns a specific character in UTF-8 from code point (number in range 0x0000..D7FF or 0xE000..10FFFF).
|
||||
* @throws Nette\InvalidArgumentException if code point is not in valid range
|
||||
*/
|
||||
public static function chr(int $code): string
|
||||
@@ -85,7 +85,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns a part of UTF-8 string.
|
||||
* Returns a part of UTF-8 string specified by starting position and length. If start is negative,
|
||||
* the returned string will start at the start'th character from the end of string.
|
||||
*/
|
||||
public static function substring(string $s, int $start, int $length = null): string
|
||||
{
|
||||
@@ -103,7 +104,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Removes special controls characters and normalizes line endings, spaces and normal form to NFC in UTF-8 string.
|
||||
* Removes control characters, normalizes line breaks to `\n`, removes leading and trailing blank lines,
|
||||
* trims end spaces on lines, normalizes UTF-8 to the normal form of NFC.
|
||||
*/
|
||||
public static function normalize(string $s): string
|
||||
{
|
||||
@@ -137,21 +139,26 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts UTF-8 string to ASCII.
|
||||
* Converts UTF-8 string to ASCII, ie removes diacritics etc.
|
||||
*/
|
||||
public static function toAscii(string $s): string
|
||||
{
|
||||
$iconv = defined('ICONV_IMPL') ? ICONV_IMPL : null;
|
||||
$iconv = defined('ICONV_IMPL') ? trim(ICONV_IMPL, '"\'') : null;
|
||||
static $transliterator = null;
|
||||
if ($transliterator === null && class_exists('Transliterator', false)) {
|
||||
$transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
|
||||
if ($transliterator === null) {
|
||||
if (class_exists('Transliterator', false)) {
|
||||
$transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
|
||||
} else {
|
||||
trigger_error(__METHOD__ . "(): it is recommended to enable PHP extensions 'intl'.", E_USER_NOTICE);
|
||||
$transliterator = false;
|
||||
}
|
||||
}
|
||||
|
||||
// remove control characters and check UTF-8 validity
|
||||
$s = self::pcre('preg_replace', ['#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s]);
|
||||
|
||||
// transliteration (by Transliterator and iconv) is not optimal, replace some characters directly
|
||||
$s = strtr($s, ["\u{201E}" => '"', "\u{201C}" => '"', "\u{201D}" => '"', "\u{201A}" => "'", "\u{2018}" => "'", "\u{2019}" => "'", "\u{B0}" => '^', "\u{42F}" => 'Ya', "\u{44F}" => 'ya', "\u{42E}" => 'Yu', "\u{44E}" => 'yu']); // „ “ ” ‚ ‘ ’ ° Я я Ю ю
|
||||
$s = strtr($s, ["\u{201E}" => '"', "\u{201C}" => '"', "\u{201D}" => '"', "\u{201A}" => "'", "\u{2018}" => "'", "\u{2019}" => "'", "\u{B0}" => '^', "\u{42F}" => 'Ya', "\u{44F}" => 'ya', "\u{42E}" => 'Yu', "\u{44E}" => 'yu', "\u{c4}" => 'Ae', "\u{d6}" => 'Oe', "\u{dc}" => 'Ue', "\u{1e9e}" => 'Ss', "\u{e4}" => 'ae', "\u{f6}" => 'oe', "\u{fc}" => 'ue', "\u{df}" => 'ss']); // „ “ ” ‚ ‘ ’ ° Я я Ю ю Ä Ö Ü ẞ ä ö ü ß
|
||||
if ($iconv !== 'libiconv') {
|
||||
$s = strtr($s, ["\u{AE}" => '(R)', "\u{A9}" => '(c)', "\u{2026}" => '...', "\u{AB}" => '<<', "\u{BB}" => '>>', "\u{A3}" => 'lb', "\u{A5}" => 'yen', "\u{B2}" => '^2', "\u{B3}" => '^3', "\u{B5}" => 'u', "\u{B9}" => '^1', "\u{BA}" => 'o', "\u{BF}" => '?', "\u{2CA}" => "'", "\u{2CD}" => '_', "\u{2DD}" => '"', "\u{1FEF}" => '', "\u{20AC}" => 'EUR', "\u{2122}" => 'TM', "\u{212E}" => 'e', "\u{2190}" => '<-', "\u{2191}" => '^', "\u{2192}" => '->', "\u{2193}" => 'V', "\u{2194}" => '<->']); // ® © … « » £ ¥ ² ³ µ ¹ º ¿ ˊ ˍ ˝ ` € ™ ℮ ← ↑ → ↓ ↔
|
||||
}
|
||||
@@ -174,9 +181,11 @@ class Strings
|
||||
if ($iconv === 'glibc') {
|
||||
// glibc implementation is very limited. transliterate into Windows-1250 and then into ASCII, so most Eastern European characters are preserved
|
||||
$s = iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s);
|
||||
$s = strtr($s,
|
||||
$s = strtr(
|
||||
$s,
|
||||
"\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\x96\xa0\x8b\x97\x9b\xa6\xad\xb7",
|
||||
'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.');
|
||||
'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.'
|
||||
);
|
||||
$s = self::pcre('preg_replace', ['#[^\x00-\x7F]++#', '', $s]);
|
||||
} else {
|
||||
$s = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s);
|
||||
@@ -194,7 +203,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts UTF-8 string to web safe characters [a-z0-9-] text.
|
||||
* Modifies the UTF-8 string to the form used in the URL, ie removes diacritics and replaces all characters
|
||||
* except letters of the English alphabet and numbers with a hyphens.
|
||||
*/
|
||||
public static function webalize(string $s, string $charlist = null, bool $lower = true): string
|
||||
{
|
||||
@@ -209,7 +219,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Truncates UTF-8 string to maximal length.
|
||||
* Truncates a UTF-8 string to given maximal length, while trying not to split whole words. Only if the string is truncated,
|
||||
* an ellipsis (or something else set with third argument) is appended to the string.
|
||||
*/
|
||||
public static function truncate(string $s, int $maxLen, string $append = "\u{2026}"): string
|
||||
{
|
||||
@@ -230,7 +241,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Indents UTF-8 string from the left.
|
||||
* Indents a multiline text from the left. Second argument sets how many indentation chars should be used,
|
||||
* while the indent itself is the third argument (*tab* by default).
|
||||
*/
|
||||
public static function indent(string $s, int $level = 1, string $chars = "\t"): string
|
||||
{
|
||||
@@ -242,7 +254,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts UTF-8 string to lower case.
|
||||
* Converts all characters of UTF-8 string to lower case.
|
||||
*/
|
||||
public static function lower(string $s): string
|
||||
{
|
||||
@@ -251,7 +263,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts first character to lower case.
|
||||
* Converts the first character of a UTF-8 string to lower case and leaves the other characters unchanged.
|
||||
*/
|
||||
public static function firstLower(string $s): string
|
||||
{
|
||||
@@ -260,7 +272,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts UTF-8 string to upper case.
|
||||
* Converts all characters of a UTF-8 string to upper case.
|
||||
*/
|
||||
public static function upper(string $s): string
|
||||
{
|
||||
@@ -269,7 +281,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Converts first character to upper case.
|
||||
* Converts the first character of a UTF-8 string to upper case and leaves the other characters unchanged.
|
||||
*/
|
||||
public static function firstUpper(string $s): string
|
||||
{
|
||||
@@ -278,7 +290,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Capitalizes UTF-8 string.
|
||||
* Converts the first character of every word of a UTF-8 string to upper case and the others to lower case.
|
||||
*/
|
||||
public static function capitalize(string $s): string
|
||||
{
|
||||
@@ -287,28 +299,30 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Case-insensitive compares UTF-8 strings.
|
||||
* Compares two UTF-8 strings or their parts, without taking character case into account. If length is null, whole strings are compared,
|
||||
* if it is negative, the corresponding number of characters from the end of the strings is compared,
|
||||
* otherwise the appropriate number of characters from the beginning is compared.
|
||||
*/
|
||||
public static function compare(string $left, string $right, int $len = null): bool
|
||||
public static function compare(string $left, string $right, int $length = null): bool
|
||||
{
|
||||
if (class_exists('Normalizer', false)) {
|
||||
$left = \Normalizer::normalize($left, \Normalizer::FORM_D); // form NFD is faster
|
||||
$right = \Normalizer::normalize($right, \Normalizer::FORM_D); // form NFD is faster
|
||||
}
|
||||
|
||||
if ($len < 0) {
|
||||
$left = self::substring($left, $len, -$len);
|
||||
$right = self::substring($right, $len, -$len);
|
||||
} elseif ($len !== null) {
|
||||
$left = self::substring($left, 0, $len);
|
||||
$right = self::substring($right, 0, $len);
|
||||
if ($length < 0) {
|
||||
$left = self::substring($left, $length, -$length);
|
||||
$right = self::substring($right, $length, -$length);
|
||||
} elseif ($length !== null) {
|
||||
$left = self::substring($left, 0, $length);
|
||||
$right = self::substring($right, 0, $length);
|
||||
}
|
||||
return self::lower($left) === self::lower($right);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the length of common prefix of strings.
|
||||
* Finds the common prefix of strings or returns empty string if the prefix was not found.
|
||||
* @param string[] $strings
|
||||
*/
|
||||
public static function findPrefix(array $strings): string
|
||||
@@ -334,12 +348,14 @@ class Strings
|
||||
*/
|
||||
public static function length(string $s): int
|
||||
{
|
||||
return function_exists('mb_strlen') ? mb_strlen($s, 'UTF-8') : strlen(utf8_decode($s));
|
||||
return function_exists('mb_strlen')
|
||||
? mb_strlen($s, 'UTF-8')
|
||||
: strlen(utf8_decode($s));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strips whitespace from UTF-8 string.
|
||||
* Removes all left and right side spaces (or the characters passed as second argument) from a UTF-8 encoded string.
|
||||
*/
|
||||
public static function trim(string $s, string $charlist = self::TRIM_CHARACTERS): string
|
||||
{
|
||||
@@ -349,7 +365,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Pad a UTF-8 string to a certain length with another string.
|
||||
* Pads a UTF-8 string to given length by prepending the $pad string to the beginning.
|
||||
*/
|
||||
public static function padLeft(string $s, int $length, string $pad = ' '): string
|
||||
{
|
||||
@@ -360,7 +376,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Pad a UTF-8 string to a certain length with another string.
|
||||
* Pads UTF-8 string to given length by appending the $pad string to the end.
|
||||
*/
|
||||
public static function padRight(string $s, int $length, string $pad = ' '): string
|
||||
{
|
||||
@@ -371,7 +387,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Reverse string.
|
||||
* Reverses UTF-8 string.
|
||||
*/
|
||||
public static function reverse(string $s): string
|
||||
{
|
||||
@@ -383,8 +399,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns part of $haystack before $nth occurence of $needle (negative value means searching from the end).
|
||||
* @return string|null returns null if the needle was not found
|
||||
* Returns part of $haystack before $nth occurence of $needle or returns null if the needle was not found.
|
||||
* Negative value means searching from the end.
|
||||
*/
|
||||
public static function before(string $haystack, string $needle, int $nth = 1): ?string
|
||||
{
|
||||
@@ -396,8 +412,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns part of $haystack after $nth occurence of $needle (negative value means searching from the end).
|
||||
* @return string|null returns null if the needle was not found
|
||||
* Returns part of $haystack after $nth occurence of $needle or returns null if the needle was not found.
|
||||
* Negative value means searching from the end.
|
||||
*/
|
||||
public static function after(string $haystack, string $needle, int $nth = 1): ?string
|
||||
{
|
||||
@@ -409,8 +425,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns position of $nth occurence of $needle in $haystack (negative value means searching from the end).
|
||||
* @return int|null offset in characters or null if the needle was not found
|
||||
* Returns position in bytes of $nth occurence of $needle in $haystack or null if the $needle was not found.
|
||||
* Negative value of `$nth` means searching from the end.
|
||||
*/
|
||||
public static function indexOf(string $haystack, string $needle, int $nth = 1): ?int
|
||||
{
|
||||
@@ -422,8 +438,7 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Returns position of $nth occurence of $needle in $haystack.
|
||||
* @return int|null offset in bytes or null if the needle was not found
|
||||
* Returns position in bytes of $nth occurence of $needle in $haystack or null if the needle was not found.
|
||||
*/
|
||||
private static function pos(string $haystack, string $needle, int $nth = 1): ?int
|
||||
{
|
||||
@@ -452,7 +467,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Splits string by a regular expression.
|
||||
* Splits a string into array by the regular expression.
|
||||
* Argument $flag takes same arguments as preg_split(), but PREG_SPLIT_DELIM_CAPTURE is set by default.
|
||||
*/
|
||||
public static function split(string $subject, string $pattern, int $flags = 0): array
|
||||
{
|
||||
@@ -461,7 +477,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Performs a regular expression match. Accepts flag PREG_OFFSET_CAPTURE (returned in bytes).
|
||||
* Checks if given string matches a regular expression pattern and returns an array with first found match and each subpattern.
|
||||
* Argument $flag takes same arguments as function preg_match().
|
||||
*/
|
||||
public static function match(string $subject, string $pattern, int $flags = 0, int $offset = 0): ?array
|
||||
{
|
||||
@@ -475,7 +492,8 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Performs a global regular expression match. Accepts flag PREG_OFFSET_CAPTURE (returned in bytes), PREG_SET_ORDER is default.
|
||||
* Finds all occurrences matching regular expression pattern and returns a two-dimensional array.
|
||||
* Argument $flag takes same arguments as function preg_match_all(), but PREG_SET_ORDER is set by default.
|
||||
*/
|
||||
public static function matchAll(string $subject, string $pattern, int $flags = 0, int $offset = 0): array
|
||||
{
|
||||
@@ -492,11 +510,11 @@ class Strings
|
||||
|
||||
|
||||
/**
|
||||
* Perform a regular expression search and replace.
|
||||
* Replaces all occurrences matching regular expression $pattern which can be string or array in the form `pattern => replacement`.
|
||||
* @param string|array $pattern
|
||||
* @param string|callable $replacement
|
||||
*/
|
||||
public static function replace(string $subject, $pattern, $replacement = null, int $limit = -1): string
|
||||
public static function replace(string $subject, $pattern, $replacement = '', int $limit = -1): string
|
||||
{
|
||||
if (is_object($replacement) || is_array($replacement)) {
|
||||
if (!is_callable($replacement, false, $textual)) {
|
||||
@@ -504,7 +522,7 @@ class Strings
|
||||
}
|
||||
return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit]);
|
||||
|
||||
} elseif ($replacement === null && is_array($pattern)) {
|
||||
} elseif (is_array($pattern) && is_string(key($pattern))) {
|
||||
$replacement = array_values($pattern);
|
||||
$pattern = array_keys($pattern);
|
||||
}
|
||||
|
||||
+45
-37
@@ -35,14 +35,14 @@ class Validators
|
||||
'string' => 'is_string',
|
||||
|
||||
// pseudo-types
|
||||
'callable' => [__CLASS__, 'isCallable'],
|
||||
'callable' => [self::class, 'isCallable'],
|
||||
'iterable' => 'is_iterable',
|
||||
'list' => [Arrays::class, 'isList'],
|
||||
'mixed' => [__CLASS__, 'isMixed'],
|
||||
'none' => [__CLASS__, 'isNone'],
|
||||
'number' => [__CLASS__, 'isNumber'],
|
||||
'numeric' => [__CLASS__, 'isNumeric'],
|
||||
'numericint' => [__CLASS__, 'isNumericInt'],
|
||||
'mixed' => [self::class, 'isMixed'],
|
||||
'none' => [self::class, 'isNone'],
|
||||
'number' => [self::class, 'isNumber'],
|
||||
'numeric' => [self::class, 'isNumeric'],
|
||||
'numericint' => [self::class, 'isNumericInt'],
|
||||
|
||||
// string patterns
|
||||
'alnum' => 'ctype_alnum',
|
||||
@@ -51,22 +51,22 @@ class Validators
|
||||
'lower' => 'ctype_lower',
|
||||
'pattern' => null,
|
||||
'space' => 'ctype_space',
|
||||
'unicode' => [__CLASS__, 'isUnicode'],
|
||||
'unicode' => [self::class, 'isUnicode'],
|
||||
'upper' => 'ctype_upper',
|
||||
'xdigit' => 'ctype_xdigit',
|
||||
|
||||
// syntax validation
|
||||
'email' => [__CLASS__, 'isEmail'],
|
||||
'identifier' => [__CLASS__, 'isPhpIdentifier'],
|
||||
'uri' => [__CLASS__, 'isUri'],
|
||||
'url' => [__CLASS__, 'isUrl'],
|
||||
'email' => [self::class, 'isEmail'],
|
||||
'identifier' => [self::class, 'isPhpIdentifier'],
|
||||
'uri' => [self::class, 'isUri'],
|
||||
'url' => [self::class, 'isUrl'],
|
||||
|
||||
// environment validation
|
||||
'class' => 'class_exists',
|
||||
'interface' => 'interface_exists',
|
||||
'directory' => 'is_dir',
|
||||
'file' => 'is_file',
|
||||
'type' => [__CLASS__, 'isType'],
|
||||
'type' => [self::class, 'isType'],
|
||||
];
|
||||
|
||||
/** @var array<string,callable> */
|
||||
@@ -86,8 +86,9 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Throws exception if a variable is of unexpected type (separated by pipe).
|
||||
* Verifies that the value is of expected types separated by pipe.
|
||||
* @param mixed $value
|
||||
* @throws AssertionException
|
||||
*/
|
||||
public static function assert($value, string $expected, string $label = 'variable'): void
|
||||
{
|
||||
@@ -106,23 +107,28 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Throws exception if an array field is missing or of unexpected type (separated by pipe).
|
||||
* @param mixed[] $arr
|
||||
* @param int|string $field
|
||||
* Verifies that element $key in array is of expected types separated by pipe.
|
||||
* @param mixed[] $array
|
||||
* @param int|string $key
|
||||
* @throws AssertionException
|
||||
*/
|
||||
public static function assertField(array $arr, $field, string $expected = null, string $label = "item '%' in array"): void
|
||||
{
|
||||
if (!array_key_exists($field, $arr)) {
|
||||
throw new AssertionException('Missing ' . str_replace('%', $field, $label) . '.');
|
||||
public static function assertField(
|
||||
array $array,
|
||||
$key,
|
||||
string $expected = null,
|
||||
string $label = "item '%' in array"
|
||||
): void {
|
||||
if (!array_key_exists($key, $array)) {
|
||||
throw new AssertionException('Missing ' . str_replace('%', $key, $label) . '.');
|
||||
|
||||
} elseif ($expected) {
|
||||
static::assert($arr[$field], $expected, str_replace('%', $field, $label));
|
||||
static::assert($array[$key], $expected, str_replace('%', $key, $label));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a variable is of expected type (separated by pipe).
|
||||
* Verifies that the value is of expected types separated by pipe.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function is($value, string $expected): bool
|
||||
@@ -178,7 +184,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether all values are of expected type (separated by pipe).
|
||||
* Finds whether all values are of expected types separated by pipe.
|
||||
* @param mixed[] $values
|
||||
*/
|
||||
public static function everyIs(iterable $values, string $expected): bool
|
||||
@@ -193,7 +199,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a value is an integer or a float.
|
||||
* Checks if the value is an integer or a float.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isNumber($value): bool
|
||||
@@ -203,7 +209,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a value is an integer.
|
||||
* Checks if the value is an integer or a integer written in a string.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isNumericInt($value): bool
|
||||
@@ -213,7 +219,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a string is a floating point number in decimal base.
|
||||
* Checks if the value is a number or a number written in a string.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isNumeric($value): bool
|
||||
@@ -223,7 +229,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a value is a syntactically correct callback.
|
||||
* Checks if the value is a syntactically correct callback.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isCallable($value): bool
|
||||
@@ -233,7 +239,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a value is an UTF-8 encoded string.
|
||||
* Checks if the value is a valid UTF-8 string.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isUnicode($value): bool
|
||||
@@ -243,7 +249,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a value is "falsy".
|
||||
* Checks if the value is 0, '', false or null.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isNone($value): bool
|
||||
@@ -260,8 +266,9 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a variable is a zero-based integer indexed array.
|
||||
* Checks if a variable is a zero-based integer indexed array.
|
||||
* @param mixed $value
|
||||
* @deprecated use Nette\Utils\Arrays::isList
|
||||
*/
|
||||
public static function isList($value): bool
|
||||
{
|
||||
@@ -270,7 +277,8 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Is a value in specified min and max value pair?
|
||||
* Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null).
|
||||
* Numbers, strings and DateTime objects can be compared.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function isInRange($value, array $range): bool
|
||||
@@ -295,7 +303,7 @@ class Validators
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a string is a valid email address.
|
||||
* Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified.
|
||||
*/
|
||||
public static function isEmail(string $value): bool
|
||||
{
|
||||
@@ -314,7 +322,7 @@ XX
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a string is a valid http(s) URL.
|
||||
* Checks if the value is a valid URL address.
|
||||
*/
|
||||
public static function isUrl(string $value): bool
|
||||
{
|
||||
@@ -326,11 +334,11 @@ XX
|
||||
[0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)? # domain
|
||||
[$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
|
||||
|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3} # IPv4
|
||||
|\[[0-9a-f:]{3,39}\] # IPv6
|
||||
|\\[[0-9a-f:]{3,39}\\] # IPv6
|
||||
)(:\\d{1,5})? # port
|
||||
(/\\S*)? # path
|
||||
(\?\\S*)? # query
|
||||
(\#\\S*)? # fragment
|
||||
(\\?\\S*)? # query
|
||||
(\\#\\S*)? # fragment
|
||||
$)Dix
|
||||
XX
|
||||
, $value);
|
||||
@@ -338,7 +346,7 @@ XX
|
||||
|
||||
|
||||
/**
|
||||
* Finds whether a string is a valid URI according to RFC 1738.
|
||||
* Checks if the value is a valid URI address, that is, actually a string beginning with a syntactically valid schema.
|
||||
*/
|
||||
public static function isUri(string $value): bool
|
||||
{
|
||||
|
||||
-101
@@ -7,107 +7,6 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
class InvalidStateException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is not implemented.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
class NotSupportedException extends \LogicException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is deprecated.
|
||||
*/
|
||||
class DeprecatedException extends NotSupportedException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a class member (property or method) fails.
|
||||
*/
|
||||
class MemberAccessException extends \Error
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an I/O error occurs.
|
||||
*/
|
||||
class IOException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a file that does not exist on disk.
|
||||
*/
|
||||
class FileNotFoundException extends IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when part of a file or directory cannot be found.
|
||||
*/
|
||||
class DirectoryNotFoundException extends IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an argument does not match with the expected value.
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an illegal index was requested.
|
||||
*/
|
||||
class OutOfRangeException extends \OutOfRangeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a value (typically returned by function) does not match with the expected value.
|
||||
*/
|
||||
class UnexpectedValueException extends \UnexpectedValueException
|
||||
{
|
||||
}
|
||||
|
||||
namespace Nette\Utils;
|
||||
|
||||
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Nette\Utils;
|
||||
|
||||
use Nette;
|
||||
|
||||
if (false) {
|
||||
/** @deprecated use Nette\HtmlStringable */
|
||||
interface IHtmlString extends Nette\HtmlStringable
|
||||
{
|
||||
}
|
||||
} elseif (!interface_exists(IHtmlString::class)) {
|
||||
class_alias(Nette\HtmlStringable::class, IHtmlString::class);
|
||||
}
|
||||
|
||||
namespace Nette\Localization;
|
||||
|
||||
if (false) {
|
||||
/** @deprecated use Nette\Localization\Translator */
|
||||
interface ITranslator extends Translator
|
||||
{
|
||||
}
|
||||
} elseif (!interface_exists(ITranslator::class)) {
|
||||
class_alias(Translator::class, ITranslator::class);
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Nette Framework (https://nette.org)
|
||||
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
class InvalidStateException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is not implemented.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
class NotSupportedException extends \LogicException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a requested method or operation is deprecated.
|
||||
*/
|
||||
class DeprecatedException extends NotSupportedException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a class member (property or method) fails.
|
||||
*/
|
||||
class MemberAccessException extends \Error
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an I/O error occurs.
|
||||
*/
|
||||
class IOException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when accessing a file that does not exist on disk.
|
||||
*/
|
||||
class FileNotFoundException extends IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when part of a file or directory cannot be found.
|
||||
*/
|
||||
class DirectoryNotFoundException extends IOException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an argument does not match with the expected value.
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when an illegal index was requested.
|
||||
*/
|
||||
class OutOfRangeException extends \OutOfRangeException
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The exception that is thrown when a value (typically returned by function) does not match with the expected value.
|
||||
*/
|
||||
class UnexpectedValueException extends \UnexpectedValueException
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user