1
0
mirror of synced 2024-11-21 12:56:08 +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/Parser/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/ArraySupportDecorator.php</exclude-pattern>
</ruleset>

View File

@ -1,4 +1,6 @@
parameters:
excludePaths:
- src/Component/Serializer/ArraySupportDecorator.php
ignoreErrors:
-
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 Pnz\JsonException\Json;
/**
* Class ArraySupportDecorator
*
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
class ArraySupportDecorator implements SerializerInterface
{
private SerializerInterface $serializer;
if (PHP_VERSION_ID >= 80000) {
/**
* 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
* @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');
/**
* ArraySupportDecorator constructor.
*
* @param \Liip\Serializer\SerializerInterface $serializer
*/
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
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): 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);
/**
* @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');
}
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;
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);
}
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');
}
/**
* 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;
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);
}
$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 $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);
/**
* 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');
}
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
}
/**
* 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 = [];
$result[$key] = $item;
}
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
return $result;
}
if (count($matches) > 0) {
return $matches[count($matches) - 1];
return $data;
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
/**
* 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');
}
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';
}
}
}