1
0
mirror of synced 2024-11-21 21:06:07 +03:00

better php 7.4 support

This commit is contained in:
Pavel 2024-03-11 20:45:58 +03:00
parent 7a4d755f83
commit 312dfeffd7
3 changed files with 392 additions and 178 deletions

View File

@ -13,4 +13,5 @@
<exclude-pattern>src/Component/Serializer/Generator/*</exclude-pattern> <exclude-pattern>src/Component/Serializer/Generator/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/Parser/*</exclude-pattern> <exclude-pattern>src/Component/Serializer/Parser/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/ArraySupportDecorator.php</exclude-pattern>
</ruleset> </ruleset>

View File

@ -1,4 +1,6 @@
parameters: parameters:
excludePaths:
- src/Component/Serializer/ArraySupportDecorator.php
ignoreErrors: ignoreErrors:
- -
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Builder\\\\ClientBuilder\\:\\:buildHandlersChain\\(\\) through static\\:\\:\\.$#" message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Builder\\\\ClientBuilder\\:\\:buildHandlersChain\\(\\) through static\\:\\:\\.$#"

View File

@ -16,211 +16,422 @@ use Liip\Serializer\Exception\UnsupportedFormatException;
use Liip\Serializer\SerializerInterface; use Liip\Serializer\SerializerInterface;
use Pnz\JsonException\Json; use Pnz\JsonException\Json;
/** if (PHP_VERSION_ID >= 80000) {
* Class ArraySupportDecorator
*
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
class ArraySupportDecorator implements SerializerInterface
{
private SerializerInterface $serializer;
/** /**
* ArraySupportDecorator constructor. * Class ArraySupportDecorator
* *
* @param \Liip\Serializer\SerializerInterface $serializer * @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/ */
public function __construct(SerializerInterface $serializer) class ArraySupportDecorator implements SerializerInterface
{ {
$this->serializer = $serializer; private SerializerInterface $serializer;
}
/** /**
* @inheritDoc * ArraySupportDecorator constructor.
* @throws \JsonException *
*/ * @param \Liip\Serializer\SerializerInterface $serializer
public function serialize($data, string $format, ?Context $context = null): string */
{ public function __construct(SerializerInterface $serializer)
if ('json' !== $format) { {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now'); $this->serializer = $serializer;
} }
if (is_array($data)) { /**
try { * @inheritDoc
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES); * @throws \JsonException
} catch (JsonException $exception) { */
throw new Exception( public function serialize($data, string $format, ?Context $context = null): string
sprintf( {
'Failed to JSON encode data for %s. This is not supposed to happen.', if ('json' !== $format) {
// @phpstan-ignore-next-line throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
is_object($data) ? get_class($data) : gettype($data)
),
0,
$exception
);
}
}
return $this->serializer->serialize($data, $format, $context);
}
/**
* @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null): mixed
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (static::isArrayType($type)) {
try {
$array = Json::decode($data, true);
} catch (JsonException $exception) {
throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
} }
return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context); if (is_array($data)) {
} try {
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES);
return $this->serializer->deserialize($data, $type, $format, $context); } catch (JsonException $exception) {
} throw new Exception(
sprintf(
/** 'Failed to JSON encode data for %s. This is not supposed to happen.',
* @inheritDoc // @phpstan-ignore-next-line
* is_object($data) ? get_class($data) : gettype($data)
* @return array<int|string, mixed> ),
*/ 0,
public function toArray($data, ?Context $context = null): array $exception
{ );
if (is_array($data)) { }
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null): mixed
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
} }
return $this->serializer->serialize($data, $format, $context);
} }
return $result; /**
} * @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null): mixed
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
/** if (static::isArrayType($type)) {
* Decodes array of arrays to array of objects. try {
* $array = Json::decode($data, true);
* @param mixed[] $data } catch (JsonException $exception) {
* @param string $type throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
} }
$result[$key] = $item; return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context);
}
return $this->serializer->deserialize($data, $type, $format, $context);
}
/**
* @inheritDoc
*
* @return array<int|string, mixed>
*/
public function toArray($data, ?Context $context = null): array
{
if (is_array($data)) {
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null): mixed
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
}
} }
return $result; return $result;
} }
return $data; /**
} * Decodes array of arrays to array of objects.
*
* @param mixed[] $data
* @param string $type
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
/** if (class_exists($subtype)) {
* Returns true if provided type is an array. foreach ($data as $key => $item) {
* if (is_array($item)) {
* @param string $type $result[$key] = $this->decodeArray($item, $subtype, $context);
* continue;
* @return bool }
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
}
/** $result[$key] = $item;
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'. }
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
preg_match_all( return $result;
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m', }
$type,
$matches,
PREG_SET_ORDER,
0
);
if (count($matches) > 0) { return $data;
return $matches[count($matches) - 1];
} }
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0); /**
* Returns true if provided type is an array.
if (count($matches) > 0) { *
return $matches[count($matches) - 1]; * @param string $type
*
* @return bool
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
} }
return 'mixed'; /**
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'.
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
return 'mixed';
}
}
} else {
/**
* Class ArraySupportDecorator
*
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
class ArraySupportDecorator implements SerializerInterface
{
private SerializerInterface $serializer;
/**
* ArraySupportDecorator constructor.
*
* @param \Liip\Serializer\SerializerInterface $serializer
*/
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
/**
* @inheritDoc
* @throws \JsonException
*/
public function serialize($data, string $format, ?Context $context = null): string
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (is_array($data)) {
try {
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES);
} catch (JsonException $exception) {
throw new Exception(
sprintf(
'Failed to JSON encode data for %s. This is not supposed to happen.',
// @phpstan-ignore-next-line
is_object($data) ? get_class($data) : gettype($data)
),
0,
$exception
);
}
}
return $this->serializer->serialize($data, $format, $context);
}
/**
* @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null)
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (static::isArrayType($type)) {
try {
$array = Json::decode($data, true);
} catch (JsonException $exception) {
throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
}
return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context);
}
return $this->serializer->deserialize($data, $type, $format, $context);
}
/**
* @inheritDoc
*
* @return array<int|string, mixed>
*/
public function toArray($data, ?Context $context = null): array
{
if (is_array($data)) {
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null)
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
}
}
return $result;
}
/**
* Decodes array of arrays to array of objects.
*
* @param mixed[] $data
* @param string $type
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
}
$result[$key] = $item;
}
return $result;
}
return $data;
}
/**
* Returns true if provided type is an array.
*
* @param string $type
*
* @return bool
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
}
/**
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'.
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
return 'mixed';
}
} }
} }