Skip to content

Commit

Permalink
Merge pull request #2 from richcongress/interruption
Browse files Browse the repository at this point in the history
Interruption
  • Loading branch information
mdevlamynck authored Aug 24, 2020
2 parents 3dcf349 + 237610b commit 89dbcbc
Show file tree
Hide file tree
Showing 11 changed files with 1,596 additions and 716 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Changelog

# v1.1.0

- Add skip Exception to interrupt the serialization of a property.
- Fix a bug in serialization groups
27 changes: 0 additions & 27 deletions DependencyInjection/Configuration.php

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

namespace RichCongress\NormalizerExtensionBundle\DependencyInjection;

use RichCongress\BundleToolbox\Configuration\AbstractExtension;
use RichCongress\NormalizerExtensionBundle\DependencyInjection\CompilerPass\SerializerPass;
use RichCongress\NormalizerExtensionBundle\Serializer\Handler\CircularReferenceHandler;
use RichCongress\NormalizerExtensionBundle\Serializer\Normalizer\Extension\NormalizerExtensionInterface;
use RichCongress\NormalizerExtensionBundle\Serializer\Serializer;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\Extension;

/**
* Class RichCongressNormalizerExtensionExtension
Expand All @@ -17,7 +17,7 @@
* @author Nicolas Guilloux <nguilloux@richcongress.com>
* @copyright 2014 - 2020 RichCongress (https://www.richcongress.com)
*/
class RichCongressNormalizerExtensionExtension extends Extension
class RichCongressNormalizerExtensionExtension extends AbstractExtension
{
public const SERIALIZER_SERVICE = 'rich_congress.serializer';

Expand All @@ -30,9 +30,6 @@ class RichCongressNormalizerExtensionExtension extends Extension
*/
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = new Configuration();
$this->processConfiguration($configuration, $configs);

self::autoconfigure($container);
self::configureSerializer($container);
self::configureCircularReferenceHandler($container);
Expand Down
17 changes: 16 additions & 1 deletion Docs/NormalizerExtension.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class DummyEntityNormalizerExtension extends AbstractObjectNormalizerExtension
];
}

