Score:0

How to keep similar custom services from conflicting?

in flag

I have two modules, each of which is defining a normalizer service

module_one.services.yml

services:
  module_one.normalizer.node_entity:
    class: Drupal\module_one\Normalizer\ModuleOneEntityNormalizer
    arguments: ['@entity_type.manager']
    tags:
      - { name: normalizer, priority: 10 }

module_two.services.yml

services:
  module_two.normalizer.node_entity:
    class: Drupal\module_two\Normalizer\ModuleTwoEntityNormalizer
    arguments: ['@entity_type.manager']
    tags:
      - { name: normalizer, priority: 10 }

For each module, I am creating a distinct normalizer and presumably defining a separate namespace, ex:

<?php

namespace Drupal\module_one\Normalizer;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\serialization\Normalizer\ContentEntityNormalizer;
use Drupal\node\NodeInterface;

/**
 * Converts the Drupal entity object structures to a normalized array.
 */
class ModuleOneEntityNormalizer extends ContentEntityNormalizer {
...

The problem is that with both modules enabled, one service is blocking the other - the serializer / normalizer fires as expected for the first one but not for the second. The only way to get the other one to be recognized is to increase its priority but that blocks the first.

What am I missing in the definitions that would prevent these two services from conflicting with each other?

Update: Thanks for the really helpful comments, starting to dial in on this. Both normalizers have the same protected $supportedInterface, ex:

  /**
   * The interface or class that this Normalizer supports.
   *
   * @var string
   */
  protected $supportedInterfaceOrClass = [
    'Drupal\node\NodeInterface'
  ];

Which is flagged in the Drupal Serialization API handbook as an issue

Kevin avatar
in flag
Why not change the priority and then adjust its selection rules as to when its applicable? https://api.drupal.org/api/drupal/core%21modules%21serialization%21src%21Normalizer%21NormalizerBase.php/function/NormalizerBase%3A%3AsupportsNormalization/9.2.x if they operate on the same exact entity types with no conditional differences, you likely need to add context information when serializing.
ru flag
Or maybe a [decorator service](https://symfony.com/doc/current/service_container/service_decoration.html)
4uk4 avatar
cn flag
You need to clarify what is in `protected $supportedInterfaceOrClass`. If it's the same, what other parameter if not the priority or format selects which normalizer should be used?
Score:1
in flag

Found a working answer with the helpful guidance from the comments here. The key is that in both Normalizer classes, I was not using the supportsNormalization function

 /**
 * Checks whether the given class is supported for normalization by this normalizer.
 */
   public function supportsNormalization($data, $format = NULL) {
      if (!is_object($data) || !$this->checkFormat($format)) {
        return FALSE;
      }
      if ($data instanceof NodeInterface && $data->getType() == 'myContentType') {
        return TRUE;
      }
        return FALSE;
      }
    }

With the above function, I can continue to have the priority for both normalizers in the services.yml set to the same value (ex. '10'), it will fire for both but return false if it doesn't match the particular content type.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.