3

I cannot get my head around this dependency injection theory. How are we supposed to get the below methods aligned with dependency injection?

\Drupal::routeMatch()->getParameter('node');
\Drupal::request();
\Drupal::formBuilder()->getForm('Drupal\enquirycart\Form\EnquiryForm');
\Drupal::config()

Here is a class that I need to fix this warning message when viewed in https://pareview.sh/

"\Drupal calls should be avoided in classes, use | | dependency injection instead"

    class EnquirycartBlock extends BlockBase implements BlockPluginInterface {

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    $default_config = \Drupal::config('enquirycart.settings');

    return [
      'label_display' => FALSE,
      'enquiry_email' => $default_config->get('enquirycart.email'),
    ];

  }

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

    $builtForm = \Drupal::formBuilder()->getForm('Drupal\enquirycart\Form\EnquirycartButtonForm');
    $renderArray['form'] = $builtForm;

    return $renderArray;

  }

  /**
   * {@inheritdoc}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $form_new = parent::blockForm($form, $form_state);

    return $form_new;

  }
  • 1
    This article is one of the best I have seen for DI on blocks or plugins chromatichq.com/blog/dependency-injection-drupal-8-plugins – Kevin Jul 3 '17 at 3:39
  • 1
    So, you need to implement ContainerFactoryPluginInterface. – Kevin Jul 3 '17 at 3:40
  • Big help mate! I had no idea how to do this. definitely the best article... now i see the light :D – danuddara Jul 3 '17 at 5:00
10

For future reference, from the link by @Kevin:

The key to making plugins use dependency injection is to implement the ContainerFactoryPluginInterface. When plugins are created, the code first checks if the plugin implements this interface. If it does, it uses the create() and __construct() pattern, if not, it uses just the __construct() pattern. - From Acquia's Lesson 11.4 - Dependency injection and plugins

The example code below is written by Mart Matsoo from Chromatic. Please check the full article here: https://chromatichq.com/blog/dependency-injection-drupal-8-plugins. As @Kevin already mentioned in the comments it is a great article about Depencency Injection in Plugins.

Dependency Injection example in a block

Note the injection of the 'current_user' service via $container->get('current_user') in the create() method. You can pass extra services there.

<?php

namespace Drupal\heytaco\Plugin\Block;

use Drupal\Core\Session\AccountProxy;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a Hey Taco Results Block
 *
 * @Block(
 *   id = "heytaco_block",
 *   admin_label = @Translation("HeyTaco! Leaderboard"),
 * )
 */
class HeyTacoBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * @var $account \Drupal\Core\Session\AccountProxyInterface
   */
  protected $account;

  /**
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   *
   * @return static
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('current_user')
    );
  }

  /**
   * @param array $configuration
   * @param string $plugin_id
   * @param mixed $plugin_definition
   * @param \Drupal\Core\Session\AccountProxyInterface $account
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, AccountProxyInterface $account) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->account = $account;
  }

Dependency Injection example in a controller

The same concept applies here, pass extra services via $container->get() in the create() method.

<?php

namespace Drupal\heytaco\Controller;

use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Controller\ControllerBase;

/**
 * Controller routines for HeyTaco! block.
 */
class HeyTacoController extends ControllerBase {

  protected $account;

  public function __construct(AccountInterface $account) {
    $this->account = $account;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('current_user')
    );
  }
  • I'm pretty sure you need to call parent::__construct() in your constructor there, or you get weird errors when adding blocks. – George Apr 11 '18 at 5:19
1

Thanks to @kevin, I managed to get this DI working as i wanted. If anyone wants to check the core services follow the link below.

All the services are listed in the core API https://api.drupal.org/api/drupal/core%21core.services.yml/8.3.x

Just Posting an example class where it used all the \Drupal services i mentioned in the question. here's how you do it.

namespace Drupal\enquirycart\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\Routing\CurrentRouteMatch;

class EnquirycartBlock extends BlockBase implements BlockPluginInterface, ContainerFactoryPluginInterface {


    /**
     * @var  \Drupal\Core\Form\FormBuilderInterface $formbuilder
     */
    protected $formbuilder;

    protected $configfactory;

    protected $routematch;

    protected $requestmatch;

    /**
    * @param array $configuration
    * @param string $plugin_id
    * @param mixed $plugin_definition
    * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
    */
    public function __construct(array $configuration, $plugin_id, $plugin_definition, FormBuilderInterface $form_builder, ConfigFactoryInterface $config_factory, CurrentRouteMatch $route_match, RequestStack $requestdi) {
        parent::__construct($configuration, $plugin_id, $plugin_definition);

        $this->formbuilder = $form_builder;
        $this->configfactory = $config_factory;
        $this->routematch = $route_match;
        $this->requestmatch = $requestdi;
       /*  dpm($this->configfactory->get('enquirycart.settings'));     
         dpm($this->routematch->getParameter('node')->getTitle()); 
         dpm($this->requestmatch->getCurrentRequest()->getSession()->get('enquire'));*/
    }

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


}
  • 1
    Note that you don't need BlockPluginInterface since BlockBase implements it already. – George Apr 5 '18 at 7:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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