1

I'm getting an error when I wrote the code using Dependency injection:

TypeError: Argument 1 passed to Drupal\sydneypro_exchange_rates_block\Plugin\Block\ExchangeRatesBlock::__construct() must implement interface Drupal\Core\Cache\CacheBackendInterface, array given, called in /var/www/web/core/lib/Drupal/Core/Plugin/Factory/ContainerFactory.php on line 25 in Drupal\sydneypro_exchange_rates_block\Plugin\Block\ExchangeRatesBlock->__construct() (line 55 of modules/custom/sydneypro_exchange_rates_block/src/Plugin/Block/ExchangeRatesBlock.php).

ExchangeRatesBlock.php:

<?php

namespace Drupal\sydneypro_exchange_rates_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Render\Markup;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use Psr\Container\ContainerInterface;

/**
 * Provides a block with Exchange Rates.
 *
 * @Block(
 *   id = "block_exchange_rates",
 *   admin_label = @Translation("Exchange rates block"),
 * )
 */
class ExchangeRatesBlock extends BlockBase {

  /**
   * Cache for Data.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cacheBackend;

  /**
   * Guzzle Http Client.
   *
   * @var \GuzzleHttp\Client
   */
  protected $httpClient;

  /**
   * Configuration for module.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  protected $config;

  /**
   * ExchangeRatesBlock constructor.
   *
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cacheBackendInterface.
   * @param \GuzzleHttp\Client $http_Client
   *   The httpclient.
   * @param \Drupal\Core\Config\ImmutableConfig $immutable_config
   *   The configuration.
   */
  public function __construct(CacheBackendInterface $cache_backend, Client $http_Client, ImmutableConfig $immutable_config) {
    $this->cacheBackend = $cache_backend;
    $this->httpClient = $http_Client;
    $this->config = $immutable_config;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('cache.default'),
      $container->get('http_client'),
      $container->get('config.factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    $client = $this->httpClient;
    $access_key = $this->config->get('exchange.settings')->get('exchange_access_key');
    $cid = 'sydneypro_exchange_rates_block';

    try {
      if ($cache = $this->cacheBackend->get($cid)) {
        $data = $cache->data;
      }
      else {
        $response = $client->get('http://api.exchangeratesapi.io/v1/latest?access_key=' . $access_key);
        $response_data = $response->getBody();
        $data = json_decode($response_data);
        $this->cacheBackend->set($cid, $data);
      }

      $properties = [
        'uah' => [
          'label' => $this->t('Hryvnia'),
          'value' => round($data->rates->UAH, 2),
        ],
        'usd' => [
          'label' => $this->t('Dollar'),
          'value' => round($data->rates->USD, 2),
        ],
        'gbp' => [
          'label' => $this->t('Pound sterling'),
          'value' => round($data->rates->GBP, 2),
        ],
      ];

      $build = [];

      foreach ($properties as $exchange_property => $data) {
        $build[$exchange_property] = ['#type' => 'container'];
        $build[$exchange_property]['label'] = ['#markup' => $data['label']];
        $build[$exchange_property]['separator'] = ['#markup' => ': '];
        $build[$exchange_property]['value'] = ['#markup' => $data['value']];
      }
      $build[] = [
        '#attached' => [
          'library' => [
            'sydneypro_exchange_rates_block/sydneypro_exchange_rates_block',
          ],
        ],
      ];

      return $build;
    }
    catch (ConnectException $e) {
      return [
        '#markup' => Markup::create('<h1>Internet, DNS, or other connection error</h1>'),
      ];
    }
    catch (RequestException $e) {
      return [
        '#markup' => Markup::create('<h1>Sorry, no data available</h1>'),
      ];
    }
  }

  /**
   * Disable cache for a block because my own cache doesn't work with it.
   *
   * @return int
   *   return cacheMaxAge 0
   */
  public function getCacheMaxAge() {
    return 0;
  }

}


How to fix it?

1 Answer 1

2

The constructor of a class that extends Drupal\Component\Plugin\PluginBase, such as in your case (as Drupal\Core\Block\BlockBase extends that class) receives the following arguments.

  • array $configuration
  • $plugin_id
  • $plugin_definition

That's what that error message means: You defined the first parameter of the constructor to implement Drupal\Core\Cache\CacheBackendInterface, but it receives an array.

The create() method defined for your block is ignored by Drupal. If you need to pull dependencies from the container, a plugin (such as a block plugin) needs to implement ContainerFactoryPluginInterface, which is what the BookNavigationBlock class does. (The following is only part of the class code.)

class BookNavigationBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * Constructs a new BookNavigationBlock instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match.
   * @param \Drupal\book\BookManagerInterface $book_manager
   *   The book manager.
   * @param \Drupal\Core\Entity\EntityStorageInterface $node_storage
   *   The node storage.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, BookManagerInterface $book_manager, EntityStorageInterface $node_storage) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->routeMatch = $route_match;
    $this->bookManager = $book_manager;
    $this->nodeStorage = $node_storage;
  }

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

}

In your case, the class should use the following code. (I am showing what needs to be changed in the code shown in the question.)

namespace Drupal\sydneypro_exchange_rates_block\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Markup;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a block with Exchange Rates.
 *
 * @Block(
 *   id = "block_exchange_rates",
 *   admin_label = @Translation("Exchange rates block"),
 * )
 */
class ExchangeRatesBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * ExchangeRatesBlock constructor.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cacheBackendInterface.
   * @param \GuzzleHttp\Client $http_Client
   *   The httpclient.
   * @param \Drupal\Core\Config\ImmutableConfig $immutable_config
   *   The configuration.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, CacheBackendInterface $cache_backend, Client $http_Client, ImmutableConfig $immutable_config) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->cacheBackend = $cache_backend;
    $this->httpClient = $http_Client;
    $this->config = $immutable_config;
  }

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

}

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.