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

move logic to strategies

This commit is contained in:
Pavel 2020-07-28 21:50:51 +03:00
parent 923292a224
commit 1119759d1d
15 changed files with 617 additions and 96 deletions

View file

@ -12,9 +12,7 @@
*/
namespace Intaro\RetailCrm\Component\Json;
use Intaro\RetailCrm\Component\Json\Mapping\JsonProperty;
use Intaro\RetailCrm\Component\Json\Mapping\Name;
use Intaro\RetailCrm\Component\Json\Mapping\Type;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
use RetailCrm\Exception\InvalidJsonException;
/**
@ -24,68 +22,31 @@ use RetailCrm\Exception\InvalidJsonException;
*/
class Deserializer
{
use AnnotationReaderTrait;
/**
* @param string $type
* @param string $json
* @param string $className
*
* @return mixed
* @throws \ReflectionException
*/
public static function deserialize(string $json, string $className)
public static function deserialize(string $type, $json)
{
return static::deserializeArray(json_decode($json, true), $className);
$result = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new InvalidJsonException(json_last_error_msg(), json_last_error());
}
return static::deserializeArray($type, $result);
}
/**
* @param array $data
* @param string $className
* @param string $type
* @param array $value
*
* @return mixed
* @throws \ReflectionException
*/
public static function deserializeArray(array $data, string $className)
public static function deserializeArray(string $type, array $value)
{
$reflection = new \ReflectionClass($className);
$instance = new $className();
foreach ($reflection->getProperties() as $property) {
static::deserializeProperty($instance, $property, $data);
}
return $instance;
}
/**
* @param object $object
* @param \ReflectionProperty $property
* @param array $data
*
* @throws \ReflectionException
*/
protected static function deserializeProperty($object, \ReflectionProperty $property, array $data)
{
$property->setAccessible(true);
$name = $property->getName();
$fqcn = '';
$nameData = static::annotationReader()->getPropertyAnnotation($property, Name::class);
$fqcnData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($nameData instanceof Name) {
$name = !empty($nameData->name) ? $nameData->name : $name;
}
if ($fqcnData instanceof Type) {
$fqcn = $fqcnData->type;
}
if (empty($fqcn)) {
$property->setValue($object, $data[$name]);
} else {
$property->setValue($object, static::deserializeArray($data[$name], $fqcn));
}
return StrategyFactory::deserializeStrategyByType($type)->deserialize($type, $value);
}
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json\Mapping
* @author retailCRM <integration@retailcrm.ru>
* @license MIT
* @link http://retailcrm.ru
* @see http://retailcrm.ru/docs
*/
namespace Intaro\RetailCrm\Component\Json\Mapping;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\Annotation;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\Annotation\Target;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\Annotation\Attribute;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\Annotation\Attributes;
/**
* Class Accessor
*
* @package Intaro\RetailCrm\Component\Json\Mapping
* @Annotation
* @Attributes(
* @Attribute("getter", required=false, type="string"),
* @Attribute("setter", required=false, type="string")
* )
* @Target({"PROPERTY","ANNOTATION"})
*/
final class Accessor
{
/**
* Property getter
*
* @var string
*/
public $getter;
/**
* Property setter
*
* @var string
*/
public $setter;
}

View file

@ -12,9 +12,7 @@
*/
namespace Intaro\RetailCrm\Component\Json;
use Intaro\RetailCrm\Component\Json\Mapping\JsonProperty;
use Intaro\RetailCrm\Component\Json\Mapping\Name;
use Intaro\RetailCrm\Model\Customer;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
use RetailCrm\Exception\InvalidJsonException;
/**
@ -24,13 +22,10 @@ use RetailCrm\Exception\InvalidJsonException;
*/
class Serializer
{
use AnnotationReaderTrait;
/**
* @param object $object
*
* @return string
* @throws \ReflectionException
*/
public static function serialize($object): string
{
@ -47,43 +42,9 @@ class Serializer
* @param object $object
*
* @return array
* @throws \ReflectionException
*/
public static function serializeArray($object): array
{
$result = [];
$ref = new \ReflectionClass(get_class($object));
foreach ($ref->getProperties() as $property) {
static::serializeProperty($object, $property, $result);
}
return $result;
}
/**
* @param object $object
* @param \ReflectionProperty $property
* @param array $result
*
* @throws \ReflectionException
*/
protected static function serializeProperty($object, \ReflectionProperty $property, array &$result)
{
$property->setAccessible(true);
$name = $property->getName();
$value = $property->getValue($object);
$annotation = static::annotationReader()->getPropertyAnnotation($property, Name::class);
if ($annotation instanceof Name) {
$name = !empty($annotation->name) ? $annotation->name : $name;
}
if (is_object($value)) {
$result[$name] = static::serializeArray($value);
} else {
$result[$name] = $value;
}
return (array) StrategyFactory::serializeStrategyByType(gettype($object))->serialize($object);
}
}

View file

@ -4,13 +4,13 @@
* PHP version 7.1
*
* @category Integration
* @package Intaro\RetailCrm\Component\Json
* @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;
namespace Intaro\RetailCrm\Component\Json\Strategy;
use Intaro\RetailCrm\Component\Doctrine\Common\Annotations\AnnotationReader;

View file

@ -0,0 +1,40 @@
<?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;
/**
* Interface DeserializeStrategyInterface
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
interface DeserializeStrategyInterface
{
/**
* Deserialize value
*
* @param string $type
* @param mixed $value
*
* @return mixed
*/
public function deserialize(string $type, $value);
/**
* Sets inner type for types like array<key, value> and \DateTime<format>
*
* @param string $type
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Deserialize\DeserializeStrategyInterface
*/
public function setInnerType(string $type): DeserializeStrategyInterface;
}

