Как настроить и ввести несколько подключений к базе данных PDO в Slim 4?
Я мог бы привести пример PDO
и успешно введите его. Я определилPDO::class
напрямую и внедрил его в конструктор с помощью __construct(PDO $pdo)
. Мне нужно что-то вродеPDO1::class
а также PDO2::class
ввести его следующим образом: __construct(PDO1 $pdo1, PDO2 $pdo2)
но это явно не работает. Здесь только одинPDO
class, и мне нужно сделать 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 ответа
У вас есть несколько вариантов:
- Прокси-сервер подключения
- Расширение PDO
- Автономные объекты
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();
},
];