首页 > 解决方案 > 联盟路线、集装箱和 PDO

问题描述

TL;博士;

如何使 PDO 连接对CardOnFile\Controller类可用,以便它可以进行数据库查询?(我想我必须使用容器,但不确定如何使用)。

背景

每次实例化需要数据库访问的对象时,我都希望避免与数据库建立多个连接。所以,我认为我需要实例化一个数据库连接 (PDO) 的副本,然后使用 League\Route 和 League\Container 将其注入到需要它的类中。

我不想将容器注入到类中,因为那是服务位置。但是,我完全不确定如何将 PDO 对象放入需要它的类中,以便它可以工作。

如何使映射的可调用对象具有数据库访问权限?

代码:

/* Connect to a MySQL database using driver invocation */
$dsn = 'mysql:dbname=foo;host=localhost';
$user = 'bar';
$password = 'supersecret';

try {
    $pdo = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    die(__FILE__ . ":" . __LINE__);
}

$container = new League\Container\Container;

$container->share('response', Zend\Diactoros\Response::class);
$container->share('request', function () {
    return Zend\Diactoros\ServerRequestFactory::fromGlobals(
        $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
    );
});

$container->share('emitter', Zend\Diactoros\Response\SapiEmitter::class);

//DI PDO instance and connection.
$container->share('PDO', $pdo);

$route = new League\Route\RouteCollection($container);

$route->map('GET', '/cards/', 'CardOnFile\Controller::requestEmail' );
$route->map('GET', '/cards/emails/confirm', 'CardOnFile\Controller::getUserController' );
$route->map('GET', '/cards/emails/', 'CardOnFile\Controller::getCardController' );

$response = $route->dispatch($container->get('request'), $container->get('response'));

$container->get('emitter')->emit($response);

标签: phpdependency-injectionroutescontainers

解决方案


我想到了。

文档并没有使这一点尽可能明显,但是 Container 对象要求您定义了一个接口并使用这些->add()->withArgument()方法。

所以,把它们放在一起,我们有这个:

实例化你的初始对象

下面的代码使用一个闭包来添加一个具有正确数据库连接的 PDO 对象到容器。这是将对象添加到容器中的最高效方式,因为它们在使用之前不会被实例化。

//DI PDO instance and connection.
$container->add('pdo', function() {
    /* Connect to a MySQL database using driver invocation */
    $dsn = 'mysql:dbname=foo;host=localhost';
    $user = 'bar';
    $password = 'supersecret';

    try {
        $pdo = new PDO($dsn, $user, $password);
    } catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
        die(__FILE__ . ":" . __LINE__);
    }

    return $pdo;
});

将您的类添加到容器中并指定构造函数*

$container
    ->add('controller', 'CardOnFile\Controller')
    ->withArgument($container->get('pdo'));

此时,Container 对象将尝试使用类型提示来确定它是否应该向构造函数添加一些内容,因此请确保您的类在其构造函数中具有类型提示。在这种情况下,我们使用的是 PDO 类,但我们也在 CardOnFile 的命名空间中,因此我们需要添加use语句以及类型提示:

<?php

namespace CardOnFile;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
**use \PDO;**

class Controller implements CardControllerInterface
{
    public $content = '';
    protected $pdo = null;

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

    // ...
}

创建一个接口,以便容器可以找到/识别应该将 PDO 对象注入到实例化对象中

<?php

namespace CardOnFile;

interface CardControllerInterface
{

}

是的。它是空白的。它只是用来帮助容器系统。

现在,您已经成功地将 PDO 依赖对象注入到您的应用程序及其类中。


推荐阅读