chill-bundles/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodWorkDenormalizer.php
2021-11-30 12:27:49 +01:00

127 lines
4.4 KiB
PHP

<?php
/**
* 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\PersonBundle\Serializer\Normalizer;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use function array_key_exists;
use function array_merge;
use function in_array;
use function is_array;
/**
* This denormalizer rely on AbstractNormalizer for most of the job, and
* add some logic for synchronizing collection.
*/
class AccompanyingPeriodWorkDenormalizer implements ContextAwareDenormalizerInterface, DenormalizerAwareInterface
{
use DenormalizerAwareTrait;
use ObjectToPopulateTrait;
public const GROUP_CREATE = 'accompanying_period_work:create';
public const GROUP_EDIT = 'accompanying_period_work:edit';
private EntityManagerInterface $em;
private AccompanyingPeriodWorkRepository $workRepository;
public function __construct(
AccompanyingPeriodWorkRepository $workRepository,
EntityManagerInterface $em
) {
$this->workRepository = $workRepository;
$this->em = $em;
}
public function denormalize($data, string $type, ?string $format = null, array $context = [])
{
$work = $this->denormalizer->denormalize($data, $type, $format, array_merge(
$context,
['skip' => self::class]
));
if (in_array('accompanying_period_work:edit', $context['groups'] ?? [])) {
$this->handleEvaluationCollection($data, $work, $format, $context);
}
return $work;
}
public function supportsDenormalization($data, string $type, ?string $format = null, array $context = []): bool
{
return AccompanyingPeriodWork::class === $type
&& self::class !== ($context['skip'] ?? null)
&& is_array($data)
&& array_key_exists('type', $data)
&& 'accompanying_period_work' === $data['type'];
}
private function handleEvaluationCollection(array $data, AccompanyingPeriodWork $work, string $format, array $context)
{
$dataById = [];
$dataWithoutId = [];
foreach ($data['accompanyingPeriodWorkEvaluations'] as $e) {
if (array_key_exists('id', $e)) {
$dataById[$e['id']] = $e;
} else {
$dataWithoutId[] = $e;
}
}
// partition the separate kept evaluations and removed one
[$kept, $removed] = $work->getAccompanyingPeriodWorkEvaluations()
->partition(
static fn (int $key, AccompanyingPeriodWorkEvaluation $a) => array_key_exists($a->getId(), $dataById)
);
// remove the evaluations from work
foreach ($removed as $r) {
$work->removeAccompanyingPeriodWorkEvaluation($r);
}
// handle the evaluation kept
foreach ($kept as $k) {
$this->denormalizer->denormalize(
$dataById[$k->getId()],
AccompanyingPeriodWorkEvaluation::class,
$format,
array_merge(
$context,
[
'groups' => ['write'],
AbstractNormalizer::OBJECT_TO_POPULATE => $k,
]
)
);
}
// create new evaluation
foreach ($dataWithoutId as $newData) {
$evaluation = $this->denormalizer->denormalize(
$newData,
AccompanyingPeriodWorkEvaluation::class,
$format,
array_merge(
$context,
['groups' => ['accompanying_period_work_evaluation:create']]
)
);
$work->addAccompanyingPeriodWorkEvaluation($evaluation);
}
}
}