如何在PHP软件包中访问Doctrine?

时间:2019-06-05 06:59:46

标签: php symfony doctrine

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

public function __construct(EntityManagerInterface $em)

但是,这仅适用于Symfony,似乎不适用于公共捆绑包。请注意,我需要访问默认的数据库连接,如果已经存在,则不想创建一个新连接。

我正在尝试创建一个可以在Symfony或不与Symfony一起使用的程序包,所以我真正需要的是原始PHP,以在没有所有自动装配魔术的情况下获得当前数据库连接(而不是新连接)。

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:0)

您应该将类​​定义为服务,并将EntityManager注入为参数:

# vendor/Acme/HelloBundle/Resources/Config/services.yml

services:
    acme_hellp.service_id:
        class: Acme\HelloBundle\Class   
        arguments: ['@doctrine.orm.entity_manager']   

// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php

namespace Acme\HelloBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;

class AcmeHelloExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
           $container,
           new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');
    }
}

此外,请在Symfony网站上查看此文档,了解如何加载配置文件: https://symfony.com/doc/current/bundles/extension.html

答案 1 :(得分:0)

让我了解您的问题,您是否正在寻找一个使用Symfony的理论实体管理器共享的软件包?因此,让我与您分享我的经验。

这是可能的,并且没有可见的解决方案可供阅读或观看,因此您需要查看一些软件包以了解它们如何解决该问题,我所审查的软件包位于此link上,该软件包提供了不但支持该学说,还支持Mongo等其他平台,所以让我与您分享他们如何制定解决方案。

首先,您需要在bitbucket或github中创建一个程序包,并将其设置为“ type”:“ symfony-bundle”。我之前阅读过评论,但您是正确的,您需要创建一个配置和扩展文件以启用您的软件包,因此在扩展文件中,您需要实现 Symfony \ Component \ DependencyInjection \ Extension \ PrependExtensionInterface 这个包装会让你神奇。因此,您可以编写一些与此类似的代码行并替换您的命名空间:

<?php
namespace NameSpaceBundle\CoreBundle\DependencyInjection;

use Exception;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * Class NameSpaceBundleExtension Configurations of the Core
 * @package NameSpaceBundle\CoreBundle\DependencyInjection
 */
class NameSpaceBundleExtension extends Extension implements PrependExtensionInterface
{
    /**
     * {@inheritdoc}
     * @param array $configs
     * @param ContainerBuilder $container
     * @throws Exception
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
        $loader->load('routing.yml');
        $this->processConfiguration(new Configuration(), $configs);
    }
    /**
     * {@inheritdoc}
     * @param ContainerBuilder $container
     */
    public function prepend(ContainerBuilder $container)
    {
        $configs = $container->getExtensionConfig($this->getAlias());
        $this->processConfiguration(new Configuration(), $configs);
        $doctrineConfig = [];
        $doctrineConfig['orm']['mappings'][] = array(
            'name' => 'NameSpaceBundle',
            'is_bundle' => true,
            'type' => 'annotation',
            'prefix' => 'NameSpaceBundle\CoreBundle\Entity'
        );
        $container->prependExtensionConfig('doctrine', $doctrineConfig);
    }
    /**
     * {@inheritdoc}
     * @return string
     */
    public function getAlias()
    {
        return 'bundelName_core';
    }
}

查看在Resouces / config上分配的service.yaml,现在您不仅可以注入EntityManagerInterface。

services:
  _defaults:
    autowire: false      # Automatically injects dependencies in your services.
    autoconfigure: false # Automatically registers your services as commands, event subscribers, etc.
    public: false

  NameSpaceBundle\CoreBundle\Manager\Company:
    public: false
    class: NameSpaceBundle\CoreBundle\Doctrine\CompanyManager
    arguments:
      - '@doctrine'
      - '\NameSpaceBundle\CoreBundle\Entity\Company'

这也和FriendsOfSymfony的某些软件包和我之前告诉过的软件包类似。

PD。对不起,我的英语不是我的母语

答案 2 :(得分:0)

在尝试创建一个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多个文件和数十行代码更容易理解和维护(而旧系统无法识别捆绑包)。我已将此类放在一个专用的作曲家程序包中,该程序包可同时用于旧系统和Symfony。在我们将所有旧版内容迁移到Symfony之前,这将使保持运行状态变得更加容易。完成之后,我就可以正确地做事了。