如何在 slim 4 中设置和注入多个 PDO 数据库连接?
How to set up and inject multiple PDO database connections in 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;
}
}
我在 this 文章中看到过类似的内容:
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);
},
]);
};
但这是最好的方法吗?以及如何访问存储库中的连接 class 而无需注入整个容器?
如果您的应用程序中有多个 class 实例(这里您有多个 PDO
class 实例),那么您必须配置每次注入哪一个.
这意味着 PDO
无法自动装配,因为 PHP-DI 无法根据 service/controller/etc.
来决定您想要哪个实例
您需要使用配置(参见 http://php-di.org/doc/php-definitions.html#autowired-objects)来定义为每个服务注入哪个实例(在您的示例中为 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();
},
];
您有多种选择:
- 扩展 PDO
- 自动装配对象
1.扩展 PDO
use PDO;
class PDO2 extends PDO
{
// must be empty
}
容器定义:
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;
}
}
2。自动装配对象
查看 Matthieu Napoli 的回答:
我可以创建一个 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;
}
}
我在 this 文章中看到过类似的内容:
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);
},
]);
};
但这是最好的方法吗?以及如何访问存储库中的连接 class 而无需注入整个容器?
如果您的应用程序中有多个 class 实例(这里您有多个 PDO
class 实例),那么您必须配置每次注入哪一个.
这意味着 PDO
无法自动装配,因为 PHP-DI 无法根据 service/controller/etc.
您需要使用配置(参见 http://php-di.org/doc/php-definitions.html#autowired-objects)来定义为每个服务注入哪个实例(在您的示例中为 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();
},
];
您有多种选择:
- 扩展 PDO
- 自动装配对象
1.扩展 PDO
use PDO;
class PDO2 extends PDO
{
// must be empty
}
容器定义:
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;
}
}
2。自动装配对象
查看 Matthieu Napoli 的回答: