Refactor AccompanyingPeriodWorkEvaluationDocument serialization: remove redundant read groups, adjust normalization logic, and add dedicated test class.

This commit is contained in:
2026-01-02 17:30:40 +01:00
parent de5bdf7aa6
commit 38b24c18bf
3 changed files with 113 additions and 17 deletions

View File

@@ -19,7 +19,6 @@ use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute as Serializer;
use Symfony\Component\Validator\Constraints as Assert;
#[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['accompanying_period_work_evaluation_document' => AccompanyingPeriodWorkEvaluationDocument::class])]
#[ORM\Entity]
#[ORM\Table('chill_person_accompanying_period_work_evaluation_document')]
class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doctrine\Model\TrackCreationInterface, \Chill\MainBundle\Doctrine\Model\TrackUpdateInterface
@@ -34,7 +33,7 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
/**
* @internal the default name exceeds 64 characters, we must set manually:
*/
#[Serializer\Groups(['read', 'accompanying_period_work_evaluation:create'])]
#[Serializer\Groups(['accompanying_period_work_evaluation:create'])]
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
@@ -48,15 +47,15 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
* This data is not persisted into database, but will appears on the data
* normalized during the same request (like PUT/PATCH request)
*/
#[Serializer\Groups(['read', 'write', 'accompanying_period_work_evaluation:create'])]
#[Serializer\Groups(['write', 'accompanying_period_work_evaluation:create'])]
private $key;
#[Serializer\Groups(['read', 'write', 'accompanying_period_work_evaluation:create'])]
#[Serializer\Groups(['write', 'accompanying_period_work_evaluation:create'])]
#[Assert\Valid]
#[ORM\ManyToOne(targetEntity: StoredObject::class)]
private ?StoredObject $storedObject = null;
#[Serializer\Groups(['read', 'accompanying_period_work_evaluation:create'])]
#[Serializer\Groups(['accompanying_period_work_evaluation:create'])]
#[ORM\ManyToOne(targetEntity: DocGeneratorTemplate::class)]
private ?DocGeneratorTemplate $template = null;
@@ -90,8 +89,7 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
return $this->template;
}
#[Serializer\Groups(['read'])]
public function getTitle(): ?string
public function getTitle(): string
{
return (string) $this->getStoredObject()?->getTitle();
}

View File

@@ -14,6 +14,7 @@ namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Workflow\Helper\MetadataExtractor;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -23,15 +24,17 @@ class AccompanyingPeriodWorkEvaluationDocumentNormalizer implements NormalizerIn
{
use NormalizerAwareTrait;
private const string SKIP = 'accompanying_period_work_evaluation_document_skip';
public function __construct(private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly MetadataExtractor $metadataExtractor, private readonly Registry $registry) {}
public function normalize($object, ?string $format = null, array $context = []): array
{
$initial = $this->normalizer->normalize($object, $format, array_merge($context, [
self::SKIP => spl_object_hash($object),
]));
if (!$object instanceof AccompanyingPeriodWorkEvaluationDocument) {
throw new UnexpectedValueException('Expected AccompanyingPeriodWorkEvaluationDocument object, got '.(is_object($object) ? get_class($object) : gettype($object)));
}
$initial = $this->normalizeProperties($object, $format, $context);
$initial['type'] = 'accompanying_period_work_evaluation_document';
$initial['workflows_availables'] = $this->metadataExtractor->availableWorkflowFor(
AccompanyingPeriodWorkEvaluationDocument::class,
@@ -45,14 +48,32 @@ class AccompanyingPeriodWorkEvaluationDocumentNormalizer implements NormalizerIn
return $initial;
}
private function normalizeProperties(AccompanyingPeriodWorkEvaluationDocument $object, ?string $format, array $context): array
{
$data = [];
$groups = (array) ($context['groups'] ?? []);
if (in_array('read', $groups, true)) {
$data['id'] = $object->getId();
$data['key'] = $object->getKey();
$data['storedObject'] = $this->normalizer->normalize($object->getStoredObject(), $format, $context);
$data['template'] = $this->normalizer->normalize($object->getTemplate(), $format, $context);
$data['title'] = $object->getTitle();
}
return $data;
}
public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{
$groups = $context['groups'] ?? [];
if (is_string($groups)) {
$groups = [$groups];
}
return $data instanceof AccompanyingPeriodWorkEvaluationDocument
&& 'json' === $format
&& (
!\array_key_exists(self::SKIP, $context)
|| spl_object_hash($data) !== $context[self::SKIP]
);
&& in_array('read', $groups, true)
&& 'json' === $format;
}
public function getSupportedTypes(?string $format): array

View File

@@ -0,0 +1,77 @@
<?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\PersonBundle\Tests\Serializer\Normalizer;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Workflow\Helper\MetadataExtractor;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Serializer\Normalizer\AccompanyingPeriodWorkEvaluationDocumentNormalizer;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Workflow\Registry;
/**
* @internal
*
* @covers \Chill\PersonBundle\Serializer\Normalizer\AccompanyingPeriodWorkEvaluationDocumentNormalizer
*/
final class AccompanyingPeriodWorkEvaluationDocumentNormalizerTest extends TestCase
{
use ProphecyTrait;
public function testNormalize(): void
{
$entityWorkflowRepository = $this->prophesize(EntityWorkflowRepository::class);
$metadataExtractor = $this->prophesize(MetadataExtractor::class);
$registry = $this->prophesize(Registry::class);
$serializer = $this->prophesize(NormalizerInterface::class);
$normalizer = new AccompanyingPeriodWorkEvaluationDocumentNormalizer(
$entityWorkflowRepository->reveal(),
$metadataExtractor->reveal(),
$registry->reveal()
);
$normalizer->setNormalizer($serializer->reveal());
$storedObject = new StoredObject();
$template = new DocGeneratorTemplate();
$object = new AccompanyingPeriodWorkEvaluationDocument();
$object->setStoredObject($storedObject);
$object->setTemplate($template);
$object->setKey('abc');
$context = ['groups' => ['read']];
$serializer->normalize($storedObject, 'json', $context)->willReturn(['id' => 1]);
$serializer->normalize($template, 'json', $context)->willReturn(['id' => 2]);
$metadataExtractor->availableWorkflowFor(AccompanyingPeriodWorkEvaluationDocument::class)
->willReturn(['workflow_1']);
$entityWorkflowRepository->findBy(['relatedEntityClass' => AccompanyingPeriodWorkEvaluationDocument::class])
->willReturn([]);
$serializer->normalize([], 'json', $context)->willReturn([]);
$result = $normalizer->normalize($object, 'json', $context);
$this->assertEquals('abc', $result['key']);
$this->assertEquals(['id' => 1], $result['storedObject']);
$this->assertEquals(['id' => 2], $result['template']);
$this->assertEquals('accompanying_period_work_evaluation_document', $result['type']);
$this->assertEquals(['workflow_1'], $result['workflows_availables']);
$this->assertEquals([], $result['workflows']);
}
}