Skip to content

Refactor serialization logic and reorganize contracts. #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 31, 2024
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
444 changes: 256 additions & 188 deletions clover.xml

Large diffs are not rendered by default.

12 changes: 4 additions & 8 deletions src/Concerns/BaseData.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ final public static function from(mixed $value): static
$value = static::normalizeValue($value, static::class);

if ($value === false) {
throw new DeserializeException(
code: DeserializeException::INVALID_VALUE_ERROR_CODE
);
throw DeserializeException::invalidValue();
}

/** @var ClassContext<static> $context */
Expand All @@ -73,7 +71,7 @@ classContext: $context,
? static::instanceWithConstructorCallFrom($context, $data)
: static::instanceWithoutConstructorFrom($context, $data);
} catch (Throwable $e) {
throw new DeserializeException($e->getMessage(), $e->getCode(), $e);
throw DeserializeException::generic($e);
}
}

Expand Down Expand Up @@ -111,9 +109,7 @@ protected static function instanceWithConstructorCallFrom(ClassContext $context,
$propertyContext = $context->properties[$paramName] ?? null;

if (!$propertyContext) {
throw new DeserializeException(
"Could not find property context for constructor param: $paramName"
);
throw DeserializeException::invalidParamsPassed();
}

$args[$paramName] = $propertyContext->deserializeFrom($value);
Expand Down Expand Up @@ -145,7 +141,7 @@ final public function jsonSerialize(): array

return $serializedData;
} catch (Throwable $e) {
throw new SerializeException($e->getMessage(), $e->getCode(), $e);
throw SerializeException::generic($e);
}
}

Expand Down
25 changes: 12 additions & 13 deletions src/Contexts/PropertyContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,29 +194,28 @@ public function deserializeFrom(array $value): mixed
}
}

throw new DeserializeException('Could not deserialize value for property: ' . $this->propertyName);
throw DeserializeException::generic();
}

