Skip to content

Commit

Permalink
Merge pull request biig-io#32 from swagindustries/feature/serializati…
Browse files Browse the repository at this point in the history
…on-context

Add context builder
  • Loading branch information
Nek- authored Aug 18, 2020
2 parents 234df73 + 3b26242 commit 741f796
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 4 deletions.
5 changes: 5 additions & 0 deletions src/Bridge/Symfony/DependencyInjection/MelodiiaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use SwagIndustries\Melodiia\Documentation\Controller\OpenApiController;
use SwagIndustries\Melodiia\Documentation\Controller\OpenApiJsonController;
use SwagIndustries\Melodiia\Documentation\OpenApiDocFactory;
use SwagIndustries\Melodiia\Serialization\Context\ContextBuilderInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
Expand All @@ -21,6 +22,7 @@
class MelodiiaExtension extends Extension
{
const TAG_CRUD_FILTER = 'melodiia.crud_filter';
const TAG_CONTEXT_BUILDER = 'melodiia.context_builder';

public function load(array $configs, ContainerBuilder $container)
{
Expand All @@ -42,6 +44,9 @@ public function load(array $configs, ContainerBuilder $container)

// Autoconf
$container->registerForAutoconfiguration(FilterInterface::class)->addTag(self::TAG_CRUD_FILTER);
$container
->registerForAutoconfiguration(ContextBuilderInterface::class)
->addTag(self::TAG_CONTEXT_BUILDER);
}

private function configureApi(string $name, array $apiConf, ContainerBuilder $container)
Expand Down
7 changes: 7 additions & 0 deletions src/Bridge/Symfony/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ services:
class: SwagIndustries\Melodiia\Response\Listener\SerializeOnKernelView
autoconfigure: true
autowire: true
arguments:
$contextBuilderChain: '@melodiia.context_builder_chain'

melodiia.context_builder_chain:
class: SwagIndustries\Melodiia\Serialization\Context\ContextBuilderChain
arguments:
$builders: !tagged_iterator melodiia.context_builder

imports:
- 'crud.yaml'
Expand Down
11 changes: 9 additions & 2 deletions src/Response/Listener/SerializeOnKernelView.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace SwagIndustries\Melodiia\Response\Listener;

use SwagIndustries\Melodiia\Response\ApiResponse;
use SwagIndustries\Melodiia\Serialization\Context\ContextBuilderChainInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ViewEvent;
Expand All @@ -23,9 +24,13 @@ class SerializeOnKernelView implements EventSubscriberInterface
*/
private $serializer;

public function __construct(SerializerInterface $serializer)
/** @var ContextBuilderChainInterface */
private $contextBuilderChain;

public function __construct(SerializerInterface $serializer, ContextBuilderChainInterface $contextBuilderChain)
{
$this->serializer = $serializer;
$this->contextBuilderChain = $contextBuilderChain;
}

public static function getSubscribedEvents()
Expand All @@ -42,9 +47,11 @@ public function onKernelView(ViewEvent $event)
return;
}

$context = $this->contextBuilderChain->buildContext([], $response);

$event->setResponse(
new JsonResponse(
$this->serializer->serialize($response, 'json'),
$this->serializer->serialize($response, 'json', $context),
$response->httpStatus(),
[],
true
Expand Down
29 changes: 29 additions & 0 deletions src/Serialization/Context/ContextBuilderChain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace SwagIndustries\Melodiia\Serialization\Context;

use SwagIndustries\Melodiia\Response\ApiResponse;

final class ContextBuilderChain implements ContextBuilderChainInterface
{
/** @var ContextBuilderInterface[] */
private $builders;

public function __construct(iterable $builders)
{
$this->builders = $builders;
}

public function buildContext(array $context, ApiResponse $response): array
{
foreach ($this->builders as $builder) {
if ($builder->supports($response)) {
$context = $builder->buildContext($context, $response);
}
}

return $context;
}
}
12 changes: 12 additions & 0 deletions src/Serialization/Context/ContextBuilderChainInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace SwagIndustries\Melodiia\Serialization\Context;

use SwagIndustries\Melodiia\Response\ApiResponse;

interface ContextBuilderChainInterface
{
public function buildContext(array $context, ApiResponse $response): array;
}
18 changes: 18 additions & 0 deletions src/Serialization/Context/ContextBuilderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace SwagIndustries\Melodiia\Serialization\Context;

use SwagIndustries\Melodiia\Response\ApiResponse;

/**
* Build a part of the serialization context.
*/
interface ContextBuilderInterface extends ContextBuilderChainInterface
{
/**
* Return true if the buildContext method can be called.
*/
public function supports(ApiResponse $response): bool;
}
17 changes: 15 additions & 2 deletions tests/Melodiia/Response/Listener/SerializeOnKernelViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Prophecy\Prophecy\ObjectProphecy;
use SwagIndustries\Melodiia\Response\ApiResponse;
use SwagIndustries\Melodiia\Response\Listener\SerializeOnKernelView;
use SwagIndustries\Melodiia\Serialization\Context\ContextBuilderChainInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
Expand All @@ -21,13 +22,25 @@ class SerializeOnKernelViewTest extends TestCase
/** @var SerializerInterface|ObjectProphecy */
private $serializer;

/** @var ContextBuilderChainInterface|ObjectProphecy */
private $contextChain;

/** @var SerializeOnKernelView */
private $listener;

public function setUp()
public function setUp(): void
{
$this->serializer = $this->prophesize(SerializerInterface::class);
$this->listener = new SerializeOnKernelView($this->serializer->reveal());
$this->contextChain = $this->prophesize(ContextBuilderChainInterface::class);
$this->contextChain->buildContext(Argument::cetera())->willReturn([]);
$this->listener = new SerializeOnKernelView($this->serializer->reveal(), $this->contextChain->reveal());
}

public function tearDown(): void
{
$this->serializer = null;
$this->contextChain = null;
$this->listener = null;
}

public function testItSubscribeOnKernelView()
Expand Down
63 changes: 63 additions & 0 deletions tests/Melodiia/Serialization/Context/ContextBuilderFactoryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);

namespace Melodiia\Serialization\Context;

use PHPUnit\Framework\TestCase;
use SwagIndustries\Melodiia\Response\ApiResponse;
use SwagIndustries\Melodiia\Serialization\Context\ContextBuilderChain;
use SwagIndustries\Melodiia\Serialization\Context\ContextBuilderInterface;

class ContextBuilderFactoryTest extends TestCase
{
public function testItBuildContextUsingGivenBuilders()
{
$builder1 = new class() implements ContextBuilderInterface {
public function buildContext(array $context, ApiResponse $response): array
{
$context['foo'] = true;

return $context;
}

public function supports(ApiResponse $response): bool
{
return true;
}
};
$builder2 = new class() implements ContextBuilderInterface {
public function buildContext(array $context, ApiResponse $response): array
{
$context['baz'] = true;

return $context;
}

public function supports(ApiResponse $response): bool
{
return false;
}
};
$builder3 = new class() implements ContextBuilderInterface {
public function buildContext(array $context, ApiResponse $response): array
{
$context['bar'] = true;

return $context;
}

public function supports(ApiResponse $response): bool
{
return true;
}
};

$chain = new ContextBuilderChain([$builder1, $builder2, $builder3]);

$context = $chain->buildContext([], $this->prophesize(ApiResponse::class)->reveal());
$this->assertTrue($context['foo']);
$this->assertTrue($context['bar']);
$this->assertFalse(isset($context['baz']));
}
}

0 comments on commit 741f796

Please sign in to comment.