refactor: susun semula struktur folder — Laravel source ke src/
This commit is contained in:
50
vendor/league/csv/src/Serializer/AfterMapping.php
vendored
Normal file
50
vendor/league/csv/src/Serializer/AfterMapping.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Attribute;
|
||||
use Deprecated;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @deprecated since version 9.17.0
|
||||
*
|
||||
* @see MapRecord
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class AfterMapping
|
||||
{
|
||||
public readonly MapRecord $mapRecord;
|
||||
public readonly array $methods;
|
||||
|
||||
#[Deprecated(message: 'use League\Csv\Serializer\MapRecord instead', since: 'league/csv:9.17.0')]
|
||||
public function __construct(string ...$methods)
|
||||
{
|
||||
$this->mapRecord = new MapRecord($methods);
|
||||
$this->methods = $this->mapRecord->afterMapping;
|
||||
}
|
||||
|
||||
public static function from(ReflectionClass $class): ?self
|
||||
{
|
||||
$attributes = $class->getAttributes(self::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
$nbAttributes = count($attributes);
|
||||
|
||||
return match (true) {
|
||||
0 === $nbAttributes => null,
|
||||
1 < $nbAttributes => throw new MappingFailed('Using more than one `'.self::class.'` attribute on a class property or method is not supported.'),
|
||||
default => $attributes[0]->newInstance(),
|
||||
};
|
||||
}
|
||||
}
|
||||
32
vendor/league/csv/src/Serializer/ArrayShape.php
vendored
Normal file
32
vendor/league/csv/src/Serializer/ArrayShape.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Csv\Serializer;
|
||||
|
||||
use function in_array;
|
||||
|
||||
enum ArrayShape: string
|
||||
{
|
||||
case List = 'list';
|
||||
case Csv = 'csv';
|
||||
case Json = 'json';
|
||||
|
||||
public function equals(mixed $value): bool
|
||||
{
|
||||
return $value instanceof self
|
||||
&& $value === $this;
|
||||
}
|
||||
|
||||
public function isOneOf(self ...$types): bool
|
||||
{
|
||||
return in_array($this, $types, true);
|
||||
}
|
||||
}
|
||||
392
vendor/league/csv/src/Serializer/CallbackCasting.php
vendored
Normal file
392
vendor/league/csv/src/Serializer/CallbackCasting.php
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Deprecated;
|
||||
use ReflectionClass;
|
||||
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(mixed, bool, mixed...): mixed> */
|
||||
private static array $types = [];
|
||||
/** @var array<string, array<string, Closure(mixed, bool, mixed...): mixed>> */
|
||||
private static array $aliases = [];
|
||||
|
||||
private string $type;
|
||||
private readonly bool $isNullable;
|
||||
/** @var Closure(mixed, bool, mixed...): mixed */
|
||||
private Closure $callback;
|
||||
private array $options = [];
|
||||
private string $message;
|
||||
private readonly TypeCastingInfo $info;
|
||||
|
||||
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 (mixed $value, bool $isNullable, mixed ...$arguments): mixed => $value;
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->callback = self::resolveTypeCallback($this->type); /* @phpstan-ignore-line */
|
||||
$this->options = $options;
|
||||
|
||||
return;
|
||||
} catch (Throwable) {
|
||||
|
||||
}
|
||||
|
||||
throw new MappingFailed($this->message);
|
||||
}
|
||||
|
||||
if (Type::Mixed->value === $this->type) {
|
||||
$this->type = self::aliases()[$this->alias];
|
||||
}
|
||||
|
||||
$this->callback = self::resolveAliasCallback($this->type, $this->alias);
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TValue
|
||||
*/
|
||||
public function toVariable(mixed $value): mixed
|
||||
{
|
||||
try {
|
||||
return ($this->callback)($value, $this->isNullable, ...$this->options);
|
||||
} catch (Throwable $exception) {
|
||||
! $exception instanceof TypeCastingFailed || throw $exception;
|
||||
null !== $value || throw TypeCastingFailed::dueToNotNullableType($this->type, $exception, $this->info);
|
||||
|
||||
throw TypeCastingFailed::dueToInvalidValue(match (true) {
|
||||
'' === $value => 'empty string',
|
||||
default => $value,
|
||||
}, $this->type, $exception, $this->info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(mixed, 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;
|
||||
}
|
||||
|
||||
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 => $__) {
|
||||
$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::unregisterTypes();
|
||||
self::unregisterAliases();
|
||||
}
|
||||
|
||||
public static function supportsAlias(?string $alias): bool
|
||||
{
|
||||
return null !== $alias && array_key_exists($alias, self::aliases());
|
||||
}
|
||||
|
||||
public static function supportsType(?string $type): bool
|
||||
{
|
||||
if (null === $type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
self::resolveTypeCallback($type); /* @phpstan-ignore-line */
|
||||
|
||||
return true;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 (self::supportsType($type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::aliasSupportsType($type) || (Type::Mixed->value === $type && self::supportsAlias($alias))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function aliasSupportsType(string $type): bool
|
||||
{
|
||||
foreach (self::aliases() as $registeredType) {
|
||||
if ($type === $registeredType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((new ReflectionClass($type))->implementsInterface($registeredType)) { /* @phpstan-ignore-line */
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $type
|
||||
*/
|
||||
private static function resolveTypeCallback(string $type): Closure
|
||||
{
|
||||
foreach (self::$types as $registeredType => $callback) {
|
||||
if ($type === $registeredType) {
|
||||
return $callback;
|
||||
}
|
||||
|
||||
try {
|
||||
$reflType = new ReflectionClass($type);
|
||||
if ($reflType->implementsInterface($registeredType)) {
|
||||
return $callback;
|
||||
}
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new MappingFailed('The `'.$type.'` could not be resolved.');
|
||||
}
|
||||
|
||||
private static function resolveAliasCallback(string $type, string $alias): Closure
|
||||
{
|
||||
$rType = self::aliases()[$alias] ?? null;
|
||||
if (isset($rType)) {
|
||||
return self::$aliases[$rType][$alias];
|
||||
}
|
||||
|
||||
foreach (self::aliases() as $aliasName => $registeredType) {
|
||||
try {
|
||||
$reflType = new ReflectionClass($type); /* @phpstan-ignore-line */
|
||||
if ($reflType->implementsInterface($registeredType)) {
|
||||
return self::$aliases[$registeredType][$aliasName];
|
||||
}
|
||||
} catch (Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new MappingFailed('The `'.$type.'` could not be resolved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
$instanceName = $foundType->getName();
|
||||
if (self::supportsType($instanceName) || array_key_exists($instanceName, self::$aliases)) {
|
||||
$type = $foundType;
|
||||
}
|
||||
|
||||
if (true !== $hasMixed && Type::Mixed->value === $instanceName) {
|
||||
$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
|
||||
*/
|
||||
#[Deprecated(message:'use League\Csv\Serializer\CallbackCasting::unregisterType() instead', since:'league/csv:9.13.0')]
|
||||
public static function unregister(string $type): bool
|
||||
{
|
||||
return self::unregisterType($type);
|
||||
}
|
||||
}
|
||||
228
vendor/league/csv/src/Serializer/CastToArray.php
vendored
Normal file
228
vendor/league/csv/src/Serializer/CastToArray.php
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 JsonException;
|
||||
use League\Csv\Exception;
|
||||
use League\Csv\Reader;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function array_map;
|
||||
use function explode;
|
||||
use function filter_var;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function strlen;
|
||||
|
||||
use const FILTER_REQUIRE_ARRAY;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<array|null>
|
||||
*/
|
||||
final class CastToArray implements TypeCasting
|
||||
{
|
||||
private readonly Type $type;
|
||||
private readonly bool $isNullable;
|
||||
private ArrayShape $shape;
|
||||
private int $filterFlag;
|
||||
/** @var non-empty-string */
|
||||
private string $separator = ',';
|
||||
private string $delimiter = '';
|
||||
private string $enclosure = '"';
|
||||
/** @var int<1, max> $depth */
|
||||
private int $depth = 512;
|
||||
private int $flags = 0;
|
||||
private ?array $default = null;
|
||||
private bool $trimElementValueBeforeCasting = false;
|
||||
private ?int $headerOffset = null;
|
||||
private readonly TypeCastingInfo $info;
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
[$this->type, $this->isNullable] = $this->init($reflectionProperty);
|
||||
$this->shape = ArrayShape::List;
|
||||
$this->filterFlag = Type::String->filterFlag();
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $delimiter
|
||||
* @param non-empty-string $separator
|
||||
* @param int<1, max> $depth
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function setOptions(
|
||||
?array $default = null,
|
||||
ArrayShape|string $shape = ArrayShape::List,
|
||||
string $separator = ',',
|
||||
string $delimiter = ',',
|
||||
string $enclosure = '"',
|
||||
int $depth = 512,
|
||||
int $flags = 0,
|
||||
Type|string $type = Type::String,
|
||||
bool $trimElementValueBeforeCasting = false,
|
||||
?int $headerOffset = null,
|
||||
): void {
|
||||
if (!$shape instanceof ArrayShape) {
|
||||
$shape = ArrayShape::tryFrom($shape) ?? throw new MappingFailed('Unable to resolve the array shape; Verify your options arguments.');
|
||||
}
|
||||
|
||||
if (!$type instanceof Type) {
|
||||
$type = Type::tryFrom($type) ?? throw new MappingFailed('Unable to resolve the array value type; Verify your options arguments.');
|
||||
}
|
||||
|
||||
$this->shape = $shape;
|
||||
$this->depth = $depth;
|
||||
$this->separator = $separator;
|
||||
$this->delimiter = $delimiter;
|
||||
$this->enclosure = $enclosure;
|
||||
$this->flags = $flags;
|
||||
$this->default = $default;
|
||||
$this->filterFlag = match (true) {
|
||||
1 > $this->depth && $this->shape->equals(ArrayShape::Json) => throw new MappingFailed('the json depth can not be less than 1.'),
|
||||
1 > strlen($this->separator) && $this->shape->equals(ArrayShape::List) => throw new MappingFailed('expects separator to be a non-empty string for list conversion; empty string given.'),
|
||||
1 !== strlen($this->delimiter) && $this->shape->equals(ArrayShape::Csv) => throw new MappingFailed('expects delimiter to be a single character for CSV conversion; `'.$this->delimiter.'` given.'),
|
||||
1 !== strlen($this->enclosure) && $this->shape->equals(ArrayShape::Csv) => throw new MappingFailed('expects enclosure to be a single character; `'.$this->enclosure.'` given.'),
|
||||
default => $this->resolveFilterFlag($type),
|
||||
};
|
||||
$this->trimElementValueBeforeCasting = $trimElementValueBeforeCasting;
|
||||
$this->headerOffset = $headerOffset;
|
||||
}
|
||||
|
||||
public function toVariable(mixed $value): ?array
|
||||
{
|
||||
if (null === $value) {
|
||||
return match (true) {
|
||||
$this->isNullable,
|
||||
Type::Mixed->equals($this->type) => $this->default,
|
||||
default => throw TypeCastingFailed::dueToNotNullableType($this->type->value, info: $this->info),
|
||||
};
|
||||
}
|
||||
|
||||
if ('' === $value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!is_string($value)) {
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->type->value, info: $this->info);
|
||||
}
|
||||
|
||||
if ($this->shape->equals(ArrayShape::Json)) {
|
||||
try {
|
||||
$data = json_decode($value, true, $this->depth, $this->flags | JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $exception) {
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->type->value, $exception, $this->info);
|
||||
}
|
||||
|
||||
if (!is_array($data)) {
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->type->value, info: $this->info);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($this->shape->equals(ArrayShape::Csv)) {
|
||||
try {
|
||||
$data = Reader::fromString($value);
|
||||
$data->setDelimiter($this->delimiter);
|
||||
$data->setEnclosure($this->enclosure);
|
||||
$data->setEscape('');
|
||||
$data->setHeaderOffset($this->headerOffset);
|
||||
if ($this->trimElementValueBeforeCasting) {
|
||||
$data->addFormatter($this->trimString(...));
|
||||
}
|
||||
$data->addFormatter($this->filterElement(...));
|
||||
|
||||
return [...$data];
|
||||
} catch (Exception $exception) {
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->type->value, $exception, $this->info);
|
||||
}
|
||||
}
|
||||
|
||||
$data = explode($this->separator, $value);
|
||||
|
||||
return $this->filterElement(match (true) {
|
||||
$this->trimElementValueBeforeCasting => $this->trimString($data),
|
||||
default => $data,
|
||||
});
|
||||
}
|
||||
|
||||
private function trimString(array $record): array
|
||||
{
|
||||
return array_map(
|
||||
fn (mixed $value): mixed => is_string($value) ? trim($value) : $value,
|
||||
$record
|
||||
);
|
||||
}
|
||||
|
||||
private function filterElement(array $record): array
|
||||
{
|
||||
return filter_var($record, $this->filterFlag, FILTER_REQUIRE_ARRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed if the type is not supported
|
||||
*/
|
||||
private function resolveFilterFlag(?Type $type): int
|
||||
{
|
||||
return match (true) {
|
||||
$this->shape->equals(ArrayShape::Json) => Type::String->filterFlag(),
|
||||
$type instanceof Type && $type->isOneOf(Type::Bool, Type::True, Type::False, Type::String, Type::Float, Type::Int) => $type->filterFlag(),
|
||||
default => throw new MappingFailed('Only scalar type are supported for `array` value casting.'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Type, 1:bool}
|
||||
*/
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): array
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return [Type::Mixed, true];
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Array, Type::Iterable)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $type) {
|
||||
throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'array', 'iterable', 'mixed');
|
||||
}
|
||||
|
||||
return [$type[0], $isNullable];
|
||||
}
|
||||
}
|
||||
99
vendor/league/csv/src/Serializer/CastToBool.php
vendored
Normal file
99
vendor/league/csv/src/Serializer/CastToBool.php
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function filter_var;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<?bool>
|
||||
*/
|
||||
final class CastToBool implements TypeCasting
|
||||
{
|
||||
private readonly bool $isNullable;
|
||||
private readonly Type $type;
|
||||
private readonly TypeCastingInfo $info;
|
||||
private ?bool $default = null;
|
||||
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
[$this->type, $this->isNullable] = $this->init($reflectionProperty);
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function setOptions(
|
||||
?bool $default = null,
|
||||
bool $emptyStringAsNull = false,
|
||||
): void {
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): ?bool
|
||||
{
|
||||
$returnValue = match (true) {
|
||||
is_bool($value) => $value,
|
||||
null !== $value => filter_var($value, Type::Bool->filterFlag()),
|
||||
$this->isNullable => $this->default,
|
||||
default => throw TypeCastingFailed::dueToNotNullableType('boolean', info: $this->info),
|
||||
};
|
||||
|
||||
return match (true) {
|
||||
Type::True->equals($this->type) && true !== $returnValue && !$this->isNullable,
|
||||
Type::False->equals($this->type) && false !== $returnValue && !$this->isNullable => throw TypeCastingFailed::dueToInvalidValue(match (true) {
|
||||
null === $value => 'null',
|
||||
'' === $value => 'empty string',
|
||||
default => $value,
|
||||
}, $this->type->value, info: $this->info),
|
||||
default => $returnValue,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Type, 1:bool}
|
||||
*/
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): array
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return [Type::Mixed, true];
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Bool, Type::True, Type::False)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $type) {
|
||||
throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'bool', 'mixed');
|
||||
}
|
||||
|
||||
return [$type[0], $isNullable];
|
||||
}
|
||||
}
|
||||
159
vendor/league/csv/src/Serializer/CastToDate.php
vendored
Normal file
159
vendor/league/csv/src/Serializer/CastToDate.php
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
use ReflectionClass;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use Throwable;
|
||||
|
||||
use function class_exists;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<DateTimeImmutable|DateTime|null>
|
||||
*/
|
||||
final class CastToDate implements TypeCasting
|
||||
{
|
||||
/** @var class-string */
|
||||
private string $class;
|
||||
private readonly bool $isNullable;
|
||||
private DateTimeImmutable|DateTime|null $default = null;
|
||||
private readonly Type $type;
|
||||
private readonly TypeCastingInfo $info;
|
||||
private ?DateTimeZone $timezone = null;
|
||||
private ?string $format = null;
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function __construct(
|
||||
ReflectionProperty|ReflectionParameter $reflectionProperty,
|
||||
) {
|
||||
[$this->type, $this->class, $this->isNullable] = $this->init($reflectionProperty);
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?class-string $className
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function setOptions(
|
||||
?string $default = null,
|
||||
?string $format = null,
|
||||
DateTimeZone|string|null $timezone = null,
|
||||
?string $className = null,
|
||||
): void {
|
||||
$this->class = match (true) {
|
||||
!interface_exists($this->class) && !Type::Mixed->equals($this->type) => $this->class,
|
||||
DateTimeInterface::class === $this->class && null === $className => DateTimeImmutable::class,
|
||||
interface_exists($this->class) && null !== $className && class_exists($className) && (new ReflectionClass($className))->implementsInterface($this->class) => $className,
|
||||
default => throw new MappingFailed('`'.$this->info->targetName.'` type is `'.($this->class ?? 'mixed').'` but the specified class via the `$className` argument is invalid or could not be found.'),
|
||||
};
|
||||
|
||||
try {
|
||||
$this->format = $format;
|
||||
$this->timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
|
||||
$this->default = (null !== $default) ? $this->cast($default) : $default;
|
||||
} catch (Throwable $exception) {
|
||||
throw new MappingFailed('The `timezone` and/or `format` options used for `'.self::class.'` are invalud.', 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): DateTimeImmutable|DateTime|null
|
||||
{
|
||||
return match (true) {
|
||||
null !== $value && '' !== $value => $this->cast($value),
|
||||
$this->isNullable => $this->default,
|
||||
default => throw TypeCastingFailed::dueToNotNullableType($this->class, info: $this->info),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
private function cast(mixed $value): DateTimeImmutable|DateTime
|
||||
{
|
||||
if ($value instanceof DateTimeInterface) {
|
||||
if ($value instanceof $this->class) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return ($this->class)::createFromInterface($value);
|
||||
}
|
||||
|
||||
is_string($value) || throw TypeCastingFailed::dueToInvalidValue($value, $this->class, info: $this->info);
|
||||
|
||||
try {
|
||||
$date = null !== $this->format ?
|
||||
($this->class)::createFromFormat($this->format, $value, $this->timezone) :
|
||||
new ($this->class)($value, $this->timezone);
|
||||
if (false === $date) {
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->class);
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
if ($exception instanceof TypeCastingFailed) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
throw TypeCastingFailed::dueToInvalidValue($value, $this->class, $exception, $this->info);
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*
|
||||
* @return array{0:Type, 1:class-string<DateTimeInterface>, 2:bool}
|
||||
*/
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): array
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return [Type::Mixed, DateTimeInterface::class, true];
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Date)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
null !== $type || throw throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, DateTimeInterface::class, 'mixed');
|
||||
|
||||
/** @var class-string<DateTimeInterface> $className */
|
||||
$className = $type[1]->getName();
|
||||
|
||||
return [$type[0], $className, $isNullable];
|
||||
}
|
||||
}
|
||||
136
vendor/league/csv/src/Serializer/CastToEnum.php
vendored
Normal file
136
vendor/league/csv/src/Serializer/CastToEnum.php
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 BackedEnum;
|
||||
use ReflectionEnum;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use Throwable;
|
||||
use UnitEnum;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<BackedEnum|UnitEnum|null>
|
||||
*/
|
||||
class CastToEnum implements TypeCasting
|
||||
{
|
||||
private readonly bool $isNullable;
|
||||
private readonly Type $type;
|
||||
private ?UnitEnum $default = null;
|
||||
private readonly TypeCastingInfo $info;
|
||||
/** @var class-string<UnitEnum|BackedEnum> */
|
||||
private string $class;
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
[$this->type, $this->class, $this->isNullable] = $this->init($reflectionProperty);
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ?class-string<UnitEnum|BackedEnum> $className *
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function setOptions(
|
||||
?string $default = null,
|
||||
?string $className = null,
|
||||
bool $emptyStringAsNull = false,
|
||||
): void {
|
||||
if (Type::Mixed->equals($this->type) || in_array($this->class, [BackedEnum::class , UnitEnum::class], true)) {
|
||||
(null !== $className && enum_exists($className)) || throw new MappingFailed('`'.$this->info->targetName.'` type is `'.($this->class ?? 'mixed').'` but the specified class via the `$className` argument is invalid or could not be found.');
|
||||
$this->class = $className;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->default = (null !== $default) ? $this->cast($default) : $default;
|
||||
} catch (TypeCastingFailed $exception) {
|
||||
throw new MappingFailed(message:'The `default` option is invalid.', previous: $exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): BackedEnum|UnitEnum|null
|
||||
{
|
||||
return match (true) {
|
||||
null !== $value => $this->cast($value),
|
||||
$this->isNullable => $this->default,
|
||||
default => throw TypeCastingFailed::dueToNotNullableType($this->class, info: $this->info),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
private function cast(mixed $value): BackedEnum|UnitEnum
|
||||
{
|
||||
if ($value instanceof $this->class) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
is_string($value) || throw throw TypeCastingFailed::dueToInvalidValue($value, $this->class, info: $this->info);
|
||||
|
||||
try {
|
||||
$enum = new ReflectionEnum($this->class);
|
||||
if (!$enum->isBacked()) {
|
||||
return $enum->getCase($value)->getValue();
|
||||
}
|
||||
|
||||
$backedValue = 'int' === $enum->getBackingType()->getName() ? filter_var($value, Type::Int->filterFlag()) : $value;
|
||||
|
||||
return $this->class::from($backedValue); /* @phpstan-ignore-line */
|
||||
} catch (Throwable $exception) {
|
||||
throw throw TypeCastingFailed::dueToInvalidValue($value, $this->class, $exception, $this->info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Type, 1:class-string<UnitEnum|BackedEnum>, 2:bool}
|
||||
*/
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): array
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return [Type::Mixed, UnitEnum::class, true];
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Enum)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
null !== $type || throw throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'enum', 'mixed');
|
||||
|
||||
/** @var class-string<UnitEnum|BackedEnum> $className */
|
||||
$className = $type[1]->getName();
|
||||
|
||||
return [$type[0], $className, $isNullable];
|
||||
}
|
||||
}
|
||||
92
vendor/league/csv/src/Serializer/CastToFloat.php
vendored
Normal file
92
vendor/league/csv/src/Serializer/CastToFloat.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function filter_var;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<?float>
|
||||
*/
|
||||
final class CastToFloat implements TypeCasting
|
||||
{
|
||||
private readonly bool $isNullable;
|
||||
private ?float $default = null;
|
||||
private readonly TypeCastingInfo $info;
|
||||
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
$this->isNullable = $this->init($reflectionProperty);
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
public function setOptions(
|
||||
int|float|null $default = null,
|
||||
bool $emptyStringAsNull = false,
|
||||
): void {
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): ?float
|
||||
{
|
||||
if (null === $value) {
|
||||
return match ($this->isNullable) {
|
||||
true => $this->default,
|
||||
false => throw TypeCastingFailed::dueToNotNullableType('float', info: $this->info),
|
||||
};
|
||||
}
|
||||
|
||||
is_scalar($value) || throw TypeCastingFailed::dueToInvalidValue($value, Type::Int->value, info: $this->info);
|
||||
|
||||
$float = filter_var($value, Type::Float->filterFlag());
|
||||
|
||||
return match ($float) {
|
||||
false => throw TypeCastingFailed::dueToInvalidValue($value, Type::Float->value, info: $this->info),
|
||||
default => $float,
|
||||
};
|
||||
}
|
||||
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): bool
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Float)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
null !== $type || throw throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'float', 'null', 'mixed');
|
||||
|
||||
return $isNullable;
|
||||
}
|
||||
}
|
||||
92
vendor/league/csv/src/Serializer/CastToInt.php
vendored
Normal file
92
vendor/league/csv/src/Serializer/CastToInt.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function filter_var;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<?int>
|
||||
*/
|
||||
final class CastToInt implements TypeCasting
|
||||
{
|
||||
private readonly bool $isNullable;
|
||||
private ?int $default = null;
|
||||
private readonly TypeCastingInfo $info;
|
||||
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
$this->isNullable = $this->init($reflectionProperty);
|
||||
$this->info = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
public function setOptions(
|
||||
?int $default = null,
|
||||
bool $emptyStringAsNull = false,
|
||||
): void {
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): ?int
|
||||
{
|
||||
if (null === $value) {
|
||||
return match ($this->isNullable) {
|
||||
true => $this->default,
|
||||
false => throw TypeCastingFailed::dueToNotNullableType('integer', info: $this->info),
|
||||
};
|
||||
}
|
||||
|
||||
is_scalar($value) || throw TypeCastingFailed::dueToInvalidValue($value, Type::Int->value, info: $this->info);
|
||||
|
||||
$int = filter_var($value, Type::Int->filterFlag());
|
||||
|
||||
return match ($int) {
|
||||
false => throw TypeCastingFailed::dueToInvalidValue($value, Type::Int->value, info: $this->info),
|
||||
default => $int,
|
||||
};
|
||||
}
|
||||
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): bool
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::Mixed, Type::Int, Type::Float)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
null !== $type || throw throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'int', 'float', 'null', 'mixed');
|
||||
|
||||
return $isNullable;
|
||||
}
|
||||
}
|
||||
93
vendor/league/csv/src/Serializer/CastToString.php
vendored
Normal file
93
vendor/league/csv/src/Serializer/CastToString.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
/**
|
||||
* @implements TypeCasting<?string>
|
||||
*/
|
||||
final class CastToString implements TypeCasting
|
||||
{
|
||||
private readonly bool $isNullable;
|
||||
private readonly Type $type;
|
||||
private ?string $default = null;
|
||||
private readonly TypeCastingInfo $variableName;
|
||||
|
||||
public function __construct(ReflectionProperty|ReflectionParameter $reflectionProperty)
|
||||
{
|
||||
[$this->type, $this->isNullable] = $this->init($reflectionProperty);
|
||||
$this->variableName = TypeCastingInfo::fromAccessor($reflectionProperty);
|
||||
}
|
||||
|
||||
public function info(): TypeCastingInfo
|
||||
{
|
||||
return $this->variableName;
|
||||
}
|
||||
|
||||
public function setOptions(
|
||||
?string $default = null,
|
||||
bool $emptyStringAsNull = false,
|
||||
): void {
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function toVariable(mixed $value): ?string
|
||||
{
|
||||
$returnedValue = match (true) {
|
||||
is_string($value) => $value,
|
||||
$this->isNullable => $this->default,
|
||||
default => throw TypeCastingFailed::dueToNotNullableType($this->type->value, info: $this->variableName),
|
||||
};
|
||||
|
||||
return match (true) {
|
||||
Type::Null->equals($this->type) && null !== $returnedValue => throw TypeCastingFailed::dueToInvalidValue(match (true) {
|
||||
null === $value => 'null',
|
||||
'' === $value => 'empty string',
|
||||
default => $value,
|
||||
}, $this->type->value, info: $this->variableName),
|
||||
default => $returnedValue,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Type, 1:bool}
|
||||
*/
|
||||
private function init(ReflectionProperty|ReflectionParameter $reflectionProperty): array
|
||||
{
|
||||
if (null === $reflectionProperty->getType()) {
|
||||
return [Type::Mixed, true];
|
||||
}
|
||||
|
||||
$type = null;
|
||||
$isNullable = false;
|
||||
foreach (Type::list($reflectionProperty) as $found) {
|
||||
if (!$isNullable && $found[1]->allowsNull()) {
|
||||
$isNullable = true;
|
||||
}
|
||||
|
||||
if (null === $type && $found[0]->isOneOf(Type::String, Type::Mixed, Type::Null)) {
|
||||
$type = $found;
|
||||
}
|
||||
}
|
||||
|
||||
null !== $type || throw throw MappingFailed::dueToTypeCastingUnsupportedType($reflectionProperty, $this, 'string', 'mixed', 'null');
|
||||
|
||||
return [$type[0], $isNullable];
|
||||
}
|
||||
}
|
||||
25
vendor/league/csv/src/Serializer/DenormalizationFailed.php
vendored
Normal file
25
vendor/league/csv/src/Serializer/DenormalizationFailed.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionProperty;
|
||||
use RuntimeException;
|
||||
|
||||
final class DenormalizationFailed extends RuntimeException implements SerializationFailed
|
||||
{
|
||||
public static function dueToUninitializedProperty(ReflectionProperty $reflectionProperty): self
|
||||
{
|
||||
return new self('The property '.$reflectionProperty->getDeclaringClass()->getName().'::'.$reflectionProperty->getName().' is not initialized; its value is missing from the source data.');
|
||||
}
|
||||
}
|
||||
461
vendor/league/csv/src/Serializer/Denormalizer.php
vendored
Normal file
461
vendor/league/csv/src/Serializer/Denormalizer.php
vendored
Normal file
@@ -0,0 +1,461 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Deprecated;
|
||||
use Iterator;
|
||||
use League\Csv\MapIterator;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use Throwable;
|
||||
|
||||
use function array_search;
|
||||
use function array_values;
|
||||
use function count;
|
||||
use function is_int;
|
||||
|
||||
final class Denormalizer
|
||||
{
|
||||
private static bool $convertEmptyStringToNull = true;
|
||||
|
||||
private readonly ReflectionClass $class;
|
||||
/** @var array<ReflectionProperty> */
|
||||
private readonly array $properties;
|
||||
/** @var array<PropertySetter> */
|
||||
private readonly array $propertySetters;
|
||||
/** @var array<ReflectionMethod> */
|
||||
private readonly array $afterMappingCalls;
|
||||
private readonly ?MapRecord $mapRecord;
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
* @param array<string> $propertyNames
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function __construct(string $className, array $propertyNames = [])
|
||||
{
|
||||
$this->class = $this->setClass($className);
|
||||
$this->properties = $this->class->getProperties();
|
||||
$this->mapRecord = MapRecord::tryFrom($this->class);
|
||||
$this->propertySetters = $this->setPropertySetters($propertyNames);
|
||||
$this->afterMappingCalls = $this->setAfterMappingCalls();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 9.17.0
|
||||
*
|
||||
* @see MapRecord::$convertEmptyStringToNull
|
||||
* @see MapCell::$convertEmptyStringToNull
|
||||
*
|
||||
* Enables converting empty string to the null value.
|
||||
*/
|
||||
#[Deprecated(message:'use League\Csv\Serializer\MapRecord::$convertEmptyStringToNull or League\Csv\Serializer\MapCell::$convertEmptyStringToNullinstead', since:'league/csv:9.17.0')]
|
||||
public static function allowEmptyStringAsNull(): void
|
||||
{
|
||||
self::$convertEmptyStringToNull = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since version 9.17.0
|
||||
*
|
||||
* @see MapRecord::$convertEmptyStringToNull
|
||||
* @see MapCell::$convertEmptyStringToNull
|
||||
*
|
||||
* Disables converting empty string to the null value.
|
||||
*/
|
||||
#[Deprecated(message:'use League\Csv\Serializer\MapRecord::$convertEmptyStringToNull or League\Csv\Serializer\MapCell::$convertEmptyStringToNullinstead', since:'league/csv:9.17.0')]
|
||||
public static function disallowEmptyStringAsNull(): void
|
||||
{
|
||||
self::$convertEmptyStringToNull = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a global type conversion callback to convert a field into a specific type.
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public static function registerType(string $type, Closure $callback): void
|
||||
{
|
||||
CallbackCasting::register($type, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a global type conversion callback to convert a field into a specific type.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static function unregisterType(string $type): bool
|
||||
{
|
||||
return CallbackCasting::unregisterType($type);
|
||||
}
|
||||
|
||||
public static function unregisterAllTypes(): void
|
||||
{
|
||||
CallbackCasting::unregisterTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to convert a field into a specific type.
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public static function registerAlias(string $alias, string $type, Closure $callback): void
|
||||
{
|
||||
CallbackCasting::register($type, $callback, $alias);
|
||||
}
|
||||
|
||||
public static function unregisterAlias(string $alias): bool
|
||||
{
|
||||
return CallbackCasting::unregisterAlias($alias);
|
||||
}
|
||||
|
||||
public static function unregisterAllAliases(): void
|
||||
{
|
||||
CallbackCasting::unregisterAliases();
|
||||
}
|
||||
|
||||
public static function unregisterAll(): void
|
||||
{
|
||||
CallbackCasting::unregisterAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public static function types(): array
|
||||
{
|
||||
$default = [...array_column(Type::cases(), 'value'), ...CallbackCasting::types()];
|
||||
|
||||
return array_values(array_unique($default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function aliases(): array
|
||||
{
|
||||
return CallbackCasting::aliases();
|
||||
}
|
||||
|
||||
public static function supportsAlias(string $alias): bool
|
||||
{
|
||||
return CallbackCasting::supportsAlias($alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
* @param array<array-key, mixed> $record
|
||||
*
|
||||
* @throws DenormalizationFailed
|
||||
* @throws MappingFailed
|
||||
* @throws ReflectionException
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public static function assign(string $className, array $record): object
|
||||
{
|
||||
return (new self($className, array_keys($record)))->denormalize($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
* @param array<string> $propertyNames
|
||||
*
|
||||
* @throws MappingFailed
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public static function assignAll(string $className, iterable $records, array $propertyNames = []): Iterator
|
||||
{
|
||||
return (new self($className, $propertyNames))->denormalizeAll($records);
|
||||
}
|
||||
|
||||
public function denormalizeAll(iterable $records): Iterator
|
||||
{
|
||||
return MapIterator::fromIterable($records, $this->denormalize(...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DenormalizationFailed
|
||||
* @throws ReflectionException
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function denormalize(array $record): object
|
||||
{
|
||||
$object = $this->class->newInstanceWithoutConstructor();
|
||||
$values = array_values($record);
|
||||
|
||||
foreach ($this->propertySetters as $propertySetter) {
|
||||
$propertySetter($object, $values);
|
||||
}
|
||||
|
||||
foreach ($this->afterMappingCalls as $callback) {
|
||||
$callback->invoke($object);
|
||||
}
|
||||
|
||||
foreach ($this->properties as $property) {
|
||||
$property->isInitialized($object) || throw DenormalizationFailed::dueToUninitializedProperty($property);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string $className
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function setClass(string $className): ReflectionClass
|
||||
{
|
||||
class_exists($className) || throw new MappingFailed('The class `'.$className.'` can not be denormalized; The class does not exist or could not be found.');
|
||||
|
||||
$class = new ReflectionClass($className);
|
||||
if ($class->isInternal() && $class->isFinal()) {
|
||||
throw new MappingFailed('The class `'.$className.'` can not be denormalized; PHP internal class marked as final can not be instantiated without using the constructor.');
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $propertyNames
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*
|
||||
* @return array<PropertySetter>
|
||||
*/
|
||||
private function setPropertySetters(array $propertyNames): array
|
||||
{
|
||||
$propertySetters = [];
|
||||
$methodNames = array_map(fn (string $propertyName) => 'set'.ucfirst($propertyName), $propertyNames);
|
||||
|
||||
foreach ([...$this->properties, ...$this->class->getMethods()] as $accessor) {
|
||||
$attributes = $accessor->getAttributes(MapCell::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
$propertySetter = match (count($attributes)) {
|
||||
0 => $this->autoDiscoverPropertySetter($accessor, $propertyNames, $methodNames),
|
||||
1 => $this->findPropertySetter($attributes[0]->newInstance(), $accessor, $propertyNames),
|
||||
default => throw new MappingFailed('Using more than one `'.MapCell::class.'` attribute on a class property or method is not supported.'),
|
||||
};
|
||||
if (null !== $propertySetter) {
|
||||
$propertySetters[] = $propertySetter;
|
||||
}
|
||||
}
|
||||
|
||||
return match ([]) {
|
||||
$propertySetters => throw new MappingFailed('No property or method from `'.$this->class->getName().'` could be used for denormalization.'),
|
||||
default => $propertySetters,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @return array<ReflectionMethod>
|
||||
*/
|
||||
private function setAfterMappingCalls(): array
|
||||
{
|
||||
return $this->mapRecord?->afterMappingMethods($this->class)
|
||||
?? AfterMapping::from($this->class)?->mapRecord->afterMappingMethods($this->class) /* @phpstan-ignore-line */
|
||||
?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $propertyNames
|
||||
* @param array<?string> $methodNames
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function autoDiscoverPropertySetter(ReflectionMethod|ReflectionProperty $accessor, array $propertyNames, array $methodNames): ?PropertySetter
|
||||
{
|
||||
if ($accessor->isStatic() || !$accessor->isPublic()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($accessor instanceof ReflectionMethod) {
|
||||
if ($accessor->isConstructor()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ([] === $accessor->getParameters()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (1 < $accessor->getNumberOfRequiredParameters()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** @var int|false $offset */
|
||||
/** @var ReflectionParameter|ReflectionProperty $reflectionProperty */
|
||||
[$offset, $reflectionProperty] = match (true) {
|
||||
$accessor instanceof ReflectionMethod => [array_search($accessor->getName(), $methodNames, true), $accessor->getParameters()[0]],
|
||||
$accessor instanceof ReflectionProperty => [array_search($accessor->getName(), $propertyNames, true), $accessor],
|
||||
};
|
||||
|
||||
return match (true) {
|
||||
false === $offset,
|
||||
null === $reflectionProperty->getType() => null,
|
||||
default => new PropertySetter(
|
||||
$accessor,
|
||||
$offset,
|
||||
$this->resolveTypeCasting($reflectionProperty),
|
||||
$this->mapRecord?->convertEmptyStringToNull ?? self::$convertEmptyStringToNull,
|
||||
$this->mapRecord?->trimFieldValueBeforeCasting ?? false
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $propertyNames
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function findPropertySetter(MapCell $mapCell, ReflectionMethod|ReflectionProperty $accessor, array $propertyNames): ?PropertySetter
|
||||
{
|
||||
if ($mapCell->ignore) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$typeCaster = $this->resolveTypeCaster($mapCell, $accessor);
|
||||
|
||||
$offset = $mapCell->column ?? match (true) {
|
||||
$accessor instanceof ReflectionMethod => $this->getMethodFirstArgument($accessor)->getName(),
|
||||
$accessor instanceof ReflectionProperty => $accessor->getName(),
|
||||
};
|
||||
|
||||
if (!is_int($offset)) {
|
||||
if ([] === $propertyNames) {
|
||||
throw new MappingFailed('offset as string are only supported if the property names list is not empty.');
|
||||
}
|
||||
|
||||
/** @var int<0, max>|false $index */
|
||||
$index = array_search($offset, $propertyNames, true);
|
||||
if (false === $index) {
|
||||
throw new MappingFailed('The `'.$offset.'` property could not be found in the property names list; Please verify your property names list.');
|
||||
}
|
||||
|
||||
$offset = $index;
|
||||
}
|
||||
|
||||
$reflectionProperty = match (true) {
|
||||
$accessor instanceof ReflectionMethod => $accessor->getParameters()[0],
|
||||
$accessor instanceof ReflectionProperty => $accessor,
|
||||
};
|
||||
|
||||
$convertEmptyStringToNull = $mapCell->convertEmptyStringToNull
|
||||
?? $this->mapRecord?->convertEmptyStringToNull
|
||||
?? self::$convertEmptyStringToNull;
|
||||
|
||||
$trimFieldValueBeforeCasting = $mapCell->trimFieldValueBeforeCasting
|
||||
?? $this->mapRecord?->trimFieldValueBeforeCasting
|
||||
?? false;
|
||||
|
||||
return match (true) {
|
||||
0 > $offset => throw new MappingFailed('offset integer position can only be positive or equals to 0; received `'.$offset.'`'),
|
||||
[] !== $propertyNames && $offset > count($propertyNames) - 1 => throw new MappingFailed('offset integer position can not exceed property names count.'),
|
||||
null === $typeCaster => new PropertySetter($accessor, $offset, $this->resolveTypeCasting($reflectionProperty, $mapCell->options), $convertEmptyStringToNull, $trimFieldValueBeforeCasting),
|
||||
default => new PropertySetter($accessor, $offset, $this->getTypeCasting($typeCaster, $reflectionProperty, $mapCell->options), $convertEmptyStringToNull, $trimFieldValueBeforeCasting),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function getMethodFirstArgument(ReflectionMethod $reflectionMethod): ReflectionParameter
|
||||
{
|
||||
$arguments = $reflectionMethod->getParameters();
|
||||
|
||||
return match (true) {
|
||||
[] === $arguments => throw new MappingFailed('The method `'.$reflectionMethod->getDeclaringClass()->getName().'::'.$reflectionMethod->getName().'` does not use parameters.'),
|
||||
1 < $reflectionMethod->getNumberOfRequiredParameters() => throw new MappingFailed('The method `'.$reflectionMethod->getDeclaringClass()->getName().'::'.$reflectionMethod->getName().'` has too many required parameters.'),
|
||||
default => $arguments[0]
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function getTypeCasting(
|
||||
string $typeCaster,
|
||||
ReflectionProperty|ReflectionParameter $reflectionProperty,
|
||||
array $options
|
||||
): TypeCasting {
|
||||
try {
|
||||
/** @var TypeCasting $cast */
|
||||
$cast = match (str_starts_with($typeCaster, CallbackCasting::class.'@')) {
|
||||
true => new CallbackCasting($reflectionProperty, substr($typeCaster, strlen(CallbackCasting::class))),
|
||||
false => new $typeCaster($reflectionProperty),
|
||||
};
|
||||
$cast->setOptions(...$options);
|
||||
|
||||
return $cast;
|
||||
} catch (MappingFailed $exception) {
|
||||
throw $exception;
|
||||
} catch (Throwable $exception) {
|
||||
throw MappingFailed::dueToInvalidCastingArguments($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
private function resolveTypeCasting(ReflectionProperty|ReflectionParameter $reflectionProperty, array $options = []): TypeCasting
|
||||
{
|
||||
$castResolver = function (ReflectionProperty|ReflectionParameter $reflectionProperty, $options): CallbackCasting {
|
||||
$cast = new CallbackCasting($reflectionProperty);
|
||||
$cast->setOptions(...$options);
|
||||
|
||||
return $cast;
|
||||
};
|
||||
|
||||
try {
|
||||
return match (true) {
|
||||
CallbackCasting::supports($reflectionProperty) => $castResolver($reflectionProperty, $options),
|
||||
default => Type::resolve($reflectionProperty, $options),
|
||||
};
|
||||
} catch (MappingFailed $exception) {
|
||||
throw $exception;
|
||||
} catch (Throwable $exception) {
|
||||
throw MappingFailed::dueToInvalidCastingArguments($exception);
|
||||
}
|
||||
}
|
||||
|
||||
public function resolveTypeCaster(MapCell $mapCell, ReflectionMethod|ReflectionProperty $accessor): ?string
|
||||
{
|
||||
/** @var ?class-string<TypeCasting> $typeCaster */
|
||||
$typeCaster = $mapCell->cast;
|
||||
if (null === $typeCaster) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (class_exists($typeCaster)) {
|
||||
if (!(new ReflectionClass($typeCaster))->implementsInterface(TypeCasting::class)) {
|
||||
throw MappingFailed::dueToInvalidTypeCastingClass($typeCaster);
|
||||
}
|
||||
|
||||
return $typeCaster;
|
||||
}
|
||||
|
||||
if ($accessor instanceof ReflectionMethod) {
|
||||
$accessor = $accessor->getParameters()[0];
|
||||
}
|
||||
|
||||
if (!CallbackCasting::supports($accessor, $typeCaster)) {
|
||||
throw MappingFailed::dueToInvalidTypeCastingClass($typeCaster);
|
||||
}
|
||||
|
||||
return CallbackCasting::class.$typeCaster;
|
||||
}
|
||||
}
|
||||
33
vendor/league/csv/src/Serializer/MapCell.php
vendored
Normal file
33
vendor/league/csv/src/Serializer/MapCell.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_PROPERTY)]
|
||||
final class MapCell
|
||||
{
|
||||
/**
|
||||
* @param class-string|string|null $cast
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string|int|null $column = null,
|
||||
public readonly ?string $cast = null,
|
||||
public readonly array $options = [],
|
||||
public readonly bool $ignore = false,
|
||||
public readonly ?bool $convertEmptyStringToNull = null,
|
||||
public readonly ?bool $trimFieldValueBeforeCasting = false,
|
||||
) {
|
||||
}
|
||||
}
|
||||
71
vendor/league/csv/src/Serializer/MapRecord.php
vendored
Normal file
71
vendor/league/csv/src/Serializer/MapRecord.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Attribute;
|
||||
use ReflectionAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionMethod;
|
||||
use ValueError;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
final class MapRecord
|
||||
{
|
||||
public function __construct(
|
||||
/** @var array<string> $afterMapping */
|
||||
public readonly array $afterMapping = [],
|
||||
public readonly ?bool $convertEmptyStringToNull = null,
|
||||
public readonly bool $trimFieldValueBeforeCasting = false,
|
||||
) {
|
||||
foreach ($this->afterMapping as $method) {
|
||||
is_string($method) || throw new ValueError('The method names must be string.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<ReflectionMethod>
|
||||
*/
|
||||
public function afterMappingMethods(ReflectionClass $class): array
|
||||
{
|
||||
$methods = [];
|
||||
foreach ($this->afterMapping as $method) {
|
||||
try {
|
||||
$accessor = $class->getMethod($method);
|
||||
} catch (ReflectionException $exception) {
|
||||
throw new MappingFailed('The method `'.$method.'` is not defined on the `'.$class->getName().'` class.', 0, $exception);
|
||||
}
|
||||
|
||||
0 === $accessor->getNumberOfRequiredParameters() || throw new MappingFailed('The method `'.$class->getName().'::'.$accessor->getName().'` has too many required parameters.');
|
||||
$methods[] = $accessor;
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public static function tryFrom(ReflectionClass $class): ?self
|
||||
{
|
||||
$attributes = $class->getAttributes(self::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
$nbAttributes = count($attributes);
|
||||
|
||||
return match ($nbAttributes) {
|
||||
0 => null,
|
||||
1 => $attributes[0]->newInstance(),
|
||||
default => throw new MappingFailed('Using more than one `'.self::class.'` attribute on a class property or method is not supported.'),
|
||||
};
|
||||
}
|
||||
}
|
||||
56
vendor/league/csv/src/Serializer/MappingFailed.php
vendored
Normal file
56
vendor/league/csv/src/Serializer/MappingFailed.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 LogicException;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use Throwable;
|
||||
|
||||
final class MappingFailed extends LogicException implements SerializationFailed
|
||||
{
|
||||
public static function dueToUnsupportedType(ReflectionProperty|ReflectionParameter $reflectionProperty): self
|
||||
{
|
||||
$suffix = 'is missing; register it using the `'.Denormalizer::class.'` class.';
|
||||
|
||||
return new self(match (true) {
|
||||
$reflectionProperty instanceof ReflectionParameter => 'The type definition for the method `'.$reflectionProperty->getDeclaringClass()?->getName().'::'.$reflectionProperty->getDeclaringFunction()->getName().'` first argument `'.$reflectionProperty->getName().'` '.$suffix,
|
||||
$reflectionProperty instanceof ReflectionProperty => 'The property type definition for `'.$reflectionProperty->getDeclaringClass()->getName().'::'.$reflectionProperty->getName().'` '.$suffix,
|
||||
});
|
||||
}
|
||||
|
||||
public static function dueToTypeCastingUnsupportedType(
|
||||
ReflectionProperty|ReflectionParameter $reflectionProperty,
|
||||
TypeCasting $typeCasting,
|
||||
string ...$types
|
||||
): self {
|
||||
|
||||
$suffix = 'is invalid; `'.implode('` or `', $types).'` type must be used with the `'.$typeCasting::class.'`.';
|
||||
|
||||
return new self(match (true) {
|
||||
$reflectionProperty instanceof ReflectionParameter => 'The type for the method `'.$reflectionProperty->getDeclaringClass()?->getName().'::'.$reflectionProperty->getDeclaringFunction()->getName().'` first argument `'.$reflectionProperty->getName().'` '.$suffix,
|
||||
$reflectionProperty instanceof ReflectionProperty => 'The property type for `'.$reflectionProperty->getDeclaringClass()->getName().'::'.$reflectionProperty->getName().'` '.$suffix,
|
||||
});
|
||||
}
|
||||
|
||||
public static function dueToInvalidCastingArguments(?Throwable $exception = null): self
|
||||
{
|
||||
return new self('Unable to load the casting mechanism. Please verify your casting arguments', 0, $exception);
|
||||
}
|
||||
|
||||
public static function dueToInvalidTypeCastingClass(string $typeCaster): self
|
||||
{
|
||||
return new self('`'.$typeCaster.'` must be an resolvable class implementing the `'.TypeCasting::class.'` interface or a supported alias.');
|
||||
}
|
||||
}
|
||||
71
vendor/league/csv/src/Serializer/PropertySetter.php
vendored
Normal file
71
vendor/league/csv/src/Serializer/PropertySetter.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionException;
|
||||
use ReflectionMethod;
|
||||
use ReflectionProperty;
|
||||
|
||||
use function array_key_exists;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class PropertySetter
|
||||
{
|
||||
public function __construct(
|
||||
public readonly ReflectionMethod|ReflectionProperty $accessor,
|
||||
public readonly int $offset,
|
||||
public readonly TypeCasting $cast,
|
||||
public readonly bool $convertEmptyStringToNull,
|
||||
public readonly bool $trimFieldValueBeforeCasting,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReflectionException
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
public function __invoke(object $object, array $recordValues): void
|
||||
{
|
||||
$typeCastedValue = $this->cast->toVariable($this->getRecordValue($recordValues));
|
||||
|
||||
match (true) {
|
||||
$this->accessor instanceof ReflectionMethod => $this->accessor->invoke($object, $typeCastedValue),
|
||||
$this->accessor instanceof ReflectionProperty => $this->accessor->setValue($object, $typeCastedValue),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*/
|
||||
private function getRecordValue(array $record): mixed
|
||||
{
|
||||
if (!array_key_exists($this->offset, $record)) {
|
||||
throw TypeCastingFailed::dueToUndefinedValue($this->offset, TypeCastingInfo::fromAccessor($this->accessor));
|
||||
}
|
||||
|
||||
$value = $record[$this->offset];
|
||||
if (is_string($value) && $this->trimFieldValueBeforeCasting) {
|
||||
$value = trim($value);
|
||||
}
|
||||
|
||||
if ('' === $value && $this->convertEmptyStringToNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
20
vendor/league/csv/src/Serializer/SerializationFailed.php
vendored
Normal file
20
vendor/league/csv/src/Serializer/SerializationFailed.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 Throwable;
|
||||
|
||||
interface SerializationFailed extends Throwable
|
||||
{
|
||||
}
|
||||
163
vendor/league/csv/src/Serializer/Type.php
vendored
Normal file
163
vendor/league/csv/src/Serializer/Type.php
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Csv\Serializer;
|
||||
|
||||
use DateTimeInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use ReflectionType;
|
||||
use ReflectionUnionType;
|
||||
use Throwable;
|
||||
use UnitEnum;
|
||||
|
||||
use function class_exists;
|
||||
use function enum_exists;
|
||||
use function in_array;
|
||||
|
||||
use const FILTER_UNSAFE_RAW;
|
||||
use const FILTER_VALIDATE_BOOL;
|
||||
use const FILTER_VALIDATE_FLOAT;
|
||||
use const FILTER_VALIDATE_INT;
|
||||
|
||||
enum Type: string
|
||||
{
|
||||
case Bool = 'bool';
|
||||
case True = 'true';
|
||||
case False = 'false';
|
||||
case Null = 'null';
|
||||
case Int = 'int';
|
||||
case Float = 'float';
|
||||
case String = 'string';
|
||||
case Mixed = 'mixed';
|
||||
case Array = 'array';
|
||||
case Iterable = 'iterable';
|
||||
case Enum = UnitEnum::class;
|
||||
case Date = DateTimeInterface::class;
|
||||
|
||||
public function equals(mixed $value): bool
|
||||
{
|
||||
return $value instanceof self
|
||||
&& $value === $this;
|
||||
}
|
||||
|
||||
public function isOneOf(self ...$types): bool
|
||||
{
|
||||
return in_array($this, $types, true);
|
||||
}
|
||||
|
||||
public function filterFlag(): int
|
||||
{
|
||||
return match ($this) {
|
||||
self::Bool,
|
||||
self::True,
|
||||
self::False => FILTER_VALIDATE_BOOL,
|
||||
self::Int => FILTER_VALIDATE_INT,
|
||||
self::Float => FILTER_VALIDATE_FLOAT,
|
||||
default => FILTER_UNSAFE_RAW,
|
||||
};
|
||||
}
|
||||
|
||||
public static function resolve(ReflectionProperty|ReflectionParameter $reflectionProperty, array $arguments = []): TypeCasting
|
||||
{
|
||||
try {
|
||||
$cast = match (self::tryFromAccessor($reflectionProperty)) {
|
||||
self::Mixed, self::Null, self::String => new CastToString($reflectionProperty),
|
||||
self::Iterable, self::Array => new CastToArray($reflectionProperty),
|
||||
self::False, self::True, self::Bool => new CastToBool($reflectionProperty),
|
||||
self::Float => new CastToFloat($reflectionProperty),
|
||||
self::Int => new CastToInt($reflectionProperty),
|
||||
self::Date => new CastToDate($reflectionProperty),
|
||||
self::Enum => new CastToEnum($reflectionProperty),
|
||||
null => throw MappingFailed::dueToUnsupportedType($reflectionProperty),
|
||||
};
|
||||
|
||||
$cast->setOptions(...$arguments);
|
||||
|
||||
return $cast;
|
||||
} catch (MappingFailed $exception) {
|
||||
throw $exception;
|
||||
} catch (Throwable $exception) {
|
||||
throw MappingFailed::dueToInvalidCastingArguments($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{0:Type, 1: ReflectionNamedType}>
|
||||
*/
|
||||
public static function list(ReflectionParameter|ReflectionProperty $reflectionProperty): array
|
||||
{
|
||||
$reflectionType = $reflectionProperty->getType() ?? throw MappingFailed::dueToUnsupportedType($reflectionProperty);
|
||||
|
||||
$foundTypes = static function (array $res, ReflectionType $reflectionType) {
|
||||
if (!$reflectionType instanceof ReflectionNamedType) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
$type = self::tryFromName($reflectionType->getName());
|
||||
if (null !== $type) {
|
||||
$res[] = [$type, $reflectionType];
|
||||
}
|
||||
|
||||
return $res;
|
||||
};
|
||||
|
||||
return match (true) {
|
||||
$reflectionType instanceof ReflectionNamedType => $foundTypes([], $reflectionType),
|
||||
$reflectionType instanceof ReflectionUnionType => array_reduce($reflectionType->getTypes(), $foundTypes, []),
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
public static function tryFromName(string $propertyType): ?self
|
||||
{
|
||||
$interfaceExists = interface_exists($propertyType);
|
||||
|
||||
return match (true) {
|
||||
enum_exists($propertyType),
|
||||
$interfaceExists && (new ReflectionClass($propertyType))->implementsInterface(UnitEnum::class) => self::Enum,
|
||||
$interfaceExists && (new ReflectionClass($propertyType))->implementsInterface(DateTimeInterface::class),
|
||||
class_exists($propertyType) && (new ReflectionClass($propertyType))->implementsInterface(DateTimeInterface::class) => self::Date,
|
||||
default => self::tryFrom($propertyType),
|
||||
};
|
||||
}
|
||||
|
||||
public static function tryFromAccessor(ReflectionProperty|ReflectionParameter $reflectionProperty): ?self
|
||||
{
|
||||
$type = $reflectionProperty->getType();
|
||||
if (null === $type) {
|
||||
return Type::Mixed;
|
||||
}
|
||||
|
||||
if ($type instanceof ReflectionNamedType) {
|
||||
return self::tryFromName($type->getName());
|
||||
}
|
||||
|
||||
if (!$type instanceof ReflectionUnionType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($type->getTypes() as $innerType) {
|
||||
if (!$innerType instanceof ReflectionNamedType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = self::tryFromName($innerType->getName());
|
||||
if ($result instanceof self) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
38
vendor/league/csv/src/Serializer/TypeCasting.php
vendored
Normal file
38
vendor/league/csv/src/Serializer/TypeCasting.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @template TValue
|
||||
*
|
||||
* @method TypeCastingInfo info() the name of the property the value will be assigned to
|
||||
*/
|
||||
interface TypeCasting
|
||||
{
|
||||
/**
|
||||
* @throws TypeCastingFailed
|
||||
*
|
||||
* @return TValue
|
||||
*/
|
||||
public function toVariable(mixed $value): mixed;
|
||||
|
||||
/**
|
||||
* Accepts additional parameters to configure the class
|
||||
* Parameters should be scalar value, null or array containing
|
||||
* only scalar value and null.
|
||||
*
|
||||
* @throws MappingFailed
|
||||
*/
|
||||
public function setOptions(): void;
|
||||
}
|
||||
74
vendor/league/csv/src/Serializer/TypeCastingFailed.php
vendored
Normal file
74
vendor/league/csv/src/Serializer/TypeCastingFailed.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
use function is_int;
|
||||
|
||||
final class TypeCastingFailed extends RuntimeException implements SerializationFailed
|
||||
{
|
||||
public readonly ?TypeCastingInfo $info;
|
||||
|
||||
public function __construct(string $message, int $code = 0, ?Throwable $previous = null, ?TypeCastingInfo $info = null)
|
||||
{
|
||||
parent::__construct(self::format($message, $info), $code, $previous);
|
||||
|
||||
$this->info = $info;
|
||||
}
|
||||
|
||||
private static function format(string $message, ?TypeCastingInfo $info = null): string
|
||||
{
|
||||
if (null === $info) {
|
||||
return $message;
|
||||
}
|
||||
|
||||
$className = $info->targetClassName;
|
||||
if (null !== $className) {
|
||||
$className .= '::';
|
||||
}
|
||||
|
||||
$target = $info->targetName;
|
||||
$target = (TypeCastingTargetType::MethodFirstArgument === $info->targetType)
|
||||
? 'the first argument `'.$target.'` of the method `'.$className.$info->targetMethodName.'()`'
|
||||
: 'the property `'.$className.$target.'`';
|
||||
|
||||
$source = $info->source;
|
||||
$source = is_int($source)
|
||||
? "the record field offset `$source`"
|
||||
: "the record field `$source`";
|
||||
|
||||
return "Casting $target using $source failed; $message";
|
||||
}
|
||||
|
||||
public static function dueToNotNullableType(string $type, ?Throwable $exception = null, ?TypeCastingInfo $info = null): self
|
||||
{
|
||||
return new self('The `null` value can not be cast to a `'.$type.'`; the property type is not nullable.', 0, $exception, $info);
|
||||
}
|
||||
|
||||
public static function dueToInvalidValue(mixed $value, string $type, ?Throwable $previous = null, ?TypeCastingInfo $info = null): self
|
||||
{
|
||||
if (!is_scalar($value)) {
|
||||
$value = gettype($value);
|
||||
}
|
||||
|
||||
return new self('Unable to cast the given data `'.$value.'` to a `'.$type.'`.', 0, $previous, $info);
|
||||
}
|
||||
|
||||
public static function dueToUndefinedValue(string|int $offset, ?TypeCastingInfo $info = null): self
|
||||
{
|
||||
return new self('Unable to cast the record value; Missing value was for offset `'.$offset.'`.', 0, info: $info);
|
||||
}
|
||||
}
|
||||
111
vendor/league/csv/src/Serializer/TypeCastingInfo.php
vendored
Normal file
111
vendor/league/csv/src/Serializer/TypeCastingInfo.php
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* 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 ReflectionAttribute;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
use ValueError;
|
||||
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
final class TypeCastingInfo
|
||||
{
|
||||
public function __construct(
|
||||
public readonly int|string $source,
|
||||
public readonly TypeCastingTargetType $targetType,
|
||||
public readonly string $targetName,
|
||||
public readonly ?string $targetMethodName,
|
||||
public readonly ?string $targetClassName,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function fromAccessor(ReflectionMethod|ReflectionProperty|ReflectionParameter $accessor): self
|
||||
{
|
||||
return match (true) {
|
||||
$accessor instanceof ReflectionMethod => self::fromMethod($accessor),
|
||||
$accessor instanceof ReflectionParameter => self::fromMethodFirstArgument($accessor),
|
||||
$accessor instanceof ReflectionProperty => self::fromProperty($accessor),
|
||||
};
|
||||
}
|
||||
|
||||
public static function fromMethod(ReflectionMethod $accessor): self
|
||||
{
|
||||
$accessor = $accessor->getParameters()[0] ?? null;
|
||||
if (null === $accessor) {
|
||||
throw new ValueError('The method must contain at least one parameter in its signature.');
|
||||
}
|
||||
|
||||
return self::fromMethodFirstArgument($accessor);
|
||||
}
|
||||
|
||||
public static function fromMethodFirstArgument(ReflectionParameter $accessor): self
|
||||
{
|
||||
/** @var ReflectionMethod $method */
|
||||
$method = $accessor->getDeclaringFunction();
|
||||
$className = $method->getDeclaringClass()->getName();
|
||||
|
||||
return new self(
|
||||
self::resolveSource($method),
|
||||
TypeCastingTargetType::MethodFirstArgument,
|
||||
$accessor->getName(),
|
||||
$method->getName(),
|
||||
$className,
|
||||
);
|
||||
}
|
||||
|
||||
public static function fromProperty(ReflectionProperty $accessor): self
|
||||
{
|
||||
$attributes = $accessor->getAttributes(MapCell::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
$source = [] === $attributes ? $accessor->getName() : ($attributes[0]->newInstance()->column ?? $accessor->getName());
|
||||
|
||||
$className = $accessor->getDeclaringClass()->getName();
|
||||
|
||||
return new self(
|
||||
$source,
|
||||
TypeCastingTargetType::PropertyName,
|
||||
$accessor->getName(),
|
||||
null,
|
||||
$className,
|
||||
);
|
||||
}
|
||||
|
||||
private static function resolveSource(ReflectionFunctionAbstract $method): int|string
|
||||
{
|
||||
$attributes = $method->getAttributes(MapCell::class, ReflectionAttribute::IS_INSTANCEOF);
|
||||
if ([] === $attributes) {
|
||||
return self::getColumnName($method);
|
||||
}
|
||||
|
||||
$name = $attributes[0]->newInstance()->column;
|
||||
if (null !== $name) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
return self::getColumnName($method);
|
||||
}
|
||||
|
||||
private static function getColumnName(ReflectionFunctionAbstract $method): string
|
||||
{
|
||||
$name = $method->getName();
|
||||
if (!str_starts_with($name, 'set')) {
|
||||
throw new ValueError('The method `'.$name.'` has no Mapping information and does not start with `set`.');
|
||||
}
|
||||
|
||||
return strtolower($name[3]).substr($name, 4);
|
||||
}
|
||||
}
|
||||
30
vendor/league/csv/src/Serializer/TypeCastingTargetType.php
vendored
Normal file
30
vendor/league/csv/src/Serializer/TypeCastingTargetType.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Csv (https://csv.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\Csv\Serializer;
|
||||
|
||||
use ReflectionParameter;
|
||||
use ReflectionProperty;
|
||||
|
||||
enum TypeCastingTargetType
|
||||
{
|
||||
case PropertyName;
|
||||
case MethodFirstArgument;
|
||||
|
||||
public static function fromAccessor(ReflectionParameter|ReflectionProperty $accessor): self
|
||||
{
|
||||
if ($accessor instanceof ReflectionProperty) {
|
||||
return self::PropertyName;
|
||||
}
|
||||
|
||||
return self::MethodFirstArgument;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user