diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 550e072..b3b67c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,8 +28,12 @@ jobs: fail-fast: false matrix: odoo: [13, 14, 15, 16, 17] - symfony: ["^5.4", "^6.4"] + symfony: ["^6.4", "^7.1"] php: ["8.1", "8.2", "8.3"] # " required to keep the .0 + exclude: + - + symfony: ^7.1 + php: "8.1" services: postgres: image: postgres @@ -147,9 +151,6 @@ jobs: - name: Run PHPStan run: vendor/bin/phpstan analyse -l max src/ tests/ - - - name: Run Psalm - run: vendor/bin/psalm --show-info=false --output-format=github --php-version=${{ matrix.php }} - name: Run PHPUnit run: vendor/bin/phpunit --colors=always diff --git a/composer.json b/composer.json index d55ab2b..ad23c8e 100644 --- a/composer.json +++ b/composer.json @@ -30,15 +30,15 @@ "php-http/client-common": "^2.1", "php-http/discovery": "^1.7", "psr/http-factory-implementation": "^1.0", - "symfony/console": "^5.4|^6.4", - "symfony/serializer": "^5.4|^6.4", - "symfony/property-access": "^5.4|^6.4", - "symfony/property-info": "^5.4|^6.4", - "symfony/string": "^5.4|^6.4", - "symfony/http-kernel": "^5.4|^6.4", + "symfony/console": "^6.4|^7.1", + "symfony/serializer": "^6.4|^7.1", + "symfony/property-access": "^6.4|^7.1", + "symfony/property-info": "^6.4|^7.1", + "symfony/string": "^6.4|^7.1", + "symfony/http-kernel": "^6.4|^7.1", "php-http/logger-plugin": "^1.1", + "phpdocumentor/reflection-docblock": "^5.4", "prometee/php-class-generator": "^1.0", - "doctrine/annotations": "^1.13|^2.0", "webmozart/assert": "^1" }, "require-dev": { @@ -49,7 +49,6 @@ "http-interop/http-factory-guzzle": "^1.0", "symplify/easy-coding-standard": "^12", "phpstan/phpstan": "^1", - "vimeo/psalm": "^5", "rector/rector": "^1.0.4" }, "suggest": { @@ -60,7 +59,8 @@ "bin/odoo-model-classes-generator" ], "autoload": { - "psr-4": { "FluxSE\\OdooApiClient\\": "src/" } + "psr-4": { "FluxSE\\OdooApiClient\\": "src/" }, + "files": ["src/functions.php"] }, "autoload-dev": { "psr-4": { "Tests\\FluxSE\\OdooApiClient\\": "tests/" } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bf149d7..1f1b69c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -12,18 +12,16 @@ parameters: - identifier: missingType.iterableValue - '/Method FluxSE\\OdooApiClient\\Manager\\ModelListManager::(find|findBy|findByIds)\(\) should return (array<|\()T of FluxSE\\OdooApiClient\\Model\\BaseInterface(>|\)\|null) but returns mixed\./' - '/Method FluxSE\\OdooApiClient\\Serializer\\(Json|Xml)Rpc\\(Json|Xml)RpcSerializerHelper::decodeResponseBody\(\) should return array\|bool\|int\|string but returns mixed\./' - - - message: '/Class FluxSE\\OdooApiClient\\Serializer\\OdooNormalizer extends \@final class Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer\./' + message: '/Method FluxSE\\OdooApiClient\\Serializer\\OdooNormalizer::normalize\(\) return type with generic class ArrayObject does not specify its types: TKey, TValue/' count: 1 path: src/Serializer/OdooNormalizer.php + # Symfony 6.4 - - message: '/Parameter #1 \$onFulfilled of method Http\\Promise\\Promise::then\(\) expects \(callable\(mixed\): Psr\\Http\\Message\\ResponseInterface\)\|null, Closure\(Psr\\Http\\Message\\ResponseInterface\): Psr\\Http\\Message\\ResponseInterface given\./' + message: '/Method Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer::supportsDenormalization\(\) invoked with 4 parameters, 2-3 required\./' count: 1 - path: src/HttPlug/Plugin/OdooApiErrorPlugin.php - # Symfony 5.4 - - '/Method FluxSE\\OdooApiClient\\Serializer\\(Json|Xml)Rpc\\(Json|Xml)RpcSerializerHelper::deserializeResponseBody\(\) should return T of object but returns mixed\./' + path: src/Serializer/OdooNormalizer.php - - message: '/Method FluxSE\\OdooApiClient\\HttPlug\\Plugin\\OdooApiErrorPlugin::handleRequest\(\) has parameter \$(first|next) with generic interface Http\\Promise\\Promise but does not specify its types: T/' - count: 2 - path: src/HttPlug/Plugin/OdooApiErrorPlugin.php + message: '/Method Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer::supportsNormalization\(\) invoked with 3 parameters, 1-2 required\./' + count: 1 + path: src/Serializer/OdooNormalizer.php diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index a804732..0000000 --- a/psalm.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Manager/ModelManager.php b/src/Manager/ModelManager.php index 9690f64..d5be41b 100644 --- a/src/Manager/ModelManager.php +++ b/src/Manager/ModelManager.php @@ -7,7 +7,7 @@ use FluxSE\OdooApiClient\Model\BaseInterface; use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\Options\OptionsInterface; use FluxSE\OdooApiClient\Operations\Object\ExecuteKw\RecordOperationsInterface; -use FluxSE\OdooApiClient\Serializer\OdooNormalizer; +use FluxSE\OdooApiClient\Serializer\OdooRelationsNormalizer; use LogicException; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -38,7 +38,7 @@ public function update(BaseInterface $model, ?OptionsInterface $options = null): } $normalizedModel = (array) $this->normalizer->normalize($model, null, [ - OdooNormalizer::NORMALIZE_FOR_UPDATE => true, + OdooRelationsNormalizer::NORMALIZE_FOR_UPDATE => true, ]); return $this->recordOperations->write( $model::getOdooModelName(), diff --git a/src/PropertyAccess/OdooPropertyAccessor.php b/src/PropertyAccess/OdooPropertyAccessor.php new file mode 100644 index 0000000..07a664c --- /dev/null +++ b/src/PropertyAccess/OdooPropertyAccessor.php @@ -0,0 +1,73 @@ +decoratedPropertyAccessor->setValue($objectOrArray, $propertyPath, $value); + + if (false !== $value) { + return; + } + + $newValue = $this->decoratedPropertyAccessor->getValue($objectOrArray, $propertyPath); + + if (false === $newValue) { + return; + } + + // set null instead of false + $this->decoratedPropertyAccessor->setValue($objectOrArray, $propertyPath, null); + } + + public function getValue(object|array $objectOrArray, PropertyPathInterface|string $propertyPath): mixed + { + /** + * Specific case of normalized data returned as null instead of being just transformed + */ + $value = $this->decoratedPropertyAccessor->getValue($objectOrArray, $propertyPath); + + if (false === $value instanceof OdooRelation) { + return $value; + } + + if (null !== $value->getCommand()) { + return $value; + } + + if (null !== $value->getId()) { + return $value; + } + + return null; + } + + public function isWritable(object|array $objectOrArray, PropertyPathInterface|string $propertyPath): bool + { + return $this->decoratedPropertyAccessor->isWritable($objectOrArray, $propertyPath); + } + + public function isReadable(object|array $objectOrArray, PropertyPathInterface|string $propertyPath): bool + { + return $this->decoratedPropertyAccessor->isReadable($objectOrArray, $propertyPath); + } +} diff --git a/src/Serializer/Factory/SerializerFactory.php b/src/Serializer/Factory/SerializerFactory.php index 4973722..0bcaccb 100644 --- a/src/Serializer/Factory/SerializerFactory.php +++ b/src/Serializer/Factory/SerializerFactory.php @@ -4,7 +4,7 @@ namespace FluxSE\OdooApiClient\Serializer\Factory; -use Doctrine\Common\Annotations\AnnotationReader; +use FluxSE\OdooApiClient\PropertyAccess\OdooPropertyAccessor; use FluxSE\OdooApiClient\Serializer\JsonRpc\JsonRpcDecoder; use FluxSE\OdooApiClient\Serializer\JsonRpc\JsonRpcEncoder; use FluxSE\OdooApiClient\Serializer\NullableDateTimeDenormalizer; @@ -17,12 +17,13 @@ use FluxSE\OdooApiClient\Serializer\OdooRelationsNormalizer; use FluxSE\OdooApiClient\Serializer\XmlRpc\XmlRpcDecoder; use FluxSE\OdooApiClient\Serializer\XmlRpc\XmlRpcEncoder; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; -use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader; use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; @@ -31,6 +32,7 @@ use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; final class SerializerFactory implements SerializerFactoryInterface @@ -82,16 +84,7 @@ public function setupEncoders(): array public function setupObjectNormalizer(): OdooNormalizer { - if (class_exists(AttributeLoader::class)) { - /** @var LoaderInterface $loader */ - $loader = new AttributeLoader(); - } else { - /** - * @var LoaderInterface $loader - * @psalm-suppress TooManyArguments - */ - $loader = new AnnotationLoader(new AnnotationReader()); - } + $loader = new AttributeLoader(); $classMetadataFactory = new ClassMetadataFactory($loader); $metadataAwareNameConverter = new MetadataAwareNameConverter( @@ -99,43 +92,53 @@ public function setupObjectNormalizer(): OdooNormalizer new CamelCaseToSnakeCaseNameConverter() ); + $odooPropertyAccessor = $this->setupPropertyAccessor(); + return new OdooNormalizer( - $classMetadataFactory, - $metadataAwareNameConverter, - null, - new PropertyInfoExtractor( - [ - new ReflectionExtractor(), - new SerializerExtractor($classMetadataFactory), - ], - [ - new PhpDocExtractor(), - new ReflectionExtractor(), - ], - [ - new PhpDocExtractor(), - ], + new ObjectNormalizer( + $classMetadataFactory, + $metadataAwareNameConverter, + $odooPropertyAccessor, + new PropertyInfoExtractor( + [ + new ReflectionExtractor(), + new SerializerExtractor($classMetadataFactory), + ], + [ + new PhpDocExtractor(), + new ReflectionExtractor(), + ], + [ + new PhpDocExtractor(), + ], + [ + new ReflectionExtractor(), + ], + [ + new ReflectionExtractor(), + ] + ), + null, + null, [ - new ReflectionExtractor(), - ], - [ - new ReflectionExtractor(), + // => array to model + AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true, + // => model to array + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) { + return $object->getId() ?? 0; + } ] - ), - null, - null, - [ - // => array to model - AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true, - // => model to array - AbstractObjectNormalizer::SKIP_NULL_VALUES => true, - AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) { - return $object->getId() ?? 0; - } - ] + ) ); } + public function setupPropertyAccessor(): PropertyAccessorInterface + { + $propertyAccessor = PropertyAccess::createPropertyAccessor(); + return new OdooPropertyAccessor($propertyAccessor); + } + public function getDateFormat(): string { return $this->dateFormat; diff --git a/src/Serializer/Factory/SerializerFactoryInterface.php b/src/Serializer/Factory/SerializerFactoryInterface.php index ef3ce32..4fa20cb 100644 --- a/src/Serializer/Factory/SerializerFactoryInterface.php +++ b/src/Serializer/Factory/SerializerFactoryInterface.php @@ -4,6 +4,8 @@ namespace FluxSE\OdooApiClient\Serializer\Factory; +use FluxSE\OdooApiClient\Serializer\OdooNormalizer; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Serializer\Serializer; interface SerializerFactoryInterface @@ -13,4 +15,8 @@ public function create(): Serializer; public function setupNormalizers(): array; public function setupEncoders(): array; + + public function setupObjectNormalizer(): OdooNormalizer; + + public function setupPropertyAccessor(): PropertyAccessorInterface; } diff --git a/src/Serializer/JsonRpc/JsonRpcDecoder.php b/src/Serializer/JsonRpc/JsonRpcDecoder.php index 7bc8a0b..3de4e41 100644 --- a/src/Serializer/JsonRpc/JsonRpcDecoder.php +++ b/src/Serializer/JsonRpc/JsonRpcDecoder.php @@ -33,7 +33,7 @@ public function supportsDecoding($format, array $context = []): bool * * @throws JsonException */ - public function decode($data, $format, array $context = []) + public function decode(string $data, string $format, array $context = []): mixed { if ('' === trim($data)) { throw new UnexpectedValueException('Invalid JSON data, it can not be empty.'); diff --git a/src/Serializer/NullOdooRelationDenormalizer.php b/src/Serializer/NullOdooRelationDenormalizer.php index fa14662..9323464 100644 --- a/src/Serializer/NullOdooRelationDenormalizer.php +++ b/src/Serializer/NullOdooRelationDenormalizer.php @@ -18,7 +18,7 @@ public function getSupportedTypes(?string $format): array return [OdooRelation::class => false]; } - public function supportsDenormalization($data, $type, $format = null): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { if ($type !== OdooRelation::class) { return false; @@ -28,7 +28,7 @@ public function supportsDenormalization($data, $type, $format = null): bool return false === $data; } - public function denormalize($data, $type, $format = null, array $context = []) + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed { if (false === $data) { return null; diff --git a/src/Serializer/NullableDateTimeDenormalizer.php b/src/Serializer/NullableDateTimeDenormalizer.php index e4781ee..361a8e2 100644 --- a/src/Serializer/NullableDateTimeDenormalizer.php +++ b/src/Serializer/NullableDateTimeDenormalizer.php @@ -21,12 +21,12 @@ public function getSupportedTypes(?string $format): array ]; } - public function denormalize($data, string $type, string $format = null, array $context = []) + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed { return null; } - public function supportsDenormalization($data, string $type, string $format = null): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { if (!\is_string($data) || '' === trim($data)) { return $this->dateTimeNormalizer->supportsDenormalization($data, $type, $format); diff --git a/src/Serializer/OdooNormalizer.php b/src/Serializer/OdooNormalizer.php index ba4c0dc..6716490 100644 --- a/src/Serializer/OdooNormalizer.php +++ b/src/Serializer/OdooNormalizer.php @@ -8,13 +8,17 @@ use FluxSE\OdooApiClient\Api\RequestBodyInterface; use FluxSE\OdooApiClient\Model\BaseInterface; use FluxSE\OdooApiClient\Model\Common\Version; -use FluxSE\OdooApiClient\Model\OdooRelation; -use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; +use Symfony\Component\Serializer\SerializerAwareInterface; +use Symfony\Component\Serializer\SerializerInterface; -final class OdooNormalizer extends ObjectNormalizer +final class OdooNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface { - public const NORMALIZE_FOR_UPDATE = 'normalize_for_update'; + public function __construct(private ObjectNormalizer $decoratedObjectNormalizer) + { + } public function getSupportedTypes(?string $format): array { @@ -26,59 +30,28 @@ public function getSupportedTypes(?string $format): array ]; } - protected function setAttributeValue(object $object, string $attribute, mixed $value, string $format = null, array $context = []): void + public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed { - /** - * Override to set null when original value is false - * - * Because null value is transformed to false by Odoo API - * There is no other way to do it simply with any features given by Symfony Serializer - */ - - parent::setAttributeValue($object, $attribute, $value, $format, $context); - - if (false !== $value) { - return; - } - - try { - $newValue = parent::getAttributeValue($object, $attribute, $format, $context); - } catch (NoSuchPropertyException $e) { - // ignore not found properties like the setAttributeValue above - return; - } - - if (false === $newValue) { - return; - } - - parent::setAttributeValue($object, $attribute, null, $format, $context); + return $this->decoratedObjectNormalizer->denormalize($data, $type, $format, $context); } - protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []): mixed + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { - /** - * Specific case of normalized data returned as null instead of being just transformed - */ - $value = parent::getAttributeValue($object, $attribute, $format, $context); - - $skipNullValue = $context[self::SKIP_NULL_VALUES] ?? $this->defaultContext[self::SKIP_NULL_VALUES] ?? false; - if (!$skipNullValue) { - return $value; - } - - if (false === $value instanceof OdooRelation) { - return $value; - } + return $this->decoratedObjectNormalizer->supportsDenormalization($data, $type, $format, $context); + } - if (null !== $value->getCommand()) { - return $value; - } + public function normalize(mixed $object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null + { + return $this->decoratedObjectNormalizer->normalize($object, $format, $context); + } - if (null !== $value->getId()) { - return $value; - } + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $this->decoratedObjectNormalizer->supportsNormalization($data, $format, $context); + } - return null; + public function setSerializer(SerializerInterface $serializer): void + { + $this->decoratedObjectNormalizer->setSerializer($serializer); } } diff --git a/src/Serializer/OdooRelationDenormalizer.php b/src/Serializer/OdooRelationDenormalizer.php index f40f000..f725dc9 100644 --- a/src/Serializer/OdooRelationDenormalizer.php +++ b/src/Serializer/OdooRelationDenormalizer.php @@ -18,7 +18,7 @@ public function getSupportedTypes(?string $format): array return [OdooRelation::class => false]; } - public function supportsDenormalization($data, $type, $format = null): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { if ($type !== OdooRelation::class) { return false; diff --git a/src/Serializer/OdooRelationNormalizer.php b/src/Serializer/OdooRelationNormalizer.php index df1286a..0d67c20 100644 --- a/src/Serializer/OdooRelationNormalizer.php +++ b/src/Serializer/OdooRelationNormalizer.php @@ -20,7 +20,7 @@ public function getSupportedTypes(?string $format): array return [OdooRelation::class => true]; } - public function supportsNormalization($data, $format = null): bool + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool { return $data instanceof OdooRelation; } diff --git a/src/Serializer/OdooRelationSingleDenormalizer.php b/src/Serializer/OdooRelationSingleDenormalizer.php index 32b43d8..fa8db53 100644 --- a/src/Serializer/OdooRelationSingleDenormalizer.php +++ b/src/Serializer/OdooRelationSingleDenormalizer.php @@ -18,7 +18,7 @@ public function getSupportedTypes(?string $format): array return [OdooRelation::class => false]; } - public function supportsDenormalization($data, $type, $format = null): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { if ($type !== OdooRelation::class) { return false; diff --git a/src/Serializer/OdooRelationsDenormalizer.php b/src/Serializer/OdooRelationsDenormalizer.php index d324b24..838fb96 100644 --- a/src/Serializer/OdooRelationsDenormalizer.php +++ b/src/Serializer/OdooRelationsDenormalizer.php @@ -18,7 +18,7 @@ public function getSupportedTypes(?string $format): array return [OdooRelation::class => false]; } - public function supportsDenormalization($data, $type, $format = null): bool + public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool { if ($type !== OdooRelation::class) { return false; diff --git a/src/Serializer/OdooRelationsNormalizer.php b/src/Serializer/OdooRelationsNormalizer.php index ebd66de..3e9a38c 100644 --- a/src/Serializer/OdooRelationsNormalizer.php +++ b/src/Serializer/OdooRelationsNormalizer.php @@ -6,15 +6,16 @@ use FluxSE\OdooApiClient\Model\OdooRelation; use Symfony\Component\Serializer\Exception\NotNormalizableValueException; -use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -final class OdooRelationsNormalizer implements NormalizerInterface, NormalizerAwareInterface, ContextAwareNormalizerInterface +final class OdooRelationsNormalizer implements NormalizerInterface, NormalizerAwareInterface { use NormalizerAwareTrait; + public const NORMALIZE_FOR_UPDATE = 'normalize_for_update'; + public function getSupportedTypes(?string $format): array { return ['native-array' => true]; @@ -26,7 +27,7 @@ public function supportsNormalization($data, string $format = null, array $conte return false; } - $normalizeForUpdate = $context[OdooNormalizer::NORMALIZE_FOR_UPDATE] ?? false; + $normalizeForUpdate = $context[self::NORMALIZE_FOR_UPDATE] ?? false; if (!$normalizeForUpdate) { return false; } diff --git a/src/Serializer/XmlRpc/XmlRpcDecoder.php b/src/Serializer/XmlRpc/XmlRpcDecoder.php index 439f6ed..ad33556 100644 --- a/src/Serializer/XmlRpc/XmlRpcDecoder.php +++ b/src/Serializer/XmlRpc/XmlRpcDecoder.php @@ -30,7 +30,7 @@ public function supportsDecoding($format, array $context = []): bool /** * @return array|integer|string|boolean */ - public function decode($data, $format, array $context = []) + public function decode(string $data, string $format, array $context = []): mixed { if ('' === trim($data)) { throw new UnexpectedValueException('Invalid XML data, it can not be empty.'); diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..7803d32 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,18 @@ +activity_state; + } + + public function setActivityState(?string $activity_state): void + { + $this->activity_state = $activity_state; + } + + public function getMoveId(): ?OdooRelation + { + return $this->move_id; + } + + public function setMoveId(?OdooRelation $move_id): void + { + $this->move_id = $move_id; + } + + public static function getOdooModelName(): string + { + return 'foo'; + } +} diff --git a/tests/PropertyAccess/OdooPropertyAccessorTest.php b/tests/PropertyAccess/OdooPropertyAccessorTest.php new file mode 100644 index 0000000..68fbbd3 --- /dev/null +++ b/tests/PropertyAccess/OdooPropertyAccessorTest.php @@ -0,0 +1,46 @@ +propertyAccessor = $serializerFactory->setupPropertyAccessor(); + } + + public function testConstruct(): void + { + $this->assertInstanceOf(OdooPropertyAccessor::class, $this->propertyAccessor); + } + + public function testSetValueFalseValueBecomeNull(): void + { + $object = new Foo(); + $object->setActivityState('aString'); + $this->propertyAccessor->setValue($object, 'activityState', false); + + $this->assertEquals(null, $object->getActivityState()); + } + + public function testGetValueOdooRelationValueBecomeNull(): void + { + $object = new Foo(); + $object->setMoveId(new OdooRelation()); + $value = $this->propertyAccessor->getValue($object, 'moveId'); + + $this->assertEquals(new OdooRelation(), $object->getMoveId()); + $this->assertNull($value); + } +} diff --git a/tests/Serializer/OdooNormalizerTest.php b/tests/Serializer/OdooNormalizerTest.php index b7426af..d1fcea8 100644 --- a/tests/Serializer/OdooNormalizerTest.php +++ b/tests/Serializer/OdooNormalizerTest.php @@ -4,14 +4,17 @@ use FluxSE\OdooApiClient\Model\OdooRelation; use FluxSE\OdooApiClient\Serializer\Factory\SerializerFactory; -use FluxSE\OdooApiClient\Serializer\OdooNormalizer; +use FluxSE\OdooApiClient\Serializer\OdooRelationsNormalizer; use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; +use Symfony\Component\PropertyInfo\PropertyInfoExtractor; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; +use Tests\FluxSE\OdooApiClient\Serializer\Model\Foo; use Tests\FluxSE\OdooApiClient\TestModel\Object\Res\Partner; class OdooNormalizerTest extends TestCase { - /** @var Serializer */ private Serializer $serializer; protected function setUp(): void @@ -33,7 +36,7 @@ public function testNormalizeForUpdate(): void ]); $arr = $this->serializer->normalize($object, null, [ - OdooNormalizer::NORMALIZE_FOR_UPDATE => true, + OdooRelationsNormalizer::NORMALIZE_FOR_UPDATE => true, ]); $this->assertEquals([ @@ -55,7 +58,7 @@ public function testNormalizeForUpdateWithNullData(): void ]); $arr = $this->serializer->normalize($object, null, [ - OdooNormalizer::NORMALIZE_FOR_UPDATE => true, + OdooRelationsNormalizer::NORMALIZE_FOR_UPDATE => true, ]); $this->assertEquals([ @@ -108,4 +111,14 @@ public function testNormalizeWithNullData(): void ], ], $arr); } + + public function testDenormalizeFalsePseudoType(): void + { + // when denormalizing some data into an object where an attribute uses the false pseudo type + /** @var Foo $object */ + $object = $this->serializer->denormalize(['id' => 2], Foo::class); + + // then the attribute that declared false was filled correctly + $this->assertEquals(2, $object->getId()); + } }