Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [ 8.2 ]
php: [ 8.2, 8.3, 8.4 ]

steps:
- name: Checkout code
Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
php-version: 8.4
extensions: dom, curl, libxml, mbstring, zip
tools: composer:v2
coverage: none
Expand All @@ -76,7 +76,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [ 8.2 ]
php: [ 8.2, 8.3, 8.4 ]
steps:
- name: Checkout code
uses: actions/checkout@v3
Expand Down
18 changes: 9 additions & 9 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
],
"require": {
"php": ">=8.2",
"good-php/reflection": "^1.0",
"illuminate/support": "^10.0 || ^11.0"
"good-php/reflection": "^2.0",
"illuminate/support": "^10.0 || ^11.0 || ^12.0"
},
"require-dev": {
"pestphp/pest": "^2.8",
"php-cs-fixer/shim": "~3.19.2",
"tenantcloud/php-cs-fixer-rule-sets": "~3.0.0",
"phpstan/phpstan": "~1.10.21",
"phpstan/phpstan-phpunit": "^1.3",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpstan/phpstan-mockery": "^1.1",
"pestphp/pest": "^3.8",
"php-cs-fixer/shim": "~3.80.0",
"tenantcloud/php-cs-fixer-rule-sets": "~3.4.1",
"phpstan/phpstan": "~2.1.17",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-webmozart-assert": "^2.0",
"phpstan/phpstan-mockery": "^2.0",
"phake/phake": "^4.2",
"tenantcloud/php-standard": "^2.2"
},
Expand Down
3 changes: 1 addition & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ parameters:
- src

ignoreErrors:
# There's no extension for that :(
# - '#Call to an undefined method Pest\\Expectations\\Expectation|Pest\\Expectations\\Support\\Extendable::#i'
- '#Parameter (\#|\$).* expects list<(.*)>, array<int, \2> given.#i'
2 changes: 1 addition & 1 deletion src/Serializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ public function reflector(): Reflector;
*
* @return A
*/
public function adapter(string $typeAdapterType, Type|string $type, Attributes $attributes = new ArrayAttributes(), TypeAdapterFactory $skipPast = null): TypeAdapter;
public function adapter(string $typeAdapterType, Type|string $type, Attributes $attributes = new ArrayAttributes(), ?TypeAdapterFactory $skipPast = null): TypeAdapter;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function __construct(
*
* @return TypeAdapterType
*/
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), TypeAdapterFactory $skipPast = null): TypeAdapter
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), ?TypeAdapterFactory $skipPast = null): TypeAdapter
{
$this->resolved[$typeAdapterType][(string) $type] ??= new WeakMap();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function __construct(
*
* @return TypeAdapterType
*/
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), TypeAdapterFactory $skipPast = null): TypeAdapter
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), ?TypeAdapterFactory $skipPast = null): TypeAdapter
{
if ($skipPast) {
$skipPastIndex = array_search($skipPast, $this->factories, true);
Expand Down
2 changes: 1 addition & 1 deletion src/Serializer/Registry/TypeAdapterNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class TypeAdapterNotFoundException extends RuntimeException
/**
* @param TypeAdapterFactory<TypeAdapter<mixed, mixed>>|null $skipPast
*/
public function __construct(string $typeAdapterType, Type $type, Attributes $attributes, ?TypeAdapterFactory $skipPast, Throwable $previous = null)
public function __construct(string $typeAdapterType, Type $type, Attributes $attributes, ?TypeAdapterFactory $skipPast, ?Throwable $previous = null)
{
$message = "A matching type adapter of type '{$typeAdapterType}' for type '{$type}' " .
($attributes->has() ? 'with attributes ' . $attributes : '') .
Expand Down
2 changes: 1 addition & 1 deletion src/Serializer/Registry/TypeAdapterRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ interface TypeAdapterRegistry
*
* @return TypeAdapterType
*/
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), TypeAdapterFactory $skipPast = null): TypeAdapter;
public function forType(string $typeAdapterType, Serializer $serializer, Type $type, Attributes $attributes = new ArrayAttributes(), ?TypeAdapterFactory $skipPast = null): TypeAdapter;
}
2 changes: 1 addition & 1 deletion src/Serializer/TypeAdapterRegistrySerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct(
private readonly Reflector $reflector,
) {}

