首页 > 解决方案 > 如何在 PHP 包中访问 Doctrine?

问题描述

我正在创建一个将驻留在/vendor目录中的 PHP 包,它需要使用 Doctrine 访问数据库。在我的 Symfony 4.2 主代码中,我可以通过在构造函数中使用自动装配来访问数据库,如下所示:

public function __construct(EntityManagerInterface $em)

然而,这只适用于 Symfony,并且似乎不适用于公共包。请注意,我需要访问默认数据库连接,如果已经存在,我不想创建新连接。

我正在尝试创建一个可以使用和不使用 Symfony 的包,所以我真正需要的是原始 PHP 来获取当前数据库连接(不是新连接),而不需要所有的自动装配魔法。

如果包在 Symfony 下运行,它应该使用当前的 Symfony 数据库连接。如果没有,它应该创建自己的连接。

例如,我可以像这样打开一个新连接:

$conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config)

这很好,但我需要一种方法来获取当前的 Symfony 数据库连接(类似这样):

$conn = \Doctrine\DBAL\DriverManager::getCurrentConnection()

不幸的是,没有这样的功能,我不知道如何创建自己的版本。

标签: phpsymfonydoctrine

解决方案


经过几天尝试创建一个 Symfony 捆绑包以使事情以“官方”方式运行后,我想出了一个单行黑客,它可以获取 Symfony Doctrine 连接并满足我的需要。$kernel它依赖于Symfony 全局的事实:

// Singleton to get Doctrine database connection
//
// If we are running on the legacy system, it will open a new database connection.
//
// If we are running under Symfony, it will use the existing Doctrine
// connection.

class Doctrine
{
     static private $instance = null;
     private $conn;

     // The database connection is established in a private constructor
     private function __construct()
     {
         global $kernel;

         if (class_exists('\config')) {
             // running on legacy system
             $cfg = new \config();

             //
             // set up Doctrine connection
             //
             $params = [
                 'driver'   => 'pdo_mysql',
                 'user'     => $cfg->db_username,
                 'password' => $cfg->db_password,
                 'host'     => $cfg->db_hostname,
                 'dbname'   => $cfg->db_name,
             ];
             $config = new \Doctrine\DBAL\Configuration();

             $this->conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config);
         } else {
             // running on Symfony system
             $this->conn = $kernel->getContainer()->get('doctrine.orm.default_entity_manager')->getConnection();
         }
     }

     static public function getInstance()
     {
         if (!self::$instance) {
             self::$instance = new Doctrine();
         }

         return self::$instance;
     }

     static public function connection()
     {
         return self::getInstance()->getConnection();
     }

     public function getConnection()
     {
         return $this->conn;
     }
 }

通过使用上面的类,这个简单的语句将在 Symfony 和我们的遗留代码中获得一个 Doctrine 连接:

$conn = Doctrine::connection()

现在我们可以在 Symfony 和我们的遗留代码上使用相同的库。是的,我知道这是一个 hack,但它比创建一个简单的 Symfony 包所需的 10 多个文件和数十行代码更容易理解和维护(并且遗留系统不会识别一个包)。我已经把这个类放在一个私有的 composer 包中,遗留系统和 Symfony 都可以使用它。在我们可以将所有遗留的东西迁移到 Symfony 之前,这将使保持运行变得更加容易。完成之后,我就可以以正确的方式做事了。


推荐阅读