Skip to content

Commit

Permalink
Merge pull request doctrine#53 from doctrine/master_slave
Browse files Browse the repository at this point in the history
Master slave
  • Loading branch information
beberlei committed Apr 1, 2012
2 parents ef0f74a + 9f8dbfb commit 02569f5
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 65 deletions.
158 changes: 99 additions & 59 deletions DependencyInjection/Configuration.php
Expand Up @@ -64,30 +64,15 @@ private function addDbalSection(ArrayNodeDefinition $node)
->beforeNormalization()
->ifTrue(function ($v) { return is_array($v) && !array_key_exists('connections', $v) && !array_key_exists('connection', $v); })
->then(function ($v) {
// Key that should not be rewritten to the connection config
$excludedKeys = array('default_connection' => true, 'types' => true, 'type' => true);
$connection = array();
foreach (array(
'dbname',
'host',
'port',
'user',
'password',
'driver',
'driver_class',
'options',
'path',
'memory',
'unix_socket',
'wrapper_class',
'platform_service',
'charset',
'logging',
'profiling',
'mapping_types',
) as $key) {
if (array_key_exists($key, $v)) {
$connection[$key] = $v[$key];
unset($v[$key]);
foreach ($v as $key => $value) {
if (isset($excludedKeys[$key])) {
continue;
}
$connection[$key] = $v[$key];
unset($v[$key]);
}
$v['default_connection'] = isset($v['default_connection']) ? (string) $v['default_connection'] : 'default';
$v['connections'] = array($v['default_connection'] => $connection);
Expand Down Expand Up @@ -125,42 +110,98 @@ private function getDbalConnectionsNode()
$treeBuilder = new TreeBuilder();
$node = $treeBuilder->root('connections');

$node
/** @var $connectionNode ArrayNodeDefinition */
$connectionNode = $node
->requiresAtLeastOneElement()
->useAttributeAsKey('name')
->prototype('array')
->fixXmlConfig('mapping_type')
->children()
->scalarNode('dbname')->end()
->scalarNode('host')->defaultValue('localhost')->end()
->scalarNode('port')->defaultNull()->end()
->scalarNode('user')->defaultValue('root')->end()
->scalarNode('password')->defaultNull()->end()
->scalarNode('driver')->defaultValue('pdo_mysql')->end()
->scalarNode('path')->end()
->booleanNode('memory')->end()
->scalarNode('unix_socket')->end()
->scalarNode('platform_service')->end()
->scalarNode('charset')->end()
->booleanNode('logging')->defaultValue($this->debug)->end()
->booleanNode('profiling')->defaultValue($this->debug)->end()
->scalarNode('driver_class')->end()
->scalarNode('wrapper_class')->end()
->arrayNode('options')
->useAttributeAsKey('key')
->prototype('scalar')->end()
->end()
->arrayNode('mapping_types')
->useAttributeAsKey('name')
->prototype('scalar')->end()
->end()
;

$this->configureDbalDriverNode($connectionNode);

$connectionNode
->fixXmlConfig('option')
->fixXmlConfig('mapping_type')
->fixXmlConfig('slave')
->children()
->scalarNode('driver')->defaultValue('pdo_mysql')->end()
->scalarNode('platform_service')->end()
->booleanNode('logging')->defaultValue($this->debug)->end()
->booleanNode('profiling')->defaultValue($this->debug)->end()
->scalarNode('driver_class')->end()
->scalarNode('wrapper_class')->end()
->arrayNode('options')
->useAttributeAsKey('key')
->prototype('scalar')->end()
->end()
->arrayNode('mapping_types')
->useAttributeAsKey('name')
->prototype('scalar')->end()
->end()
->end()
;

$slaveNode = $connectionNode
->children()
->arrayNode('slaves')
->useAttributeAsKey('name')
->prototype('array')
;
$this->configureDbalDriverNode($slaveNode);

return $node;
}

/**
* Adds config keys related to params processed by the DBAL drivers
*
* These keys are available for slave configurations too.
*
* @param \Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition $node
*/
private function configureDbalDriverNode(ArrayNodeDefinition $node)
{
$node
->children()
->scalarNode('dbname')->end()
->scalarNode('host')->defaultValue('localhost')->end()
->scalarNode('port')->defaultNull()->end()
->scalarNode('user')->defaultValue('root')->end()
->scalarNode('password')->defaultNull()->end()
->scalarNode('charset')->end()
->scalarNode('path')->end()
->booleanNode('memory')->end()
->scalarNode('unix_socket')->setInfo('The unix socket to use for MySQL')->end()
->booleanNode('persistent')->setInfo('True to use as persistent connection for the ibm_db2 driver')->end()
->scalarNode('protocol')->setInfo('The protocol to use for the ibm_db2 driver (default to TCPIP if ommited)')->end()
->booleanNode('service')->setInfo('True to use dbname as service name instead of SID for Oracle')->end()
->scalarNode('sessionMode')
->setInfo('The session mode to use for the oci8 driver')
->end()
->booleanNode('pooled')->setInfo('True to use a pooled server with the oci8 driver')->end()
->booleanNode('MultipleActiveResultSets')->setInfo('Configuring MultipleActiveResultSets for the pdo_sqlsrv driver')->end()
->end()
->beforeNormalization()
->ifTrue(function($v) {return !isset($v['sessionMode']) && isset($v['session_mode']);})
->then(function($v) {
$v['sessionMode'] = $v['session_mode'];
unset($v['session_mode']);

return $v;
})
->end()
->beforeNormalization()
->ifTrue(function($v) {return !isset($v['MultipleActiveResultSets']) && isset($v['multiple_active_result_sets']);})
->then(function($v) {
$v['MultipleActiveResultSets'] = $v['multiple_active_result_sets'];
unset($v['multiple_active_result_sets']);

return $v;
})
->end()
;
}

private function addOrmSection(ArrayNodeDefinition $node)
{
$node
Expand All @@ -170,19 +211,18 @@ private function addOrmSection(ArrayNodeDefinition $node)
->ifTrue(function ($v) { return null === $v || (is_array($v) && !array_key_exists('entity_managers', $v) && !array_key_exists('entity_manager', $v)); })
->then(function ($v) {
$v = (array) $v;
// Key that should not be rewritten to the connection config
$excludedKeys = array(
'default_entity_manager' => true, 'auto_generate_proxy_classes' => true,
'proxy_dir' => true, 'proxy_namespace' => true,
);
$entityManager = array();
foreach (array(
'result_cache_driver', 'result-cache-driver',
'metadata_cache_driver', 'metadata-cache-driver',
'query_cache_driver', 'query-cache-driver',
'auto_mapping', 'auto-mapping',
'mappings', 'mapping',
'connection', 'dql'
) as $key) {
if (array_key_exists($key, $v)) {
$entityManager[$key] = $v[$key];
unset($v[$key]);
foreach ($v as $key => $value) {
if (isset($excludedKeys[$key])) {
continue;
}
$entityManager[$key] = $v[$key];
unset($v[$key]);
}
$v['default_entity_manager'] = isset($v['default_entity_manager']) ? (string) $v['default_entity_manager'] : 'default';
$v['entity_managers'] = array($v['default_entity_manager'] => $entityManager);
Expand Down
22 changes: 22 additions & 0 deletions DependencyInjection/DoctrineExtension.php
Expand Up @@ -175,6 +175,28 @@ protected function getConnectionOptions($connection)
}
}

if (!empty($options['slaves'])) {
$nonRewrittenKeys = array(
'driver' => true, 'driverOptions' => true, 'driverClass' => true, 'wrapperClass' => true,
'platform' => true, 'slaves' => true, 'master' => true,
// included by safety but should have been unset already
'logging' => true, 'profiling' => true, 'mapping_types' => true, 'platform_service' => true,
);
foreach ($options as $key => $value) {
if (isset($nonRewrittenKeys[$key])) {
continue;
}
$options['master'][$key] = $value;
unset($options[$key]);
}
if (empty($options['wrapperClass'])) {
// Change the wrapper class only if the user does not already forced using a custom one.
$options['wrapperClass'] = 'Doctrine\\DBAL\\Connections\\MasterSlaveConnection';
}
} else {
unset($options['slaves']);
}

return $options;
}

Expand Down
29 changes: 23 additions & 6 deletions Resources/config/schema/doctrine-1.0.xsd
Expand Up @@ -15,21 +15,31 @@
</xsd:element>

<xsd:attributeGroup name="connection-config">
<xsd:attribute name="driver" type="xsd:string" />
<xsd:attribute name="driver-class" type="xsd:string" />
<xsd:attribute name="wrapper-class" type="xsd:string" />
<xsd:attribute name="platform-service" type="xsd:string" />
<xsd:attribute name="logging" type="xsd:string" default="false" />
<xsd:attribute name="profiling" type="xsd:string" default="false" />
<xsd:attributeGroup ref="driver-config" />
</xsd:attributeGroup>

<xsd:attributeGroup name="driver-config">
<xsd:attribute name="dbname" type="xsd:string" />
<xsd:attribute name="host" type="xsd:string" />
<xsd:attribute name="port" type="xsd:integer" />
<xsd:attribute name="user" type="xsd:string" />
<xsd:attribute name="password" type="xsd:string" />
<xsd:attribute name="driver" type="xsd:string" />
<xsd:attribute name="driver-class" type="xsd:string" />
<xsd:attribute name="path" type="xsd:string" />
<xsd:attribute name="unix-socket" type="xsd:string" />
<xsd:attribute name="memory" type="xsd:boolean" />
<xsd:attribute name="charset" type="xsd:string" />
<xsd:attribute name="wrapper-class" type="xsd:string" />
<xsd:attribute name="platform-service" type="xsd:string" />
<xsd:attribute name="logging" type="xsd:string" default="false" />
<xsd:attribute name="profiling" type="xsd:string" default="false" />
<xsd:attribute name="persistent" type="xsd:boolean" />
<xsd:attribute name="protocol" type="xsd:string" />
<xsd:attribute name="service" type="xsd:boolean" />
<xsd:attribute name="session-mode" type="xsd:string" />
<xsd:attribute name="pooled" type="xsd:boolean" />
<xsd:attribute name="multiple-active-result-sets" type="xsd:boolean" />
</xsd:attributeGroup>

<xsd:complexType name="dbal">
Expand All @@ -38,6 +48,7 @@
<xsd:element name="type" type="type" />
<xsd:element name="option" type="option" />
<xsd:element name="mapping-type" type="mapping-type" />
<xsd:element name="slave" type="slave" />
</xsd:choice>

<xsd:attribute name="default-connection" type="xsd:string" />
Expand Down Expand Up @@ -72,11 +83,17 @@
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="option" type="option" />
<xsd:element name="mapping-type" type="mapping-type" />
<xsd:element name="slave" type="slave" />
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attributeGroup ref="connection-config" />
</xsd:complexType>

<xsd:complexType name="slave">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attributeGroup ref="driver-config" />
</xsd:complexType>

<xsd:complexType name="mapping">
<xsd:attribute name="name" type="xsd:string" use="required" />
<xsd:attribute name="type" type="xsd:string" />
Expand Down
27 changes: 27 additions & 0 deletions Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
Expand Up @@ -99,6 +99,33 @@ public function testDbalLoadFromXmlSingleConnections()
$this->assertEquals('/path/to/mysqld.sock', $config['unix_socket']);
}

public function testDbalLoadSingleMasterSlaveConnection()
{
$container = $this->getContainer();
$loader = new DoctrineExtension();
$container->registerExtension($loader);

$this->loadFromFile($container, 'dbal_service_single_master_slave_connection');

$this->compileContainer($container);

// doctrine.dbal.mysql_connection
$param = $container->getDefinition('doctrine.dbal.default_connection')->getArgument(0);

$this->assertEquals('Doctrine\\DBAL\\Connections\\MasterSlaveConnection', $param['wrapperClass']);
$this->assertEquals(
array('user' => 'mysql_user', 'password' => 'mysql_s3cr3t', 'port' => null, 'dbname' => 'mysql_db', 'host' => 'localhost', 'unix_socket' => '/path/to/mysqld.sock'),
$param['master']
);
$this->assertEquals(
array(
'user' => 'slave_user', 'password' => 'slave_s3cr3t', 'port' => null, 'dbname' => 'slave_db',
'host' => 'localhost', 'unix_socket' => '/path/to/mysqld_slave.sock'
),
$param['slaves']['slave1']
);
}

public function testDependencyInjectionConfigurationDefaults()
{
$container = $this->getContainer();
Expand Down
@@ -0,0 +1,14 @@
<?xml version="1.0" ?>

<srv:container xmlns="http://symfony.com/schema/dic/doctrine"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:srv="http://symfony.com/schema/dic/services"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">

<config>
<dbal dbname="mysql_db" user="mysql_user" password="mysql_s3cr3t" unix-socket="/path/to/mysqld.sock">
<slave name="slave1" dbname="slave_db" user="slave_user" password="slave_s3cr3t" unix-socket="/path/to/mysqld_slave.sock" />
</dbal>
</config>
</srv:container>
@@ -0,0 +1,12 @@
doctrine:
dbal:
dbname: mysql_db
user: mysql_user
password: mysql_s3cr3t
unix_socket: /path/to/mysqld.sock
slaves:
slave1:
user: slave_user
dbname: slave_db
password: slave_s3cr3t
unix_socket: /path/to/mysqld_slave.sock

0 comments on commit 02569f5

Please sign in to comment.