View file

@ -0,0 +1,83 @@
<?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\Doctrine\Common\Annotations\AnnotationReader;
use Intaro\RetailCrm\Component\Json\Mapping\Accessor;
use Intaro\RetailCrm\Component\Json\Mapping\Name;
use Intaro\RetailCrm\Component\Json\Mapping\Type;
use Intaro\RetailCrm\Component\Json\Strategy\AnnotationReaderTrait;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
/**
* Class EntityStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class EntityStrategy implements DeserializeStrategyInterface
{
use InnerTypeTrait;
use AnnotationReaderTrait;
/**
* @param string $type
* @param mixed $value
*
* @return mixed
* @throws \ReflectionException
*/
public function deserialize(string $type, $value)
{
$reflection = new \ReflectionClass($type);
$instance = new $type();
foreach ($reflection->getProperties() as $property) {
static::deserializeProperty($instance, $property, $value);
}
return $instance;
}
/**
* @param object $object
* @param \ReflectionProperty $property
* @param array $data
*/
protected static function deserializeProperty($object, \ReflectionProperty $property, array $data): void
{
$type = '';
$name = $property->getName();
$accessorData = static::annotationReader()->getPropertyAnnotation($property, Accessor::class);
$nameData = static::annotationReader()->getPropertyAnnotation($property, Name::class);
$typeData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($nameData instanceof Name) {
$name = !empty($nameData->name) ? $nameData->name : $name;
}
if ($typeData instanceof Type) {
$type = $typeData->type;
} else {
$type = gettype($data[$name]);
}
$value = StrategyFactory::deserializeStrategyByType($type)->deserialize($type, $data[$name]);
if ($accessorData instanceof Accessor && !empty($accessorData->setter)) {
$object->{$accessorData->setter}($value);
} else {
$property->setAccessible(true);
$property->setValue($object, $value);
}
}
}

View file

@ -0,0 +1,37 @@
<?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;
/**
* Trait InnerTypeTrait
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Deserialize
*/
trait InnerTypeTrait
{
/** @var string $innerType */
private $innerType;
/**
* Sets inner type for types like array<key, value> and \DateTime<format>
*
* @param string $type
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Serialize\DeserializeStrategyInterface
*/
public function setInnerType(string $type): DeserializeStrategyInterface
{
$this->innerType = $type;
return $this;
}
}

View file

@ -0,0 +1,50 @@
<?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;
/**
* Class SimpleTypeStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class SimpleTypeStrategy implements DeserializeStrategyInterface
{
use InnerTypeTrait;
/**
* @inheritDoc
*/
public function deserialize(string $type, $value)
{
switch ($type) {
case 'bool':
case 'boolean':
return (bool) $value;
case 'int':
case 'integer':
return (int) $value;
case 'float':
return (float) $value;
case 'double':
return (double) $value;
case 'string':
return (string) $value;
default:
if (is_iterable($value)) {
return (array) $value;
}
return null;
}
}
}

View file

@ -0,0 +1,35 @@
<?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;
/**
* Class DateTimeStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class DateTimeStrategy implements SerializeStrategyInterface
{
use InnerTypeTrait;
/**
* @inheritDoc
*/
public function serialize($value)
{
if ($value instanceof \DateTime) {
return $value->format($this->innerType);
}
return null;
}
}

View file

@ -0,0 +1,78 @@
<?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\Doctrine\Common\Annotations\AnnotationReader;
use Intaro\RetailCrm\Component\Json\Mapping\Accessor;
use Intaro\RetailCrm\Component\Json\Mapping\Name;
use Intaro\RetailCrm\Component\Json\Mapping\Type;
use Intaro\RetailCrm\Component\Json\Strategy\AnnotationReaderTrait;
use Intaro\RetailCrm\Component\Json\Strategy\StrategyFactory;
/**
* Class EntityStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class EntityStrategy implements SerializeStrategyInterface
{
use InnerTypeTrait;
use AnnotationReaderTrait;
/**
* @inheritDoc
* @throws \ReflectionException
*/
public function serialize($value)
{
$result = [];
$ref = new \ReflectionClass(get_class($value));
foreach ($ref->getProperties() as $property) {
static::serializeProperty($value, $property, $result);
}
return $result;
}
/**
* @param object $object
* @param \ReflectionProperty $property
* @param array $result
*/
protected static function serializeProperty($object, \ReflectionProperty $property, array &$result): void
{
$accessorData = static::annotationReader()->getPropertyAnnotation($property, Accessor::class);
$name = $property->getName();
if ($accessorData instanceof Accessor && !empty($accessorData->getter)) {
$value = $object->{$accessorData->getter}();
} else {
$property->setAccessible(true);
$value = $property->getValue($object);
}
$nameData = static::annotationReader()->getPropertyAnnotation($property, Name::class);
$typeData = static::annotationReader()->getPropertyAnnotation($property, Type::class);
if ($nameData instanceof Name) {
$name = !empty($nameData->name) ? $nameData->name : $name;
}
if ($typeData instanceof Type) {
$result[$name] = StrategyFactory::serializeStrategyByType($typeData->type)->serialize($value);
} else {
$result[$name] = StrategyFactory::serializeStrategyByType(gettype($value))->serialize($value);
}
}
}

