10

When I checked the code I wrote with phpcs --standard=DrupalPractice /path/to/myController, I got the following warning.

WARNING | Node::load calls should be avoided in classes, use dependency injection instead.

The code I use to load the node is the following.

use Drupal\node\Entity\Node;

public function content_load($node = NULL) {
 $noad_data = Node::load($node, NULL, TRUE);
}

How should I use dependency injection to load a node?

0

2 Answers 2

22

The controller base class provides the method entityTypeManager() which gets the service with the same name from the container the first time you use it. You can use this service to get the node storage:

  $node_storage = $this->entityTypeManager()->getStorage('node');

and then load the node:

  $node = $node_storage->load($nid);
7
  • Shouldn't this be $node_storage = $this->entityTypeManager->getStorage('node');? Without the parenthesis after entityTypeManager?
    – leymannx
    Nov 5, 2019 at 12:55
  • 3
    No, not if you use the utility base class for thin controllers ControllerBase. This class exists so that the average user doesn't need to write that ugly pair of factory method and constructor, which you can avoid also by simply putting the controller method in a normal service and inject via container arguments.
    – 4uk4
    Nov 5, 2019 at 13:33
  • @leymannx, and 4k4 I was just going insane why my code was not working in form, which was working in controller thanks for the clarification . Jan 18, 2020 at 15:31
  • I can't get this accepted answer to work with Drupal 10. I've posted a new question about how to do this with Drupal 10. May 20 at 17:57
  • 1
    @FreeRadical, the answer begins with The controller base class provides ..., which in Drupal 10 still provides this method.
    – 4uk4
    May 20 at 20:41
15

This is how I injected the entity type manager to load nodes into a block (where the nodes to load didn't come from the block context):

<?php

namespace Drupal\MYMODULE\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;

/**
 * Provides a 'My Block' Block.
 *
 * @Block(
 *   id = "my_block",
 *   admin_label = @Translation("My Block"),
 * )
 */
class MyBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Constructs a new MyBlock.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param array $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {

    $node_storage = $this->entityTypeManager->getStorage('node');

    $node = $node_storage->load(1);

    return [
      '#markup' => $node->getTitle(),
    ];
  }

}
3
  • I don't really see how it's relevant to the original question: - why context should provide nodes? And what does it have to do that you then loaded node id:1? - Mentioning ContainerFactoryPluginInterface in general has nothing to do that you should always use storage injection loading entities. It's a different topic.
    – ssibal
    Mar 1, 2019 at 16:31
  • 1
    @ssibal – Normally, in a block, you can simply get the current node from the block context. In my case, I got some entity IDs from a database query, and then needed to load them. No context. That's why I called in entityTypeManager. ->load(1) is a placeholder. How you get your entity IDs depends on your own logic. I just extended the accepted answer to have a fully working code snippet. How would you have solved that challenge? What's your fully working code answer to the asked question?
    – leymannx
    Mar 1, 2019 at 17:18
  • 2
    While the context is slightly different, the answer still shows how to load an entity using dependency injection without using a static method of a class. This answer is not about block context. I take it as saying I would do it in the same way I would do it in a block plugin.
    – apaderno
    Mar 6, 2019 at 10:57

Your Answer

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

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