jsonapi.services.yml | 21 +++++++++--- src/Controller/RequestHandler.php | 2 +- .../RegisterNormalizerClassesCompilerPass.php | 37 ++++++++++++++++++++++ src/JsonapiServiceProvider.php | 11 ++++++- .../JsonApiDocumentTopLevelNormalizerTest.php | 4 +-- 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/jsonapi.services.yml b/jsonapi.services.yml index c111a8e..0b47f98 100644 --- a/jsonapi.services.yml +++ b/jsonapi.services.yml @@ -56,10 +56,6 @@ services: arguments: ['@jsonapi.link_manager', '@entity_field.manager', '@plugin.manager.field.field_type', '@jsonapi.resource_type.repository', '@entity.repository'] tags: - { name: normalizer, priority: 31 } - serializer.encoder.jsonapi: - class: Drupal\jsonapi\Encoder\JsonEncoder - tags: - - { name: encoder, priority: 21, format: 'api_json' } jsonapi.resource_type.repository: class: Drupal\jsonapi\ResourceType\ResourceTypeRepository arguments: ['@entity_type.manager', '@entity_type.bundle.info'] @@ -100,4 +96,19 @@ services: class: Drupal\jsonapi\EventSubscriber\DefaultExceptionSubscriber tags: - { name: event_subscriber } - arguments: ['@serializer', '%serializer.formats%'] + arguments: ['@jsonapi.serializer', '%serializer.formats%'] + + # We want the 'api_json' format to not be supported in the REST module, so we cannot register its encoder with the + # Serialization module. Hence we have an encoder without the 'encoder' tag and 'format' property. But that also means + # we cannot reuse the @serializer service. So we define our own serializer service. But we still do want to reuse the + # generic normalizers from the Serialization module. So we inject all normalizers just like the default @serializer + # service does. Only appropriate normalizers are called thanks to the supportsNormalization() API method. + # @see \Drupal\jsonapi\DependencyInjection\Compiler\RegisterNormalizerClassesCompilerPass + # @see \Drupal\jsonapi\JsonapiServiceProvider::register() + # @see \Drupal\Tests\jsonapi\Functional\RestJsonApiUnsupported + # @see \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization + jsonapi.serializer: + class: Symfony\Component\Serializer\Serializer + arguments: [{ }, ['@serializer.encoder.jsonapi']] + serializer.encoder.jsonapi: + class: Drupal\jsonapi\Encoder\JsonEncoder diff --git a/src/Controller/RequestHandler.php b/src/Controller/RequestHandler.php index 4c4fb5a..410529d 100644 --- a/src/Controller/RequestHandler.php +++ b/src/Controller/RequestHandler.php @@ -54,7 +54,7 @@ class RequestHandler implements ContainerAwareInterface, ContainerInjectionInter // Deserialize incoming data if available. /* @var \Symfony\Component\Serializer\SerializerInterface $serializer */ - $serializer = $this->container->get('serializer'); + $serializer = $this->container->get('jsonapi.serializer'); /* @var \Drupal\jsonapi\Context\CurrentContext $current_context */ $current_context = $this->container->get('jsonapi.current_context'); $unserialized = $this->deserializeBody($request, $serializer, $route->getOption('serialization_class'), $current_context); diff --git a/src/DependencyInjection/Compiler/RegisterNormalizerClassesCompilerPass.php b/src/DependencyInjection/Compiler/RegisterNormalizerClassesCompilerPass.php new file mode 100644 index 0000000..32b5394 --- /dev/null +++ b/src/DependencyInjection/Compiler/RegisterNormalizerClassesCompilerPass.php @@ -0,0 +1,37 @@ +getDefinition('jsonapi.serializer'); + + // Retrieve registered Normalizers from the container. + foreach ($container->findTaggedServiceIds('normalizer') as $id => $attributes) { + $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; + $normalizers[$priority][] = new Reference($id); + } + + // Add the registered Normalizers to the JSON API Serializer. + if (!empty($normalizers)) { + $definition->replaceArgument(0, $this->sort($normalizers)); + } + } + +} diff --git a/src/JsonapiServiceProvider.php b/src/JsonapiServiceProvider.php index b5f9ea9..349af52 100644 --- a/src/JsonapiServiceProvider.php +++ b/src/JsonapiServiceProvider.php @@ -4,13 +4,15 @@ namespace Drupal\jsonapi; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ServiceModifierInterface; +use Drupal\Core\DependencyInjection\ServiceProviderInterface; +use Drupal\jsonapi\DependencyInjection\Compiler\RegisterNormalizerClassesCompilerPass; /** * Adds api_json as known format. * * @internal */ -class JsonapiServiceProvider implements ServiceModifierInterface { +class JsonapiServiceProvider implements ServiceModifierInterface, ServiceProviderInterface { /** * {@inheritdoc} @@ -28,4 +30,11 @@ class JsonapiServiceProvider implements ServiceModifierInterface { } } + /** + * {@inheritdoc} + */ + public function register(ContainerBuilder $container) { + $container->addCompilerPass(new RegisterNormalizerClassesCompilerPass()); + } + } diff --git a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php index 1238874..16dd793 100644 --- a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php +++ b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php @@ -339,7 +339,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase { $response = new ResourceResponse(); $normalized = $this ->container - ->get('serializer') + ->get('jsonapi.serializer') ->serialize( new BadRequestHttpException('Lorem'), 'api_json', @@ -572,7 +572,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase { $request_stack = $this->container->get('request_stack'); $request_stack->push($request); $this->container->set('request_stack', $request_stack); - $this->container->get('serializer'); + $this->container->get('jsonapi.serializer'); return [$request, $resource_type]; }