![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/rentpix.corals.io/vendor/league/csv/src/Serializer/ |
<?php /** * League.Csv (https://csv.thephpleague.com) * * (c) Ignace Nyamagana Butera <[email protected]> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ declare(strict_types=1); namespace League\Csv\Serializer; use Closure; use ReflectionNamedType; use ReflectionParameter; use ReflectionProperty; use ReflectionType; use ReflectionUnionType; use Throwable; use function array_key_exists; use function class_exists; /** * @internal Container for registering Closure as type and/or type alias casting * @template TValue */ final class CallbackCasting implements TypeCasting { /** @var array<string, Closure(?string, bool, mixed...): mixed> */ private static array $types = []; /** @var array<string, array<string, Closure(?string, bool, mixed...): mixed>> */ private static array $aliases = []; private string $type; private readonly bool $isNullable; /** @var Closure(?string, bool, mixed...): mixed */ private Closure $callback; private array $options; private string $message; public function __construct( ReflectionProperty|ReflectionParameter $reflectionProperty, private readonly ?string $alias = null ) { [$this->type, $this->isNullable] = self::resolve($reflectionProperty); $this->message = match (true) { $reflectionProperty instanceof ReflectionParameter => 'The method `'.$reflectionProperty->getDeclaringClass()?->getName().'::'.$reflectionProperty->getDeclaringFunction()->getName().'` argument `'.$reflectionProperty->getName().'` must be typed with a supported type.', $reflectionProperty instanceof ReflectionProperty => 'The property `'.$reflectionProperty->getDeclaringClass()->getName().'::'.$reflectionProperty->getName().'` must be typed with a supported type.', }; $this->callback = fn (?string $value, bool $isNullable, mixed ...$arguments): ?string => $value; } /** * @throws MappingFailed */ public function setOptions(string $type = null, mixed ...$options): void { if (null === $this->alias) { if (Type::Mixed->value === $this->type && null !== $type) { $this->type = $type; } if (array_key_exists($this->type, self::$types)) { $this->callback = self::$types[$this->type]; $this->options = $options; return; } throw new MappingFailed($this->message); } if (Type::Mixed->value === $this->type) { $this->type = self::aliases()[$this->alias]; } /** @var Closure $callback */ $callback = self::$aliases[$this->type][$this->alias]; $this->callback = $callback; $this->options = $options; } /** * @return TValue */ public function toVariable(?string $value): mixed { try { return ($this->callback)($value, $this->isNullable, ...$this->options); } catch (Throwable $exception) { if ($exception instanceof TypeCastingFailed) { throw $exception; } if (null === $value) { throw TypeCastingFailed::dueToNotNullableType($this->type, $exception); } throw TypeCastingFailed::dueToInvalidValue(match (true) { '' === $value => 'empty string', default => $value, }, $this->type, $exception); } } /** * @param Closure(?string, bool, mixed...): TValue $callback */ public static function register(string $type, Closure $callback, string $alias = null): void { if (null === $alias) { self::$types[$type] = match (true) { class_exists($type), interface_exists($type), Type::tryFrom($type) instanceof Type => $callback, default => throw new MappingFailed('The `'.$type.'` could not be register.'), }; return; } if (1 !== preg_match('/^@\w+$/', $alias)) { throw new MappingFailed("The alias `$alias` is invalid. It must start with an `@` character and contain alphanumeric (letters, numbers, regardless of case) plus underscore (_)."); } foreach (self::$aliases as $aliases) { foreach ($aliases as $registeredAlias => $__) { if ($alias === $registeredAlias) { throw new MappingFailed("The alias `$alias` is already registered. Please choose another name."); } } } self::$aliases[$type][$alias] = match (true) { class_exists($type), interface_exists($type), Type::tryFrom($type) instanceof Type => $callback, default => throw new MappingFailed('The `'.$type.'` could not be register.'), }; } public static function unregisterType(string $type): bool { if (!array_key_exists($type, self::$types)) { return false; } unset(self::$types[$type]); return true; } public static function unregisterTypes(): void { self::$types = []; } public static function unregisterAlias(string $alias): bool { if (1 !== preg_match('/^@\w+$/', $alias)) { return false; } foreach (self::$aliases as $type => $aliases) { foreach ($aliases as $registeredAlias => $__) { if ($registeredAlias === $alias) { unset(self::$aliases[$type][$registeredAlias]); return true; } } } return false; } public static function unregisterAliases(): void { self::$aliases = []; } public static function unregisterAll(): void { self::$types = []; self::$aliases = []; } public static function supportsAlias(?string $alias): bool { return null !== $alias && array_key_exists($alias, self::aliases()); } public static function supportsType(?string $type): bool { return null !== $type && array_key_exists($type, self::$types); } /** * @return array<string> */ public static function types(): array { return array_keys(self::$types); } /** * @return array<string, string> */ public static function aliases(): array { $res = []; foreach (self::$aliases as $registeredType => $aliases) { foreach ($aliases as $registeredAlias => $__) { $res[$registeredAlias] = $registeredType; } } return $res; } public static function supports(ReflectionParameter|ReflectionProperty $reflectionProperty, string $alias = null): bool { $propertyTypeList = self::getTypes($reflectionProperty->getType()); if ([] === $propertyTypeList && self::supportsAlias($alias)) { return true; } foreach ($propertyTypeList as $propertyType) { $type = $propertyType->getName(); if (null === $alias) { if (array_key_exists($type, self::$types)) { return true; } continue; } if ((self::aliases()[$alias] ?? null) === $type || (Type::Mixed->value === $type && self::supportsAlias($alias))) { return true; } } return false; } /** * @throws MappingFailed * * @return array{0:string, 1:bool} */ private static function resolve(ReflectionParameter|ReflectionProperty $reflectionProperty): array { if (null === $reflectionProperty->getType()) { return [Type::Mixed->value, true]; } $types = self::getTypes($reflectionProperty->getType()); $type = null; $isNullable = false; $hasMixed = false; foreach ($types as $foundType) { if (!$isNullable && $foundType->allowsNull()) { $isNullable = true; } if (null === $type) { if ( array_key_exists($foundType->getName(), self::$types) || array_key_exists($foundType->getName(), self::$aliases) ) { $type = $foundType; } if (true !== $hasMixed && Type::Mixed->value === $foundType->getName()) { $hasMixed = true; } } } return match (true) { $type instanceof ReflectionNamedType => [$type->getName(), $isNullable], $hasMixed => [Type::Mixed->value, true], default => throw new MappingFailed(match (true) { $reflectionProperty instanceof ReflectionParameter => 'The method `'.$reflectionProperty->getDeclaringClass()?->getName().'::'.$reflectionProperty->getDeclaringFunction()->getName().'` argument `'.$reflectionProperty->getName().'` must be typed with a supported type.', $reflectionProperty instanceof ReflectionProperty => 'The property `'.$reflectionProperty->getDeclaringClass()->getName().'::'.$reflectionProperty->getName().'` must be typed with a supported type.', }), }; } /** * @return array<ReflectionNamedType> */ private static function getTypes(?ReflectionType $type): array { return match (true) { $type instanceof ReflectionNamedType => [$type], $type instanceof ReflectionUnionType => array_filter( $type->getTypes(), fn (ReflectionType $innerType) => $innerType instanceof ReflectionNamedType ), default => [], }; } /** * DEPRECATION WARNING! This method will be removed in the next major point release. * * @deprecated since version 9.13.0 * @see CallbackCasting::unregisterType() * @codeCoverageIgnore */ public static function unregister(string $type): bool { return self::unregisterType($type); } }