public function isBeautifulEnought(): bool
public function isBeautifulEnough(): bool
{
return true;
}
Expand All @@ -53,6 +53,21 @@ class DummyEntityNormalizerExtension extends AbstractObjectNormalizerExtension
}
```

### Stop the normalization

To stop the normalization and then, do not add an entry to the normalized object, you may use the exception `SkipSerializationException`.

```php
public function isBeautifulEnough(): bool
{
...
if ($notConnected) {
throw new SkipSerializationException('User not connected');
}
...
}
```

## Write your own Normalizer Extension

To write your own Normalizer Extension, create your class and implements the `NormalizerExtensionInterface`.
Expand Down
14 changes: 14 additions & 0 deletions Exception/SkipSerializationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);

namespace RichCongress\NormalizerExtensionBundle\Exception;

/**
* Class SkipSerializationException
*
* @package RichCongress\NormalizerExtensionBundle\Exception
* @author Nicolas Guilloux <nguilloux@richcongress.com>
* @copyright 2014 - 2020 RichCongress (https://www.richcongress.com)
*/
class SkipSerializationException extends \Exception
{
}
15 changes: 3 additions & 12 deletions RichCongressNormalizerExtensionBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

namespace RichCongress\NormalizerExtensionBundle;

use RichCongress\BundleToolbox\Configuration\AbstractBundle;
use RichCongress\NormalizerExtensionBundle\DependencyInjection\CompilerPass\SerializerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
* Class RichCongressNormalizerExtensionBundle
Expand All @@ -13,15 +12,7 @@
* @author Nicolas Guilloux <nguilloux@richcongress.com>
* @copyright 2014 - 2020 RichCongress (https://www.richcongress.com)
*/
class RichCongressNormalizerExtensionBundle extends Bundle
class RichCongressNormalizerExtensionBundle extends AbstractBundle
{
/**
* @param ContainerBuilder $container
*
* @return void
*/
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new SerializerPass());
}
public const COMPILER_PASSES = [SerializerPass::class];
}
106 changes: 74 additions & 32 deletions Serializer/Normalizer/Extension/AbstractObjectNormalizerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace RichCongress\NormalizerExtensionBundle\Serializer\Normalizer\Extension;

use RichCongress\NormalizerExtensionBundle\Exception\AttributeNotFoundException;
use RichCongress\NormalizerExtensionBundle\Exception\SkipSerializationException;

/**
* Class AbstractObjectNormalizerExtension
Expand Down Expand Up @@ -71,12 +72,12 @@ public function extends($object, $normalizedData, string $format = null, array $
{
$this->format = $format;
$this->context = $context;
$groups = ((array) $context['groups']) ?? [];
$supportedGroups = static::getSupportedGroups();
$groups = $context['groups'] ?? [];
$groups = (array) $groups;
$serializationGroups = static::getSerializationGroups();

foreach ($supportedGroups as $propertyGroup => $propertyNames) {
$this->currentPropertyGroup = static::$contextPrefix . $propertyGroup;
$propertyNames = (array) $propertyNames;
foreach ($serializationGroups as $propertyGroup => $propertyNames) {
$this->currentPropertyGroup = $propertyGroup;

if (!in_array($this->currentPropertyGroup, $groups, true)) {
continue;
Expand All @@ -85,17 +86,41 @@ public function extends($object, $normalizedData, string $format = null, array $
foreach ($propertyNames as $propertyName) {
$this->currentPropertyName = $propertyName;

$callbackName = static::startsWith($propertyName, ['is', 'has', 'can', 'does'])
? $propertyName
: 'get' . ucfirst($propertyName);

$normalizedData[$propertyName] = $this->getValue($callbackName, $object);
try {
$normalizedData[$propertyName] = $this->getValue($propertyName, $object);
} catch (SkipSerializationException $e) {
continue;
}
}
}

return $normalizedData;
}

/**
* @return array
*/
public static function getSerializationGroups(): array
{
$groups = static::getSupportedGroups();

$keys = array_map(
static function (string $key) {
return static::$contextPrefix . $key;
},
array_keys($groups)
);

$values = array_map(
static function ($value) {
return (array) $value;
},
array_values($groups)
);

return array_combine($keys, $values);
}

/**
* @param mixed $object
* @param array|string|int|float|bool|\ArrayObject|null $normalizedData
Expand All @@ -110,43 +135,60 @@ public function supportsExtension($object, $normalizedData, string $format = nul
}

/**
* @param string $callbackName
* @param string $propertyName
* @param mixed $object
*
* @return callable
* @return mixed
*
* @throws \ReflectionException
* @throws SkipSerializationException
*/
protected function getValue(string $callbackName, $object)
protected function getValue(string $propertyName, $object)
{
$normalizerReflectionClass = new \ReflectionClass($this);
$callbackMethod = static::getCallbackMethod($propertyName);

if ($normalizerReflectionClass->hasMethod($callbackName)) {
$callback = [$this, $callbackName];
if ($callbackMethod === null) {
$classes = [static::class, \get_class($object)];

return $callback($object);
throw new \LogicException(
sprintf(
'The method to get the property \'%s\' not found from the following classes: %s',
$propertyName,
implode(', ', $classes)
)
);
}

$objectReflectionClass = new \ReflectionClass($object);
return $callbackMethod->getDeclaringClass()->getName() === static::class
? ([$this, $callbackMethod->getName()])($object)
: ([$object, $callbackMethod->getName()])();
}

if ($objectReflectionClass->hasMethod($callbackName)) {
$callback = [$object, $callbackName];
/**
* @param string $propertyName
*
* @return \ReflectionMethod|null
*
* @throws \ReflectionException
*/
public static function getCallbackMethod(string $propertyName): ?\ReflectionMethod
{
$normalizerReflectionClass = new \ReflectionClass(static::class);
$callbackName = static::startsWith($propertyName, ['is', 'has', 'can', 'does'])
? $propertyName
: 'get' . ucfirst($propertyName);

return $callback();
if ($normalizerReflectionClass->hasMethod($callbackName)) {
return $normalizerReflectionClass->getMethod($callbackName);
}

$classes = [
static::class,
\get_class($object)
];

throw new \LogicException(
sprintf(
'The method \'%s\' not found from the following classes: %s',
$callbackName,
implode(', ', $classes)
)
$objectReflectionClass = new \ReflectionClass(
$normalizerReflectionClass->getStaticPropertyValue('objectClass')
);

return $objectReflectionClass->hasMethod($callbackName)
? $objectReflectionClass->getMethod($callbackName)
: null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tests\RichCongress\NormalizerExtensionBundle\Resources\Serializer\Normalizer\Extension;

use RichCongress\NormalizerExtensionBundle\Exception\AttributeNotFoundException;
use RichCongress\NormalizerExtensionBundle\Exception\SkipSerializationException;
use RichCongress\NormalizerExtensionBundle\Serializer\Normalizer\Extension\AbstractObjectNormalizerExtension;
use Tests\RichCongress\NormalizerExtensionBundle\Resources\Entity\DummyEntity;

Expand All @@ -24,22 +25,28 @@ class DummyNormalizerExtension extends AbstractObjectNormalizerExtension
public static function getSupportedGroups(): array
{
return [
'normalizer_field' => 'normalizerField',
'normalizer_attribute' => 'normalizerAttribute',
'normalizer_bad_attribute' => 'normalizerBadAttribute',
'normalizer_field' => 'normalizerField',
'normalizer_attribute' => 'normalizerAttribute',
'normalizer_bad_attribute' => 'normalizerBadAttribute',
'normalizer_attribute_with_default' => 'normalizerAttributeWithDefault',
'entity_boolean' => 'isEntityBoolean',
'no_functions' => 'noFunction',
'entity_boolean' => 'isEntityBoolean',
'no_functions' => 'noFunction',
];
}

/**
* @param DummyEntity $entity
*
* @return string
*
* @throws SkipSerializationException
*/
public function getNormalizerField(DummyEntity $entity): string
{
if ($entity->booleanValue === true) {
throw new SkipSerializationException('Skipped');
}

return 'content';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class AbstractObjectNormalizerExtensionExtensionTest extends NormalizerExtension
public function testNormalizeDummyEntitySuccessfully(): void
{
$entity = new DummyEntity();
$entity->booleanValue = true;
$entity->booleanValue = false;

$data = $this->serializer->normalize(
$entity,
Expand All @@ -61,13 +61,42 @@ public function testNormalizeDummyEntitySuccessfully(): void
self::assertArrayHasKey('normalizerAttributeWithDefault', $data);
self::assertArrayHasKey('isEntityBoolean', $data);

self::assertTrue($data['booleanValue']);
self::assertFalse($data['booleanValue']);
self::assertEquals('content', $data['normalizerField']);
self::assertEquals(['yes'], $data['normalizerAttribute']);
self::assertEquals('fallback', $data['normalizerAttributeWithDefault']);
self::assertTrue($data['isEntityBoolean']);
}

/**
* @return void
*
* @throws ExceptionInterface
*/
public function testNormalizeDummyEntityWithSkip(): void
{
$entity = new DummyEntity();
$entity->booleanValue = true;

$data = $this->serializer->normalize(
$entity,
'json',
[
'attribute' => ['yes'],
AbstractNormalizer::ATTRIBUTES => ['booleanValue'],
AbstractNormalizer::GROUPS => [
'dummy_entity_boolean_value',
'dummy_entity_normalizer_field',
],
]
);

self::assertArrayHasKey('booleanValue', $data);
self::assertArrayNotHasKey('normalizerField', $data);

self::assertTrue($data['booleanValue']);
}

/**
* @return void
* @throws ExceptionInterface
Expand Down
Loading

0 comments on commit 89dbcbc

Please sign in to comment.