1
0
Fork 0
mirror of synced 2025-04-05 06:03:34 +03:00

add callback argument value resolver

This commit is contained in:
Akolzin Dmitry 2021-02-03 18:08:03 +03:00
parent 9309a2d122
commit 22e03941b9
10 changed files with 314 additions and 0 deletions

34
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,34 @@
name: ci
on:
push:
branches:
- '**'
tags-ignore:
- '*.*'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.3', '7.4', '8.0']
steps:
- uses: actions/checkout@v2
- name: Setup PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: pcov
- name: Composer cache
uses: actions/cache@v2
with:
path: ${{ env.HOME }}/.composer/cache
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install -o
- name: Run tests
run: composer run tests
- name: Coverage
run: bash <(curl -s https://codecov.io/bash)

4
.gitignore vendored
View file

@ -30,6 +30,7 @@
!bin/console
!bin/symfony_requirements
/vendor/
composer.lock
# Assets and user uploads
/web/bundles/
@ -38,6 +39,7 @@
# PHPUnit
/app/phpunit.xml
/phpunit.xml
.phpunit.result.cache
# Build data
/build/
@ -50,3 +52,5 @@
# Embedded web-server pid file
/.web-server-pid
.idea

View file

@ -0,0 +1,27 @@
<?php
namespace RetailCrm\ServiceBundle\ArgumentResolver;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use InvalidArgumentException;
abstract class AbstractValueResolver
{
protected $validator;
public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}
/**
* @param object $data
*/
protected function validate(object $data): void
{
$errors = $this->validator->validate($data);
if (0 !== count($errors)) {
throw new InvalidArgumentException($errors);
}
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace RetailCrm\ServiceBundle\ArgumentResolver;
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;
class CallbackValueResolver extends AbstractValueResolver implements ArgumentValueResolverInterface
{
private $serializer;
private $requestSchema;
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
array $requestSchema
) {
parent::__construct($validator);
$this->serializer = $serializer;
$this->requestSchema = $requestSchema;
}
/**
* {@inheritdoc }
*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
if (empty($this->requestSchema) || $request->getMethod() !== Request::METHOD_POST) {
return false;
}
return null !== $this->search($request, $argument);
}
/**
* {@inheritdoc }
*/
public function resolve(Request $request, ArgumentMetadata $argument): Generator
{
$parameter = $this->search($request, $argument);
$data = $this->serializer->deserialize($request->request->get($parameter), $argument->getType(), 'json');
$this->validate($data);
yield $data;
}
private function search(Request $request, ArgumentMetadata $argument): ?string
{
foreach ($this->requestSchema as $callback) {
if (!$argument->getName() === $callback['type']) {
continue;
}
foreach ($callback['params'] as $param) {
if ($request->request->has($param)) {
return $param;
}
}
}
return null;
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace RetailCrm\ServiceBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc }
*/
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('retail_crm_service');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()
->arrayNode('request_schema')
->children()
->arrayNode('callback')
->arrayPrototype()
->children()
->scalarNode('type')->isRequired()->end()
->arrayNode('params')
->isRequired()->scalarPrototype()->end()
->end()
->end()
->end()
->end()
->arrayNode('client')
->scalarPrototype()->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace RetailCrm\ServiceBundle\DependencyInjection;
use RetailCrm\ServiceBundle\ArgumentResolver\CallbackValueResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class RetailCrmServiceExtension extends Extension
{
/**
* @param array $configs
* @param ContainerBuilder $container
*/
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter(
'retail_crm_service.request_schema.callback',
$config['request_schema']['callback']
);
$container->setParameter(
'retail_crm_service.request_schema.client',
$config['request_schema']['client']
);
$container
->register(CallbackValueResolver::class)
->setArgument('$requestSchema', '%retail_crm_service.request_schema.callback%')
->addTag('controller.argument_value_resolver', ['priority' => 50])
->setAutowired(true);
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace RetailCrm\ServiceBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class RetailCrmServiceBundle extends Bundle
{
}

View file

@ -0,0 +1,38 @@
<?php
namespace RetailCrm\ServiceBundle\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use RetailCrm\ServiceBundle\DependencyInjection\Configuration;
use Symfony\Component\Config\Definition\Processor;
class ConfigurationTest extends TestCase
{
public function testConfig(): void
{
$processor = new Processor();
$configs = [
[
'request_schema' => [
'callback' => [
[
'type' => 'type',
'params' => ['param']
]
],
'client' => [
'type1',
'type2'
]
]
]
];
$config = $processor->processConfiguration(new Configuration(), $configs);
static::assertArrayHasKey('request_schema', $config);
static::assertArrayHasKey('callback', $config['request_schema']);
static::assertArrayHasKey('client', $config['request_schema']);
}
}

39
composer.json Normal file
View file

@ -0,0 +1,39 @@
{
"name": "retailcrm/service-bundle",
"description": "Core bundle for RetailCRM integration services",
"type": "symfony-bundle",
"license": "MIT",
"authors": [
{
"name": "RetailCRM",
"email": "support@retailcrm.pro"
}
],
"minimum-stability": "stable",
"require": {
"php": ">=7.3",
"symfony/framework-bundle": "^4.0|^5.0",
"symfony/serializer": "^5.2",
"symfony/http-kernel": "^4.0|^5.0",
"symfony/validator": "^4.0|^5.0"
},
"autoload": {
"psr-4": {
"RetailCrm\\ServiceBundle\\": ""
},
"exclude-from-classmap": [
"Tests/"
]
},
"autoload-dev": {
"psr-4": {
"RetailCrm\\ServiceBundle\\Tests\\": "Tests/"
}
},
"require-dev": {
"phpunit/phpunit": "^8.0 || ^9.0"
},
"scripts": {
"tests": "./vendor/bin/phpunit -c phpunit.xml.dist"
}
}

18
phpunit.xml.dist Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="vendor/autoload.php"
>
<testsuites>
<testsuite name="RetailCRM Service Bundle Tests">
<directory>./Tests</directory>
</testsuite>
</testsuites>
</phpunit>