View file

@ -0,0 +1,37 @@
<?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;
/**
* Trait InnerTypeTrait
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
trait InnerTypeTrait
{
/** @var string $innerType */
private $innerType;
/**
* Sets inner type for types like array<key, value> and \DateTime<format>
*
* @param string $type
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Serialize\SerializeStrategyInterface
*/
public function setInnerType(string $type): SerializeStrategyInterface
{
$this->innerType = $type;
return $this;
}
}

View file

@ -0,0 +1,39 @@
<?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;
/**
* Interface SerializeStrategyInterface
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
interface SerializeStrategyInterface
{
/**
* Serialize value
*
* @param mixed $value
*
* @return mixed
*/
public function serialize($value);
/**
* Sets inner type for types like array<key, value> and \DateTime<format>
*
* @param string $type
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Serialize\SerializeStrategyInterface
*/
public function setInnerType(string $type): SerializeStrategyInterface;
}

View file

@ -0,0 +1,58 @@
<?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\Strategy\StrategyFactory;
/**
* Class SimpleTypeStrategy
*
* @package Intaro\RetailCrm\Component\Json\Strategy\Serialize
*/
class SimpleTypeStrategy implements SerializeStrategyInterface
{
use InnerTypeTrait;
/**
* @inheritDoc
*/
public function serialize($value)
{
switch (gettype($value)) {
case 'bool':
case 'boolean':
return (bool) $value;
case 'int':
case 'integer':
return (int) $value;
case 'float':
return (float) $value;
case 'double':
return (double) $value;
case 'string':
return (string) $value;
default:
if (is_iterable($value)) {
$result = [];
foreach ($value as $key => $item) {
$result[$key] = StrategyFactory::serializeStrategyByType(gettype($item))->serialize($item);
}
return $result;
}
return null;
}
}
}

View file

@ -0,0 +1,71 @@
<?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;
use Intaro\RetailCrm\Component\Json\Strategy\Deserialize\DeserializeStrategyInterface;
use Intaro\RetailCrm\Component\Json\Strategy\Serialize;
use Intaro\RetailCrm\Component\Json\Strategy\Serialize\SerializeStrategyInterface;
/**
* Class StrategyFactory
*
* @package Intaro\RetailCrm\Component\Json\Strategy
*/
class StrategyFactory
{
/** @var string[] $simpleTypes */
private static $simpleTypes = [
'bool',
'boolean',
'int',
'integer',
'float',
'double',
'string',
'array'
];
/**
* @param string $dataType
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Serialize\SerializeStrategyInterface
*/
public static function serializeStrategyByType(string $dataType): SerializeStrategyInterface
{
if (in_array($dataType, static::$simpleTypes)) {
return new Serialize\SimpleTypeStrategy();
}
// TODO: DateTime<format> strategy and array<valueType>, array<keyType, valueType> strategies
return new Serialize\EntityStrategy();
}
/**
* @param string $dataType
*
* @return \Intaro\RetailCrm\Component\Json\Strategy\Deserialize\DeserializeStrategyInterface
*/
public static function deserializeStrategyByType(string $dataType): DeserializeStrategyInterface
{
print_r($dataType);
if (in_array($dataType, static::$simpleTypes)) {
return new Deserialize\SimpleTypeStrategy();
}
// TODO: DateTime<format> strategy and array<valueType>, array<keyType, valueType> strategies
return new Deserialize\EntityStrategy();
}
}

View file

@ -12,6 +12,7 @@
*/
namespace Intaro\RetailCrm\Model;
use Intaro\RetailCrm\Component\Json\Mapping\Accessor;
use Intaro\RetailCrm\Component\Json\Mapping\Name;
/**
@ -37,6 +38,14 @@ class Customer
*/
private $isContact = false;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*
@ -48,6 +57,14 @@ class Customer
return $this;
}
/**
* @return string
*/
public function getExternalId(): string
{
return $this->externalId;
}
/**
* @param string $externalId
*
@ -59,6 +76,14 @@ class Customer
return $this;
}
/**
* @return bool
*/
public function isContact(): bool
{
return $this->isContact;
}
/**
* @param bool $isContact
*