2

I am trying to create my own Node Entity Normalizer in Drupal 10 to get rid of the unnecessary JSON structure that comes out of the box. For example, instead of my API's returning

{
  "nid": [
    {
      "value": 7
    }
  ]
}

I want to make it return

{
  "nid": 7
}

So I've tried the following options in my custom module:

  1. Typed Data Interface

example_normalizer.services.yml

services:
  example_normalizer.typed_data:
    class: Drupal\example_normalizer\Normalizer\CustomTypedDataNormalizer
    tags:
    - { name: normalizer, priority: 2 }

src/Normalizer/CustomTypedDataNormalizer.php

<?php
namespace Drupal\example_normalizer\Normalizer;
use Drupal\serialization\Normalizer\NormalizerBase;
/**
 * Converts typed data objects to arrays.
 */
class CustomTypedDataNormalizer extends NormalizerBase {
  /**
 * The interface or class that this Normalizer supports.
 *
 * @var string
 */
  protected $supportedInterfaceOrClass = 'Drupal\Core\TypedData\TypedDataInterface';
  /**
 * {@inheritdoc}
 */
  public function normalize($object, $format = NULL, array $context = array()) {
    $value = $object->getValue();
    if (isset($value[0]) && isset($value[0]['value'])) {
      $value = $value[0]['value'];
    }
    return $value;
  }
}

and

  1. Custom Node Entity Normalizer

example_normalizer.services.yml

services:
  example_normalizer.node_entity:
    class: Drupal\example_normalizer\Normalizer\NodeEntityNormalizer
    arguments: ['@entity.manager']
    tags:
    - { name: normalizer, priority: 8 }

src/Normalizer/NodeEntityNormalizer.php

<?php
namespace Drupal\example_normalizer\Normalizer;
use Drupal\serialization\Normalizer\ContentEntityNormalizer;
use Drupal\Core\Datetime\DrupalDateTime;
/**
 * Converts the Drupal entity object structures to a normalized array.
 */
class NodeEntityNormalizer extends ContentEntityNormalizer {
  /**
 * The interface or class that this Normalizer supports.
 *
 * @var string
 */
  protected $supportedInterfaceOrClass = 'Drupal\node\NodeInterface';
  /**
 * {@inheritdoc}
 */
  public function normalize($entity, $format = NULL, array $context = array()) {
    // Similar logic as above
  }
}

However, in both cases, when I clear the cache I am getting the error

PHP Fatal error:  Uncaught Error: Class "Drupal\example_normalizer\Normalizer\NodeEntityNormalizer" not found in /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php:262

What am I missing in my module that this is not getting picked up?

I'd like to be able to make a call like

$serializer = \Drupal::service('serializer')
$custom_json = $serializer->serialize($entity, 'json', ['plugin_id' => 'my_custom_normalizer']
4
  • 1
    You've cleared the cache? Are these pastes correct? The second example YAML does not validate.
    – Kevin
    May 25, 2023 at 23:10
  • The example_normalizer.services.yml file is not correctly formatted, in both the cases. The indentation must be two spaces, not a single space. Patrick Kenny's answer does not explain why you get that error, but it explains how to change the normalizer used by Drupal core.
    – apaderno
    May 26, 2023 at 8:01
  • @Kevin No, I can't clear the cache, that is when I am getting the DependencyInjection error. And the pastes were not correct, I just updated them though.
    – BlondeSwan
    May 26, 2023 at 14:24
  • @apaderno I just updated them, they are correct in my actual module (I have an auto formatter). My ultimate goal is to be able to point to my own plugin_id when I call Drupal's serialize function.
    – BlondeSwan
    May 26, 2023 at 14:28

1 Answer 1

1

JSON normalization is not declared in services.yml. Instead, you want to use MyModuleServiceProvider.php to override the core class.

This is an example from my site overriding FieldItemNormalizer:

<?php
    
namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class MyModuleServiceProvider extends ServiceProviderBase implements ServiceProviderInterface {

  /**
   * {@inheritDoc}
   */
  public function alter(ContainerBuilder $container): void {
    $jsonapi_definition = $container->getDefinition('serializer.normalizer.field_item.jsonapi');
    $jsonapi_definition->setClass('Drupal\my_module\Normalizer\MyModuleFieldItemNormalizer');
}

Here's a general guide to overriding core services.

1
  • I don't think that is what I want to actually do. I'm not looking to override the core class completely, I just want to create a new normalizer so that I can serialize with a call like: \Drupal::service('serializer')->serialize($entity, 'json', ['plugin_id' => 'my_custom_normalizer']
    – BlondeSwan
    May 26, 2023 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.