public function adapter(string $typeAdapterType, Type|string $type, Attributes $attributes = new ArrayAttributes(), TypeAdapterFactory $skipPast = null): TypeAdapter
public function adapter(string $typeAdapterType, Type|string $type, Attributes $attributes = new ArrayAttributes(), ?TypeAdapterFactory $skipPast = null): TypeAdapter
{
if (is_string($type)) {
$type = new NamedType($type);
Expand Down
2 changes: 1 addition & 1 deletion src/TypeAdapter/Exception/UnexpectedEnumValueException.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class UnexpectedEnumValueException extends RuntimeException implements Unexpecte
public function __construct(
public readonly string|int $value,
public readonly array $expectedValues,
Throwable $previous = null
?Throwable $previous = null
) {
parent::__construct(
'Expected one of [' .
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function __construct(
public readonly string $typeNameField,
public readonly string $value,
public readonly array $expectedTypeNames,
Throwable $previous = null
?Throwable $previous = null
) {
parent::__construct(
"Only the following polymorphic types for field '{$this->typeNameField}' are allowed: [" .
Expand Down
2 changes: 1 addition & 1 deletion src/TypeAdapter/Exception/UnexpectedTypeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class UnexpectedTypeException extends RuntimeException
public function __construct(
public readonly mixed $value,
public readonly Type $expectedType,
Throwable $previous = null
?Throwable $previous = null
) {
parent::__construct(
"Expected value of type '{$expectedType}', but got '" .
Expand Down
4 changes: 1 addition & 3 deletions src/TypeAdapter/Exception/UnexpectedValueException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@

use Throwable;

interface UnexpectedValueException extends Throwable
{
}
interface UnexpectedValueException extends Throwable {}
3 changes: 3 additions & 0 deletions src/TypeAdapter/Json/FromPrimitiveJsonTypeAdapterFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
final class FromPrimitiveJsonTypeAdapterFactory implements TypeAdapterFactory
{
/**
* @return JsonTypeAdapter<mixed>|null
*/
public function create(string $typeAdapterType, Type $type, Attributes $attributes, Serializer $serializer): ?JsonTypeAdapter
{
if ($typeAdapterType !== JsonTypeAdapter::class) {
Expand Down
4 changes: 1 addition & 3 deletions src/TypeAdapter/Json/JsonTypeAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@
*
* @extends TypeAdapter<T, string>
*/
interface JsonTypeAdapter extends TypeAdapter
{
}
interface JsonTypeAdapter extends TypeAdapter {}
12 changes: 6 additions & 6 deletions src/TypeAdapter/Primitive/BuiltIn/ArrayMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ final class ArrayMapper
/**
* @template T
*
* @param array<T> $value
* @param NamedType $type
* @param array<mixed, T> $value
* @param NamedType $type
*
* @return array<mixed>
* @return array<mixed, mixed>|stdClass
*/
#[MapTo(PrimitiveTypeAdapter::class)]
public function to(array $value, Type $type, Serializer $serializer): array|stdClass
Expand Down Expand Up @@ -49,10 +49,10 @@ public function to(array $value, Type $type, Serializer $serializer): array|stdC
}

/**
* @param array<mixed> $value
* @param NamedType $type
* @param array<mixed, mixed> $value
* @param NamedType $type
*
* @return array<mixed>
* @return array<mixed, mixed>
*/
#[MapFrom(PrimitiveTypeAdapter::class)]
public function from(array $value, Type $type, Serializer $serializer): array
Expand Down
1 change: 1 addition & 0 deletions src/TypeAdapter/Primitive/BuiltIn/BackedEnumMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public function to(BackedEnum $value): string|int
#[MapFrom(PrimitiveTypeAdapter::class, new BaseTypeAcceptedByAcceptanceStrategy(BackedEnum::class))]
public function from(string|int $value, Type $type): BackedEnum
{
/** @var class-string<BackedEnum> $enumClass */
$enumClass = $type->name;
$enum = $enumClass::tryFrom($value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
*/
class NullableTypeAdapterFactory implements TypeAdapterFactory
{
/**
* @return NullableTypeAdapter<mixed>|null
*/
public function create(string $typeAdapterType, Type $type, Attributes $attributes, Serializer $serializer): ?NullableTypeAdapter
{
if ($typeAdapterType !== PrimitiveTypeAdapter::class || !$type instanceof NullableType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use GoodPhp\Serialization\TypeAdapter\Primitive\ClassProperties\Property\BoundClassProperty;
use GoodPhp\Serialization\TypeAdapter\Primitive\PrimitiveTypeAdapter;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

/**
* @template T of object
Expand All @@ -20,13 +19,13 @@
final class ClassPropertiesPrimitiveTypeAdapter implements PrimitiveTypeAdapter
{
/**
* @param class-string<T> $className
* @param Collection<int, BoundClassProperty<T>> $properties
* @param class-string<T> $className
* @param list<BoundClassProperty<T>> $properties
*/
public function __construct(
private readonly Hydrator $hydrator,
private readonly string $className,
private readonly Collection $properties,
private readonly array $properties,
) {}

public function serialize(mixed $value): mixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public function __construct(
private readonly BoundClassPropertyFactory $boundClassPropertyFactory,
) {}

/**
* @return ClassPropertiesPrimitiveTypeAdapter<object>|null
*/
public function create(string $typeAdapterType, Type $type, Attributes $attributes, Serializer $serializer): ?ClassPropertiesPrimitiveTypeAdapter
{
if ($typeAdapterType !== PrimitiveTypeAdapter::class || !$type instanceof NamedType) {
Expand All @@ -43,14 +46,14 @@ public function create(string $typeAdapterType, Type $type, Attributes $attribut
return new ClassPropertiesPrimitiveTypeAdapter(
$this->hydrator,
$className,
$reflection->properties()->map(function (PropertyReflection $property) use ($serializer, $typeAdapterType) {
array_map(function (PropertyReflection $property) use ($serializer, $typeAdapterType) {
$serializedName = $this->namingStrategy->translate($property);

return PropertyMappingException::rethrow(
$serializedName,
fn () => $this->boundClassPropertyFactory->create($typeAdapterType, $serializedName, $property, $serializer),
);
})
}, $reflection->properties())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class MissingValueException extends RuntimeException
{
public function __construct(Throwable $previous = null)
public function __construct(?Throwable $previous = null)
{
parent::__construct('Missing value.', 0, $previous);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY)]
class Flatten
{
}
class Flatten {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY)]
class UseDefaultForUnexpected
{
}
class UseDefaultForUnexpected {}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
final class InstanceMapperMethod implements MapperMethod
{
/**
* @param AdapterType $adapter
* @param MethodReflection<AdapterType, HasMethods<AdapterType>> $method
* @param AdapterType $adapter
*/
public function __construct(
private readonly MethodReflection $method,
Expand All @@ -38,7 +38,7 @@ public function accepts(NamedType $type, Attributes $attributes, Serializer $ser

public function invoke(mixed $value, Type $type, Attributes $attributes, Serializer $serializer, MapperMethodsPrimitiveTypeAdapterFactory $skipPast): mixed
{
$map = [
$injectables = [
MapperMethodsPrimitiveTypeAdapterFactory::class => $skipPast,
Serializer::class => $serializer,
Type::class => $type,
Expand All @@ -50,25 +50,34 @@ public function invoke(mixed $value, Type $type, Attributes $attributes, Seriali
return $this->method->invoke(
$this->adapter,
$value,
...$this->method
->parameters()
->slice(1)
->map(function (FunctionParameterReflection $parameter) use ($map) {
$type = $parameter->type();

Assert::isInstanceOf($type, NamedType::class);
Assert::keyExists($map, $type->name);

return $map[$type->name];
})
...$this->invokeParameters($injectables),
);
} catch (TypeError $e) {
if (!str_contains($e->getMessage(), 'Argument #1')) {
throw $e;
}

/* @phpstan-ignore-next-line argument.type */
throw new UnexpectedTypeException($value, $this->method->parameters()->firstOrFail()->type());
throw new UnexpectedTypeException($value, $this->method->parameters()[0]->type());
}
}

/**
* @param array<class-string, mixed> $injectables
*
* @return list<mixed>
*/
private function invokeParameters(array $injectables): array
{
$parameters = array_slice($this->method->parameters(), 1);

return array_map(function (FunctionParameterReflection $parameter) use ($injectables) {
$type = $parameter->type();

Assert::isInstanceOf($type, NamedType::class);
Assert::keyExists($injectables, $type->name);

return $injectables[$type->name];
}, $parameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use GoodPhp\Serialization\TypeAdapter\Primitive\MapperMethods\MapperMethod\MapperMethod;
use GoodPhp\Serialization\TypeAdapter\Primitive\PrimitiveTypeAdapter;
use GoodPhp\Serialization\TypeAdapter\TypeAdapterFactory;
use Illuminate\Support\Collection;
use Illuminate\Support\Arr;
use Webmozart\Assert\Assert;

/**
Expand All @@ -18,14 +18,17 @@
final class MapperMethodsPrimitiveTypeAdapterFactory implements TypeAdapterFactory
{
public function __construct(
/** @var Collection<int, MapperMethod> */
private readonly Collection $toMappers,
/** @var Collection<int, MapperMethod> */
private readonly Collection $fromMappers,
/** @var list<MapperMethod> */
private readonly array $toMappers,
/** @var list<MapperMethod> */
private readonly array $fromMappers,
) {
Assert::true($this->toMappers->isNotEmpty() || $this->fromMappers->isNotEmpty());
Assert::true($this->toMappers || $this->fromMappers);
}

/**
* @return MapperMethodsPrimitiveTypeAdapter<mixed>|null
*/
public function create(string $typeAdapterType, Type $type, Attributes $attributes, Serializer $serializer): ?MapperMethodsPrimitiveTypeAdapter
{
if ($typeAdapterType !== PrimitiveTypeAdapter::class || !$type instanceof NamedType) {
Expand Down Expand Up @@ -53,10 +56,10 @@ public function create(string $typeAdapterType, Type $type, Attributes $attribut
}

/**
* @param Collection<int, MapperMethod> $mappers
* @param list<MapperMethod> $mappers
*/
private function findMapper(Collection $mappers, NamedType $type, Attributes $attributes, Serializer $serializer): ?MapperMethod
private function findMapper(array $mappers, NamedType $type, Attributes $attributes, Serializer $serializer): ?MapperMethod
{
return $mappers->first(fn (MapperMethod $method) => $method->accepts($type, $attributes, $serializer));
return Arr::first($mappers, fn (MapperMethod $method) => $method->accepts($type, $attributes, $serializer));
}
}
Loading