1
0
mirror of synced 2024-11-21 20:36:08 +03:00

JMS serializer supports (#3)

* add callback argument value resolver
* add jms serializer support
* add phpdoc
* fix FrontApiClientAuthenticator
This commit is contained in:
Akolzin Dmitry 2021-02-17 09:31:36 +03:00 committed by GitHub
parent 4aace1bcf5
commit 7516ec60cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 341 additions and 49 deletions

View File

@ -2,10 +2,10 @@
namespace RetailCrm\ServiceBundle\ArgumentResolver;
use RetailCrm\ServiceBundle\Serializer\Adapter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Serializer\SerializerInterface;
use Generator;
use Symfony\Component\Validator\Validator\ValidatorInterface;
@ -22,12 +22,12 @@ class CallbackValueResolver extends AbstractValueResolver implements ArgumentVal
/**
* CallbackValueResolver constructor.
*
* @param SerializerInterface $serializer
* @param Adapter $serializer
* @param ValidatorInterface $validator
* @param array $requestSchema
*/
public function __construct(
SerializerInterface $serializer,
Adapter $serializer,
ValidatorInterface $validator,
array $requestSchema
) {
@ -55,7 +55,7 @@ class CallbackValueResolver extends AbstractValueResolver implements ArgumentVal
public function resolve(Request $request, ArgumentMetadata $argument): Generator
{
$parameter = $this->search($request, $argument);
$data = $this->serializer->deserialize($request->request->get($parameter), $argument->getType(), 'json');
$data = $this->serializer->deserialize($request->request->get($parameter), $argument->getType());
$this->validate($data);
yield $data;

View File

@ -2,12 +2,10 @@
namespace RetailCrm\ServiceBundle\ArgumentResolver;
use RetailCrm\ServiceBundle\Serializer\Adapter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Generator;
@ -19,27 +17,24 @@ use Generator;
class ClientValueResolver extends AbstractValueResolver implements ArgumentValueResolverInterface
{
private $serializer;
private $denormalizer;
private $requestSchema;
/**
* ClientValueResolver constructor.
*
*
* @param Adapter $serializer
* @param ValidatorInterface $validator
* @param SerializerInterface $serializer
* @param DenormalizerInterface $denormalizer
* @param array $requestSchema
*/
public function __construct(
Adapter $serializer,
ValidatorInterface $validator,
SerializerInterface $serializer,
DenormalizerInterface $denormalizer,
array $requestSchema
) {
parent::__construct($validator);
$this->serializer = $serializer;
$this->denormalizer = $denormalizer;
$this->requestSchema = $requestSchema;
}
@ -72,12 +67,10 @@ class ClientValueResolver extends AbstractValueResolver implements ArgumentValue
* @param string $type
*
* @return object
*
* @throws ExceptionInterface
*/
private function handleGetData(array $data, string $type): object
{
return $this->denormalizer->denormalize($data, $type);
return $this->serializer->arrayToObject($data, $type);
}
/**
@ -88,6 +81,6 @@ class ClientValueResolver extends AbstractValueResolver implements ArgumentValue
*/
private function handlePostData(string $data, string $type): object
{
return $this->serializer->deserialize($data, $type, 'json');
return $this->serializer->deserialize($data, $type);
}
}

View File

@ -25,6 +25,8 @@ class Configuration implements ConfigurationInterface
->arrayNode('request_schema')
->children()
->arrayNode('callback')
->children()
->arrayNode('supports')
->arrayPrototype()
->children()
->scalarNode('type')->isRequired()->end()
@ -34,9 +36,21 @@ class Configuration implements ConfigurationInterface
->end()
->end()
->end()
->scalarNode('serializer')
->defaultValue('retail_crm_service.symfony_serializer.adapter')
->end()
->end()
->end()
->arrayNode('client')
->children()
->arrayNode('supports')
->scalarPrototype()->end()
->end()
->scalarNode('serializer')
->defaultValue('retail_crm_service.symfony_serializer.adapter')
->end()
->end()
->end()
->end()
->end()
->end();

View File

@ -7,8 +7,11 @@ use RetailCrm\ServiceBundle\ArgumentResolver\ClientValueResolver;
use RetailCrm\ServiceBundle\Response\ErrorJsonResponseFactory;
use RetailCrm\ServiceBundle\Security\CallbackClientAuthenticator;
use RetailCrm\ServiceBundle\Security\FrontApiClientAuthenticator;
use RetailCrm\ServiceBundle\Serializer\JMSSerializerAdapter;
use RetailCrm\ServiceBundle\Serializer\SymfonySerializerAdapter;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Reference;
/**
* Class RetailCrmServiceExtension
@ -27,24 +30,52 @@ class RetailCrmServiceExtension extends Extension
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter(
'retail_crm_service.request_schema.callback',
$config['request_schema']['callback']
'retail_crm_service.request_schema.callback.supports',
$config['request_schema']['callback']['supports']
);
$container->setParameter(
'retail_crm_service.request_schema.client',
$config['request_schema']['client']
'retail_crm_service.request_schema.client.supports',
$config['request_schema']['client']['supports']
);
$container->setParameter(
'retail_crm_service.request_schema.callback.serializer',
$config['request_schema']['callback']['serializer']
);
$container->setParameter(
'retail_crm_service.request_schema.client.serializer',
$config['request_schema']['client']['serializer']
);
$container
->register(SymfonySerializerAdapter::class)
->setAutowired(true);
$container->setAlias('retail_crm_service.symfony_serializer.adapter', SymfonySerializerAdapter::class);
$container
->register(JMSSerializerAdapter::class)
->setAutowired(true);
$container->setAlias('retail_crm_service.jms_serializer.adapter', JMSSerializerAdapter::class);
$container
->register(CallbackValueResolver::class)
->setArgument('$requestSchema', '%retail_crm_service.request_schema.callback%')
->setArguments([
new Reference($container->getParameter('retail_crm_service.request_schema.callback.serializer')),
new Reference('validator'),
$container->getParameter('retail_crm_service.request_schema.callback.supports')
])
->addTag('controller.argument_value_resolver', ['priority' => 50])
->setAutowired(true);
$container
->register(ClientValueResolver::class)
->setArgument('$requestSchema', '%retail_crm_service.request_schema.client%')
->setArguments([
new Reference($container->getParameter('retail_crm_service.request_schema.client.serializer')),
new Reference('validator'),
$container->getParameter('retail_crm_service.request_schema.client.supports')
])
->addTag('controller.argument_value_resolver', ['priority' => 50])
->setAutowired(true);

View File

@ -20,7 +20,9 @@ Create bundle config file in `config/packages/retail_crm_service.yaml`:
```yaml
retail_crm_service:
request_schema: ~
request_schema:
callback: ~
client: ~
```
### Deserializing incoming requests
@ -47,8 +49,8 @@ add to the config:
retail_crm_service:
request_schema:
callback:
- type: App\Dto\Callback\Activity
params: ["activity"]
supports:
- { type: App\Dto\Callback\Activity, params: ["activity"] }
```
request automatically will be deserialization to $activity.
@ -73,9 +75,28 @@ add to the config:
retail_crm_service:
request_schema:
client:
supports:
- App\Dto\Body
```
#### Serializers
At this time supported [Symfony serializer](https://symfony.com/doc/current/components/serializer.html) and [JMS serializer](https://jmsyst.com/libs/serializer).
By default, the library using a Symfony serializer. For use JMS install JMS serializer bundle - `composer require jms/serializer-bundle`
You can explicitly specify the type of serializer used for request schema:
```yaml
retail_crm_service:
request_schema:
client:
supports:
# types
serializer: retail_crm_service.symfony_serializer.adapter # or retail_crm_service.jms_serializer.adapter
callback:
supports:
# types
serializer: retail_crm_service.jms_serializer.adapter # or retail_crm_service.symfony_serializer.adapter
```
### Authentication
Example security configuration:

29
Serializer/Adapter.php Normal file
View File

@ -0,0 +1,29 @@
<?php
namespace RetailCrm\ServiceBundle\Serializer;
/**
* Interface Adapter
*
* @package RetailCrm\ServiceBundle\Serializer
*/
interface Adapter
{
/**
* @param string $data
* @param string $type
* @param string $format
*
* @return object
*/
public function deserialize(string $data, string $type, string $format = 'json'): object;
/**
* @param array $data
* @param string $type
* @param string|null $format
*
* @return object
*/
public function arrayToObject(array $data, string $type, ?string $format = null): object;
}

View File

@ -0,0 +1,57 @@
<?php
namespace RetailCrm\ServiceBundle\Serializer;
use JMS\Serializer\ArrayTransformerInterface;
use JMS\Serializer\Context;
use JMS\Serializer\SerializerInterface;
/**
* Class JMSSerializerAdapter
*
* @package RetailCrm\ServiceBundle\Serializer
*/
class JMSSerializerAdapter implements Adapter
{
private $serializer;
private $transformer;
private $context;
/**
* JMSSerializerAdapter constructor.
*
* @param SerializerInterface $serializer
* @param ArrayTransformerInterface $transformer
*/
public function __construct(
SerializerInterface $serializer,
ArrayTransformerInterface $transformer
) {
$this->serializer = $serializer;
$this->transformer = $transformer;
}
/**
* {@inheritdoc }
*/
public function deserialize(string $data, string $type, string $format = 'json'): object
{
return $this->serializer->deserialize($data, $type, $format, $this->context);
}
/**
* {@inheritdoc }
*/
public function arrayToObject(array $data, string $type, ?string $format = null): object
{
return $this->transformer->fromArray($data, $type, $this->context);
}
/**
* @param Context $context
*/
public function setContext(Context $context): void
{
$this->context = $context;
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace RetailCrm\ServiceBundle\Serializer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\SerializerInterface;
/**
* Class SymfonySerializerAdapter
*
* @package RetailCrm\ServiceBundle\Serializer
*/
class SymfonySerializerAdapter implements Adapter
{
private $serializer;
private $denormalizer;
private $context = [];
/**
* SymfonySerializerAdapter constructor.
*
* @param SerializerInterface $serializer
* @param DenormalizerInterface $denormalizer
*/
public function __construct(SerializerInterface $serializer, DenormalizerInterface $denormalizer)
{
$this->serializer = $serializer;
$this->denormalizer = $denormalizer;
}
/**
* {@inheritdoc }
*/
public function deserialize(string $data, string $type,string $format = 'json'): object
{
return $this->serializer->deserialize($data, $type, $format, $this->context);
}
/**
* {@inheritdoc }
*/
public function arrayToObject(array $data, string $type, string $format = null): object
{
return $this->denormalizer->denormalize($data, $type, $format, $this->context);
}
/**
* @param array $context
*/
public function setContext(array $context): void
{
$this->context = $context;
}
}

View File

@ -5,6 +5,7 @@ namespace RetailCrm\ServiceBundle\Tests\ArgumentResolver;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\ArgumentResolver\CallbackValueResolver;
use RetailCrm\ServiceBundle\Exceptions\InvalidRequestArgumentException;
use RetailCrm\ServiceBundle\Serializer\SymfonySerializerAdapter;
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
@ -27,7 +28,7 @@ class CallbackValueResolverTest extends TestCase
{
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$this->resolver = new CallbackValueResolver(
$serializer,
new SymfonySerializerAdapter($serializer, $serializer),
Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator(),

View File

@ -5,6 +5,7 @@ namespace RetailCrm\ServiceBundle\Tests\ArgumentResolver;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\ArgumentResolver\ClientValueResolver;
use RetailCrm\ServiceBundle\Exceptions\InvalidRequestArgumentException;
use RetailCrm\ServiceBundle\Serializer\SymfonySerializerAdapter;
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
@ -27,11 +28,10 @@ class ClientValueResolverTest extends TestCase
{
$serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$this->resolver = new ClientValueResolver(
new SymfonySerializerAdapter($serializer, $serializer),
Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator(),
$serializer,
$serializer,
[
RequestDto::class
]

View File

@ -3,6 +3,7 @@
namespace RetailCrm\ServiceBundle\Tests\DataFixtures;
use Symfony\Component\Validator\Constraints as Assert;
use JMS\Serializer\Annotation as JMS;
/**
* Class RequestDto
@ -14,6 +15,7 @@ class RequestDto
/**
* @var string
* @Assert\NotNull()
* @JMS\Type("string")
*/
public $param;
}

View File

@ -21,17 +21,21 @@ class ConfigurationTest extends TestCase
[
'request_schema' => [
'callback' => [
'supports' => [
[
'type' => 'type',
'params' => ['param']
]
]
],
'client' => [
'supports' => [
'type1',
'type2'
]
]
]
]
];
$config = $processor->processConfiguration(new Configuration(), $configs);
@ -44,14 +48,14 @@ class ConfigurationTest extends TestCase
'type' => 'type',
'params' => ['param']
],
$config['request_schema']['callback'][0]
$config['request_schema']['callback']['supports'][0]
);
static::assertEquals(
[
'type1',
'type2'
],
$config['request_schema']['client']
$config['request_schema']['client']['supports']
);
}
@ -63,15 +67,17 @@ class ConfigurationTest extends TestCase
[
'request_schema' => [
'client' => [
'supports' => [
'type',
]
]
]
]
];
$config = $processor->processConfiguration(new Configuration(), $configs);
static::assertArrayHasKey('client', $config['request_schema']);
static::assertEquals(['type'], $config['request_schema']['client']);
static::assertEquals(['type'], $config['request_schema']['client']['supports']);
}
}

View File

@ -31,7 +31,10 @@ class RetailCrmServiceExtensionTest extends TestCase
$extension->load(
[
[
'request_schema' => []
'request_schema' => [
'callback' => [],
'client' => []
]
]
],
$container
@ -44,8 +47,10 @@ class RetailCrmServiceExtensionTest extends TestCase
public function testLoad(): void
{
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.callback'));
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.client'));
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.callback.supports'));
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.callback.serializer'));
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.client.supports'));
static::assertTrue($this->container->hasParameter('retail_crm_service.request_schema.client.serializer'));
static::assertTrue($this->container->hasDefinition(CallbackValueResolver::class));
static::assertTrue($this->container->hasDefinition(ClientValueResolver::class));
static::assertTrue($this->container->hasDefinition(ErrorJsonResponseFactory::class));

View File

@ -0,0 +1,38 @@
<?php
namespace RetailCrm\ServiceBundle\Tests\Serializer;
use JMS\Serializer\SerializerBuilder;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\Serializer\JMSSerializerAdapter;
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
class JSMSerializerAdapterTest extends TestCase
{
private $serializer;
private $transformer;
protected function setUp(): void
{
$this->serializer = SerializerBuilder::create()->build();
$this->transformer = SerializerBuilder::create()->build();
}
public function testDeserialize(): void
{
$adapter = new JMSSerializerAdapter($this->serializer, $this->transformer);
$object = $adapter->deserialize('{"param": "string"}', RequestDto::class,'json');
static::assertInstanceOf(RequestDto::class, $object);
static::assertEquals('string', $object->param);
}
public function testArrayToObject(): void
{
$adapter = new JMSSerializerAdapter($this->serializer, $this->transformer);
$object = $adapter->arrayToObject(['param' => 'string'], RequestDto::class);
static::assertInstanceOf(RequestDto::class, $object);
static::assertEquals('string', $object->param);
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace RetailCrm\ServiceBundle\Tests\Serializer;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\Serializer\SymfonySerializerAdapter;
use RetailCrm\ServiceBundle\Tests\DataFixtures\RequestDto;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
class SymfonySerializerAdapterTest extends TestCase
{
private $serializer;
private $denormalizer;
protected function setUp(): void
{
$this->serializer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
$this->denormalizer = new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
}
public function testDeserialize(): void
{
$adapter = new SymfonySerializerAdapter($this->serializer, $this->denormalizer);
$object = $adapter->deserialize('{"param": "string"}', RequestDto::class,'json');
static::assertInstanceOf(RequestDto::class, $object);
static::assertEquals('string', $object->param);
}
public function testArrayToObject(): void
{
$adapter = new SymfonySerializerAdapter($this->serializer, $this->denormalizer);
$object = $adapter->arrayToObject(['param' => 'string'], RequestDto::class);
static::assertInstanceOf(RequestDto::class, $object);
static::assertEquals('string', $object->param);
}
}

View File

@ -35,7 +35,8 @@
"ext-json": "*",
"phpunit/phpunit": "^8.0 || ^9.0",
"doctrine/annotations": "^1.11",
"doctrine/cache": "^1.10"
"doctrine/cache": "^1.10",
"jms/serializer-bundle": "^3.8"
},
"scripts": {
"tests": "./vendor/bin/phpunit -c phpunit.xml.dist"