From 62d2a62efd706f5bba66fc4cd88638e8fc5c860b Mon Sep 17 00:00:00 2001 From: Peter Furesz Date: Wed, 29 Jun 2016 08:49:46 +0200 Subject: [PATCH 1/2] Add MasterSlaveConfigParser --- src/Utilities/MasterSlaveConfigParser.php | 76 ++++++++ .../Utilities/MasterSlaveConfigParserTest.php | 174 ++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 src/Utilities/MasterSlaveConfigParser.php create mode 100644 tests/Utilities/MasterSlaveConfigParserTest.php diff --git a/src/Utilities/MasterSlaveConfigParser.php b/src/Utilities/MasterSlaveConfigParser.php new file mode 100644 index 00000000..c214c63b --- /dev/null +++ b/src/Utilities/MasterSlaveConfigParser.php @@ -0,0 +1,76 @@ + [], + 'read' => [], + ]; + + $masterSlave['write'] = [ + 'user' => array_get($config, 'write.username', $config['username']), + 'password' => array_get($config, 'write.password', $config['password']), + 'host' => array_get($config, 'write.host', $config['host']), + 'dbname' => array_get($config, 'write.database', $config['database']), + 'port' => array_get($config, 'write.port', $config['port']), + ]; + + foreach (array_get($config, 'read', []) as $slaveConfig) { + $config = [ + 'user' => array_get($slaveConfig, 'username', $config['username']), + 'password' => array_get($slaveConfig, 'password', $config['password']), + 'host' => array_get($slaveConfig, 'host', $config['host']), + 'dbname' => array_get($slaveConfig, 'database', $config['database']), + 'port' => array_get($config, 'write.port', $config['port']), + ]; + + $masterSlave['read'][] = $config; + } + + return $masterSlave; + } + + /** + * @param array $config + * + * @return bool + */ + public static function hasValidConfig(array $config) + { + if ( + array_key_exists('read', $config) + && ! empty($config['read']) + && is_array($config['read']) + //All value in $config['read'] should be an array + && ! in_array(false, array_map(function ($readConfigValue) { + return is_array($readConfigValue); + }, $config['read'])) + //All value in $config['read'] should have at least one config difference + && ! in_array(false, array_map(function (array $readConfig) { + return count($readConfig) > 0; + }, $config['read'])) + ) { + return true; + } + + return false; + } +} diff --git a/tests/Utilities/MasterSlaveConfigParserTest.php b/tests/Utilities/MasterSlaveConfigParserTest.php new file mode 100644 index 00000000..955716a5 --- /dev/null +++ b/tests/Utilities/MasterSlaveConfigParserTest.php @@ -0,0 +1,174 @@ +assertTrue(MasterSlaveConfigParser::hasValidConfig($validConfig)); + } + + /** + * @dataProvider invalidConfigProvider + * + * @param array $invalidConfig + */ + public function test_HasValidConfig_returns_false_on_missing_config(array $invalidConfig) + { + $this->assertFalse(MasterSlaveConfigParser::hasValidConfig($invalidConfig)); + } + + /** + * @return array + */ + public function validConfigProvider() + { + $valid1['config'] = array_merge( + $this->getDatabaseConfigTemplate(), + [ + 'write' => [ + 'host' => '192.168.0.1', + ], + 'read' => [ + [ + 'host' => '192.168.0.2', + 'username' => 'read_user', + ], + ], + ] + ); + $valid1['expectedWrite'] = [ + 'user' => 'write_db_username', + 'password' => 'write_db_password', + 'host' => '192.168.0.1', //Override the parent's localhost + 'dbname' => 'write_db_name', + 'port' => 3306, + ]; + $valid1['expectedRead'] = [ + [ + 'user' => 'read_user', + 'password' => 'write_db_password', + 'host' => '192.168.0.2', //Override the parent's localhost + 'dbname' => 'write_db_name', + 'port' => 3306, + ], + ]; + + $valid2['config'] = array_merge( + $this->getDatabaseConfigTemplate(), + [ + 'read' => [ + [ + 'host' => '192.168.0.1', + ], + ] + ] + ); + $valid2['expectedWrite'] = [ + 'user' => 'write_db_username', + 'password' => 'write_db_password', + 'host' => 'localhost', + 'dbname' => 'write_db_name', + 'port' => 3306, + ]; + $valid2['expectedRead'] = [ + [ + 'user' => 'write_db_username', + 'password' => 'write_db_password', + 'host' => '192.168.0.1', //Override the parent's localhost + 'dbname' => 'write_db_name', + 'port' => 3306, + ], + ]; + + return [ + [$valid1['config'], $valid1['expectedWrite'], $valid1['expectedRead']], + [$valid2['config'], $valid2['expectedWrite'], $valid2['expectedRead']], + ]; + } + + /** + * @return array + */ + public function getDatabaseConfigTemplate() + { + return [ + 'host' => 'localhost', + 'database' => 'write_db_name', + 'username' => 'write_db_username', + 'password' => 'write_db_password', + 'driver' => 'mysql', + 'port' => 3306, + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + 'strict' => false, + 'engine' => null, + ]; + } + + /** + * @return array + */ + public function invalidConfigProvider() + { + $invalidConfig1 = []; + $invalidConfig2 = array_merge( + $this->getDatabaseConfigTemplate(), + [ + 'write' => [], +// 'read' => [], //Read is missing, it's invalid + ] + ); + $invalidConfig3 = array_merge( + $this->getDatabaseConfigTemplate(), + [ + 'write' => [], + 'read' => ['host' => '123'], //Read should be an array + ] + ); + + return [ + [$invalidConfig1], + [$invalidConfig2], + [$invalidConfig3], + ]; + } + + /** + * @dataProvider invalidConfigProvider + * + * @expectedException UnexpectedValueException + * + * @param array $invalidConfig + */ + public function test_ParseConfig_throws_exception_on_invalid_config(array $invalidConfig) + { + MasterSlaveConfigParser::parseConfig($invalidConfig); + } + + /** + * @dataProvider validConfigProvider + * + * @param array $config + * @param array $expectedWrite + * @param array $expectedRead + */ + public function test_ParseConfig_can_inherit_settings( + array $config, + array $expectedWrite, + array $expectedRead + ) { + $readWriteConfig = MasterSlaveConfigParser::parseConfig($config); + + $this->assertEquals($expectedRead, $readWriteConfig['read']); + $this->assertEquals($expectedWrite, $readWriteConfig['write']); + } +} From 2d81621b672c40fd7f4e49b05503363850365fa1 Mon Sep 17 00:00:00 2001 From: Peter Furesz Date: Wed, 29 Jun 2016 09:20:56 +0200 Subject: [PATCH 2/2] EntityManagerFactor use MasterSlaveConnection --- src/EntityManagerFactory.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/EntityManagerFactory.php b/src/EntityManagerFactory.php index 09aefd0d..7a6f837b 100644 --- a/src/EntityManagerFactory.php +++ b/src/EntityManagerFactory.php @@ -2,6 +2,8 @@ namespace LaravelDoctrine\ORM; +use Doctrine\DBAL\Connections\MasterSlaveConnection; +use Doctrine\DBAL\DriverManager; use Doctrine\ORM\Cache\DefaultCacheFactory; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; @@ -18,6 +20,7 @@ use LaravelDoctrine\ORM\Configuration\MetaData\MetaDataManager; use LaravelDoctrine\ORM\Extensions\MappingDriverChain; use LaravelDoctrine\ORM\Resolvers\EntityListenerResolver; +use LaravelDoctrine\ORM\Utilities\MasterSlaveConfigParser; use ReflectionException; class EntityManagerFactory @@ -100,12 +103,32 @@ public function create(array $settings = []) $this->setMetadataDriver($settings, $configuration); $driver = $this->getConnectionDriver($settings); + $slaveConfig = MasterSlaveConfigParser::hasValidConfig($driver) + ? MasterSlaveConfigParser::parseConfig($driver) + : []; $connection = $this->connection->driver( $driver['driver'], $driver ); + if (empty($slaveConfig)) { + $conn = DriverManager::getConnection($connection, $configuration); + } else { + $conn = DriverManager::getConnection([ + 'wrapperClass' => MasterSlaveConnection::class, + 'driver' => $connection['driver'], + 'master' => [ + 'user' => array_get($slaveConfig, 'write.user', ''), + 'password' => array_get($slaveConfig, 'write.password', ''), + 'host' => array_get($slaveConfig, 'write.host', ''), + 'dbname' => array_get($slaveConfig, 'write.dbname', ''), + 'port' => array_get($slaveConfig, 'write.port', ''), + ], + 'slaves' => $slaveConfig['read'], + ]); + } + $this->setNamingStrategy($settings, $configuration); $this->setCustomFunctions($configuration); $this->setCacheSettings($configuration); @@ -121,7 +144,7 @@ public function create(array $settings = []) $configuration->setEntityListenerResolver($this->resolver); $manager = EntityManager::create( - $connection, + $conn, $configuration );