|
|
@ -14,9 +14,20 @@ use Rinsvent\DTO2Data\Attribute\Schema; |
|
|
|
use Rinsvent\DTO2Data\Resolver\TransformerResolverStorage; |
|
|
|
use Rinsvent\DTO2Data\Resolver\TransformerResolverStorage; |
|
|
|
use Rinsvent\DTO2Data\Transformer\Meta; |
|
|
|
use Rinsvent\DTO2Data\Transformer\Meta; |
|
|
|
use Rinsvent\DTO2Data\Transformer\TransformerInterface; |
|
|
|
use Rinsvent\DTO2Data\Transformer\TransformerInterface; |
|
|
|
|
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccess; |
|
|
|
|
|
|
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; |
|
|
|
|
|
|
|
|
|
|
|
class Dto2DataConverter |
|
|
|
class Dto2DataConverter |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
private PropertyAccessorInterface $propertyAccessor; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function __construct() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder() |
|
|
|
|
|
|
|
->disableExceptionOnInvalidPropertyPath() |
|
|
|
|
|
|
|
->getPropertyAccessor(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public function getTags(object $object, array $tags = []): array |
|
|
|
public function getTags(object $object, array $tags = []): array |
|
|
|
{ |
|
|
|
{ |
|
|
|
return $this->processTags($object, $tags); |
|
|
|
return $this->processTags($object, $tags); |
|
|
@ -54,15 +65,11 @@ class Dto2DataConverter |
|
|
|
public function convertObjectByMap(object $object, array $map, array $tags = []): array |
|
|
|
public function convertObjectByMap(object $object, array $map, array $tags = []): array |
|
|
|
{ |
|
|
|
{ |
|
|
|
$data = []; |
|
|
|
$data = []; |
|
|
|
|
|
|
|
|
|
|
|
$reflectionObject = new \ReflectionObject($object); |
|
|
|
$reflectionObject = new \ReflectionObject($object); |
|
|
|
foreach ($map as $key => $propertyInfo) { |
|
|
|
foreach ($map as $key => $propertyInfo) { |
|
|
|
|
|
|
|
try { |
|
|
|
$sourceName = is_array($propertyInfo) ? $key : $propertyInfo; |
|
|
|
$sourceName = is_array($propertyInfo) ? $key : $propertyInfo; |
|
|
|
|
|
|
|
|
|
|
|
if (!method_exists($object, $sourceName) && !property_exists($object, $sourceName)) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$value = $this->grabValue($object, $sourceName, $tags); |
|
|
|
$value = $this->grabValue($object, $sourceName, $tags); |
|
|
|
|
|
|
|
|
|
|
|
$canSkip = false; |
|
|
|
$canSkip = false; |
|
|
@ -84,17 +91,16 @@ class Dto2DataConverter |
|
|
|
|
|
|
|
|
|
|
|
$dataPath = $this->grabIterationDataPath($object, $sourceName, $tags); |
|
|
|
$dataPath = $this->grabIterationDataPath($object, $sourceName, $tags); |
|
|
|
$data[$dataPath] = $value; |
|
|
|
$data[$dataPath] = $value; |
|
|
|
|
|
|
|
} catch (\Throwable $e) { |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$this->processClassTransformers($reflectionObject, $data, $tags); |
|
|
|
$this->processClassTransformers($reflectionObject, $data, $tags); |
|
|
|
|
|
|
|
|
|
|
|
return $data; |
|
|
|
return $data; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public function convertArrayByMap($data, ?array $map, array $tags = []): ?array |
|
|
|
public function convertArrayByMap($data, ?array $map, array $tags = []): ?array |
|
|
|
{ |
|
|
|
{ |
|
|
|
// $isAssociative = count($data) && !array_key_exists(0, $data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$tempValue = []; |
|
|
|
$tempValue = []; |
|
|
|
foreach ($data as $key => $item) { |
|
|
|
foreach ($data as $key => $item) { |
|
|
|
if (is_scalar($item)) { |
|
|
|
if (is_scalar($item)) { |
|
|
@ -113,13 +119,11 @@ class Dto2DataConverter |
|
|
|
return $tempValue; |
|
|
|
return $tempValue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected function grabValue(object $object, $sourceName, array $tags) |
|
|
|
protected function grabValue(object $object, string $sourceName, array $tags) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (method_exists($object, $sourceName)) { |
|
|
|
if (!method_exists($object, $sourceName) && !property_exists($object, $sourceName)) { |
|
|
|
$reflectionSource = new ReflectionMethod($object, $sourceName); |
|
|
|
return $this->getValueByPath($object, $sourceName); |
|
|
|
return $this->getMethodValue($object, $reflectionSource); |
|
|
|
} |
|
|
|
} elseif (property_exists($object, $sourceName)) { |
|
|
|
|
|
|
|
$reflectionSource = new ReflectionProperty($object, $sourceName); |
|
|
|
|
|
|
|
$propertyExtractor = new PropertyExtractor($object::class, $sourceName); |
|
|
|
$propertyExtractor = new PropertyExtractor($object::class, $sourceName); |
|
|
|
/** @var PropertyPath $propertyPath */ |
|
|
|
/** @var PropertyPath $propertyPath */ |
|
|
|
while ($propertyPath = $propertyExtractor->fetch(PropertyPath::class)) { |
|
|
|
while ($propertyPath = $propertyExtractor->fetch(PropertyPath::class)) { |
|
|
@ -129,29 +133,33 @@ class Dto2DataConverter |
|
|
|
} |
|
|
|
} |
|
|
|
return $this->getValueByPath($object, $propertyPath->path); |
|
|
|
return $this->getValueByPath($object, $propertyPath->path); |
|
|
|
} |
|
|
|
} |
|
|
|
return $this->getValue($object, $reflectionSource); |
|
|
|
return $this->getValueByPath($object, $sourceName); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public function processIterationTransformers(object $object, string $sourceName, &$value, array $tags): void |
|
|
|
public function processIterationTransformers(object $object, string $sourceName, &$value, array $tags): void |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (method_exists($object, $sourceName)) { |
|
|
|
if (property_exists($object, $sourceName)) { |
|
|
|
$reflectionSource = new ReflectionMethod($object, $sourceName); |
|
|
|
|
|
|
|
$this->processMethodTransformers($reflectionSource, $value, $tags); |
|
|
|
|
|
|
|
} elseif (property_exists($object, $sourceName)) { |
|
|
|
|
|
|
|
$reflectionSource = new ReflectionProperty($object, $sourceName); |
|
|
|
$reflectionSource = new ReflectionProperty($object, $sourceName); |
|
|
|
$this->processTransformers($reflectionSource, $value, $tags); |
|
|
|
$this->processTransformers($reflectionSource, $value, $tags); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
$getter = $this->grabGetterName($object, $sourceName); |
|
|
|
|
|
|
|
if ($getter) { |
|
|
|
|
|
|
|
$reflectionSource = new ReflectionMethod($object, $getter); |
|
|
|
|
|
|
|
$this->processMethodTransformers($reflectionSource, $value, $tags); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public function grabIterationDataPath(object $object, string $sourceName, array $tags): string |
|
|
|
public function grabIterationDataPath(object $object, string $sourceName, array $tags): string |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (method_exists($object, $sourceName)) { |
|
|
|
$getter = $this->grabGetterName($object, $sourceName); |
|
|
|
$reflectionSource = new ReflectionMethod($object, $sourceName); |
|
|
|
if ($getter) { |
|
|
|
|
|
|
|
$reflectionSource = new ReflectionMethod($object, $getter); |
|
|
|
$dataPath = $this->grabMethodDataPath($reflectionSource, $tags); |
|
|
|
$dataPath = $this->grabMethodDataPath($reflectionSource, $tags); |
|
|
|
} elseif (property_exists($object, $sourceName)) { |
|
|
|
if ($dataPath) { |
|
|
|
|
|
|
|
return $dataPath; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (property_exists($object, $sourceName)) { |
|
|
|
$reflectionSource = new ReflectionProperty($object, $sourceName); |
|
|
|
$reflectionSource = new ReflectionProperty($object, $sourceName); |
|
|
|
$dataPath = $this->grabDataPath($reflectionSource, $tags); |
|
|
|
$dataPath = $this->grabDataPath($reflectionSource, $tags); |
|
|
|
} |
|
|
|
} |
|
|
@ -254,71 +262,11 @@ class Dto2DataConverter |
|
|
|
|
|
|
|
|
|
|
|
private function getValueByPath($data, string $path) |
|
|
|
private function getValueByPath($data, string $path) |
|
|
|
{ |
|
|
|
{ |
|
|
|
$parts = explode('.', $path); |
|
|
|
try { |
|
|
|
$length = count($parts); |
|
|
|
return $this->propertyAccessor->getValue($data, $path); |
|
|
|
$i = 1; |
|
|
|
} catch (\Throwable $e) { |
|
|
|
foreach ($parts as $part) { |
|
|
|
|
|
|
|
// Если получили скалярное значение но прошли не весь путь, то вернем null |
|
|
|
|
|
|
|
if (is_scalar($data) && $i < $length) { |
|
|
|
|
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
// Если объекс реализует ArrayAccess, то получаем значение и идем дальше |
|
|
|
|
|
|
|
if (is_object($data) && $data instanceof \ArrayAccess) { |
|
|
|
|
|
|
|
$data = $data[$part] ?? null; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Если объект, то достаем значение |
|
|
|
|
|
|
|
if (is_object($data)) { |
|
|
|
|
|
|
|
if (!property_exists($data, $part)) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
$property = new ReflectionProperty($data, $part); |
|
|
|
|
|
|
|
$data = $this->getValue($data, $property); |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Если массив, то достаем занчение и идем дальше |
|
|
|
|
|
|
|
if (is_array($data)) { |
|
|
|
|
|
|
|
$data = $data[$part] ?? null; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
$i++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $data; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function getValue(object $object, \ReflectionProperty $property) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!$property->isPublic()) { |
|
|
|
|
|
|
|
$property->setAccessible(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!$property->isInitialized($object)) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$value = $property->getValue($object); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!$property->isPublic()) { |
|
|
|
|
|
|
|
$property->setAccessible(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function getMethodValue(object $object, ReflectionMethod $method) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!$method->isPublic()) { |
|
|
|
|
|
|
|
$method->setAccessible(true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$value = $method->invoke($object); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!$method->isPublic()) { |
|
|
|
|
|
|
|
$method->setAccessible(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $value; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private function grabSchema(object $object, array $tags): ?Schema |
|
|
|
private function grabSchema(object $object, array $tags): ?Schema |
|
|
@ -367,4 +315,15 @@ class Dto2DataConverter |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function grabGetterName(object $object, string $sourceName): ?string |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
$prefixes = ['get', 'has', 'is']; |
|
|
|
|
|
|
|
foreach ($prefixes as $prefix) { |
|
|
|
|
|
|
|
if (method_exists($object, $prefix . ucfirst($sourceName))) { |
|
|
|
|
|
|
|
return $prefix . ucfirst($sourceName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|