1
0
Fork 0
mirror of synced 2025-04-20 01:21:01 +00:00

serializer now supports typed arrays and formatted DateTime

This commit is contained in:
Pavel 2020-07-29 09:44:23 +03:00
parent 102f16cb9e
commit 2828d88069
5 changed files with 266 additions and 2 deletions

View file

@ -0,0 +1,22 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json\Exception
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Json\Exception;
/**
* Class InvalidAnnotationException
*
* @package Intaro\RetailCrm\Component\Json\Exception
*/
class InvalidAnnotationException extends \Exception
{
}

View file

@ -0,0 +1,63 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json\Strategy\Deserialize
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Json\Strategy\Deserialize;
use Intaro\RetailCrm\Component\Json\Exception\InvalidAnnotationException;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
use Intaro\RetailCrm\Component\Json\Strategy\TypedArrayTrait;
/**
* Class TypedArrayStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Deserialize
*/
class TypedArrayStrategy implements DeserializeStrategyInterface
{
use InnerTypeTrait;
use TypedArrayTrait;
/**
* @inheritDoc
*/
public function deserialize(string $type, $value)
{
$keyType = '';
$valueType = '';
$result = [];
if (strpos($this->innerType, ',') !== false) {
[$keyType, $valueType] = static::getInnerTypes($this->innerType);
if ('' === $keyType && '' === $valueType) {
$valueType = $this->innerType;
}
} else {
$valueType = $this->innerType;
}
$simpleStrategy = new SimpleTypeStrategy();
foreach (array_keys($value) as $key) {
$deserializedKey = $key;
if ('' !== $keyType) {
$deserializedKey = $simpleStrategy->deserialize($keyType, $key);
}
$result[$deserializedKey]
= StrategyFactory::deserializeStrategyByType($valueType)->deserialize($valueType, $value[$key]);
}
return $result;
}
}

View file

@ -0,0 +1,56 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Json\Strategy\Serialize;
use Intaro\RetailCrm\Component\Json\Exception\InvalidAnnotationException;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
use Intaro\RetailCrm\Component\Json\Strategy\TypedArrayTrait;
/**
* Class TypedArrayStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class TypedArrayStrategy implements SerializeStrategyInterface
{
use InnerTypeTrait;
use TypedArrayTrait;
/**
* @inheritDoc
*/
public function serialize($value)
{
$valueType = '';
$result = [];
if (strpos($this->innerType, ',') !== false) {
[$keyType, $valueType] = static::getInnerTypes($this->innerType);
if ('' === $keyType && '' === $valueType) {
$valueType = $this->innerType;
}
} else {
$valueType = $this->innerType;
}
$simpleStrategy = new SimpleTypeStrategy();
foreach (array_keys($value) as $key) {
$result[$simpleStrategy->serialize($key)]
= StrategyFactory::serializeStrategyByType($valueType)->serialize($value[$key]);
}
return $result;
}
}

View file

@ -23,6 +23,9 @@ use Intaro\RetailCrm\Component\Json\Strategy\Serialize\SerializeStrategyInterfac
*/
class StrategyFactory
{
/** @var string */
private const TYPED_MATCHER = '/^\\\\?([a-zA-Z0-9_]+)\s*\<(.+)\>$/m';
/** @var string[] $simpleTypes */
private static $simpleTypes = [
'bool',
@ -50,7 +53,17 @@ class StrategyFactory
return (new Serialize\DateTimeStrategy())->setInnerType(\DateTime::RFC3339);
}
// TODO: DateTime<format> strategy and array<valueType>, array<keyType, valueType> strategies
$arrSubType = static::getArrayInnerTypes($dataType);
if (!empty($arrSubType)) {
return (new Serialize\TypedArrayStrategy())->setInnerType($arrSubType);
}
$dateTimeFormat = static::getDateTimeFormat($dataType);
if (!empty($dateTimeFormat)) {
return (new Serialize\DateTimeStrategy())->setInnerType($dateTimeFormat);
}
return new Serialize\EntityStrategy();
}
@ -70,11 +83,76 @@ class StrategyFactory
return (new Deserialize\DateTimeStrategy())->setInnerType(\DateTime::RFC3339);
}
// TODO: DateTime<format> strategy and array<valueType>, array<keyType, valueType> strategies
$arrSubType = static::getArrayInnerTypes($dataType);
if (!empty($arrSubType)) {
return (new Deserialize\TypedArrayStrategy())->setInnerType($arrSubType);
}
$dateTimeFormat = static::getDateTimeFormat($dataType);
if (!empty($dateTimeFormat)) {
return (new Deserialize\DateTimeStrategy())->setInnerType($dateTimeFormat);
}
return new Deserialize\EntityStrategy();
}
/**
* Returns array inner type for arrays like array<int, \DateTime<Y-m-d\TH:i:sP>>
* For this example, "int, \DateTime<Y-m-d\TH:i:sP>" will be returned.
*
* Also works for arrays like int[].
*
* @param string $dataType
*
* @return string
*/
private static function getArrayInnerTypes(string $dataType): string
{
$matches = [];
preg_match_all(static::TYPED_MATCHER, $dataType, $matches, PREG_SET_ORDER, 0);
if (empty($matches)) {
if (strlen($dataType) > 2 && substr($dataType, -2) === '[]') {
return substr($dataType, 0, -2);
}
return '';
}
if ($matches[0][1] === 'array') {
return $matches[0][2];
}
return '';
}
/**
* Returns DateTime format. Example: \DateTime<Y-m-d\TH:i:sP>>
*
* @param string $dataType
*
* @return string
*/
private static function getDateTimeFormat(string $dataType): string
{
$matches = [];
preg_match_all(static::TYPED_MATCHER, $dataType, $matches, PREG_SET_ORDER, 0);
if (empty($matches)) {
return '';
}
if ($matches[0][1] === 'DateTime') {
return $matches[0][2];
}
return '';
}
/**
* Returns true if provided type is DateTime
*

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json\Strategy
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Json\Strategy;
/**
* Class StrategyFactory
*
* @package Intaro\RetailCrm\Component\Json\Strategy
*/
trait TypedArrayTrait
{
private static $innerTypesMatcher = '/^([a-z]+)\s*\,?\s*(.+?\>)/m';
/**
* Returns inner types for array with typed key (example: array<string, DateTime<Y m d H i s>>).
*
* @param string $innerType
*
* @return string[]
*/
private static function getInnerTypes(string $innerType)
{
$matches = [];
preg_match_all(static::$innerTypesMatcher, $innerType, $matches, PREG_SET_ORDER, 0);
if (empty($matches)) {
return ['', ''];
}
$matches = $matches[0];
return [trim($matches[1]), trim($matches[2])];
}
}