Style and tool updates

This commit is contained in:
Timothy Warren 2023-05-09 12:46:52 -04:00
parent 81d81f4393
commit 05d4fb1ad7
28 changed files with 514 additions and 475 deletions

View File

@ -1,8 +1,9 @@
# Changelog # Changelog
## Version 5.2 ## Version 5.2
* Updated PHP requirement to 8 * Updated PHP requirement to 8.1
* Updated to support PHP 8.1 * Updated to support PHP 8.2
* Improve Anilist <-> Kitsu mappings to be more reliable
## Version 5.1 ## Version 5.1
* Added session check, so when coming back to a page, if the session is expired, the page will refresh. * Added session check, so when coming back to a page, if the session is expired, the page will refresh.

View File

@ -4,11 +4,11 @@ default:
# Runs rector, showing what changes will be make # Runs rector, showing what changes will be make
rector-dry-run: rector-dry-run:
tools/vendor/bin/rector process --config=tools/rector.php --dry-run src tools/vendor/bin/rector process --config=tools/rector.php --dry-run src tests
# Runs rector, and updates the files # Runs rector, and updates the source files
rector: rector:
tools/vendor/bin/rector process --config=tools/rector.php src tools/vendor/bin/rector process --config=tools/rector.php src tests
# Check code formatting # Check code formatting
check-fmt: check-fmt:

View File

@ -17,6 +17,9 @@ namespace Aviat\Ion\Attribute;
use Attribute; use Attribute;
#[Attribute(Attribute::TARGET_CLASS)] #[Attribute(Attribute::TARGET_CLASS)]
class Controller { class Controller
public function __construct(public string $prefix = '') {} {
} public function __construct(public string $prefix = '')
{
}
}

View File

@ -17,4 +17,6 @@ namespace Aviat\Ion\Attribute;
use Attribute; use Attribute;
#[Attribute(Attribute::TARGET_CLASS)] #[Attribute(Attribute::TARGET_CLASS)]
class DefaultController {} class DefaultController
{
}

View File

@ -17,7 +17,8 @@ namespace Aviat\Ion\Attribute;
use Attribute; use Attribute;
#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] #[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class Route { class Route
{
public const GET = 'get'; public const GET = 'get';
public const POST = 'post'; public const POST = 'post';
@ -25,8 +26,6 @@ class Route {
public string $name, public string $name,
public string $path, public string $path,
public string $verb = self::GET, public string $verb = self::GET,
) ) {
{
} }
} }

View File

