Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'd like to modify a table's schema/DB name at runtime as is possible with the table name, but the ClassMetadataInfo class does not appear to expose an interface to get/set this property.

I can make do with modifying table names at runtime if absolutely necessary, but it is not an ideal solution due to the amount of tables we would then have to store in a single schema/DB.

Is there a way to achieve what I'd like to do? Thanks in advance.

Note: I need to be able to provide a fully qualified table name using a schema placeholder in my annotation-based entity mapping (like __schema_placeholder__.table_name, for cross-database joins). At runtime I would then like to dynamically remap the entity from __schema_placeholder__.table_name => real_schema_name.table_name.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
278 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can dynamically adjust the table names ( and mappings ) by hooking into the doctrine event-system with listeners/subscribers.

i.e. "loadClassMetadata" is one of doctrine's events you can create a listener/subscriber for as described in the cookbook article How to Register Event Listeners and Subscribers.

Example

config.yml

services:
    mapping.listener:
        class: AcmeYourBundleEventListenerMappingListener
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata }

MappingListener

use DoctrineORMEventLoadClassMetadataEventArgs;

class MappingListener
{
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $table = $classMetadata->table;

        $oldName = $table['name'];      // ... or $classMetaData->getTableName()

        // your logic here ...

        $table['name'] = 'new_table_name';

        $classMetadata->setPrimaryTable($table);

        // ... or add a field-mapping like this

        $fieldMapping = array(
          'fieldName' => 'about',
          'type' => 'string',
           'length' => 255
        );
        $classMetadata->mapField($fieldMapping);

ClassMetadata extends ClassMetadataInfo and provides a public variable "table" ( containing the mapping information provided by your annotations or yml ) which you can modify !

The public table variable is an array with the following entries:

  • name =>
  • schema =>
  • indexes => array
  • uniqueConstraints => array

You can dynamically register event-listeners/subscribers in your controller prior to saving/updating.

$mappingListener = new MappingListener();

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

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

Furthermore you can introduce multiple database connections/names and access them in your application.

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

Then get different entity managers using ...

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

or repositories

$customers = $this->get('doctrine')
    ->getRepository('AcmeCustomerBundle:Customer', 'customer')
    ->findAll()
;

... or add connections dynamically

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

Read more about the topic in the cookbook chapter How to work with Multiple Entity Managers and Connections.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...