Как настроить и ввести несколько подключений к базе данных PDO в Slim 4?

Я мог бы привести пример PDOи успешно введите его. Я определилPDO::class напрямую и внедрил его в конструктор с помощью __construct(PDO $pdo). Мне нужно что-то вродеPDO1::class а также PDO2::class ввести его следующим образом: __construct(PDO1 $pdo1, PDO2 $pdo2)но это явно не работает. Здесь только одинPDOclass, и мне нужно сделать 2 его экземпляра с разными учетными данными базы данных.
Как лучше всего это сделать?

Я установил одно определение базы данных через PDO следующим образом, и оно работает:

Файл: dependencies.php

use DI\ContainerBuilder;
use Psr\Container\ContainerInterface;

return function (ContainerBuilder $containerBuilder) {
    $containerBuilder->addDefinitions([
        PDO::class => function (ContainerInterface $c) {
            $dbSettings = $c->get('settings')['db1'];
            $dsn = 'mysql:host=' . $dbSettings['host'] . ';dbname=' . $dbSettings['dbname'];
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            return new PDO($dsn, $dbSettings['user'], $dbSettings['pass'], $options);
        },
    ]);
};

Файл: index.php

...
// Set up dependencies
$dependencies = require __DIR__ . '/../app/dependencies.php';
$dependencies($containerBuilder);
// Build PHP-DI Container instance
$container = $containerBuilder->build();
// Set container to create App with on AppFactory
AppFactory::setContainer($container);
// Instantiate the app
$app = AppFactory::create();
...

файл SomeRepository.php

use PDO;

class SomeRepository{

    protected $pdo;

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
    }
}

Я видел что-то подобное в этой статье:

return function (ContainerBuilder $containerBuilder) {
    $containerBuilder->addDefinitions([
        'db1' => function (ContainerInterface $c) {
            $db1Settings = $c->get('settings')['db1'];
            $dsn = 'mysql:host=' . $db1Settings['host'] . ';dbname=' . $db1Settings['dbname'];
            $options = [ ... ];
            return new PDO($dsn, $db1Settings['user'], $db1Settings['pass'],$options);
        },
        'db2' => function (ContainerInterface $c) {
            $db2Settings = $c->get('settings')['db2'];
            $dsn = 'mysql:host=' . $db2Settings['host'] . ';dbname=' . $db2Settings['dbname'];
            $options = [ ... ];
            return new PDO($dsn, $db2Settings['user'], $db2Settings['pass'],$options);
        },

    ]);
};

Но лучший ли это способ сделать это? И как я могу получить доступ к соединениям в классе репозитория, не вводя весь контейнер?

2 ответа

Решение

У вас есть несколько вариантов:

  1. Прокси-сервер подключения
  2. Расширение PDO
  3. Автономные объекты

1. Прокси-сервер подключения

Пример:

use PDO;

class ConnectionProxy
{
    private $pdo;

    private $pdo2;

    public function __construct(PDO $pdo, PDO $pdo2)
    {
        $this->pdo = $pdo;
        $this->pdo2 = $pdo2;
    }

    public function getPdo(): PDO
    {
        return $this->pdo;
    }

    public function getPdo2(): PDO
    {
        return $this->pdo2;
    }
}

Определение контейнера:

return [
    ConnectionProxy::class => function (ContainerInterface $c) {
        return new ConnectionProxy(
            $container->get('db1'),
            $container->get('db2')
        );
    },
    'db1' => function (ContainerInterface $container) {
        return new PDO(...);
    },
    'db2' => function (ContainerInterface $container) {
        return new PDO(...);
    },
];

Применение

class MyRepository
{
    private $pdo;

    private $pdo2;

    public function __construct(ConnectionProxy $connectionProxy)
    {
        $this->pdo = $connectionProxy->getPdo();
        $this->pdo2 = $connectionProxy->getPdo2();
    }
}

2. Расширение PDO

use PDO;

class PDO2 extends PDO
{

}

Определение контейнера:

use PDO2;

// ...

return [
    PDO::class => function (ContainerInterface $container) {
        return new PDO(...);
    },

    PDO2::class => function (ContainerInterface $container) {
        return new PDO2(...);
    },
];

Применение

use PDO;
use PDO2;

class MyRepository
{
    private $pdo;

    private $pdo2;

    public function __construct(PDO $pdo, PDO2 $pdo2)
    {
        $this->pdo = $pdo;
        $this->pdo2 = $pdo2;
    }
}

3. Автономные объекты

См. Ответ Матье Наполи: /questions/51058052/kak-nastroit-i-vvesti-neskolko-podklyuchenij-k-baze-dannyih-pdo-v-slim-4/51058067#51058067

Если у вас есть несколько экземпляров класса в вашем приложении (здесь у вас есть несколько экземпляров класса PDO class), то вы должны настроить, какой из них вводить каждый раз.

Что означает, что PDO не может быть автоматически подключен, потому что PHP-DI не может решить, какой экземпляр вы хотите, в зависимости от службы / контроллера / и т. д.

Вам необходимо использовать конфигурацию (см. http://php-di.org/doc/php-definitions.html), чтобы определить, какой экземпляр (db1 или db2 в вашем примере) для каждой службы.

return [
    MyService::class => DI\autowire()
        ->constructorParameter('pdo', DI\get('db1'))
        ->constructorParameter('pdo2', DI\get('db2')),

    'db1' => function (ContainerInterface $c) {
        return new PDO();
    },
    'db2' => function (ContainerInterface $c) {
        return new PDO();
    },
];
Другие вопросы по тегам