Rewrote PartNormalizer so that it does not use ObjectNormalizer directly

This commit is contained in:
Jan Böhmer 2024-03-03 19:28:44 +01:00
parent e53da5ad06
commit 7a90d3f281
2 changed files with 28 additions and 18 deletions

View file

@ -29,21 +29,24 @@ use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Orderdetail;
use App\Entity\PriceInformations\Pricedetail; use App\Entity\PriceInformations\Pricedetail;
use Brick\Math\BigDecimal; use Brick\Math\BigDecimal;
use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
/** /**
* @see \App\Tests\Serializer\PartNormalizerTest * @see \App\Tests\Serializer\PartNormalizerTest
* TODO: Properly rewrite this class to use the SerializerAware interface and dont use the ObjectNormalizer directly
*/ */
class PartNormalizer implements NormalizerInterface, DenormalizerInterface class PartNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerAwareInterface, DenormalizerAwareInterface
{ {
use NormalizerAwareTrait;
use DenormalizerAwareTrait;
private const ALREADY_CALLED = 'PART_NORMALIZER_ALREADY_CALLED';
private const DENORMALIZE_KEY_MAPPING = [ private const DENORMALIZE_KEY_MAPPING = [
'notes' => 'comment', 'notes' => 'comment',
'quantity' => 'instock', 'quantity' => 'instock',
@ -56,10 +59,6 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
public function __construct( public function __construct(
private readonly StructuralElementFromNameDenormalizer $locationDenormalizer, private readonly StructuralElementFromNameDenormalizer $locationDenormalizer,
#[Autowire(service: ObjectNormalizer::class)]
private readonly NormalizerInterface $normalizer,
#[Autowire(service: ObjectNormalizer::class)]
private readonly DenormalizerInterface $denormalizer,
) )
{ {
} }
@ -67,20 +66,22 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
public function supportsNormalization($data, string $format = null, array $context = []): bool public function supportsNormalization($data, string $format = null, array $context = []): bool
{ {
//We only remove the type field for CSV export //We only remove the type field for CSV export
return $format === 'csv' && $data instanceof Part ; return !isset($context[self::ALREADY_CALLED]) && $format === 'csv' && $data instanceof Part ;
} }
/** public function normalize($object, string $format = null, array $context = []): array
* @return (float|mixed)[]|\ArrayObject|null|scalar
*
* @psalm-return \ArrayObject|array{total_instock: float|mixed,...}|null|scalar
*/
public function normalize($object, string $format = null, array $context = [])
{ {
if (!$object instanceof Part) { if (!$object instanceof Part) {
throw new \InvalidArgumentException('This normalizer only supports Part objects!'); throw new \InvalidArgumentException('This normalizer only supports Part objects!');
} }
$context[self::ALREADY_CALLED] = true;
//Prevent exception in API Platform
if ($object->getID() === null) {
$context['iri'] = 'not-persisted';
}
$data = $this->normalizer->normalize($object, $format, $context); $data = $this->normalizer->normalize($object, $format, $context);
//Remove type field for CSV export //Remove type field for CSV export
@ -93,7 +94,7 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
{ {
return is_array($data) && is_a($type, Part::class, true); return !isset($context[self::ALREADY_CALLED]) && is_array($data) && is_a($type, Part::class, true);
} }
private function normalizeKeys(array &$data): array private function normalizeKeys(array &$data): array
@ -129,6 +130,8 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface
$data['minamount'] = 0.0; $data['minamount'] = 0.0;
} }
$context[self::ALREADY_CALLED] = true;
$object = $this->denormalizer->denormalize($data, $type, $format, $context); $object = $this->denormalizer->denormalize($data, $type, $format, $context);
if (!$object instanceof Part) { if (!$object instanceof Part) {

View file

@ -28,17 +28,24 @@ use App\Entity\PriceInformations\Orderdetail;
use App\Entity\PriceInformations\Pricedetail; use App\Entity\PriceInformations\Pricedetail;
use App\Serializer\PartNormalizer; use App\Serializer\PartNormalizer;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class PartNormalizerTest extends WebTestCase class PartNormalizerTest extends WebTestCase
{ {
/** @var PartNormalizer */ /** @var PartNormalizer */
protected $service; protected DenormalizerInterface&NormalizerInterface $service;
protected function setUp(): void protected function setUp(): void
{ {
//Get a service instance. //Get a service instance.
self::bootKernel(); self::bootKernel();
$this->service = self::getContainer()->get(PartNormalizer::class); $this->service = self::getContainer()->get(PartNormalizer::class);
//We need to inject the serializer into the normalizer, as we use it directly
$serializer = self::getContainer()->get('serializer');
$this->service->setNormalizer($serializer);
$this->service->setDenormalizer($serializer);
} }
public function testSupportsNormalization(): void public function testSupportsNormalization(): void