0

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.

2 Answers 2

1

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');
}
1

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;
  }

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.