/**
* @return array<string, mixed>
*
* @throws SerializeException
* @throws UnknownTypeException
*/
public function serializeFrom(object $object): array
{
foreach ($this->serializers() as $serializer) {
try {
$serializedData = $serializer->serialize($this, $object);
} catch (SerializeException) {
try {
foreach ($this->serializers() as $serializer) {
try {
$serializedData = $serializer->serialize($this, $object);
} catch (SerializeException) {
}
}
}

if (empty($serializedData)) {
throw new SerializeException('Could not serialize value for property: ' . $this->propertyName);
}
if (empty($serializedData)) {
throw new Exception();
}

try {
if ($this->cipherConfig) {
return array_map(
fn (mixed $value) => $this->cipherConfig->dataCipherClass::cipher(
Expand All @@ -229,8 +228,8 @@ public function serializeFrom(object $object): array
}

return $serializedData;
} catch (Exception) {
throw new SerializeException('Could not serialize value for property: ' . $this->propertyName);
} catch (Exception $e) {
throw SerializeException::generic($e);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/DataRefiners/DateTimeRefiner.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function refine(mixed $value, PropertyContext $property): mixed
$typeContexts = $property->getFilteredTypeContexts(Type::DATETIME);

if (empty($typeContexts)) {
throw InvalidRefiner::from($this, $property);
throw InvalidRefiner::emptyTypeContexts();
}

$refinedValue = false;
Expand Down
91 changes: 81 additions & 10 deletions src/Exceptions/DeserializeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,86 @@

class DeserializeException extends Exception
{
public const int GENERIC_ERROR_CODE = 0;
public const int INVALID_VALUE_ERROR_CODE = 1;
public const int NO_SERIALIZERS_ERROR_CODE = 2;

public function __construct(
string $message = 'Failed to deserialize data',
int $code = self::GENERIC_ERROR_CODE,
?Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
protected const int GENERIC_ERROR_CODE = 0;
protected const int INVALID_VALUE_ERROR_CODE = 1;
protected const int PROPERTY_IS_NOT_NULLABLE_ERROR_CODE = 2;
protected const int UNABLE_TO_DESERIALIZE_SCALAR_TYPE_ITEM_ERROR_CODE = 3;
protected const int UNABLE_TO_DESERIALIZE_BACKED_ENUM_ITEM_ERROR_CODE = 4;
protected const int UNABLE_TO_DESERIALIZE_DATE_TIME_ITEM_ERROR_CODE = 5;
protected const int UNABLE_TO_DESERIALIZE_DATA_ITEM_ERROR_CODE = 6;
protected const int UNABLE_TO_DESERIALIZE_ARRAY_ITEM_ERROR_CODE = 7;
protected const int INVALID_PARAMS_PASSED_ERROR_CODE = 8;

public static function generic(?Throwable $throwable = null): self
{
return new self(
message: 'An error occurred while deserializing data',
code: self::GENERIC_ERROR_CODE,
previous: $throwable
);
}

public static function invalidValue(): self
{
return new self(
message: 'Invalid value passed to from method',
code: self::INVALID_VALUE_ERROR_CODE
);
}

public static function propertyIsNotNullable(): self
{
return new self(
message: 'Property is not nullable',
code: self::PROPERTY_IS_NOT_NULLABLE_ERROR_CODE
);
}

public static function unableToDeserializeScalarTypeItem(): self
{
return new self(
message: 'Could not deserialize scalar type item',
code: self::UNABLE_TO_DESERIALIZE_SCALAR_TYPE_ITEM_ERROR_CODE
);
}

public static function unableToDeserializeBackedEnumItem(): self
{
return new self(
message: 'Could not deserialize BackedEnum item',
code: self::UNABLE_TO_DESERIALIZE_BACKED_ENUM_ITEM_ERROR_CODE
);
}

public static function unableToDeserializeDateTimeItem(): self
{
return new self(
message: 'Could not deserialize DateTime item',
code: self::UNABLE_TO_DESERIALIZE_DATE_TIME_ITEM_ERROR_CODE
);
}

public static function unableToDeserializeDataItem(): self
{
return new self(
message: 'Could not deserialize Data item',
code: self::UNABLE_TO_DESERIALIZE_DATA_ITEM_ERROR_CODE
);
}

public static function unableToDeserializeArrayItem(): self
{
return new self(
message: 'Could not deserialize array item',
code: self::UNABLE_TO_DESERIALIZE_ARRAY_ITEM_ERROR_CODE
);
}

public static function invalidParamsPassed(): self
{
return new self(
message: 'Invalid params passed',
code: self::INVALID_PARAMS_PASSED_ERROR_CODE
);
}
}
15 changes: 6 additions & 9 deletions src/Exceptions/InvalidRefiner.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@

class InvalidRefiner extends Exception
{
public static function from(
DataRefiner $refiner,
PropertyContext $property
): self {
protected const int EMPTY_TYPE_CONTEXTS_CODE = 1;

public static function emptyTypeContexts(): self
{
return new self(
sprintf(
'Refiner %s is not applicable to property %s',
get_class($refiner),
$property->propertyName
)
'Property does not have any type contexts',
self::EMPTY_TYPE_CONTEXTS_CODE
);
}
}
64 changes: 55 additions & 9 deletions src/Exceptions/SerializeException.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,60 @@

class SerializeException extends Exception
{
public const int GENERIC_ERROR_CODE = 0;
public const int NO_SERIALIZERS_ERROR_CODE = 1;

public function __construct(
string $message = "",
int $code = 0,
?Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
protected const int GENERIC_ERROR_CODE = 0;
protected const int NO_SERIALIZERS_ERROR_CODE = 1;
protected const int UNABLE_TO_SERIALIZE_SCALAR_TYPE_ITEM_ERROR_CODE = 2;
protected const int UNABLE_TO_SERIALIZE_BACKED_ENUM_ERROR_CODE = 3;
protected const int UNABLE_TO_SERIALIZE_DATE_TIME_ITEM_ERROR_CODE = 4;
protected const int UNABLE_TO_SERIALIZE_DATA_ITEM_ERROR_CODE = 5;
protected const int UNABLE_TO_SERIALIZE_ARRAY_ITEM_ERROR_CODE = 6;

public static function generic(?Throwable $throwable = null): self
{
return new self(
message: 'An error occurred while serializing data',
code: self::GENERIC_ERROR_CODE,
previous: $throwable
);
}

public static function unableToSerializeScalarTypeItem(): self
{
return new self(
message: 'Could not serialize scalar type item',
code: self::UNABLE_TO_SERIALIZE_SCALAR_TYPE_ITEM_ERROR_CODE
);
}

public static function unableToSerializeBackedEnumItem(): self
{
return new self(
message: 'Could not serialize array of BackedEnum items',
code: self::UNABLE_TO_SERIALIZE_BACKED_ENUM_ERROR_CODE
);
}

public static function unableToSerializeDateTimeItem(): self
{
return new self(
message: 'Could not serialize array of DateTime items',
code: self::UNABLE_TO_SERIALIZE_DATE_TIME_ITEM_ERROR_CODE
);
}

public static function unableToSerializeDataItem(): self
{
return new self(
message: 'Could not serialize array of data items',
code: self::UNABLE_TO_SERIALIZE_DATA_ITEM_ERROR_CODE
);
}

public static function unableToSerializeArrayItem(): self
{
return new self(
message: 'Could not serialize array of items',
code: self::UNABLE_TO_SERIALIZE_ARRAY_ITEM_ERROR_CODE
);
}
}
16 changes: 10 additions & 6 deletions src/Serializers/ArraySerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace Nuxtifyts\PhpDto\Serializers;

use Exception;
use Nuxtifyts\PhpDto\Contexts\PropertyContext;
use Nuxtifyts\PhpDto\Enums\Property\Type;
use Nuxtifyts\PhpDto\Contracts\SerializesArrayOfItems as SerializesArrayOfItemsContract;
use Nuxtifyts\PhpDto\Exceptions\DeserializeException;
use Nuxtifyts\PhpDto\Exceptions\SerializeException;
use Exception;
use Nuxtifyts\PhpDto\Serializers\Contracts\SerializesArrayOfItems;

class ArraySerializer extends Serializer
{
Expand All @@ -20,6 +20,8 @@ public static function supportedTypes(): array

/**
* @return ?array<array-key, mixed>
*
* @throws SerializeException
*/
protected function serializeItem(mixed $item, PropertyContext $property, object $object): ?array
{
Expand All @@ -32,7 +34,7 @@ protected function serializeItem(mixed $item, PropertyContext $property, object
try {
foreach ($typeContext->subTypeSerializers() as $serializer) {
try {
if ($serializer instanceof SerializesArrayOfItemsContract) {
if ($serializer instanceof SerializesArrayOfItems) {
$serializedValue = $serializer->serializeArrayOfItems($property, $object);

if (array_key_exists($property->propertyName, $serializedValue)) {
Expand All @@ -47,11 +49,13 @@ protected function serializeItem(mixed $item, PropertyContext $property, object
}
}

throw new SerializeException('Could not serialize array of items');
throw SerializeException::unableToSerializeArrayItem();
}

/**
* @return ?array<array-key, mixed>
*
* @throws DeserializeException
*/
protected function deserializeItem(mixed $item, PropertyContext $property): ?array
{
Expand All @@ -60,7 +64,7 @@ protected function deserializeItem(mixed $item, PropertyContext $property): ?arr
try {
foreach ($typeContext->subTypeSerializers() as $serializer) {
try {
if ($serializer instanceof SerializesArrayOfItemsContract) {
if ($serializer instanceof SerializesArrayOfItems) {
// @phpstan-ignore-next-line
return $serializer->deserializeArrayOfItems($property, $item);
}
Expand All @@ -74,6 +78,6 @@ protected function deserializeItem(mixed $item, PropertyContext $property): ?arr

return is_null($item) && $property->isNullable
? null
: throw new DeserializeException('Property is not nullable');
: throw DeserializeException::unableToDeserializeArrayItem();
}
}
Loading
Loading