|
|
@ -2,6 +2,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
namespace Rinsvent\Data2DTO; |
|
|
|
namespace Rinsvent\Data2DTO; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use ReflectionProperty; |
|
|
|
use Rinsvent\AttributeExtractor\ClassExtractor; |
|
|
|
use Rinsvent\AttributeExtractor\ClassExtractor; |
|
|
|
use Rinsvent\AttributeExtractor\PropertyExtractor; |
|
|
|
use Rinsvent\AttributeExtractor\PropertyExtractor; |
|
|
|
use Rinsvent\Data2DTO\Attribute\DTOMeta; |
|
|
|
use Rinsvent\Data2DTO\Attribute\DTOMeta; |
|
|
@ -19,7 +20,6 @@ class Data2DtoConverter |
|
|
|
$tags = empty($tags) ? ['default'] : $tags; |
|
|
|
$tags = empty($tags) ? ['default'] : $tags; |
|
|
|
$reflectionObject = new \ReflectionObject($object); |
|
|
|
$reflectionObject = new \ReflectionObject($object); |
|
|
|
|
|
|
|
|
|
|
|
// Трнансформируем на уровне класса |
|
|
|
|
|
|
|
$this->processClassTransformers($reflectionObject, $data, $tags); |
|
|
|
$this->processClassTransformers($reflectionObject, $data, $tags); |
|
|
|
if (is_object($data)) { |
|
|
|
if (is_object($data)) { |
|
|
|
return $data; |
|
|
|
return $data; |
|
|
@ -32,71 +32,105 @@ class Data2DtoConverter |
|
|
|
$reflectionPropertyType = $property->getType(); |
|
|
|
$reflectionPropertyType = $property->getType(); |
|
|
|
$propertyType = $reflectionPropertyType->getName(); |
|
|
|
$propertyType = $reflectionPropertyType->getName(); |
|
|
|
|
|
|
|
|
|
|
|
// Для виртуальных полей добавляем пустой масиив, чтобы заполнить поля дто |
|
|
|
if ($this->processVirtualProperty($object, $property, $data, $tags)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($dataPath = $this->grabDataPath($property, $data, $tags)) { |
|
|
|
|
|
|
|
$value = $data[$dataPath]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this->processTransformers($property, $value, $tags); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->processDataObject($object, $property, $value)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->processArray($value, $property, $tags)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$preparedPropertyType = $propertyType; |
|
|
|
|
|
|
|
if ($this->processInterface($property, $preparedPropertyType)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$this->processClass($object, $property, $preparedPropertyType, $value, $tags); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->processNull($value, $reflectionPropertyType)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$property->setValue($object, $value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $object; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Для виртуальных полей добавляем пустой масиив, чтобы заполнить поля дто |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
protected function processVirtualProperty(object $object, \ReflectionProperty $property, array $data, array $tags): bool |
|
|
|
|
|
|
|
{ |
|
|
|
$propertyExtractor = new PropertyExtractor($property->class, $property->getName()); |
|
|
|
$propertyExtractor = new PropertyExtractor($property->class, $property->getName()); |
|
|
|
if ($propertyExtractor->fetch(VirtualProperty::class)) { |
|
|
|
if ($propertyExtractor->fetch(VirtualProperty::class)) { |
|
|
|
if ($property->isInitialized($object)) { |
|
|
|
if ($property->isInitialized($object)) { |
|
|
|
$propertyValue = $property->getValue($object); |
|
|
|
$propertyValue = $property->getValue($object); |
|
|
|
$value = $this->convert($data, $propertyValue, $tags); |
|
|
|
$value = $this->convert($data, $propertyValue, $tags); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
$propertyType = $property->getType()->getName(); |
|
|
|
$value = $this->convert($data, new $propertyType, $tags); |
|
|
|
$value = $this->convert($data, new $propertyType, $tags); |
|
|
|
} |
|
|
|
} |
|
|
|
// присваиваем получившееся значение |
|
|
|
// присваиваем получившееся значение |
|
|
|
$property->setValue($object, $value); |
|
|
|
$property->setValue($object, $value); |
|
|
|
continue; |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ($dataPath = $this->grabDataPath($property, $data, $tags)) { |
|
|
|
/** |
|
|
|
$value = $data[$dataPath]; |
|
|
|
* В данных лежит объект, то дальше его не заполняем. Только присваиваем. Например, entity, document |
|
|
|
// Трансформируем данные |
|
|
|
*/ |
|
|
|
$this->processTransformers($property, $value, $tags); |
|
|
|
protected function processDataObject(object $object, \ReflectionProperty $property, $value): bool |
|
|
|
|
|
|
|
{ |
|
|
|
// В данных лежит объект, то дальше его не заполняем. Только присваиваем. Например, entity, document |
|
|
|
|
|
|
|
if (is_object($value)) { |
|
|
|
if (is_object($value)) { |
|
|
|
$property->setValue($object, $value); |
|
|
|
$property->setValue($object, $value); |
|
|
|
continue; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
if (!$this->transformArray($value, $property, $tags)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$preparedPropertyType = $propertyType; |
|
|
|
protected function processInterface(ReflectionProperty $property, &$preparedPropertyType): bool |
|
|
|
|
|
|
|
{ |
|
|
|
if (interface_exists($preparedPropertyType)) { |
|
|
|
if (interface_exists($preparedPropertyType)) { |
|
|
|
$attributedPropertyClass = $this->grabPropertyDTOClass($property); |
|
|
|
$attributedPropertyClass = $this->grabPropertyDTOClass($property); |
|
|
|
// Если не указали мета информацию для интерфейса - пропустим |
|
|
|
// Если не указали мета информацию для интерфейса - пропустим |
|
|
|
if (!$attributedPropertyClass) { |
|
|
|
if (!$attributedPropertyClass) { |
|
|
|
continue; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
// Если класс не реализует интерфейс свойства - пропустим |
|
|
|
// Если класс не реализует интерфейс свойства - пропустим |
|
|
|
$interfaces = class_implements($attributedPropertyClass); |
|
|
|
$interfaces = class_implements($attributedPropertyClass); |
|
|
|
if (!isset($interfaces[$preparedPropertyType])) { |
|
|
|
if (!isset($interfaces[$preparedPropertyType])) { |
|
|
|
continue; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
$preparedPropertyType = $attributedPropertyClass; |
|
|
|
$preparedPropertyType = $attributedPropertyClass; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Если это class, то рекурсивно заполняем дальше |
|
|
|
/** |
|
|
|
|
|
|
|
* Если это class, то рекурсивно заполняем дальше |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
protected function processClass(object $object, ReflectionProperty $property, string $preparedPropertyType, &$value, array $tags) |
|
|
|
|
|
|
|
{ |
|
|
|
if (class_exists($preparedPropertyType)) { |
|
|
|
if (class_exists($preparedPropertyType)) { |
|
|
|
if ($property->isInitialized($object)) { |
|
|
|
if ($property->isInitialized($object)) { |
|
|
|
$propertyValue = $property->getValue($object); |
|
|
|
$propertyValue = $property->getValue($object); |
|
|
|
$value = $this->convert($value, new $preparedPropertyType, $tags, $propertyValue); |
|
|
|
$value = $this->convert($value, $propertyValue, $tags); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
$value = $this->convert($value, new $preparedPropertyType, $tags); |
|
|
|
$value = $this->convert($value, new $preparedPropertyType, $tags); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ($this->checkNullRule($value, $reflectionPropertyType)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// присваиваем получившееся значение |
|
|
|
|
|
|
|
$property->setValue($object, $value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $object; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected function grabDataPath(\ReflectionProperty $property, array $data, array $tags): ?string |
|
|
|
protected function grabDataPath(\ReflectionProperty $property, array $data, array $tags): ?string |
|
|
@ -131,6 +165,9 @@ class Data2DtoConverter |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Трнансформируем на уровне класса |
|
|
|
|
|
|
|
*/ |
|
|
|
protected function processClassTransformers(\ReflectionObject $object, &$data, array $tags): void |
|
|
|
protected function processClassTransformers(\ReflectionObject $object, &$data, array $tags): void |
|
|
|
{ |
|
|
|
{ |
|
|
|
$className = $object->getName(); |
|
|
|
$className = $object->getName(); |
|
|
@ -148,6 +185,9 @@ class Data2DtoConverter |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Трнансформируем на уровне свойст объекта |
|
|
|
|
|
|
|
*/ |
|
|
|
protected function processTransformers(\ReflectionProperty $property, &$data, array $tags): void |
|
|
|
protected function processTransformers(\ReflectionProperty $property, &$data, array $tags): void |
|
|
|
{ |
|
|
|
{ |
|
|
|
$propertyName = $property->getName(); |
|
|
|
$propertyName = $property->getName(); |
|
|
@ -178,12 +218,12 @@ class Data2DtoConverter |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Если значение в $data = null, но поле не может его принять - пропустим |
|
|
|
* Если значение в $data = null, но поле не может его принять - пропустим |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private function checkNullRule($value, \ReflectionNamedType $reflectionPropertyType): bool |
|
|
|
private function processNull($value, \ReflectionNamedType $reflectionPropertyType): bool |
|
|
|
{ |
|
|
|
{ |
|
|
|
return $value === null && !$reflectionPropertyType->allowsNull(); |
|
|
|
return $value === null && !$reflectionPropertyType->allowsNull(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private function transformArray(&$value, \ReflectionProperty $property, array $tags): bool |
|
|
|
private function processArray(&$value, \ReflectionProperty $property, array $tags): bool |
|
|
|
{ |
|
|
|
{ |
|
|
|
$attributedPropertyClass = $this->grabPropertyDTOClass($property); |
|
|
|
$attributedPropertyClass = $this->grabPropertyDTOClass($property); |
|
|
|
|
|
|
|
|
|
|
@ -195,7 +235,7 @@ class Data2DtoConverter |
|
|
|
if ($propertyType === 'array' && $attributedPropertyClass) { |
|
|
|
if ($propertyType === 'array' && $attributedPropertyClass) { |
|
|
|
// Если тип у ДТО - массив, а в значении не массив - пропустим |
|
|
|
// Если тип у ДТО - массив, а в значении не массив - пропустим |
|
|
|
if (!is_array($value)) { |
|
|
|
if (!is_array($value)) { |
|
|
|
return false; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
$tempValue = []; |
|
|
|
$tempValue = []; |
|
|
|
foreach ($value as $itemValue) { |
|
|
|
foreach ($value as $itemValue) { |
|
|
@ -203,18 +243,17 @@ class Data2DtoConverter |
|
|
|
} |
|
|
|
} |
|
|
|
$value = $tempValue; |
|
|
|
$value = $tempValue; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private function grabPropertyDTOClass(\ReflectionProperty $property): ?string |
|
|
|
private function grabPropertyDTOClass(\ReflectionProperty $property): ?string |
|
|
|
{ |
|
|
|
{ |
|
|
|
$attributedPropertyClass = null; |
|
|
|
|
|
|
|
$propertyName = $property->getName(); |
|
|
|
$propertyName = $property->getName(); |
|
|
|
$propertyExtractor = new PropertyExtractor($property->class, $propertyName); |
|
|
|
$propertyExtractor = new PropertyExtractor($property->class, $propertyName); |
|
|
|
/** @var DTOMeta $dtoMeta */ |
|
|
|
/** @var DTOMeta $dtoMeta */ |
|
|
|
if ($dtoMeta = $propertyExtractor->fetch(DTOMeta::class)) { |
|
|
|
if ($dtoMeta = $propertyExtractor->fetch(DTOMeta::class)) { |
|
|
|
$attributedPropertyClass = $dtoMeta->class; |
|
|
|
return $dtoMeta->class; |
|
|
|
} |
|
|
|
} |
|
|
|
return $attributedPropertyClass; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|