Files
chill-bundles/src/Bundle/ChillMainBundle/Export/ExportDataNormalizerTrait.php

190 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Export;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Doctrine\Common\Collections\Collection;
use Doctrine\Persistence\ObjectRepository;
/**
* Provides utilities for normalizing and denormalizing data entities and dates.
*/
trait ExportDataNormalizerTrait
{
/**
* Normalizes a Doctrine entity or a collection of entities to extract their identifiers.
*
* @param object|list<object>|null $entity the entity or collection of entities to normalize
*
* @return array|int|string Returns the identifier(s) of the entity or entities. If an array of entities is provided,
* an array of their identifiers is returned. If a single entity is provided, its identifier
* is returned. If null, returns an empty value.
*/
private function normalizeDoctrineEntity(object|array|null $entity): array|int|string
{
if (is_array($entity)) {
return array_values(array_filter(array_map(static fn (object $entity) => $entity->getId(), $entity), fn ($value) => null !== $value));
}
if ($entity instanceof Collection) {
return $this->normalizeDoctrineEntity($entity->toArray());
}
return $entity?->getId();
}
/**
* Denormalizes a Doctrine entity by fetching it from the provided repository based on the given ID(s).
*
* @param list<int>|int|string $id the identifier(s) of the entity to find
* @param ObjectRepository $repository the Doctrine repository to query
*
* @return object|array<object> the found entity or an array of entities if multiple IDs are provided
*
* @throws \UnexpectedValueException when the entity with the given ID does not exist
*/
private function denormalizeDoctrineEntity(array|int|string $id, ObjectRepository $repository): object|array
{
if (is_array($id)) {
if ([] === $id) {
return [];
}
return $repository->findBy(['id' => $id]);
}
if (null === $object = $repository->find($id)) {
throw new \UnexpectedValueException(sprintf('Object with id "%s" does not exist.', $id));
}
return $object;
}
/**
* Normalizer the "user or me" values.
*
* @param 'me'|User|iterable<'me'|User> $user
*
* @return int|'me'|list<'me'|int>
*/
private function normalizeUserOrMe(string|User|iterable $user): int|string|array
{
if (is_iterable($user)) {
$users = [];
foreach ($user as $u) {
$users[] = $this->normalizeUserOrMe($u);
}
return $users;
}
if ('me' === $user) {
return $user;
}
return $user->getId();
}
/**
* @param 'me'|int|iterable<'me'|int> $userId
*
* @return 'me'|User|array|null
*/
private function denormalizeUserOrMe(string|int|iterable $userId, UserRepositoryInterface $userRepository): string|User|array|null
{
if (is_iterable($userId)) {
$users = [];
foreach ($userId as $id) {
$users[] = $this->denormalizeUserOrMe($id, $userRepository);
}
return $users;
}
if ('me' === $userId) {
return 'me';
}
return $userRepository->find($userId);
}
/**
* @param 'me'|User|iterable<'me'|User> $user
*
* @return User|list<User>
*/
private function userOrMe(string|User|iterable $user, ExportGenerationContext $context): User|array
{
if (is_iterable($user)) {
$users = [];
foreach ($user as $u) {
$users[] = $this->userOrMe($u, $context);
}
return array_values(
array_filter($users, static fn (?User $user) => null !== $user)
);
}
if ('me' === $user) {
return $context->byUser;
}
return $user;
}
/**
* Normalizes a provided date into a specific string format.
*
* @param \DateTimeImmutable|\DateTime $date the date instance to normalize
*
* @return string a formatted string containing the type and formatted date
*/
private function normalizeDate(\DateTimeImmutable|\DateTime $date): string
{
return sprintf(
'%s,%s',
$date instanceof \DateTimeImmutable ? 'imm1' : 'mut1',
$date->format('d-m-Y-H:i:s.u e'),
);
}
/**
* Denormalizes a string back into a DateTime instance.
*
* The string is expected to contain a kind selector (e.g., 'imm1' or 'mut1')
* to determine the type of DateTime object (immutable or mutable) followed by a date format.
*
* @param string $date the string to be denormalized, containing the kind selector and formatted date
*
* @return \DateTimeImmutable|\DateTime a DateTime instance created from the given string
*
* @throws \UnexpectedValueException if the kind selector or date format is invalid
*/
private function denormalizeDate(string $date): \DateTimeImmutable|\DateTime
{
$format = 'd-m-Y-H:i:s.u e';
$denormalized = match (substr($date, 0, 4)) {
'imm1' => \DateTimeImmutable::createFromFormat($format, substr($date, 5)),
'mut1' => \DateTime::createFromFormat($format, substr($date, 5)),
default => throw new \UnexpectedValueException(sprintf('Unexpected format for the kind selector: %s', substr($date, 0, 4))),
};
if (false === $denormalized) {
throw new \UnexpectedValueException(sprintf('Unexpected date format: %s', substr($date, 5)));
}
return $denormalized;
}
}