Php 以编程方式修改表';Doctrine2中的架构名称?

Php 以编程方式修改表';Doctrine2中的架构名称?,php,symfony,doctrine-orm,Php,Symfony,Doctrine Orm,我想在运行时修改表的schema/DB名称,但是ClassMetadataInfo类似乎没有公开获取/设置此属性的接口 如果绝对必要的话,我可以在运行时修改表名,但这不是一个理想的解决方案,因为我们需要在单个schema/DB中存储大量的表 有没有办法实现我想做的事情?提前谢谢 注意:我需要能够在基于注释的实体映射中使用模式占位符提供一个完全限定的表名(如跨数据库联接的\uuuu模式\u占位符\uuuu.table\u name)。在运行时,我希望动态地从\uuu schema\u placeh

我想在运行时修改表的schema/DB名称,但是
ClassMetadataInfo
类似乎没有公开获取/设置此属性的接口

如果绝对必要的话,我可以在运行时修改表名,但这不是一个理想的解决方案,因为我们需要在单个schema/DB中存储大量的表

有没有办法实现我想做的事情?提前谢谢


注意:我需要能够在基于注释的实体映射中使用模式占位符提供一个完全限定的表名(如跨数据库联接的
\uuuu模式\u占位符\uuuu.table\u name
)。在运行时,我希望动态地从
\uuu schema\u placeholder\uuu.table\u name
=>
real\u schema\u name.table\u name

您可以通过与侦听器/订阅者挂钩来动态地调整表名(和映射)

i、 e.“loadClassMetadata”是您可以为创建监听器/订阅者的工具之一,如cookbook文章中所述

例子 config.yml

映射侦听器

扩展并提供一个公共变量“”(包含批注或yml提供的映射信息),您可以修改该变量

public table变量是一个包含以下项的数组:

  • 名称=>
  • 模式=>
  • 索引=>数组
  • uniqueConstraints=>array
在保存/更新之前,您可以在控制器中动态注册事件侦听器/订阅服务器

$mappingListener = new MappingListener();

// ... maybe even modify the listener using reflection

$evm = $this->get('doctrine')->getManager()->->getEventManager();
$evm->addEventListener('loadClassMetadata', $mappingListener);

此外,您可以引入多个数据库连接/名称,并在应用程序中访问它们

app/config/config.yml

doctrine:
    dbal:
        default_connection:   default
        connections:
            default:
                driver:   "%database_driver%"
                host:     "%database_host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8
            customer:
                driver:   "%database_driver2%"
                host:     "%database_host2%"
                port:     "%database_port2%"
                dbname:   "%database_name2%"
                user:     "%database_user2%"
                password: "%database_password2%"
                charset:  UTF8
然后使用

  $em = $this->get('doctrine')->getManager('default');
  $em2 = $this->get('doctrine')->getManager('customer');
或存储库

$customers = $this->get('doctrine')
    ->getRepository('AcmeCustomerBundle:Customer', 'customer')
    ->findAll()
;
。。。或者动态地

$this->get('doctrine')
  ->connection('mysql://username:password@localhost/test', 'dynamic_connection');

阅读烹饪书一章中有关该主题的更多信息。

您可以使用@Table中未记录的“options”参数,并将一个变量传递给侦听器,以决定使用哪个数据库

“选项”用于在生成模式时在SQL中包含DBMS特定的选项。例如:“字符集”=“utf8mb4”,“引擎”=“InnoDB”等

选择变量名时,请确保它不是DBMS支持的有效选项。在下面的示例中,我选择了“模式”:

@ORM\Table(name="person", options={"schema"="readonly"})
之后,我在services.yml中创建了一个名为“schema”的参数数组,它将通过ParameterBag传递给服务。这些值可以在yml中编辑,也可以从环境变量中提取

parameters:
    env(SCHEMA_READONLY): 'readonly_database' #default if env variable has not been set
    schema:
        readonly: 'readonly_database'
        client: 'client_database'
        runtime: '%env(SCHEMA_READONLY)%' #pulled from env variables
现在我的听众是这样的:

class MappingListener
{
    protected $parameterBag;

    public function __construct(ParameterBagInterface $parameterBag) {
        $this->parameterBag = $parameterBag;
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) {
        $schemaParamaters = $this->parameterBag->has('schema') ? $this->parameterBag->get('schema') : array();

        $classMetadata = $eventArgs->getClassMetadata();

        if(isset($classMetadata->table['options']['schema']) && isset($schemaParamaters[$classMetadata->table['options']['schema']])) {
            $classMetadata->setPrimaryTable(['schema' => $schemaParamaters[$classMetadata->table['options']['schema']]]);
        }
    } 
}
这将导致所有具有表选项“schema”的实体将被设置为使用service.yml中的参数或环境变量中定义的数据库

parameters:
    env(SCHEMA_READONLY): 'readonly_database' #default if env variable has not been set
    schema:
        readonly: 'readonly_database'
        client: 'client_database'
        runtime: '%env(SCHEMA_READONLY)%' #pulled from env variables

这意味着您可以选择设置模式,或将其保留为默认模式,而无需编辑实体或任何其他类。

谢谢,但这并不能解决我的特殊问题,因为我还需要进行跨数据库连接,因此必须在ORM映射中提供完全限定的表名(schema.table)。我可能可以使用YAML映射配置中的参数来实现这一点,但我使用的是注释,不希望转换。我需要能够将一个实体映射到
\uuuuu schema\u placeholder\uuuu.tableName
,然后通过用实际名称替换此schema placeholder来动态更改映射。我已使用新信息对我的答案进行了验证,这将帮助您解决问题。请通过至少向上投票来显示一些信用。。。如果你需要进一步的信息,可能会接受或评论。这看起来正是我需要的。这就是我在凌晨3点读事件一章的收获。投票通过并接受,谢谢:)
class MappingListener
{
    protected $parameterBag;

    public function __construct(ParameterBagInterface $parameterBag) {
        $this->parameterBag = $parameterBag;
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) {
        $schemaParamaters = $this->parameterBag->has('schema') ? $this->parameterBag->get('schema') : array();

        $classMetadata = $eventArgs->getClassMetadata();

        if(isset($classMetadata->table['options']['schema']) && isset($schemaParamaters[$classMetadata->table['options']['schema']])) {
            $classMetadata->setPrimaryTable(['schema' => $schemaParamaters[$classMetadata->table['options']['schema']]]);
        }
    } 
}