【问题标题】:League route, container, and PDO联盟路线、集装箱和 PDO
【发布时间】:2018-07-23 20:03:43
【问题描述】:

TL;DR;

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

背景

每次实例化需要访问数据库的对象时,我都希望避免与数据库建立多个连接。所以,我认为我需要实例化一个数据库连接 (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);

【问题讨论】:

  • FWIW:Design Patterns: How to create database object/connection only when needed?。猜猜我的典型方法是单例(带有工厂/注册表?)。我想在 ZF 和 Symfony 中如何使用 Doctrine。
  • 这很有用,我同意它,但我不知道如何穿透$route->map() 的范围来提供数据库实例或将$pdo 变量传递给类本身。
  • 编辑重新措辞问题,使我需要帮助更清楚。
  • Controller 中获取连接,我可能只是从静态工厂类中获取默认连接。不确定您的应用程序是否像某些框架一样具有“控制器助手”的概念。 $db = $this->_helper->dbManager()...你在使用框架吗?你有某种数据库/模型方法吗?
  • 我没有使用框架。您在此处列出的方法是有效的,但我试图远离使用全局命名空间。不确定我是否可以通过这种方式对其进行单元测试。

标签: php dependency-injection routes containers


【解决方案1】:

我想通了。

docs 并没有使这一点尽可能明显,但 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;
    }

    // ...
}

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

<?php

namespace CardOnFile;

interface CardControllerInterface
{

}

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

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

【讨论】:

    猜你喜欢
    • 2021-10-20
    • 1970-01-01
    • 2015-10-15
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 2021-12-28
    • 2011-03-19
    相关资源
    最近更新 更多