我正在创建一个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()
不幸的是,没有这样的功能,我不知道如何创建自己的版本。
答案 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之前,这将使保持运行状态变得更加容易。完成之后,我就可以正确地做事了。