Skip to content

Instantly share code, notes, and snippets.

@kmuenkel
Last active February 12, 2024 23:05
Show Gist options
  • Save kmuenkel/a35ad658e30f5c80f35b7669e5b58492 to your computer and use it in GitHub Desktop.
Save kmuenkel/a35ad658e30f5c80f35b7669e5b58492 to your computer and use it in GitHub Desktop.
Entity to array
<?php
/**
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
$self = function entityToArray(
\Chess\WebBundle\Entity\EntityInterface|array $entity,
\Chess\WebBundle\Doctrine\ORM\EntityRepository|\Doctrine\ORM\EntityManager|string $manager = null,
\Psr\Container\ContainerInterface $container = null
) use(&$self): array {
if (!$entity) {
return [];
}
if (is_array($entity)) {
return array_map(fn ($item) => $self($item, $depth, $manager, $container), $entity);
}
if (!$container) {
require_once __DIR__ . '/../app/AppKernel.php';
$kernel = new AppKernel('test', true);
$kernel->boot();
$container = $kernel->getContainer();
}
$entityManagerName = is_string($manager) ? $manager
: ($manager instanceof \Doctrine\ORM\EntityRepository
? ($manager->getConnection()?->getParams()['name'] ?: 'default') : 'default');
/** @var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $manager instanceof \Doctrine\ORM\EntityManager ? $manager
: $container->get('doctrine.orm.' . $entityManagerName . '_entity_manager');
if ($entityManagerName == 'default' && null === $manager) {
try {
$entityManager->getRepository(get_class($entity));
} catch (\Doctrine\Persistence\Mapping\MappingException) {
$entityManagers = [];
/** @var \Doctrine\ORM\EntityManagerInterface $entityManager */
foreach ($container->get('doctrine')->getManagers() as $entityManager) {
try {
$entityManager->getRepository(get_class($entity));
$entityManagers[] = $entityManager;
break;
} catch (\Doctrine\Persistence\Mapping\MappingException) {
}
}
if (count($entityManagers) != 1) {
throw new RuntimeException('Unable to identify a single EntityManager.');
}
$entityManager = current($entityManagers);
}
}
$values = ($entityToArray = function (
?Chess\WebBundle\Entity\EntityInterface $entity,
Doctrine\ORM\Mapping\ClassMetadataFactory $entityManager,
$depth
) use (&$entityToArray): array {
static $records = [];
if (in_array($recordId = $entity::class . '@' . $entity->getId(), $records)) {
return [$recordId => '{{RECURSION DETECTED}}'];
}
$records[] = $recordId;
$entityMetaData = $entityManager->getMetadataFor($entity::class);
$properties = array_keys($entityMetaData->getReflectionProperties());
$values = array_map(function (string $property) use ($entityToArray, $entityMetaData, $entity, $entityManager, $depth) {
$value = $entityMetaData->getFieldValue($entity, $property);
return ($normalize = function ($value) use (&$normalize, $entityToArray, $entityManager, $depth) {
static $level = 0;
++$level;
if ($level > 5) {
throw new RuntimeException('Recursion detected');
}
if ($value instanceof DateTimeImmutable || $value instanceof DateTime) {
$value = $value->format($value::ATOM);
} elseif (is_object($value) && in_array('__toString', get_class_methods($value))) {
$value = (string) $value;
$value = json_decode($value, true) ?: $value;
} elseif ($value instanceof \Chess\WebBundle\Entity\EntityInterface) {
$value = ($depth && $level >= $depth) ? '_DEPTH_REACHED' : $entityToArray($value, $entityManager, $depth);
} elseif ($value instanceof \Chess\Common\JsonData\DataTypeInterface) {
$properties = (new ReflectionClass($value))->getProperties();
$values = array_map(fn (ReflectionProperty $property) => $normalize($property->getValue($value)), $properties);
$names = array_map(fn (ReflectionProperty $property): string => $property->name, $properties);
$value = array_combine($names, $values);
} elseif ($value instanceof \Doctrine\ORM\PersistentCollection) {
$value = array_map(fn ($collectionValue) => $normalize($collectionValue), $value->getValues());
} elseif ($value instanceof stdClass) {
$value = json_decode(json_encode($value));
} elseif (is_object($value)) {
$value = (array) $value;
} elseif (is_string($value) && ($decoded = json_decode($value, true))) {
$value = $decoded;
}
--$level;
return $value;
})($value);
}, $properties);
return array_combine($properties, $values);
})($entity, $entityManager->getMetadataFactory(), $depth);
return $values;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment