5

I have a custom module that pulls data from several different external databases that have been defined as connections in settings.php. The current setup includes a series of controllers that have a service I have created called DataAccess injected into them. My DataAccess service has several methods that accept a $schema parameter and based on this I use the following each time:

$connection = Database::getConnection('default', $schema);

I can then query each database as needed with this setup. I thought about injecting Database into my service from the Drupal container, but I would then need a base class like ControllerBase's create method to get that service in the first place. What would be the correct way to do this as it isn't a controller - would I use a different base class here? I am new to Drupal 8 development and trying to ensure I am following the best practices, but at the same time I don't want to overcomplicate things.

Any advice?

5

You can't inject Drupal\Core\Database\Database, it's a container of static functions, constants, & variables for core database functions.

If you'd like to inject the Connection object, that is be possible, and is more like something you want (unless you have scenario where setting.php is dynamic an all possible values of $schema can't be known).

You can follow the example Drupal sets with the default @database class in core.services.yml:

  database:
    class: Drupal\Core\Database\Connection
    factory: Drupal\Core\Database\Database::getConnection
    arguments: [default]

In your mymodule.services.yml you can define the factory/arguments for each database connection you have, plus your DataAccess service class with the injected connections.

services:
  mymodule.database_schema:
    class: Drupal\Core\Database\Connection
    factory: Drupal\Core\Database\Database::getConnection
    arguments: [default, schema]
  mymodule.database_schema2:
    class: Drupal\Core\Database\Connection
    factory: Drupal\Core\Database\Database::getConnection
    arguments: [default, schema2]
  mymodule.data_access:
    class: Drupal\mymodule\DataAccess
    arguments: ['@mymodule.database_schema', '@mymodule.database_schema2']

From there you can store the database connections in DataAccess's constructor and reference them as required by DataAccess's methods.

  • In general good answer but I fear this won't work in this case, $schema is an array and is passed as an argument to the service. – Berdir Sep 4 '16 at 6:53
5

As commented on another answer, the answer here is probably, you can't.

The database API isn't fully converted to use services. I tried to do it for quite some time, in https://www.drupal.org/node/1811730, but didn't succeed and neither did others.

So, for now, you need to use the static methods. The best you can do is wrap it in a method or another service that does just that to simplify mocking it when you want to write unit tests.

  • I think that now is possible to inject it, at least it works for me like in my answer. – Adrian Cid Almaguer Dec 6 '17 at 16:32
  • 1
    There is a change record related to the DB function, see drupal.org/node/2993033 You can find examples where and how you can get the database connection. – voleger Aug 29 '18 at 22:28
1

At this moment I'm using this code to inject the database service:

*.services.yml

services:
  onlyone:
    class: Drupal\onlyone\OnlyOne
    arguments: ['@entity_type.manager', '@database', '@language_manager']

Drupal\onlyone\OnlyOne

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Language\LanguageManagerInterface;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $connection, LanguageManagerInterface $language_manager) {
    $this->entityTypeManager = $entity_type_manager;
    $this->connection = $connection;
    $this->languageManager = $language_manager;
  }
  • 1
    That's the default database service, sure, that works. The question was as far as I understood about connection to a different database. That might also work by defining your own service with the right arguments for that, but it's a bit more complicated than this – Berdir Dec 6 '17 at 18:13
  • @Berdir I see, maybe was me that misread the question. – Adrian Cid Almaguer Dec 6 '17 at 18:34

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.