Skip to content

Commit

Permalink
Merge pull request #906 from schmittjoh/instances3
Browse files Browse the repository at this point in the history
Allow multiple serializer instances
  • Loading branch information
goetas committed Sep 14, 2022
2 parents d402554 + eaaabd4 commit 86db61a
Show file tree
Hide file tree
Showing 34 changed files with 965 additions and 259 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -3,3 +3,4 @@
*~
composer.lock
/vendor/
/.phpcs-cache
2 changes: 2 additions & 0 deletions .phpcs.xml.dist
Expand Up @@ -10,6 +10,8 @@
<arg name="colors"/>
<arg value="nps"/>

<config name="php_version" value="70200"/>

<file>Cache/</file>
<file>ContextFactory/</file>
<file>DependencyInjection/</file>
Expand Down
15 changes: 14 additions & 1 deletion Debug/DataCollector.php
Expand Up @@ -15,20 +15,23 @@
final class DataCollector extends BaseDataCollector implements LateDataCollectorInterface
{
private $eventDispatcher;
private $instance;
private $handler;
private $metadataFactory;
private $locator;
private $loadedDirs;
private $runsListener;

public function __construct(
string $instance,
array $loadedDirs,
TraceableEventDispatcher $eventDispatcher,
TraceableHandlerRegistry $handler,
TraceableMetadataFactory $metadataFactory,
TraceableFileLocator $locator,
RunsListener $runsListener
) {
$this->instance = $instance;
$this->eventDispatcher = $eventDispatcher;
$this->handler = $handler;
$this->metadataFactory = $metadataFactory;
Expand All @@ -51,11 +54,21 @@ public function reset(): void
$this->data['metadata_files'] = [];
$this->data['loaded_dirs'] = [];
$this->data['runs'] = [];
$this->data['instance'] = $this->instance;
}

public function getInstance(): string
{
return $this->data['instance'];
}

public function getName(): string
{
return 'jms_serializer';
if (($this->instance ?? $this->data['instance']) === 'default'){
return 'jms_serializer';
}

return 'jms_serializer_'. ($this->instance ?? $this->data['instance']);
}

public function getNumListeners($type): int
Expand Down
6 changes: 5 additions & 1 deletion Debug/RunsListener.php
Expand Up @@ -14,7 +14,11 @@ final class RunsListener
public function saveRunInfo(Event $event)
{
$context = $event->getContext();
$this->runs[$context->getDirection()][spl_object_hash($context)] = true;
if (!isset($this->runs[$context->getDirection()][spl_object_hash($context)])) {
$this->runs[$context->getDirection()][spl_object_hash($context)] = [
'type' => $event->getType()
];
}
}

public function getRuns(): array
Expand Down
1 change: 0 additions & 1 deletion Debug/TraceableEventDispatcher.php
Expand Up @@ -94,7 +94,6 @@ public function getNotTriggeredListeners(): array
protected function initializeListeners(string $eventName, string $loweredClass, string $format): array
{
$listeners = parent::initializeListeners($eventName, $loweredClass, $format);
$this->storage = [];
foreach ($listeners as &$listener) {
$listener[0] = $f = function (...$args) use ($listener, &$f) {
$t = microtime(true);
Expand Down
28 changes: 28 additions & 0 deletions DependencyInjection/Compiler/AdjustDecorationPass.php
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use JMS\SerializerBundle\DependencyInjection\DIUtils;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* This step changes the service decoration targets to match the serializer instance
* In this way when calling
*
* $container->getDefinition('xxx')
* ->setDecoratedService('jms_serializer.object_constructor')
*
* You do not need to worry to which serializer instance jms_serializer.object_constructor refers to.
*
* @internal
*/
final class AdjustDecorationPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
DIUtils::adjustDecorators($container);
}
}
36 changes: 36 additions & 0 deletions DependencyInjection/Compiler/AssignVisitorsPass.php
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Reference;

/**
* @internal
*/
final class AssignVisitorsPass extends PerInstancePass
{
protected function processInstance(ScopedContainer $container): void
{
$def = $container->getDefinition('jms_serializer.serializer');
$serializers = [];
foreach ($container->findTaggedServiceIds('jms_serializer.serialization_visitor') as $id => $multipleTags) {
foreach ($multipleTags as $attributes) {
$serializers[$attributes['format']] = new Reference($id);
}
}

$def->replaceArgument(2, $serializers);

$deserializers = [];
foreach ($container->findTaggedServiceIds('jms_serializer.deserialization_visitor') as $id => $multipleTags) {
foreach ($multipleTags as $attributes) {
$deserializers[$attributes['format']] = new Reference($id);
}
}

$def->replaceArgument(3, $deserializers);
}
}
9 changes: 4 additions & 5 deletions DependencyInjection/Compiler/CustomHandlersPass.php
Expand Up @@ -6,17 +6,16 @@

use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\HandlerRegistry;
use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* @internal
*/
final class CustomHandlersPass implements CompilerPassInterface
final class CustomHandlersPass extends PerInstancePass
{
public function process(ContainerBuilder $container)
protected function processInstance(ScopedContainer $container): void
{
$handlersByDirection = $this->findHandlers($container);
$handlerRegistryDef = $container->findDefinition('jms_serializer.handler_registry');
Expand All @@ -39,7 +38,7 @@ public function process(ContainerBuilder $container)
->setArgument(0, $handlerServices);
}

private function findHandlers(ContainerBuilder $container): array
private function findHandlers(ScopedContainer $container): array
{
$handlers = [];
foreach ($container->findTaggedServiceIds('jms_serializer.handler') as $id => $tags) {
Expand Down
33 changes: 14 additions & 19 deletions DependencyInjection/Compiler/DoctrinePass.php
Expand Up @@ -4,45 +4,40 @@

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Reference;

/**
* @internal
*/
final class DoctrinePass implements CompilerPassInterface
final class DoctrinePass extends PerInstancePass
{
public function process(ContainerBuilder $container)
protected function processInstance(ScopedContainer $container): void
{
if (
$container->hasParameter('jms_serializer.infer_types_from_doctrine_metadata')
&& false === $container->getParameter('jms_serializer.infer_types_from_doctrine_metadata')
) {
return;
}

$registries = [
'doctrine.orm.entity_manager' => 'doctrine',
'doctrine_phpcr.odm.document_manager' => 'doctrine_phpcr',
];

foreach ($registries as $managerId => $registry) {
if (!$container->has($managerId)) {
$container->removeDefinition(sprintf('jms_serializer.metadata.%s_type_driver', $registry));
unset($registries[$managerId]);
}
}

foreach ($registries as $registry) {
$container->getDefinition(sprintf('jms_serializer.metadata.%s_type_driver', $registry))
->setDecoratedService('jms_serializer.metadata_driver')
->replaceArgument(0, new Reference(sprintf('jms_serializer.metadata.%s_type_driver.inner', $registry)))
->setPublic(false);
if ($container->hasDefinition(sprintf('jms_serializer.metadata.%s_type_driver', $registry))) {
$container->getDefinition(sprintf('jms_serializer.metadata.%s_type_driver', $registry))
->setDecoratedService('jms_serializer.metadata_driver')
->replaceArgument(0, new Reference(sprintf('jms_serializer.metadata.%s_type_driver.inner', $registry)));
}

$container->getDefinition(sprintf('jms_serializer.%s_object_constructor', $registry))
->setDecoratedService('jms_serializer.object_constructor')
->replaceArgument(1, new Reference(sprintf('jms_serializer.%s_object_constructor.inner', $registry)))
->setPublic(false);
if ($container->hasDefinition(sprintf('jms_serializer.%s_object_constructor', $registry))) {
$container->getDefinition(sprintf('jms_serializer.%s_object_constructor', $registry))
->setDecoratedService('jms_serializer.object_constructor')
->replaceArgument(1, new Reference(sprintf('jms_serializer.%s_object_constructor.inner', $registry)));
}
}
}
}
10 changes: 3 additions & 7 deletions DependencyInjection/Compiler/ExpressionFunctionProviderPass.php
Expand Up @@ -4,20 +4,16 @@

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Reference;

/**
* @internal
*/
final class ExpressionFunctionProviderPass implements CompilerPassInterface
final class ExpressionFunctionProviderPass extends PerInstancePass
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
protected function processInstance(ScopedContainer $container): void
{
try {
$registryDefinition = $container->findDefinition('jms_serializer.expression_language');
Expand Down
Expand Up @@ -4,21 +4,20 @@

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use JMS\SerializerBundle\DependencyInjection\ScopedContainer;

/**
* @internal
*/
final class FormErrorHandlerTranslationDomainPass implements CompilerPassInterface
final class FormErrorHandlerTranslationDomainPass extends PerInstancePass
{
public function process(ContainerBuilder $container)
protected function processInstance(ScopedContainer $container): void
{
if (!$container->hasParameter('validator.translation_domain')) {
return;
}

$container->findDefinition('jms_serializer.form_error_handler')
->addArgument('%validator.translation_domain%');
->setArgument(1, '%validator.translation_domain%');
}
}
42 changes: 42 additions & 0 deletions DependencyInjection/Compiler/PerInstancePass.php
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
* @internal
*/
abstract class PerInstancePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
foreach (self::getSerializers($container) as $scopedContainer) {
$this->processInstance($scopedContainer);
}
}

/**
* @param ContainerBuilder $container
*
* @return ScopedContainer[]
*/
private static function getSerializers(ContainerBuilder $container): array
{
$serializers = [];

foreach ($container->findTaggedServiceIds('jms_serializer.serializer') as $serializerId => $serializerAttributes) {
foreach ($serializerAttributes as $serializerAttribute) {
$serializers[$serializerId] = new ScopedContainer($container, $serializerAttribute['name']);
}
}

return $serializers;
}

abstract protected function processInstance(ScopedContainer $container): void;
}
Expand Up @@ -5,17 +5,16 @@
namespace JMS\SerializerBundle\DependencyInjection\Compiler;

use JMS\Serializer\EventDispatcher\EventDispatcher;
use JMS\SerializerBundle\DependencyInjection\ScopedContainer;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* @internal
*/
final class RegisterEventListenersAndSubscribersPass implements CompilerPassInterface
final class RegisterEventListenersAndSubscribersPass extends PerInstancePass
{
public function process(ContainerBuilder $container)
protected function processInstance(ScopedContainer $container): void
{
$listeners = $this->findListeners($container);

Expand All @@ -41,7 +40,7 @@ public function process(ContainerBuilder $container)
->setArgument(0, $listenerServices);
}

private function findListeners(ContainerBuilder $container): array
private function findListeners(ScopedContainer $container): array
{
$listeners = [];

Expand Down

0 comments on commit 86db61a

Please sign in to comment.