Skip to content

Commit

Permalink
Check format in serializer (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
liquetsoft authored Sep 30, 2024
1 parent fc4d1b5 commit 1bcf3c7
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 44 deletions.
11 changes: 8 additions & 3 deletions Generator/DenormalizerGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Generator;

use Liquetsoft\Fias\Component\EntityDescriptor\EntityDescriptor;
use Liquetsoft\Fias\Component\Serializer\FiasSerializerFormat;
use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Method;
use Nette\PhpGenerator\PhpFile;
Expand Down Expand Up @@ -57,6 +58,7 @@ protected function decorateNamespace(PhpNamespace $namespace): void
$namespace->addUse(InvalidArgumentException::class);
$namespace->addUse(DenormalizerAwareInterface::class);
$namespace->addUse(DenormalizerAwareTrait::class);
$namespace->addUse(FiasSerializerFormat::class);

$descriptors = $this->getRegistry()->getDescriptors();
foreach ($descriptors as $descriptor) {
Expand All @@ -79,9 +81,12 @@ protected function decorateClass(ClassType $class): void
$class->addComment('Скомпилированный класс для денормализации сущностей ФИАС в модели.');

$compiledDataSet = 'fias_compiled_data_set';
$supportsBody = "return empty(\$context['{$compiledDataSet}'])\n && (\n";
$supportsBody = "return empty(\$context['{$compiledDataSet}'])\n && FiasSerializerFormat::XML->isEqual(\$format)\n && (\n";
$getSupportedTypesBody = '';
$denormalizeBody = '$data = \\is_array($data) ? $data : [];' . "\nunset(\$data['#']);\n";
$denormalizeBody = "if (!is_array(\$data)) {\n";
$denormalizeBody .= " throw new InvalidArgumentException('Bad data parameter. Array instance is required');\n";
$denormalizeBody .= "}\n\n";
$denormalizeBody .= "unset(\$data['#']);\n\n";
$denormalizeBody .= '$type = trim($type, " \t\n\r\0\x0B/");' . "\n\n";
$denormalizeBody .= "\$entity = \$context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? new \$type();\n\n";
$descriptors = $this->registry->getDescriptors();
Expand Down Expand Up @@ -131,7 +136,7 @@ protected function decorateClass(ClassType $class): void
->addComment('@return array<string, bool|null>')
->setReturnType('array')
->setVisibility('public')
->setBody("return [\n{$getSupportedTypesBody}];");
->setBody("return !FiasSerializerFormat::XML->isEqual(\$format) ? [] : [\n{$getSupportedTypesBody}];");
$getSupportedTypes->addParameter('format')->setType('string')->setNullable(true);

foreach ($descriptors as $descriptor) {
Expand Down
17 changes: 12 additions & 5 deletions Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,15 @@ services:



liquetsoft_fias.serializer.serializer:
class: Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer\FiasSerializer
liquetsoft_fias.serializer.uuid_denormalizer:
class: Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer\FiasUuidNormalizer
tags:
- { name: 'serializer.normalizer' }

liquetsoft_fias.serializer.compiled_denormalizer:
class: Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer\CompiledEntitesDenormalizer
tags:
- { name: 'serializer.normalizer' }



Expand Down Expand Up @@ -183,23 +190,23 @@ services:
- '@liquetsoft_fias.entity_manager.service'
- '@liquetsoft_fias.xml_reader.service'
- '@liquetsoft_fias.storage.service'
- '@liquetsoft_fias.serializer.serializer'
- '@serializer'

liquetsoft_fias.task.data.delete:
class: Liquetsoft\Fias\Component\Pipeline\Task\DataDeleteTask
arguments:
- '@liquetsoft_fias.entity_manager.service'
- '@liquetsoft_fias.xml_reader.service'
- '@liquetsoft_fias.storage.service'
- '@liquetsoft_fias.serializer.serializer'
- '@serializer'

liquetsoft_fias.task.data.upsert:
class: Liquetsoft\Fias\Component\Pipeline\Task\DataUpsertTask
arguments:
- '@liquetsoft_fias.entity_manager.service'
- '@liquetsoft_fias.xml_reader.service'
- '@liquetsoft_fias.storage.service'
- '@liquetsoft_fias.serializer.serializer'
- '@serializer'

liquetsoft_fias.task.version.get:
class: Liquetsoft\Fias\Component\Pipeline\Task\VersionGetTask
Expand Down
10 changes: 8 additions & 2 deletions Serializer/CompiledEntitesDenormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer;

use Liquetsoft\Fias\Component\Serializer\FiasSerializerFormat;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Entity\AddrObj;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Entity\AddrObjDivision;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Entity\AddrObjTypes;
Expand Down Expand Up @@ -49,6 +50,7 @@ class CompiledEntitesDenormalizer implements DenormalizerAwareInterface, Denorma
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
{
return empty($context['fias_compiled_data_set'])
&& FiasSerializerFormat::XML->isEqual($format)
&& (
is_subclass_of($type, Apartments::class)
|| is_subclass_of($type, AddrObjDivision::class)
Expand Down Expand Up @@ -84,8 +86,12 @@ public function supportsDenormalization(mixed $data, string $type, ?string $form
*/
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
{
$data = \is_array($data) ? $data : [];
if (!\is_array($data)) {
throw new InvalidArgumentException('Bad data parameter. Array instance is required');
}

unset($data['#']);

$type = trim($type, " \t\n\r\0\x0B/");

$entity = $context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? new $type();
Expand Down Expand Up @@ -156,7 +162,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
*/
public function getSupportedTypes(?string $format): array
{
return [
return !FiasSerializerFormat::XML->isEqual($format) ? [] : [
Apartments::class => false,
AddrObjDivision::class => false,
NormativeDocsTypes::class => false,
Expand Down
2 changes: 1 addition & 1 deletion Serializer/FiasSerializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function __construct(?array $normalizers = null, ?array $encoders = null)
if ($normalizers === null) {
$normalizers = [
new CompiledEntitesDenormalizer(),
new UuidNormalizer(),
new FiasUuidNormalizer(),
new DateTimeNormalizer(),
new ObjectNormalizer(
nameConverter: new FiasNameConverter(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/**
* Нормализатор для объектов uuid.
*/
final class UuidNormalizer implements DenormalizerInterface, NormalizerInterface
final class FiasUuidNormalizer implements DenormalizerInterface, NormalizerInterface
{
/**
* {@inheritDoc}
Expand Down
141 changes: 141 additions & 0 deletions Tests/Serializer/CompiledEntitesDenormalizerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

declare(strict_types=1);

namespace Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\Serializer;

use App\Entity\AddrObj;
use Liquetsoft\Fias\Component\Serializer\FiasSerializerFormat;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer\CompiledEntitesDenormalizer;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\BaseCase;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\MockEntities\FiasSerializerObject;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;

/**
* Тест для объекта, который сереализует данные из ФИАС.
*
* @internal
*/
final class CompiledEntitesDenormalizerTest extends BaseCase
{
/**
* Проверяет, что денормалайзер правильно определит, что может преобразовать тип.
*
* @dataProvider provideSupportsDenormalization
*/
public function testSupportsDenormalization(string $type, string $format, bool $expected): void
{
$denormalizer = new CompiledEntitesDenormalizer();
$res = $denormalizer->supportsDenormalization([], $type, $format);

$this->assertSame($expected, $res);
}

public static function provideSupportsDenormalization(): array
{
return [
'supported type and format' => [
FiasSerializerObject::class,
FiasSerializerFormat::XML->value,
true,
],
'unsupported type' => [
'test',
FiasSerializerFormat::XML->value,
false,
],
'unsupported format' => [
FiasSerializerObject::class,
'json',
false,
],
];
}

/**
* Проверяет, что объект правильно разберет данные из xml в объект.
*/
public function testDenormalize(): void
{
$id = 123321;
$objectGUID = 'f81d4fae-7dec-11d0-a765-00a0c91e6bf6';
$name = 'test name';
$updateDate = '2024-10-10';
$operTypeId = 321;

$data = [
'@ID' => $id,
'@OBJECTGUID' => $objectGUID,
'@NEXTID' => '',
'@NAME' => $name,
'@OPERTYPEID' => $operTypeId,
'@UPDATEDATE' => $updateDate,
];

$serializer = new CompiledEntitesDenormalizer();
$object = $serializer->denormalize($data, FiasSerializerObject::class, FiasSerializerFormat::XML->value);

$this->assertInstanceOf(FiasSerializerObject::class, $object);
$this->assertSame($id, $object->getId());
$this->assertSame($name, $object->getName());
$this->assertSame($operTypeId, $object->getOpertypeid());
$this->assertSame($updateDate, $object->getUpdatedate()->format('Y-m-d'));
$this->assertSame($objectGUID, (string) $object->getObjectguid());
$this->assertNull($object->getNextid());
}

/**
* Проверяет, что денормалайзер не будет обрабатывать данные, если предоставлен не массив.
*/
public function testDenormalizeNotAnArrayException(): void
{
$denormalizer = new CompiledEntitesDenormalizer();

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Array instance is required');
$denormalizer->denormalize(123, AddrObj::class, FiasSerializerFormat::XML->value);
}

/**
* Проверяет, что денормалайзер не будет обрабатывать данные, если указан неправильный тип.
*/
public function testDenormalizeWrongTypeException(): void
{
$denormalizer = new CompiledEntitesDenormalizer();

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Can't find data extractor");
$denormalizer->denormalize([], \stdClass::class, FiasSerializerFormat::XML->value);
}

/**
* Проверяет, что денормалайзер вернет верный список поддерживаемых объектов.
*
* @dataProvider provideGetSupportedTypes
*/
public function testGetSupportedTypes(?string $format, array|true $expected): void
{
$denormalizer = new CompiledEntitesDenormalizer();
$res = $denormalizer->getSupportedTypes($format);

if ($expected === true) {
$this->assertNotEmpty($res);
} else {
$this->assertSame($expected, $res);
}
}

public static function provideGetSupportedTypes(): array
{
return [
'xml format' => [
FiasSerializerFormat::XML->value,
true,
],
'non xml format' => [
'json',
[],
],
];
}
}
5 changes: 3 additions & 2 deletions Tests/Serializer/FiasSerializerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\Serializer;

use Liquetsoft\Fias\Component\Serializer\FiasSerializerFormat;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Serializer\FiasSerializer;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\BaseCase;
use Liquetsoft\Fias\Symfony\LiquetsoftFiasBundle\Tests\MockEntities\FiasSerializerObject;
Expand All @@ -16,7 +17,7 @@
final class FiasSerializerTest extends BaseCase
{
/**
* Проверяет, что объект правильно разберет данные их xml в объект.
* Проверяет, что объект правильно разберет данные из xml в объект.
*/
public function testDenormalize(): void
{
Expand All @@ -42,7 +43,7 @@ public function testDenormalize(): void
EOT;

$serializer = new FiasSerializer();
$object = $serializer->deserialize($data, FiasSerializerObject::class, 'xml');
$object = $serializer->deserialize($data, FiasSerializerObject::class, FiasSerializerFormat::XML->value);

$this->assertInstanceOf(FiasSerializerObject::class, $object);
$this->assertSame($id, $object->getId());
Expand Down
Loading

0 comments on commit 1bcf3c7

Please sign in to comment.