Score:0

How use DependencySerializationTrait?

br flag

I'm on Drupal 9. I'm trying to edit the ProductVariationAccessControlHandler class of Commerce.

The class extends Drupal\Core\Entity\EntityAccessControlHandler which in turn extends the abstract class EntityHandlerBase

This abstract class use the DependencySerializationTrait trait.

Now, I want to inject a new service inside ProductVariationAccessControlHandler. The parent class has a __construct method:

  /**
   * Constructs an access control handler instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type definition.
   */
  public function __construct(EntityTypeInterface $entity_type) {
    $this->entityTypeId = $entity_type->id();
    $this->entityType = $entity_type;
  }

I've searched, but found no documentation nor understood what is the way to use that "trait" in order to inject another service - e.g. entity_type.manager.

Score:1
us flag

DependencySerializationTrait is used to avoid that a service contained in a class property is fully serialized when that class instance is serialized. Instead, the service identifier is serialized within the class instance.

DependencySerializationTrait isn't used to add dependencies to a class that uses Dependency Injection. If you are editing an existing access control handler class (which isn't the correct thing to do when the class is implemented by Drupal core or a contributed module hosted on drupal.org) to add more dependencies, you should edit its createInstance() method, if it exists, or add it. For example, the WorkflowAccessControlHandler class uses the following code, to inject the dependencies it needs.

  /**
   * {@inheritdoc}
   */
  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    return new static($entity_type, $container
      ->get('plugin.manager.workflows.type'));
  }

  /**
   * Constructs the workflow access control handler instance.
   *
   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
   *   The entity type definition.
   * @param \Drupal\Component\Plugin\PluginManagerInterface $workflow_type_manager
   *   The workflow type plugin manager.
   */
  public function __construct(EntityTypeInterface $entity_type, PluginManagerInterface $workflow_type_manager) {
    parent::__construct($entity_type);
    $this->workflowTypeManager = $workflow_type_manager;
  }

The correct way to alter an access control handler used by an entity is implementing hook_entity_type_build() and change the access control handler with EntityTypeInterface::setAccessClass(). For example, for the Node entity, I could use the following code.

function book_entity_type_build(array &$entity_types) {
  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['node']->setAccessClass('Drupal\\mymodule\\Access\\ExtendedNodeAccessControlHandler');
}
Score:1
cn flag

This trait has nothing to do with injecting another service, see When should I use DependencySerializationTrait?

The basic way to inject another service is overriding __construct:

  public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($entity_type);
    $this->entityTypeManager = $entity_type_manager;
  }

You need to be careful, though. Modules could consider the method to be internal and when they decide to inject another service themselve this will break others code. Best practice for modules is to provide a fallback with a deprecation message in such cases. See this change record NodeAccessControlHandler and MediaAccessControlHandler constructor adds a $entity_type_manager argument and the __construct method:

  public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager = NULL) {
    parent::__construct($entity_type);
    if (!isset($entity_type_manager)) {
      @trigger_error('Calling ' . __METHOD__ . '() without the $entity_type_manager argument is deprecated in drupal:9.3.0 and will be required in drupal:10.0.0. See https://www.drupal.org/node/3214171', E_USER_DEPRECATED);
      $entity_type_manager = \Drupal::entityTypeManager();
    }
    $this->entityTypeManager = $entity_type_manager;
  }
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.