@ -39,8 +39,8 @@ class Container implements ContainerInterface
*/ */
public function __construct( public function __construct(
/** /**
* Array of container Generator functions * Array of container Generator functions
*/ */
protected array $container = [] protected array $container = []
) { ) {
$this->loggers = []; $this->loggers = [];

View File

@ -156,7 +156,7 @@ class ArrayType
/** /**
* Find an array key by its associated value * Find an array key by its associated value
*/ */
public function search(mixed $value, bool $strict = TRUE): int|string|FALSE|null public function search(mixed $value, bool $strict = TRUE): int|string|false|null
{ {
return array_search($value, $this->arr, $strict); return array_search($value, $this->arr, $strict);
} }
@ -172,7 +172,7 @@ class ArrayType
/** /**
* Return the array, or a key * Return the array, or a key
*/ */
public function &get(string|int|NULL $key = NULL): mixed public function &get(string|int|null $key = NULL): mixed
{ {
$value = NULL; $value = NULL;
if ($key === NULL) if ($key === NULL)

View File

@ -21,7 +21,22 @@ use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use IteratorAggregate; use IteratorAggregate;
use OutOfBoundsException; use OutOfBoundsException;
use RuntimeException;
use Traversable; use Traversable;
use function mb_convert_case;
use function mb_ereg_match;
use function mb_ereg_replace;
use function mb_internal_encoding;
use function mb_regex_encoding;
use function mb_split;
use function mb_stripos;
use function mb_strlen;
use function mb_strrpos;
use function mb_strtolower;
use function mb_strtoupper;
use function mb_substr;
use function mb_substr_count;
use const MB_CASE_TITLE;
/** /**
* Vendored, slightly modernized version of Stringy * Vendored, slightly modernized version of Stringy
@ -29,16 +44,12 @@ use Traversable;
abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess { abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
/** /**
* An instance's string. * An instance's string.
*
* @var string
*/ */
protected string $str; protected string $str;
/** /**
* The string's encoding, which should be one of the mbstring module's * The string's encoding, which should be one of the mbstring module's
* supported encodings. * supported encodings.
*
* @var string
*/ */
protected string $encoding; protected string $encoding;
@ -51,8 +62,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param mixed $str Value to modify, after being cast to string * @param mixed $str Value to modify, after being cast to string
* @param string|null $encoding The character encoding * @param string|null $encoding The character encoding
* @throws \InvalidArgumentException if an array or object without a * @throws InvalidArgumentException if an array or object without a
* __toString method is passed as the first argument * __toString method is passed as the first argument
*/ */
public function __construct(mixed $str = '', ?string $encoding = NULL) public function __construct(mixed $str = '', ?string $encoding = NULL)
{ {
@ -61,7 +72,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
throw new InvalidArgumentException( throw new InvalidArgumentException(
'Passed value cannot be an array' 'Passed value cannot be an array'
); );
} elseif (is_object($str) && ! method_exists($str, '__toString')) }
if (is_object($str) && ! method_exists($str, '__toString'))
{ {
throw new InvalidArgumentException( throw new InvalidArgumentException(
'Passed object must have a __toString method' 'Passed object must have a __toString method'
@ -69,7 +81,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
} }
$this->str = (string)$str; $this->str = (string)$str;
$this->encoding = $encoding ?: \mb_internal_encoding(); $this->encoding = $encoding ?: mb_internal_encoding();
} }
/** /**
@ -82,8 +94,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* @param mixed $str Value to modify, after being cast to string * @param mixed $str Value to modify, after being cast to string
* @param string|null $encoding The character encoding * @param string|null $encoding The character encoding
* @return static A Stringy object * @return static A Stringy object
* @throws \InvalidArgumentException if an array or object without a * @throws InvalidArgumentException if an array or object without a
* __toString method is passed as the first argument * __toString method is passed as the first argument
*/ */
public static function create(mixed $str = '', ?string $encoding = NULL): self public static function create(mixed $str = '', ?string $encoding = NULL): self
{ {
@ -140,7 +152,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return static::create('', $this->encoding); return static::create('', $this->encoding);
} }
$substrIndex = $startIndex + \mb_strlen($start, $this->encoding); $substrIndex = $startIndex + mb_strlen($start, $this->encoding);
$endIndex = $this->indexOf($end, $substrIndex); $endIndex = $this->indexOf($end, $substrIndex);
if ($endIndex === FALSE) if ($endIndex === FALSE)
{ {
@ -165,10 +177,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$stringy->str = preg_replace_callback( $stringy->str = preg_replace_callback(
'/[-_\s]+(.)?/u', '/[-_\s]+(.)?/u',
function ($match) use ($encoding) { static function ($match) use ($encoding): string {
if (isset($match[1])) if (isset($match[1]))
{ {
return \mb_strtoupper($match[1], $encoding); return mb_strtoupper($match[1], $encoding);
} }
return ''; return '';
@ -178,9 +190,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$stringy->str = preg_replace_callback( $stringy->str = preg_replace_callback(
'/[\d]+(.)?/u', '/[\d]+(.)?/u',
function ($match) use ($encoding) { static fn($match) => mb_strtoupper($match[0], $encoding),
return \mb_strtoupper($match[0], $encoding);
},
$stringy->str $stringy->str
); );
@ -195,6 +205,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
public function chars(): array public function chars(): array
{ {
$chars = []; $chars = [];
for ($i = 0, $l = $this->length(); $i < $l; $i++) for ($i = 0, $l = $this->length(); $i < $l; $i++)
{ {
$chars[] = $this->at($i)->str; $chars[] = $this->at($i)->str;
@ -222,7 +233,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $needle Substring to look for * @param string $needle Substring to look for
* @param bool $caseSensitive Whether or not to enforce case-sensitivity * @param bool $caseSensitive Whether or not to enforce case-sensitivity
* @return bool Whether or not $str contains $needle * @return bool Whether or not $str contains $needle
*/ */
public function contains(string $needle, bool $caseSensitive = TRUE): bool public function contains(string $needle, bool $caseSensitive = TRUE): bool
{ {
@ -230,10 +241,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($caseSensitive) if ($caseSensitive)
{ {
return (\mb_strpos($this->str, $needle, 0, $encoding) !== FALSE); return \mb_strpos($this->str, $needle, 0, $encoding) !== FALSE;
} }
return (\mb_stripos($this->str, $needle, 0, $encoding) !== FALSE); return mb_stripos($this->str, $needle, 0, $encoding) !== FALSE;
} }
/** /**
@ -243,7 +254,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string[] $needles Substrings to look for * @param string[] $needles Substrings to look for
* @param bool $caseSensitive Whether or not to enforce case-sensitivity * @param bool $caseSensitive Whether or not to enforce case-sensitivity
* @return bool Whether or not $str contains $needle * @return bool Whether or not $str contains $needle
*/ */
public function containsAll(array $needles, bool $caseSensitive = TRUE): bool public function containsAll(array $needles, bool $caseSensitive = TRUE): bool
{ {
@ -270,7 +281,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string[] $needles Substrings to look for * @param string[] $needles Substrings to look for
* @param bool $caseSensitive Whether or not to enforce case-sensitivity * @param bool $caseSensitive Whether or not to enforce case-sensitivity
* @return bool Whether or not $str contains $needle * @return bool Whether or not $str contains $needle
*/ */
public function containsAny(array $needles, bool $caseSensitive = TRUE): bool public function containsAny(array $needles, bool $caseSensitive = TRUE): bool
{ {
@ -307,19 +318,19 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $substring The substring to search for * @param string $substring The substring to search for
* @param bool $caseSensitive Whether or not to enforce case-sensitivity * @param bool $caseSensitive Whether or not to enforce case-sensitivity
* @return int The number of $substring occurrences * @return int The number of $substring occurrences
*/ */
public function countSubstr(string $substring, bool $caseSensitive = TRUE): int public function countSubstr(string $substring, bool $caseSensitive = TRUE): int
{ {
if ($caseSensitive) if ($caseSensitive)
{ {
return \mb_substr_count($this->str, $substring, $this->encoding); return mb_substr_count($this->str, $substring, $this->encoding);
} }
$str = \mb_strtoupper($this->str, $this->encoding); $str = mb_strtoupper($this->str, $this->encoding);
$substring = \mb_strtoupper($substring, $this->encoding); $substring = mb_strtoupper($substring, $this->encoding);
return \mb_substr_count($str, $substring, $this->encoding); return mb_substr_count($str, $substring, $this->encoding);
} }
/** /**
@ -349,7 +360,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$this->regexEncoding($this->encoding); $this->regexEncoding($this->encoding);
$str = $this->eregReplace('\B([A-Z])', '-\1', $this->trim()->__toString()); $str = $this->eregReplace('\B([A-Z])', '-\1', $this->trim()->__toString());
$str = \mb_strtolower($str, $this->encoding); $str = mb_strtolower($str, $this->encoding);
$str = $this->eregReplace('[-_\s]+', $delimiter, $str); $str = $this->eregReplace('[-_\s]+', $delimiter, $str);
$this->regexEncoding($regexEncoding); $this->regexEncoding($regexEncoding);
@ -364,20 +375,24 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $substring The substring to look for * @param string $substring The substring to look for
* @param bool $caseSensitive Whether or not to enforce case-sensitivity * @param bool $caseSensitive Whether or not to enforce case-sensitivity
* @return bool Whether or not $str ends with $substring * @return bool Whether or not $str ends with $substring
*/ */
public function endsWith(string $substring, bool $caseSensitive = TRUE): bool public function endsWith(string $substring, bool $caseSensitive = TRUE): bool
{ {
$substringLength = \mb_strlen($substring, $this->encoding); $substringLength = mb_strlen($substring, $this->encoding);
$strLength = $this->length(); $strLength = $this->length();
$endOfStr = \mb_substr($this->str, $strLength - $substringLength, $endOfStr = mb_substr(
$substringLength, $this->encoding); $this->str,
$strLength - $substringLength,
$substringLength,
$this->encoding
);
if ( ! $caseSensitive) if ( ! $caseSensitive)
{ {
$substring = \mb_strtolower($substring, $this->encoding); $substring = mb_strtolower($substring, $this->encoding);
$endOfStr = \mb_strtolower($endOfStr, $this->encoding); $endOfStr = mb_strtolower($endOfStr, $this->encoding);
} }
return (string)$substring === $endOfStr; return (string)$substring === $endOfStr;
@ -390,8 +405,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string[] $substrings Substrings to look for * @param string[] $substrings Substrings to look for
* @param bool $caseSensitive Whether or not to enforce * @param bool $caseSensitive Whether or not to enforce
* case-sensitivity * case-sensitivity
* @return bool Whether or not $str ends with $substring * @return bool Whether or not $str ends with $substring
*/ */
public function endsWithAny(array $substrings, bool $caseSensitive = TRUE): bool public function endsWithAny(array $substrings, bool $caseSensitive = TRUE): bool
{ {
@ -462,6 +477,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($n < 0) if ($n < 0)
{ {
$stringy->str = ''; $stringy->str = '';
return $stringy; return $stringy;
} }
@ -513,14 +529,13 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return $this->matchesPattern('.*[[:upper:]]'); return $this->matchesPattern('.*[[:upper:]]');
} }
/** /**
* Convert all HTML entities to their applicable characters. An alias of * Convert all HTML entities to their applicable characters. An alias of
* html_entity_decode. For a list of flags, refer to * html_entity_decode. For a list of flags, refer to
* http://php.net/manual/en/function.html-entity-decode.php * http://php.net/manual/en/function.html-entity-decode.php
* *
* @param int|null $flags Optional flags * @param int|null $flags Optional flags
* @return static Object with the resulting $str after being html decoded. * @return static Object with the resulting $str after being html decoded.
*/ */
public function htmlDecode(?int $flags = ENT_COMPAT): self public function htmlDecode(?int $flags = ENT_COMPAT): self
{ {
@ -535,7 +550,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* for a list of flags. * for a list of flags.
* *
* @param int|null $flags Optional flags * @param int|null $flags Optional flags
* @return static Object with the resulting $str after being html encoded. * @return static Object with the resulting $str after being html encoded.
*/ */
public function htmlEncode(?int $flags = ENT_COMPAT): self public function htmlEncode(?int $flags = ENT_COMPAT): self
{ {
@ -564,12 +579,16 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $needle Substring to look for * @param string $needle Substring to look for
* @param int $offset Offset from which to search * @param int $offset Offset from which to search
* @return int|bool The occurrence's index if found, otherwise false * @return bool|int The occurrence's index if found, otherwise false
*/ */
public function indexOf(string $needle, int $offset = 0): int|false public function indexOf(string $needle, int $offset = 0): int|false
{ {
return \mb_strpos($this->str, (string)$needle, return \mb_strpos(
(int)$offset, $this->encoding); $this->str,
(string)$needle,
(int)$offset,
$this->encoding
);
} }
/** /**
@ -580,12 +599,16 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $needle Substring to look for * @param string $needle Substring to look for
* @param int $offset Offset from which to search * @param int $offset Offset from which to search
* @return int|bool The last occurrence's index if found, otherwise false * @return bool|int The last occurrence's index if found, otherwise false
*/ */
public function indexOfLast(string $needle, int $offset = 0): int|false public function indexOfLast(string $needle, int $offset = 0): int|false
{ {
return \mb_strrpos($this->str, (string)$needle, return mb_strrpos(
(int)$offset, $this->encoding); $this->str,
(string)$needle,
(int)$offset,
$this->encoding
);
} }
/** /**
@ -603,9 +626,13 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return $stringy; return $stringy;
} }
$start = \mb_substr($stringy->str, 0, $index, $stringy->encoding); $start = mb_substr($stringy->str, 0, $index, $stringy->encoding);
$end = \mb_substr($stringy->str, $index, $stringy->length(), $end = mb_substr(
$stringy->encoding); $stringy->str,
$index,
$stringy->length(),
$stringy->encoding
);
$stringy->str = $start . $substring . $end; $stringy->str = $start . $substring . $end;
@ -672,7 +699,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
json_decode($this->str); json_decode($this->str);
return (json_last_error() === JSON_ERROR_NONE); return json_last_error() === JSON_ERROR_NONE;
} }
/** /**
@ -696,7 +723,6 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return $this->str === 'b:0;' || @unserialize($this->str) !== FALSE; return $this->str === 'b:0;' || @unserialize($this->str) !== FALSE;
} }
/** /**
* Returns true if the string is base64 encoded, false otherwise. * Returns true if the string is base64 encoded, false otherwise.
* *
@ -704,7 +730,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function isBase64(): bool public function isBase64(): bool
{ {
return (base64_encode(base64_decode($this->str, TRUE)) === $this->str); return base64_encode(base64_decode($this->str, TRUE)) === $this->str;
} }
/** /**
@ -731,6 +757,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($n <= 0) if ($n <= 0)
{ {
$stringy->str = ''; $stringy->str = '';
return $stringy; return $stringy;
} }
@ -744,7 +771,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function length(): int public function length(): int
{ {
return \mb_strlen($this->str, $this->encoding); return mb_strlen($this->str, $this->encoding);
} }
/** /**
@ -756,7 +783,9 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
public function lines(): array public function lines(): array
{ {
$array = $this->split('[\r\n]{1,2}', $this->str); $array = $this->split('[\r\n]{1,2}', $this->str);
for ($i = 0; $i < count($array); $i++) $arrayCount = count($array);
for ($i = 0; $i < $arrayCount; $i++)
{ {
$array[$i] = static::create($array[$i], $this->encoding); $array[$i] = static::create($array[$i], $this->encoding);
} }
@ -773,14 +802,15 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
public function longestCommonPrefix(string $otherStr): self public function longestCommonPrefix(string $otherStr): self
{ {
$encoding = $this->encoding; $encoding = $this->encoding;
$maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); $maxLength = min($this->length(), mb_strlen($otherStr, $encoding));
$longestCommonPrefix = ''; $longestCommonPrefix = '';
for ($i = 0; $i < $maxLength; $i++) for ($i = 0; $i < $maxLength; $i++)
{ {
$char = \mb_substr($this->str, $i, 1, $encoding); $char = mb_substr($this->str, $i, 1, $encoding);
if ($char == \mb_substr($otherStr, $i, 1, $encoding)) if ($char === mb_substr($otherStr, $i, 1, $encoding))
{ {
$longestCommonPrefix .= $char; $longestCommonPrefix .= $char;
} else } else
@ -801,14 +831,15 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
public function longestCommonSuffix(string $otherStr): self public function longestCommonSuffix(string $otherStr): self
{ {
$encoding = $this->encoding; $encoding = $this->encoding;
$maxLength = min($this->length(), \mb_strlen($otherStr, $encoding)); $maxLength = min($this->length(), mb_strlen($otherStr, $encoding));
$longestCommonSuffix = ''; $longestCommonSuffix = '';
for ($i = 1; $i <= $maxLength; $i++) for ($i = 1; $i <= $maxLength; $i++)
{ {
$char = \mb_substr($this->str, -$i, 1, $encoding); $char = mb_substr($this->str, -$i, 1, $encoding);
if ($char == \mb_substr($otherStr, -$i, 1, $encoding)) if ($char === mb_substr($otherStr, -$i, 1, $encoding))
{ {
$longestCommonSuffix = $char . $longestCommonSuffix; $longestCommonSuffix = $char . $longestCommonSuffix;
} else } else
@ -834,28 +865,32 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$encoding = $this->encoding; $encoding = $this->encoding;
$stringy = static::create($this->str, $encoding); $stringy = static::create($this->str, $encoding);
$strLength = $stringy->length(); $strLength = $stringy->length();
$otherLength = \mb_strlen($otherStr, $encoding); $otherLength = mb_strlen($otherStr, $encoding);
// Return if either string is empty // Return if either string is empty
if ($strLength == 0 || $otherLength == 0) if ($strLength === 0 || $otherLength === 0)
{ {
$stringy->str = ''; $stringy->str = '';
return $stringy; return $stringy;
} }
$len = 0; $len = 0;
$end = 0; $end = 0;
$table = array_fill(0, $strLength + 1, $table = array_fill(
array_fill(0, $otherLength + 1, 0)); 0,
$strLength + 1,
array_fill(0, $otherLength + 1, 0)
);
for ($i = 1; $i <= $strLength; $i++) for ($i = 1; $i <= $strLength; $i++)
{ {
for ($j = 1; $j <= $otherLength; $j++) for ($j = 1; $j <= $otherLength; $j++)
{ {
$strChar = \mb_substr($stringy->str, $i - 1, 1, $encoding); $strChar = mb_substr($stringy->str, $i - 1, 1, $encoding);
$otherChar = \mb_substr($otherStr, $j - 1, 1, $encoding); $otherChar = mb_substr($otherStr, $j - 1, 1, $encoding);
if ($strChar == $otherChar) if ($strChar === $otherChar)
{ {
$table[$i][$j] = $table[$i - 1][$j - 1] + 1; $table[$i][$j] = $table[$i - 1][$j - 1] + 1;
if ($table[$i][$j] > $len) if ($table[$i][$j] > $len)
@ -870,7 +905,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
} }
} }
$stringy->str = \mb_substr($stringy->str, $end - $len, $len, $encoding); $stringy->str = mb_substr($stringy->str, $end - $len, $len, $encoding);
return $stringy; return $stringy;
} }
@ -882,11 +917,15 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function lowerCaseFirst(): self public function lowerCaseFirst(): self
{ {
$first = \mb_substr($this->str, 0, 1, $this->encoding); $first = mb_substr($this->str, 0, 1, $this->encoding);
$rest = \mb_substr($this->str, 1, $this->length() - 1, $rest = mb_substr(
$this->encoding); $this->str,
1,
$this->length() - 1,
$this->encoding
);
$str = \mb_strtolower($first, $this->encoding) . $rest; $str = mb_strtolower($first, $this->encoding) . $rest;
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -897,7 +936,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* part of the ArrayAccess interface. * part of the ArrayAccess interface.
* *
* @param mixed $offset The index to check * @param mixed $offset The index to check
* @return boolean Whether or not the index exists * @return bool Whether or not the index exists
*/ */
public function offsetExists(mixed $offset): bool public function offsetExists(mixed $offset): bool
{ {
@ -906,10 +945,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($offset >= 0) if ($offset >= 0)
{ {
return ($length > $offset); return $length > $offset;
} }
return ($length >= abs($offset)); return $length >= abs($offset);
} }
/** /**
@ -919,9 +958,9 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* does not exist. * does not exist.
* *
* @param mixed $offset The index from which to retrieve the char * @param mixed $offset The index from which to retrieve the char
* @return string The character at the specified index * @return string The character at the specified index
* @throws \OutOfBoundsException If the positive or negative offset does * @throws OutOfBoundsException If the positive or negative offset does
* not exist * not exist
*/ */
public function offsetGet(mixed $offset): string public function offsetGet(mixed $offset): string
{ {
@ -933,7 +972,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
throw new OutOfBoundsException('No character exists at the index'); throw new OutOfBoundsException('No character exists at the index');
} }
return \mb_substr($this->str, $offset, 1, $this->encoding); return mb_substr($this->str, $offset, 1, $this->encoding);
} }
/** /**
@ -942,7 +981,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param mixed $offset The index of the character * @param mixed $offset The index of the character
* @param mixed $value Value to set * @param mixed $value Value to set
* @throws \Exception When called * @throws Exception When called
*/ */
public function offsetSet(mixed $offset, mixed $value): void public function offsetSet(mixed $offset, mixed $value): void
{ {
@ -955,7 +994,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* when called. This maintains the immutability of Stringy objects. * when called. This maintains the immutability of Stringy objects.
* *
* @param mixed $offset The index of the character * @param mixed $offset The index of the character
* @throws \Exception When called * @throws Exception When called
*/ */
public function offsetUnset(mixed $offset): void public function offsetUnset(mixed $offset): void
{ {
@ -979,7 +1018,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self public function pad(int $length, string $padStr = ' ', string $padType = 'right'): self
{ {
if ( ! in_array($padType, ['left', 'right', 'both'])) if ( ! in_array($padType, ['left', 'right', 'both'], TRUE))
{ {
throw new InvalidArgumentException('Pad expects $padType ' . throw new InvalidArgumentException('Pad expects $padType ' .
"to be one of 'left', 'right' or 'both'"); "to be one of 'left', 'right' or 'both'");
@ -989,8 +1028,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
case 'left': case 'left':
return $this->padLeft($length, $padStr); return $this->padLeft($length, $padStr);
case 'right': case 'right':
return $this->padRight($length, $padStr); return $this->padRight($length, $padStr);
default: default:
return $this->padBoth($length, $padStr); return $this->padBoth($length, $padStr);
} }
@ -1008,8 +1049,11 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
$padding = $length - $this->length(); $padding = $length - $this->length();
return $this->applyPadding(floor($padding / 2), ceil($padding / 2), return $this->applyPadding(
$padStr); floor($padding / 2),
ceil($padding / 2),
$padStr
);
} }
/** /**
@ -1084,7 +1128,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($stringy->startsWith($substring)) if ($stringy->startsWith($substring))
{ {
$substringLength = \mb_strlen($substring, $stringy->encoding); $substringLength = mb_strlen($substring, $stringy->encoding);
return $stringy->substr($substringLength); return $stringy->substr($substringLength);
} }
@ -1103,7 +1148,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($stringy->endsWith($substring)) if ($stringy->endsWith($substring))
{ {
$substringLength = \mb_strlen($substring, $stringy->encoding); $substringLength = mb_strlen($substring, $stringy->encoding);
return $stringy->substr(0, $stringy->length() - $substringLength); return $stringy->substr(0, $stringy->length() - $substringLength);
} }
@ -1148,7 +1194,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
// Loop from last index of string to first // Loop from last index of string to first
for ($i = $strLength - 1; $i >= 0; $i--) for ($i = $strLength - 1; $i >= 0; $i--)
{ {
$reversed .= \mb_substr($this->str, $i, 1, $this->encoding); $reversed .= mb_substr($this->str, $i, 1, $this->encoding);
} }
return static::create($reversed, $this->encoding); return static::create($reversed, $this->encoding);
@ -1174,19 +1220,19 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
// Need to further trim the string so we can append the substring // Need to further trim the string so we can append the substring
$encoding = $stringy->encoding; $encoding = $stringy->encoding;
$substringLength = \mb_strlen($substring, $encoding); $substringLength = mb_strlen($substring, $encoding);
$length = $length - $substringLength; $length = $length - $substringLength;
$truncated = \mb_substr($stringy->str, 0, $length, $encoding); $truncated = mb_substr($stringy->str, 0, $length, $encoding);
// If the last word was truncated // If the last word was truncated
if (mb_strpos($stringy->str, ' ', $length - 1, $encoding) != $length) if (mb_strpos($stringy->str, ' ', $length - 1, $encoding) !== $length)
{ {
// Find pos of the last occurrence of a space, get up to that // Find pos of the last occurrence of a space, get up to that
$lastPos = \mb_strrpos($truncated, ' ', 0, $encoding); $lastPos = mb_strrpos($truncated, ' ', 0, $encoding);
if ($lastPos !== FALSE) if ($lastPos !== FALSE)
{ {
$truncated = \mb_substr($truncated, 0, $lastPos, $encoding); $truncated = mb_substr($truncated, 0, $lastPos, $encoding);
} }
} }
@ -1195,7 +1241,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return $stringy; return $stringy;
} }
/* /**
* A multibyte str_shuffle() function. It returns a string with its * A multibyte str_shuffle() function. It returns a string with its
* characters in random order. * characters in random order.
* *
@ -1207,9 +1253,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
shuffle($indexes); shuffle($indexes);
$shuffledStr = ''; $shuffledStr = '';
foreach ($indexes as $i) foreach ($indexes as $i)
{ {
$shuffledStr .= \mb_substr($this->str, $i, 1, $this->encoding); $shuffledStr .= mb_substr($this->str, $i, 1, $this->encoding);
} }
return static::create($shuffledStr, $this->encoding); return static::create($shuffledStr, $this->encoding);
@ -1233,7 +1280,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$stringy->str = str_replace('@', $replacement, $stringy); $stringy->str = str_replace('@', $replacement, $stringy);
$quotedReplacement = preg_quote($replacement); $quotedReplacement = preg_quote($replacement);
$pattern = "/[^a-zA-Z\d\s-_$quotedReplacement]/u"; $pattern = "/[^a-zA-Z\\d\\s-_{$quotedReplacement}]/u";
$stringy->str = preg_replace($pattern, '', $stringy); $stringy->str = preg_replace($pattern, '', $stringy);
return $stringy->toLowerCase()->delimit($replacement) return $stringy->toLowerCase()->delimit($replacement)
@ -1247,19 +1294,23 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $substring The substring to look for * @param string $substring The substring to look for
* @param bool $caseSensitive Whether or not to enforce * @param bool $caseSensitive Whether or not to enforce
* case-sensitivity * case-sensitivity
* @return bool Whether or not $str starts with $substring * @return bool Whether or not $str starts with $substring
*/ */
public function startsWith(string $substring, bool $caseSensitive = TRUE): bool public function startsWith(string $substring, bool $caseSensitive = TRUE): bool
{ {
$substringLength = \mb_strlen($substring, $this->encoding); $substringLength = mb_strlen($substring, $this->encoding);
$startOfStr = \mb_substr($this->str, 0, $substringLength, $startOfStr = mb_substr(
$this->encoding); $this->str,
0,
$substringLength,
$this->encoding
);
if ( ! $caseSensitive) if ( ! $caseSensitive)
{ {
$substring = \mb_strtolower($substring, $this->encoding); $substring = mb_strtolower($substring, $this->encoding);
$startOfStr = \mb_strtolower($startOfStr, $this->encoding); $startOfStr = mb_strtolower($startOfStr, $this->encoding);
} }
return (string)$substring === $startOfStr; return (string)$substring === $startOfStr;
@ -1272,8 +1323,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string[] $substrings Substrings to look for * @param string[] $substrings Substrings to look for
* @param bool $caseSensitive Whether or not to enforce * @param bool $caseSensitive Whether or not to enforce
* case-sensitivity * case-sensitivity
* @return bool Whether or not $str starts with $substring * @return bool Whether or not $str starts with $substring
*/ */
public function startsWithAny(array $substrings, bool $caseSensitive = TRUE): bool public function startsWithAny(array $substrings, bool $caseSensitive = TRUE): bool
{ {
@ -1303,7 +1354,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* @param int $end Optional index at which to end extraction * @param int $end Optional index at which to end extraction
* @return static Object with its $str being the extracted substring * @return static Object with its $str being the extracted substring
*/ */
public function slice(int $start, int $end = NULL): self public function slice(int $start, ?int $end = NULL): self
{ {
if ($end === NULL) if ($end === NULL)
{ {
@ -1331,7 +1382,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* @param int $limit Optional maximum number of results to return * @param int $limit Optional maximum number of results to return
* @return static[] An array of Stringy objects * @return static[] An array of Stringy objects
*/ */
public function split(string $pattern, int $limit = NULL): array public function split(string $pattern, ?int $limit = NULL): array
{ {
if ($limit === 0) if ($limit === 0)
{ {
@ -1350,7 +1401,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
// mb_split returns the remaining unsplit string in the last index when // mb_split returns the remaining unsplit string in the last index when
// supplying a limit // supplying a limit
$limit = ($limit > 0) ? $limit += 1 : -1; $limit = ($limit > 0) ? ++$limit : -1;
static $functionExists; static $functionExists;
if ($functionExists === NULL) if ($functionExists === NULL)
@ -1360,10 +1411,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($functionExists) if ($functionExists)
{ {
$array = \mb_split($pattern, $this->str, $limit); $array = mb_split($pattern, $this->str, $limit);
} else if ($this->supportsEncoding()) } elseif ($this->supportsEncoding())
{ {
$array = \preg_split("/$pattern/", $this->str, $limit); $array = \preg_split("/{$pattern}/", $this->str, $limit);
} }
$this->regexEncoding($regexEncoding); $this->regexEncoding($regexEncoding);
@ -1372,8 +1423,9 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
array_pop($array); array_pop($array);
} }
$arrayCount = count($array);
for ($i = 0; $i < count($array); $i++) for ($i = 0; $i < $arrayCount; $i++)
{ {
$array[$i] = static::create($array[$i], $this->encoding); $array[$i] = static::create($array[$i], $this->encoding);
} }
@ -1405,7 +1457,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
public function substr(int $start, ?int $length = NULL): self public function substr(int $start, ?int $length = NULL): self
{ {
$length = $length === NULL ? $this->length() : $length; $length = $length === NULL ? $this->length() : $length;
$str = \mb_substr($this->str, $start, $length, $this->encoding); $str = mb_substr($this->str, $start, $length, $this->encoding);
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -1415,7 +1467,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $substring The substring to add to both sides * @param string $substring The substring to add to both sides
* @return static Object whose $str had the substring both prepended and * @return static Object whose $str had the substring both prepended and
* appended * appended
*/ */
public function surround(string $substring): self public function surround(string $substring): self
{ {
@ -1436,13 +1488,13 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$stringy->str = preg_replace_callback( $stringy->str = preg_replace_callback(
'/[\S]/u', '/[\S]/u',
function ($match) use ($encoding) { static function ($match) use ($encoding): string {
if ($match[0] == \mb_strtoupper($match[0], $encoding)) if ($match[0] === mb_strtoupper($match[0], $encoding))
{ {
return \mb_strtolower($match[0], $encoding); return mb_strtolower($match[0], $encoding);
} }
return \mb_strtoupper($match[0], $encoding); return mb_strtoupper($match[0], $encoding);
}, },
$stringy->str $stringy->str
); );
@ -1489,8 +1541,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
$stringy->str = preg_replace_callback( $stringy->str = preg_replace_callback(
'/([\S]+)/u', '/([\S]+)/u',
function ($match) use ($encoding, $ignore) { static function ($match) use ($encoding, $ignore): string {
if ($ignore && in_array($match[0], $ignore)) if ($ignore && in_array($match[0], $ignore, TRUE))
{ {
return $match[0]; return $match[0];
} }
@ -1515,7 +1567,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* *
* @param string $language Language of the source string * @param string $language Language of the source string
* @param bool $removeUnsupported Whether or not to remove the * @param bool $removeUnsupported Whether or not to remove the
* unsupported characters * unsupported characters
* @return static Object whose $str contains only ASCII characters * @return static Object whose $str contains only ASCII characters
*/ */
public function toAscii(string $language = 'en', bool $removeUnsupported = TRUE): self public function toAscii(string $language = 'en', bool $removeUnsupported = TRUE): self
@ -1563,15 +1615,16 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
'false' => FALSE, 'false' => FALSE,
'0' => FALSE, '0' => FALSE,
'off' => FALSE, 'off' => FALSE,
'no' => FALSE 'no' => FALSE,
]; ];
if (array_key_exists($key, $map)) if (array_key_exists($key, $map))
{ {
return $map[$key]; return $map[$key];
} elseif (is_numeric($this->str)) }
if (is_numeric($this->str))
{ {
return (intval($this->str) > 0); return (int)($this->str) > 0;
} }
return (bool)$this->regexReplace('[[:space:]]', '')->str; return (bool)$this->regexReplace('[[:space:]]', '')->str;
@ -1585,7 +1638,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function toLowerCase(): self public function toLowerCase(): self
{ {
$str = \mb_strtolower($this->str, $this->encoding); $str = mb_strtolower($this->str, $this->encoding);
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -1628,7 +1681,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function toTitleCase(): self public function toTitleCase(): self
{ {
$str = \mb_convert_case($this->str, \MB_CASE_TITLE, $this->encoding); $str = mb_convert_case($this->str, MB_CASE_TITLE, $this->encoding);
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -1641,7 +1694,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function toUpperCase(): self public function toUpperCase(): self
{ {
$str = \mb_strtoupper($this->str, $this->encoding); $str = mb_strtoupper($this->str, $this->encoding);
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -1658,7 +1711,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
$chars = ($chars) ? preg_quote($chars) : '[:space:]'; $chars = ($chars) ? preg_quote($chars) : '[:space:]';
return $this->regexReplace("^[$chars]+|[$chars]+\$", ''); return $this->regexReplace("^[{$chars}]+|[{$chars}]+\$", '');
} }
/** /**
@ -1673,7 +1726,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
$chars = ($chars) ? preg_quote($chars) : '[:space:]'; $chars = ($chars) ? preg_quote($chars) : '[:space:]';
return $this->regexReplace("^[$chars]+", ''); return $this->regexReplace("^[{$chars}]+", '');
} }
/** /**
@ -1688,7 +1741,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
{ {
$chars = ($chars) ? preg_quote($chars) : '[:space:]'; $chars = ($chars) ? preg_quote($chars) : '[:space:]';
return $this->regexReplace("[$chars]+\$", ''); return $this->regexReplace("[{$chars}]+\$", '');
} }
/** /**
@ -1709,10 +1762,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
} }
// Need to further trim the string so we can append the substring // Need to further trim the string so we can append the substring
$substringLength = \mb_strlen($substring, $stringy->encoding); $substringLength = mb_strlen($substring, $stringy->encoding);
$length = $length - $substringLength; $length = $length - $substringLength;
$truncated = \mb_substr($stringy->str, 0, $length, $stringy->encoding); $truncated = mb_substr($stringy->str, 0, $length, $stringy->encoding);
$stringy->str = $truncated . $substring; $stringy->str = $truncated . $substring;
return $stringy; return $stringy;
@ -1750,11 +1803,15 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
*/ */
public function upperCaseFirst(): self public function upperCaseFirst(): self
{ {
$first = \mb_substr($this->str, 0, 1, $this->encoding); $first = mb_substr($this->str, 0, 1, $this->encoding);
$rest = \mb_substr($this->str, 1, $this->length() - 1, $rest = mb_substr(
$this->encoding); $this->str,
1,
$this->length() - 1,
$this->encoding
);
$str = \mb_strtoupper($first, $this->encoding) . $rest; $str = mb_strtoupper($first, $this->encoding) . $rest;
return static::create($str, $this->encoding); return static::create($str, $this->encoding);
} }
@ -1767,7 +1824,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
protected function charsArray(): array protected function charsArray(): array
{ {
static $charsArray; static $charsArray;
if (isset($charsArray)) return $charsArray; if (isset($charsArray))
{
return $charsArray;
}
return $charsArray = [ return $charsArray = [
'0' => ['°', '₀', '۰', ''], '0' => ['°', '₀', '۰', ''],
@ -1940,7 +2000,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* will simply return 'a'. * will simply return 'a'.
* *
* @param string $language Language of the source string * @param string $language Language of the source string
* @return array An array of replacements. * @return array An array of replacements.
*/ */
protected static function langSpecificCharsArray(string $language = 'en'): array protected static function langSpecificCharsArray(string $language = 'en'): array
{ {
@ -1960,17 +2020,11 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
], ],
'bg' => [ 'bg' => [
['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'], ['х', 'Х', 'щ', 'Щ', 'ъ', 'Ъ', 'ь', 'Ь'],
['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'] ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'],
] ],
]; ];
if (isset($languageSpecific[$language])) $charsArray[$language] = isset($languageSpecific[$language]) ? $languageSpecific[$language] : [];
{
$charsArray[$language] = $languageSpecific[$language];
} else
{
$charsArray[$language] = [];
}
return $charsArray[$language]; return $charsArray[$language];
} }
@ -1987,7 +2041,7 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
protected function applyPadding(int $left = 0, int $right = 0, string $padStr = ' '): self protected function applyPadding(int $left = 0, int $right = 0, string $padStr = ' '): self
{ {
$stringy = static::create($this->str, $this->encoding); $stringy = static::create($this->str, $this->encoding);
$length = \mb_strlen($padStr, $stringy->encoding); $length = mb_strlen($padStr, $stringy->encoding);
$strLength = $stringy->length(); $strLength = $stringy->length();
$paddedLength = $strLength + $left + $right; $paddedLength = $strLength + $left + $right;
@ -1997,10 +2051,18 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
return $stringy; return $stringy;
} }
$leftPadding = \mb_substr(str_repeat($padStr, ceil($left / $length)), 0, $leftPadding = mb_substr(
$left, $stringy->encoding); str_repeat($padStr, ceil($left / $length)),
$rightPadding = \mb_substr(str_repeat($padStr, ceil($right / $length)), 0,
0, $right, $stringy->encoding); $left,
$stringy->encoding
);
$rightPadding = mb_substr(
str_repeat($padStr, ceil($right / $length)),
0,
$right,
$stringy->encoding
);
$stringy->str = $leftPadding . $stringy->str . $rightPadding; $stringy->str = $leftPadding . $stringy->str . $rightPadding;
@ -2011,14 +2073,14 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
* Returns true if $str matches the supplied pattern, false otherwise. * Returns true if $str matches the supplied pattern, false otherwise.
* *
* @param string $pattern Regex pattern to match against * @param string $pattern Regex pattern to match against
* @return bool Whether or not $str matches the pattern * @return bool Whether or not $str matches the pattern
*/ */
protected function matchesPattern(string $pattern): bool protected function matchesPattern(string $pattern): bool
{ {
$regexEncoding = $this->regexEncoding(); $regexEncoding = $this->regexEncoding();
$this->regexEncoding($this->encoding); $this->regexEncoding($this->encoding);
$match = \mb_ereg_match($pattern, $this->str); $match = mb_ereg_match($pattern, $this->str);
$this->regexEncoding($regexEncoding); $this->regexEncoding($regexEncoding);
return $match; return $match;
@ -2038,11 +2100,13 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($functionExists) if ($functionExists)
{ {
return \mb_ereg_replace($pattern, $replacement, $string, $option); return mb_ereg_replace($pattern, $replacement, $string, $option);
} else if ($this->supportsEncoding()) }
if ($this->supportsEncoding())
{ {
$option = str_replace('r', '', (string)$option); $option = str_replace('r', '', (string)$option);
return \preg_replace("/$pattern/u$option", $replacement, $string);
return \preg_replace("/{$pattern}/u{$option}", $replacement, $string);
} }
} }
@ -2062,7 +2126,8 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if ($functionExists) if ($functionExists)
{ {
$args = func_get_args(); $args = func_get_args();
return call_user_func_array('\mb_regex_encoding', $args);
return mb_regex_encoding(...$args);
} }
} }
@ -2073,11 +2138,10 @@ abstract class Stringy implements Countable, IteratorAggregate, ArrayAccess {
if (isset($supported[$this->encoding])) if (isset($supported[$this->encoding]))
{ {
return TRUE; return TRUE;
} else
{
throw new \RuntimeException('Stringy method requires the ' .
'mbstring module for encodings other than ASCII and UTF-8. ' .
'Encoding used: ' . $this->encoding);
} }
throw new RuntimeException('Stringy method requires the ' .
'mbstring module for encodings other than ASCII and UTF-8. ' .
'Encoding used: ' . $this->encoding);
} }
} }

View File

@ -20,6 +20,7 @@ use InvalidArgumentException;
use Laminas\Diactoros\Response; use Laminas\Diactoros\Response;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter; use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
use PHPUnit\Framework\Attributes\CodeCoverageIgnore;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Stringable; use Stringable;
@ -168,10 +169,10 @@ class HttpView implements HttpViewInterface, Stringable
/** /**
* Send the appropriate response * Send the appropriate response
* *
* @codeCoverageIgnore
* @throws DoubleRenderException * @throws DoubleRenderException
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
#[CodeCoverageIgnore]
protected function output(): void protected function output(): void
{ {
if ($this->hasRendered) if ($this->hasRendered)

View File

@ -46,7 +46,7 @@ final class AnimeListTransformerTest extends AnimeClientTestCase
$this->assertMatchesSnapshot($actual); $this->assertMatchesSnapshot($actual);
} }
public function dataUntransform(): array public static function dataUntransform(): array
{ {
return [[ return [[
'input' => [ 'input' => [
@ -87,12 +87,10 @@ final class AnimeListTransformerTest extends AnimeClientTestCase
]]; ]];
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('dataUntransform')]
* @dataProvider dataUntransform public function testUntransform(array $input): void
*/ {
public function testUntransform(array $input): void $actual = $this->transformer->untransform($input);
{ $this->assertMatchesSnapshot($actual);
$actual = $this->transformer->untransform($input); }
$this->assertMatchesSnapshot($actual);
}
} }

View File

@ -71,7 +71,7 @@ final class DispatcherTest extends AnimeClientTestCase
$this->assertIsObject($this->router); $this->assertIsObject($this->router);
} }
public function dataRoute(): array public static function dataRoute(): array
{ {
$defaultConfig = [ $defaultConfig = [
'routes' => [ 'routes' => [
@ -141,35 +141,32 @@ final class DispatcherTest extends AnimeClientTestCase
return $data; return $data;
} }
/** /**
* @dataProvider dataRoute * @param mixed $config
* @param mixed $config */
* @param mixed $controller #[\PHPUnit\Framework\Attributes\DataProvider('dataRoute')]
* @param mixed $host public function testRoute($config, mixed $controller, mixed $host, mixed $uri): void
* @param mixed $uri {
*/ $this->doSetUp($config, $uri, $host);
public function testRoute($config, $controller, $host, $uri): void
{
$this->doSetUp($config, $uri, $host);
$request = $this->container->get('request'); $request = $this->container->get('request');
// Check route setup // Check route setup
$this->assertSame($config['routes'], $this->config->get('routes'), 'Incorrect route path'); $this->assertSame($config['routes'], $this->config->get('routes'), 'Incorrect route path');
$this->assertIsArray($this->router->getOutputRoutes()); $this->assertIsArray($this->router->getOutputRoutes());
// Check environment variables // Check environment variables
$this->assertSame($uri, $request->getServerParams()['REQUEST_URI']); $this->assertSame($uri, $request->getServerParams()['REQUEST_URI']);
$this->assertSame($host, $request->getServerParams()['HTTP_HOST']); $this->assertSame($host, $request->getServerParams()['HTTP_HOST']);
// Make sure the route is an anime type // Make sure the route is an anime type
//$this->assertTrue($matcher->count() > 0, '0 routes'); //$this->assertTrue($matcher->count() > 0, '0 routes');
$this->assertSame($controller, $this->router->getController(), 'Incorrect Route type'); $this->assertSame($controller, $this->router->getController(), 'Incorrect Route type');
// Make sure the route matches, by checking that it is actually an object // Make sure the route matches, by checking that it is actually an object
$route = $this->router->getRoute(); $route = $this->router->getRoute();
$this->assertInstanceOf(Route::class, $route, 'Route is invalid, not matched'); $this->assertInstanceOf(Route::class, $route, 'Route is invalid, not matched');
} }
public function testDefaultRoute(): void public function testDefaultRoute(): void
{ {
@ -209,53 +206,51 @@ final class DispatcherTest extends AnimeClientTestCase
} }
#[ArrayShape(['controller_list_sanity_check' => 'array', 'empty_controller_list' => 'array'])] #[ArrayShape(['controller_list_sanity_check' => 'array', 'empty_controller_list' => 'array'])]
public function dataGetControllerList(): array public static function dataGetControllerList(): array
{ {
$expectedList = [ $expectedList = [
'anime' => Controller\Anime::class, 'anime' => Controller\Anime::class,
'anime-collection' => Controller\AnimeCollection::class, 'anime-collection' => Controller\AnimeCollection::class,
'character' => Controller\Character::class, 'character' => Controller\Character::class,
'misc' => Controller\Misc::class, 'misc' => Controller\Misc::class,
'manga' => Controller\Manga::class, 'manga' => Controller\Manga::class,
'people' => Controller\People::class, 'people' => Controller\People::class,
'settings' => Controller\Settings::class, 'settings' => Controller\Settings::class,
'user' => Controller\User::class, 'user' => Controller\User::class,
'images' => Controller\Images::class, 'images' => Controller\Images::class,
'history' => Controller\History::class, 'history' => Controller\History::class,
]; ];
return [ return [
'controller_list_sanity_check' => [ 'controller_list_sanity_check' => [
'config' => [ 'config' => [
'anime_path' => 'anime', 'anime_path' => 'anime',
'manga_path' => 'manga', 'manga_path' => 'manga',
'default_anime_list_path' => 'watching', 'default_anime_list_path' => 'watching',
'default_manga_list_path' => 'all', 'default_manga_list_path' => 'all',
'default_list' => 'manga', 'default_list' => 'manga',
'routes' => [], 'routes' => [],
],
'expected' => $expectedList,
], ],
'empty_controller_list' => [ 'expected' => $expectedList,
'config' => [ ],
'anime_path' => 'anime', 'empty_controller_list' => [
'manga_path' => 'manga', 'config' => [
'default_anime_path' => '/anime/watching', 'anime_path' => 'anime',
'default_manga_path' => '/manga/all', 'manga_path' => 'manga',
'default_list' => 'manga', 'default_anime_path' => '/anime/watching',
'routes' => [], 'default_manga_path' => '/manga/all',
], 'default_list' => 'manga',
'expected' => $expectedList, 'routes' => [],
], ],
]; 'expected' => $expectedList,
} ],
];
/** }
* @dataProvider dataGetControllerList
*/ #[\PHPUnit\Framework\Attributes\DataProvider('dataGetControllerList')]
public function testGetControllerList(array $config, array $expected): void public function testGetControllerList(array $config, array $expected): void
{ {
$this->doSetUp($config, '/', 'localhost'); $this->doSetUp($config, '/', 'localhost');
$this->assertEquals($expected, $this->router->getControllerList()); $this->assertEquals($expected, $this->router->getControllerList());
} }
} }

View File

@ -22,9 +22,7 @@ use Aviat\AnimeClient\Tests\AnimeClientTestCase;
*/ */
final class PictureHelperTest extends AnimeClientTestCase final class PictureHelperTest extends AnimeClientTestCase
{ {
/** #[\PHPUnit\Framework\Attributes\DataProvider('dataPictureCase')]
* @dataProvider dataPictureCase
*/
public function testPictureHelper(array $params): void public function testPictureHelper(array $params): void
{ {
$helper = new PictureHelper(); $helper = new PictureHelper();
@ -35,9 +33,7 @@ final class PictureHelperTest extends AnimeClientTestCase
$this->assertMatchesSnapshot($actual); $this->assertMatchesSnapshot($actual);
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('dataSimpleImageCase')]
* @dataProvider dataSimpleImageCase
*/
public function testSimpleImage(string $ext, bool $isSimple, string $fallbackExt = 'jpg'): void public function testSimpleImage(string $ext, bool $isSimple, string $fallbackExt = 'jpg'): void
{ {
$helper = new PictureHelper(); $helper = new PictureHelper();
@ -61,7 +57,7 @@ final class PictureHelperTest extends AnimeClientTestCase
$this->assertTrue( ! str_contains($actual, '<picture')); $this->assertTrue( ! str_contains($actual, '<picture'));
} }
public function dataPictureCase(): array public static function dataPictureCase(): array
{ {
return [ return [
'Full AVIF URL' => [ 'Full AVIF URL' => [
@ -119,7 +115,7 @@ final class PictureHelperTest extends AnimeClientTestCase
]; ];
} }
public function dataSimpleImageCase(): array public static function dataSimpleImageCase(): array
{ {
return [ return [
'avif' => [ 'avif' => [

View File

@ -77,7 +77,7 @@ final class KitsuTest extends TestCase
$this->assertSame(AnimeAiringStatus::AIRING, Kitsu::getAiringStatus('yesterday')); $this->assertSame(AnimeAiringStatus::AIRING, Kitsu::getAiringStatus('yesterday'));
} }
public function getPublishingStatus(): array public static function getPublishingStatus(): array
{ {
return [ return [
'current' => [ 'current' => [
@ -91,16 +91,14 @@ final class KitsuTest extends TestCase
]; ];
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('getPublishingStatus')]
* @dataProvider getPublishingStatus public function testGetPublishingStatus(string $kitsuStatus, string $expected): void
*/ {
public function testGetPublishingStatus(string $kitsuStatus, string $expected): void $actual = Kitsu::getPublishingStatus($kitsuStatus);
{ $this->assertSame($expected, $actual);
$actual = Kitsu::getPublishingStatus($kitsuStatus); }
$this->assertSame($expected, $actual);
}
public function getFriendlyTime(): array public static function getFriendlyTime(): array
{ {
$SECONDS_IN_DAY = Kitsu::SECONDS_IN_MINUTE * Kitsu::MINUTES_IN_DAY; $SECONDS_IN_DAY = Kitsu::SECONDS_IN_MINUTE * Kitsu::MINUTES_IN_DAY;
$SECONDS_IN_HOUR = Kitsu::SECONDS_IN_MINUTE * Kitsu::MINUTES_IN_HOUR; $SECONDS_IN_HOUR = Kitsu::SECONDS_IN_MINUTE * Kitsu::MINUTES_IN_HOUR;
@ -121,15 +119,13 @@ final class KitsuTest extends TestCase
]]; ]];
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('getFriendlyTime')]
* @dataProvider getFriendlyTime public function testGetFriendlyTime(int $seconds, string $expected): void
*/ {
public function testGetFriendlyTime(int $seconds, string $expected): void $actual = Kitsu::friendlyTime($seconds);
{
$actual = Kitsu::friendlyTime($seconds);
$this->assertSame($expected, $actual); $this->assertSame($expected, $actual);
} }
public function testFilterLocalizedTitles(): void public function testFilterLocalizedTitles(): void
{ {

View File

@ -23,7 +23,7 @@ use JetBrains\PhpStorm\ArrayShape;
final class RoutingBaseTest extends AnimeClientTestCase final class RoutingBaseTest extends AnimeClientTestCase
{ {
#[ArrayShape(['empty_segment' => 'array', 'three_segments' => 'array'])] #[ArrayShape(['empty_segment' => 'array', 'three_segments' => 'array'])]
public function dataSegments() public static function dataSegments()
{ {
return [ return [
'empty_segment' => [ 'empty_segment' => [
@ -41,26 +41,24 @@ final class RoutingBaseTest extends AnimeClientTestCase
]; ];
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('dataSegments')]
* @dataProvider dataSegments public function testSegments(string $requestUri, string $path, array $segments, ?string $lastSegment): void
*/ {
public function testSegments(string $requestUri, string $path, array $segments, ?string $lastSegment): void $this->setSuperGlobals([
{ '_SERVER' => [
$this->setSuperGlobals([ 'REQUEST_URI' => $requestUri,
'_SERVER' => [ ],
'REQUEST_URI' => $requestUri, ]);
],
]);
$routingBase = new RoutingBase($this->container); $routingBase = new RoutingBase($this->container);
$this->assertSame($path, $routingBase->path(), 'Path is invalid'); $this->assertSame($path, $routingBase->path(), 'Path is invalid');
$this->assertSame($segments, $routingBase->segments(), 'Segments array is invalid'); $this->assertSame($segments, $routingBase->segments(), 'Segments array is invalid');
$this->assertEquals($lastSegment, $routingBase->lastSegment(), 'Last segment is invalid'); $this->assertEquals($lastSegment, $routingBase->lastSegment(), 'Last segment is invalid');
foreach ($segments as $i => $value) foreach ($segments as $i => $value)
{ {
$this->assertEquals($value, $routingBase->getSegment($i), "Segment {$i} is invalid"); $this->assertEquals($value, $routingBase->getSegment($i), "Segment {$i} is invalid");
} }
} }
} }

View File

@ -16,13 +16,14 @@ namespace Aviat\AnimeClient\Tests;
use Aviat\AnimeClient\UrlGenerator; use Aviat\AnimeClient\UrlGenerator;
use InvalidArgumentException; use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
/** /**
* @internal * @internal
*/ */
final class UrlGeneratorTest extends AnimeClientTestCase final class UrlGeneratorTest extends AnimeClientTestCase
{ {
public function assetUrlProvider() public static function assetUrlProvider(): array
{ {
return [ return [
'single argument' => [ 'single argument' => [
@ -40,12 +41,8 @@ final class UrlGeneratorTest extends AnimeClientTestCase
]; ];
} }
/** #[DataProvider('assetUrlProvider')]
* @dataProvider assetUrlProvider public function testAssetUrl(mixed $args, string $expected): void
* @param mixed $args
* @param mixed $expected
*/
public function testAssetUrl($args, $expected)
{ {
$urlGenerator = new UrlGenerator($this->container); $urlGenerator = new UrlGenerator($this->container);

View File

@ -47,7 +47,7 @@ final class UtilTest extends AnimeClientTestCase
$this->assertSame('', Util::isNotSelected('foo', 'foo')); $this->assertSame('', Util::isNotSelected('foo', 'foo'));
} }
public function dataIsViewPage() public static function dataIsViewPage()
{ {
return [ return [
[ [
@ -69,35 +69,34 @@ final class UtilTest extends AnimeClientTestCase
]; ];
} }
/** /**
* @dataProvider dataIsViewPage * @param mixed $uri
* @param mixed $uri */
* @param mixed $expected #[\PHPUnit\Framework\Attributes\DataProvider('dataIsViewPage')]
*/ public function testIsViewPage($uri, mixed $expected)
public function testIsViewPage($uri, $expected) {
{ $this->setSuperGlobals([
$this->setSuperGlobals([ '_SERVER' => [
'_SERVER' => [ 'REQUEST_URI' => $uri,
'REQUEST_URI' => $uri, ],
], ]);
]); $this->assertSame($expected, $this->util->isViewPage());
$this->assertSame($expected, $this->util->isViewPage()); }
}
/** /**
* @dataProvider dataIsViewPage * @param mixed $uri
* @param mixed $uri * @param mixed $expected
* @param mixed $expected */
*/ #[\PHPUnit\Framework\Attributes\DataProvider('dataIsViewPage')]
public function testIsFormPage($uri, $expected) public function testIsFormPage($uri, $expected)
{ {
$this->setSuperGlobals([ $this->setSuperGlobals([
'_SERVER' => [ '_SERVER' => [
'REQUEST_URI' => $uri, 'REQUEST_URI' => $uri,
], ],
]); ]);
$this->assertSame( ! $expected, $this->util->isFormPage()); $this->assertSame( ! $expected, $this->util->isFormPage());
} }
public function testAriaCurrent(): void public function testAriaCurrent(): void
{ {

View File

@ -15,6 +15,7 @@
namespace Aviat\Ion\Tests; namespace Aviat\Ion\Tests;
use Aviat\Ion\Config; use Aviat\Ion\Config;
use PHPUnit\Framework\Attributes\DataProvider;
/** /**
* @internal * @internal
@ -67,7 +68,7 @@ final class ConfigTest extends IonTestCase
$this->assertSame('great', $this->config->get(['apple', 'sauce', 'is']), 'Array argument get for config failed.'); $this->assertSame('great', $this->config->get(['apple', 'sauce', 'is']), 'Array argument get for config failed.');
} }
public function dataConfigDelete(): array public static function dataConfigDelete(): array
{ {
return [ return [
'top level delete' => [ 'top level delete' => [
@ -124,11 +125,8 @@ final class ConfigTest extends IonTestCase
]; ];
} }
/** #[DataProvider('dataConfigDelete')]
* @dataProvider dataConfigDelete public function testConfigDelete(string|array $key, array $assertKeys): void
* @param mixed $key
*/
public function testConfigDelete($key, array $assertKeys): void
{ {
$config = new Config([]); $config = new Config([]);
$config->set(['apple', 'sauce', 'is'], 'great'); $config->set(['apple', 'sauce', 'is'], 'great');

View File

@ -20,6 +20,7 @@ use Aviat\Ion\Di\{Container, ContainerAware};
use Aviat\Ion\Tests\IonTestCase; use Aviat\Ion\Tests\IonTestCase;
use Monolog\Handler\{NullHandler, TestHandler}; use Monolog\Handler\{NullHandler, TestHandler};
use Monolog\Logger; use Monolog\Logger;
use PHPUnit\Framework\Attributes\DataProvider;
use Throwable; use Throwable;
use TypeError; use TypeError;
@ -51,7 +52,7 @@ final class ContainerTest extends IonTestCase
$this->container = new Container(); $this->container = new Container();
} }
public function dataGetWithException(): array public static function dataGetWithException(): array
{ {
return [ return [
'Bad index type: number' => [ 'Bad index type: number' => [
@ -71,9 +72,9 @@ final class ContainerTest extends IonTestCase
} }
/** /**
* @dataProvider dataGetWithException
* @param mixed $exception * @param mixed $exception
*/ */
#[DataProvider('dataGetWithException')]
public function testGetWithException(mixed $id, $exception, ?string $message = NULL): void public function testGetWithException(mixed $id, $exception, ?string $message = NULL): void
{ {
try try
@ -92,9 +93,9 @@ final class ContainerTest extends IonTestCase
} }
/** /**
* @dataProvider dataGetWithException
* @param mixed $exception * @param mixed $exception
*/ */
#[DataProvider('dataGetWithException')]
public function testGetNewWithException(mixed $id, $exception, ?string $message = NULL): void public function testGetNewWithException(mixed $id, $exception, ?string $message = NULL): void
{ {
$this->expectException($exception); $this->expectException($exception);
@ -106,7 +107,7 @@ final class ContainerTest extends IonTestCase
$this->container->getNew($id); $this->container->getNew($id);
} }
public function dataSetInstanceWithException(): array public static function dataSetInstanceWithException(): array
{ {
return [ return [
'Non-existent id' => [ 'Non-existent id' => [
@ -123,11 +124,11 @@ final class ContainerTest extends IonTestCase
} }
/** /**
* @dataProvider dataSetInstanceWithException
* @param mixed $id * @param mixed $id
* @param mixed $exception * @param mixed $exception
* @param mixed $message * @param mixed $message
*/ */
#[DataProvider('dataSetInstanceWithException')]
public function testSetInstanceWithException($id, $exception, $message): void public function testSetInstanceWithException($id, $exception, $message): void
{ {
try try

View File

@ -19,6 +19,7 @@ namespace Aviat\Ion\Tests;
*/ */
final class EnumTest extends IonTestCase final class EnumTest extends IonTestCase
{ {
public $enum;
protected $expectedConstList = [ protected $expectedConstList = [
'FOO' => 'bar', 'FOO' => 'bar',
'BAR' => 'foo', 'BAR' => 'foo',
@ -43,7 +44,7 @@ final class EnumTest extends IonTestCase
$this->assertSame($this->expectedConstList, $actual); $this->assertSame($this->expectedConstList, $actual);
} }
public function dataIsValid() public static function dataIsValid()
{ {
return [ return [
'Valid' => [ 'Valid' => [
@ -69,18 +70,17 @@ final class EnumTest extends IonTestCase
]; ];
} }
/** /**
* @dataProvider dataIsValid * @param mixed $value
* @param mixed $value * @param mixed $static
* @param mixed $expected */
* @param mixed $static #[\PHPUnit\Framework\Attributes\DataProvider('dataIsValid')]
*/ public function testIsValid($value, mixed $expected, $static)
public function testIsValid($value, $expected, $static) {
{ $actual = ($static)
$actual = ($static) ? TestEnum::isValid($value)
? TestEnum::isValid($value) : $this->enum->isValid($value);
: $this->enum->isValid($value);
$this->assertSame($expected, $actual); $this->assertSame($expected, $actual);
} }
} }

View File

@ -32,7 +32,7 @@ final class JsonTest extends IonTestCase
$this->assertSame($expected, Json::encode($data)); $this->assertSame($expected, Json::encode($data));
} }
public function dataEncodeDecode(): array public static function dataEncodeDecode(): array
{ {
return [ return [
'set1' => [ 'set1' => [
@ -47,24 +47,22 @@ final class JsonTest extends IonTestCase
]; ];
} }
/** #[\PHPUnit\Framework\Attributes\DataProvider('dataEncodeDecode')]
* @dataProvider dataEncodeDecode public function testEncodeDecodeFile(array $data, int $expected_size, string $expected_json): void
*/ {
public function testEncodeDecodeFile(array $data, int $expected_size, string $expected_json): void $target_file = _dir(self::TEST_DATA_DIR, 'json_write.json');
{
$target_file = _dir(self::TEST_DATA_DIR, 'json_write.json');
$actual_size = Json::encodeFile($target_file, $data); $actual_size = Json::encodeFile($target_file, $data);
$actual_json = file_get_contents($target_file); $actual_json = file_get_contents($target_file);
$this->assertTrue(Json::isJson($actual_json)); $this->assertTrue(Json::isJson($actual_json));
$this->assertSame($expected_size, $actual_size); $this->assertSame($expected_size, $actual_size);
$this->assertSame($expected_json, $actual_json); $this->assertSame($expected_json, $actual_json);
$this->assertEquals($data, Json::decodeFile($target_file)); $this->assertEquals($data, Json::decodeFile($target_file));
unlink($target_file); unlink($target_file);
} }
public function testDecode() public function testDecode()
{ {

View File

@ -32,7 +32,7 @@ final class AbstractTransformerTest extends IonTestCase
$this->untransformer = new TestTransformerUntransform(); $this->untransformer = new TestTransformerUntransform();
} }
public function dataTransformCollection() public static function dataTransformCollection()
{ {
return [ return [
'object' => [ 'object' => [
@ -90,7 +90,7 @@ final class AbstractTransformerTest extends IonTestCase
]; ];
} }
public function dataUnTransformCollection() public static function dataUnTransformCollection()
{ {
return [ return [
'object' => [ 'object' => [
@ -130,36 +130,34 @@ final class AbstractTransformerTest extends IonTestCase
$this->assertSame($expected, $actual); $this->assertSame($expected, $actual);
} }
/** /**
* @dataProvider dataTransformCollection * @param mixed $original
* @param mixed $original */
* @param mixed $expected #[\PHPUnit\Framework\Attributes\DataProvider('dataTransformCollection')]
*/ public function testTransformCollection($original, mixed $expected)
public function testTransformCollection($original, $expected) {
{ $actual = $this->transformer->transformCollection($original);
$actual = $this->transformer->transformCollection($original); $this->assertSame($expected, $actual);
$this->assertSame($expected, $actual); }
}
/** /**
* @dataProvider dataUnTransformCollection * @param mixed $original
* @param mixed $original */
* @param mixed $expected #[\PHPUnit\Framework\Attributes\DataProvider('dataUnTransformCollection')]
*/ public function testUntransformCollection($original, mixed $expected)
public function testUntransformCollection($original, $expected) {
{ $actual = $this->untransformer->untransformCollection($original);
$actual = $this->untransformer->untransformCollection($original); $this->assertSame($expected, $actual);
$this->assertSame($expected, $actual); }
}
/** /**
* @dataProvider dataUnTransformCollection * @param mixed $original
* @param mixed $original * @param mixed $expected
* @param mixed $expected */
*/ #[\PHPUnit\Framework\Attributes\DataProvider('dataUnTransformCollection')]
public function testUntransformCollectionWithException($original, $expected) public function testUntransformCollectionWithException($original, $expected)
{ {
$this->expectException(BadMethodCallException::class); $this->expectException(BadMethodCallException::class);
$this->transformer->untransformCollection($original); $this->transformer->untransformCollection($original);
} }
} }

View File

@ -22,7 +22,7 @@ use Aviat\Ion\Type\ArrayType;
*/ */
final class ArrayTypeTest extends IonTestCase final class ArrayTypeTest extends IonTestCase
{ {
public function dataCall() public static function dataCall()
{ {
$method_map = [ $method_map = [
'chunk' => 'array_chunk', 'chunk' => 'array_chunk',
@ -80,18 +80,16 @@ final class ArrayTypeTest extends IonTestCase
]; ];
} }
/** /**
* Test the array methods defined for the __Call method * Test the array methods defined for the __Call method
* */
* @dataProvider dataCall #[\PHPUnit\Framework\Attributes\DataProvider('dataCall')]
* @param $expected public function testCall(string $method, array $array, array $args, mixed $expected): void
*/ {
public function testCall(string $method, array $array, array $args, $expected): void $obj = ArrayType::from($array);
{ $actual = $obj->__call($method, $args);
$obj = ArrayType::from($array); $this->assertSame($expected, $actual);
$actual = $obj->__call($method, $args); }
$this->assertSame($expected, $actual);
}
public function testSet(): void public function testSet(): void
{ {

View File

@ -16,13 +16,14 @@ namespace Aviat\Ion\Tests\Type;
use Aviat\Ion\Tests\IonTestCase; use Aviat\Ion\Tests\IonTestCase;
use Aviat\Ion\Type\StringType; use Aviat\Ion\Type\StringType;
use PHPUnit\Framework\Attributes\DataProvider;
/** /**
* @internal * @internal
*/ */
final class StringTypeTest extends IonTestCase final class StringTypeTest extends IonTestCase
{ {
public function dataFuzzyCaseMatch(): array public static function dataFuzzyCaseMatch(): array
{ {
return [ return [
'space separated' => [ 'space separated' => [
@ -53,9 +54,7 @@ final class StringTypeTest extends IonTestCase
]; ];
} }
/** #[DataProvider('dataFuzzyCaseMatch')]
* @dataProvider dataFuzzyCaseMatch
*/
public function testFuzzyCaseMatch(string $str1, string $str2, bool $expected): void public function testFuzzyCaseMatch(string $str1, string $str2, bool $expected): void
{ {
$actual = StringType::from($str1)->fuzzyCaseMatch($str2); $actual = StringType::from($str1)->fuzzyCaseMatch($str2);

View File

@ -1,6 +1,6 @@
{ {
"require": { "require": {
"friendsofphp/php-cs-fixer": "^3.6", "friendsofphp/php-cs-fixer": "^3.6",
"rector/rector": "^0.12.16" "rector/rector": "^0.15.21"
} }
} }

View File

@ -3,11 +3,11 @@
* *
* An API client for Kitsu to manage anime and manga watch lists * An API client for Kitsu to manage anime and manga watch lists
* *
* PHP version 8 * PHP version 8.1
* *
* @copyright 2015 - 2022 Timothy J. Warren <tim@timshome.page> * @copyright 2015 - 2023 Timothy J. Warren <tim@timshome.page>
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.2 * @version 5.2
* @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/ */

View File

View File

@ -1,65 +1,54 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
use Rector\CodeQuality\Rector\BooleanNot\SimplifyDeMorganBinaryRector;
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector; use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
use Rector\CodeQuality\Rector\For_\{ForRepeatedCountToOwnVariableRector, ForToForeachRector}; use Rector\CodeQuality\Rector\For_\{ForRepeatedCountToOwnVariableRector, ForToForeachRector};
use Rector\CodeQuality\Rector\If_\{ConsecutiveNullCompareReturnsToNullCoalesceQueueRector, SimplifyIfElseToTernaryRector, SimplifyIfReturnBoolRector}; use Rector\CodeQuality\Rector\If_\{ConsecutiveNullCompareReturnsToNullCoalesceQueueRector, SimplifyIfElseToTernaryRector, SimplifyIfReturnBoolRector};
use Rector\CodeQuality\Rector\Ternary\{SimplifyDuplicatedTernaryRector, SimplifyTautologyTernaryRector, SwitchNegatedTernaryRector}; use Rector\CodingStyle\Rector\String_\SymplifyQuoteEscapeRector;
use Rector\Php74\Rector\Property\RestoreDefaultNullToNullableTypePropertyRector;
use Rector\Php81\Rector\Property\ReadOnlyPropertyRector;
use Rector\Set\ValueObject\LevelSetList;
use Rector\CodeQuality\Rector\Ternary\{SimplifyTautologyTernaryRector, SwitchNegatedTernaryRector};
use Rector\CodingStyle\Rector\ArrowFunction\StaticArrowFunctionRector;
use Rector\CodingStyle\Rector\Class_\AddArrayDefaultToArrayPropertyRector; use Rector\CodingStyle\Rector\Class_\AddArrayDefaultToArrayPropertyRector;
use Rector\CodingStyle\Rector\ClassConst\RemoveFinalFromConstRector; use Rector\CodingStyle\Rector\ClassConst\RemoveFinalFromConstRector;
use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector; use Rector\CodingStyle\Rector\ClassMethod\{NewlineBeforeNewAssignSetRector, OrderAttributesRector};
use Rector\CodingStyle\Rector\Encapsed\WrapEncapsedVariableInCurlyBracesRector; use Rector\CodingStyle\Rector\Encapsed\WrapEncapsedVariableInCurlyBracesRector;
use Rector\CodingStyle\Rector\FuncCall\{CallUserFuncArrayToVariadicRector, CallUserFuncToMethodCallRector, CountArrayToEmptyArrayComparisonRector}; use Rector\CodingStyle\Rector\FuncCall\
{CallUserFuncArrayToVariadicRector,
CallUserFuncToMethodCallRector,
CountArrayToEmptyArrayComparisonRector,
VersionCompareFuncCallToConstantRector};
use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector; use Rector\CodingStyle\Rector\Stmt\NewlineAfterStatementRector;
use Rector\Core\Configuration\Option; use Rector\Config\RectorConfig;
use Rector\DeadCode\Rector\ClassMethod\{RemoveUselessParamTagRector, RemoveUselessReturnTagRector}; use Rector\DeadCode\Rector\ClassMethod\{RemoveUselessParamTagRector, RemoveUselessReturnTagRector};
use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector;
use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector; use Rector\DeadCode\Rector\Property\RemoveUselessVarTagRector;
use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector;
use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector;
use Rector\EarlyReturn\Rector\If_\{ChangeIfElseValueAssignToEarlyReturnRector, RemoveAlwaysElseRector}; use Rector\EarlyReturn\Rector\If_\{ChangeIfElseValueAssignToEarlyReturnRector, RemoveAlwaysElseRector};
use Rector\Php74\Rector\Property\RestoreDefaultNullToNullableTypePropertyRector; use Rector\PHPUnit\Set\PHPUnitSetList;
use Rector\Php81\Rector\Property\ReadOnlyPropertyRector; use Rector\TypeDeclaration\Rector\ClassMethod\{AddMethodCallBasedStrictParamTypeRector, ParamTypeByMethodCallTypeRector, ParamTypeByParentCallTypeRector};
use Rector\Restoration\Rector\Property\MakeTypedPropertyNullableIfCheckedRector;
use Rector\Set\ValueObject\LevelSetList;
use Rector\TypeDeclaration\Rector\ClassMethod\{AddArrayParamDocTypeRector, AddArrayReturnDocTypeRector, AddMethodCallBasedStrictParamTypeRector, ParamTypeByMethodCallTypeRector, ParamTypeByParentCallTypeRector};
use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector; use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector; use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromAssignsRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
if ( ! function_exists('walk_array')) return static function (RectorConfig $config): void {
{ // Import names with use statements
function walk_array(callable $method, array $items): void $config->importNames();
{ $config->importShortClasses(false);
foreach ($items as $item)
{
$method($item);
}
}
}
return static function (ContainerConfigurator $config): void { $config->sets([
$parameters = $config->parameters(); LevelSetList::UP_TO_PHP_81,
$parameters->set(Option::AUTO_IMPORT_NAMES, FALSE); PHPUnitSetList::ANNOTATIONS_TO_ATTRIBUTES,
$parameters->set(Option::IMPORT_SHORT_CLASSES, FALSE); PHPUnitSetList::PHPUNIT_100,
$parameters->set(Option::SKIP, [
ReadOnlyPropertyRector::class,
RestoreDefaultNullToNullableTypePropertyRector::class,
]); ]);
walk_array([$config, 'import'], [ $config->rules([
LevelSetList::UP_TO_PHP_80,
]);
$services = $config->services();
walk_array([$services, 'set'], [
AddArrayDefaultToArrayPropertyRector::class, AddArrayDefaultToArrayPropertyRector::class,
AddArrayParamDocTypeRector::class,
AddArrayReturnDocTypeRector::class,
AddClosureReturnTypeRector::class, AddClosureReturnTypeRector::class,
AddMethodCallBasedStrictParamTypeRector::class, AddMethodCallBasedStrictParamTypeRector::class,
CallUserFuncArrayToVariadicRector::class, CallUserFuncArrayToVariadicRector::class,
CallUserFuncToMethodCallRector::class, CallUserFuncToMethodCallRector::class,
CountArrayToEmptyArrayComparisonRector::class,
ChangeIfElseValueAssignToEarlyReturnRector::class, ChangeIfElseValueAssignToEarlyReturnRector::class,
ChangeNestedForeachIfsToEarlyContinueRector::class, ChangeNestedForeachIfsToEarlyContinueRector::class,
CompleteDynamicPropertiesRector::class, CompleteDynamicPropertiesRector::class,
@ -67,7 +56,6 @@ return static function (ContainerConfigurator $config): void {
CountArrayToEmptyArrayComparisonRector::class, CountArrayToEmptyArrayComparisonRector::class,
ForRepeatedCountToOwnVariableRector::class, ForRepeatedCountToOwnVariableRector::class,
ForToForeachRector::class, ForToForeachRector::class,
// MakeTypedPropertyNullableIfCheckedRector::class,
// NewlineAfterStatementRector::class, // NewlineAfterStatementRector::class,
NewlineBeforeNewAssignSetRector::class, NewlineBeforeNewAssignSetRector::class,
ParamTypeByMethodCallTypeRector::class, ParamTypeByMethodCallTypeRector::class,
@ -79,13 +67,23 @@ return static function (ContainerConfigurator $config): void {
RemoveUselessParamTagRector::class, RemoveUselessParamTagRector::class,
RemoveUselessReturnTagRector::class, RemoveUselessReturnTagRector::class,
RemoveUselessVarTagRector::class, RemoveUselessVarTagRector::class,
// SimplifyDeMorganBinaryRector::class,
SimplifyDuplicatedTernaryRector::class,
SimplifyIfElseToTernaryRector::class, SimplifyIfElseToTernaryRector::class,
SimplifyIfReturnBoolRector::class, SimplifyIfReturnBoolRector::class,
SimplifyTautologyTernaryRector::class, SimplifyTautologyTernaryRector::class,
SymplifyQuoteEscapeRector::class,
StaticArrowFunctionRector::class,
SwitchNegatedTernaryRector::class, SwitchNegatedTernaryRector::class,
TypedPropertyFromAssignsRector::class, TypedPropertyFromAssignsRector::class,
VersionCompareFuncCallToConstantRector::class,
WrapEncapsedVariableInCurlyBracesRector::class, WrapEncapsedVariableInCurlyBracesRector::class,
]); ]);
$config->ruleWithConfiguration(OrderAttributesRector::class, [
'alphabetically',
]);
$config->skip([
ReadOnlyPropertyRector::class,
RestoreDefaultNullToNullableTypePropertyRector::class,
]);
}; };

View File

@ -39,7 +39,7 @@ function get_text_to_replace(array $tokens): string
// [0] => token type constant // [0] => token type constant
// [1] => raw syntax parsed to that token // [1] => raw syntax parsed to that token
// [2] => line number // [2] => line number
foreach($tokens as $token) foreach ($tokens as $token)
{ {
// Since we only care about opening docblocks, // Since we only care about opening docblocks,
// bail out when we get to the namespace token // bail out when we get to the namespace token
@ -81,9 +81,9 @@ function replace_file(string $file, string $template): void
$files = array_filter( $files = array_filter(
glob_recursive('*.php'), glob_recursive('*.php'),
fn (string $file) => ! (str_contains($file, '/vendor/') || str_contains($file, '/tmp/')) static fn (string $file) => ! (str_contains($file, '/vendor/') || str_contains($file, '/tmp/'))
); );
array_walk($files, fn (string $file) => replace_file($file, '/header_comment.txt')); array_walk($files, static fn (string $file) => replace_file($file, '/header_comment.txt'));
echo json_encode(array_values($files), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) . "\n"; echo json_encode(array_values($files), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) . "\n";
printf("Successfully updated header comments in %d files\n", count($files)); printf("Successfully updated header comments in %d files\n", count($files));