I'm sure I must be missing the obvious - been staring at this for way too long, and am about to pull my hair out lol.

I am trying to inject a dependency for the database connection into a block class. Here are the relevants:

namespace Drupal\mymodule\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Database\Connection;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyModuleBlock extends BlockBase implements ContainerFactoryPluginInterface {

  protected $connection;

  public function __construct( Connection $connection ) {
    $this->connection = $connection;
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('database')
    );
  }

  ...
}

I have this in my services YML file:

services:
  mymodule.mymodule_block:
    class: Drupal\mymodule\Plugin\Block\MyModuleBlock
    arguments: ['@database']

And I keep getting this error:

 Recoverable fatal error: Argument 1 passed to Drupal\\mymodule\\Plugin\\Block\\MyModuleBlock::__construct() must be an instance of Drupal\\Core\\Database\\Connection, array given ...

I appreciate any guidance! Thanks in advance!

Comments

incursus’s picture

Never mind, I walked away for a few minutes, came back, and was like WTF? Fixed it .... lol.

Cheers.

Sam Moore’s picture

For the rest of us - could you kindly
- marked your issue "SOLVED" by editing the title, and
- post what you did to fix it?
Future strugglers will thank you.

incursus’s picture

Here is the working code:

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Database\Connection;

class MyModuleController extends ControllerBase {

  protected $connection;

  public function __construct( Connection $connection) {
    $this->connection = $connection;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('database'),
    );
  }

  ...

}
drupalfever’s picture

Hello, Scott Burkett! Thanks for sharing this information with the community.

First of all, the code you shared has an extra comma at the end of the following line:
$container->get('database'),

I actually have created a Controller in one of my custom modules and tried your code with no success.

I am pretty frustrated after spending a whole day trying to implement "Database Injection" without success. The documentation on this subject is virtually none existent. People talk about it but there is no practical example.

Would you mind making a small example module that shows how to create and use a "Database Injection"?

drupalfever’s picture

By the way, I keep getting the same error message when using your code:

__construct() "must be an instance of Drupal\Core\Database\Connection, none given

I tried first to create a Controller using this following lines of code I found elsewhere without success:

use Drupal\Core\Database\Connection;

class DatabaseQueryExample {

  protected $connection;

  public function __construct(Connection $connection) {
    $this->connection = $connection;
  }

  public function queryExamples($sql) {
    // db_query()
    $this->connection->query("$sql");
  }
}

What is funny is that I got the same error message!

incursus’s picture

Did you remember to add the service tag entry in your mymodule.services.yml file? It should look something like this:

  mymodule.my_controller:
    class: Drupal\mymodule\Controller\MyController
    arguments: ['@database']
Tsegaye’s picture

#report.routing.yml
report.dbtesting:
  path: '/dbtesting'
  defaults:
    _controller: Drupal\report\Controller\dbTest::showContent
  requirements:
    _permission: 'access content'

In my report.services.yml, I have:

services:
      drupal.testcontroller:
        class: Drupal\report\Controller\dbtest
        arguments: ['@database']

In my dbtest.php controller, I have:

<?php

namespace Drupal\report\controller;


use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
use Symfony\Component\DependencyInjection\ContainerInterface;

class dbTestController extends ControllerBase {

  /**
   * @var \Drupal\Core\Database\Connection
   */
  private $connection;

  public function __construct(Connection $connection) {
    $this->connection = $connection;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('database')
    );
  }

  public function showContent() {
    //db_select is deprecated
    $select = $this->connection->select('node', 'n');
    $select->fields('n');
    $select->condition('type', "article", "=");
    $entries = $select->execute()->fetchAll(\PDO::FETCH_ASSOC);
    $article_count = count($entries);
    return [
      '#markup' => t('There are @articles articles on the current site.', ['@articles' => $article_count])
    ];
  }
}
imclean’s picture

You don't need the create() method as you've listed @database in your *.services.yml file. This passes the service directly to the constructor. See: Services and Dependency Injection

You would then specify the service and method in your *.routing.yml instead of the controller. See: https://www.drupal.org/docs/8/api/routing-system/structure-of-routes

imclean’s picture

Also, the filename and class name need to match. For example, dbTestController.php and class dbTestController.

Tsegaye’s picture

Thanks for this piece of knowledge.