Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/Configuration/Connections/MasterSlaveConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace LaravelDoctrine\ORM\Configuration\Connections;

use Doctrine\DBAL\Connections\MasterSlaveConnection as MasterSlaveDoctrineWrapper;
use Illuminate\Contracts\Config\Repository;

/**
* Handles master slave connection settings.
*/
class MasterSlaveConnection extends Connection
{
/**
* @var array|Connection
*/
private $resolvedBaseSettings;

/**
* @var array Ignored configuration fields for master slave configuration.
*/
private $masterSlaveConfigIgnored = ['driver'];

/**
* MasterSlaveConnection constructor.
*
* @param Repository $config
* @param array|Connection $resolvedBaseSettings
*/
public function __construct(Repository $config, $resolvedBaseSettings)
{
parent::__construct($config);

$this->resolvedBaseSettings = $resolvedBaseSettings;
}

/**
* {@inheritdoc}
*/
public function resolve(array $settings = [])
{
$driver = $this->resolvedBaseSettings['driver'];

return [
'wrapperClass' => MasterSlaveDoctrineWrapper::class,
'driver' => $driver,
'master' => $this->getConnectionData(isset($settings['write']) ? $settings['write'] : [], $driver),
'slaves' => $this->getSlavesConfig($settings['read'], $driver),
];
}

/**
* Returns config for slave connections.
*
* @param array $slaves
* @param string $driver
*
* @return array
*/
public function getSlavesConfig(array $slaves, $driver)
{
$handledSlaves = [];
foreach ($slaves as $slave) {
$handledSlaves[] = $this->getConnectionData($slave, $driver);
}

return $handledSlaves;
}

/**
* Returns single connection (slave or master) config.
*
* @param array $connection
* @param string $driver
*
* @return array
*/
private function getConnectionData(array $connection, $driver)
{
$connection = $this->replaceKeyIfExists($connection, 'database', $driver === 'pdo_sqlite' ? 'path' : 'dbname');
$connection = $this->replaceKeyIfExists($connection, 'username', 'user');

return array_merge($this->getFilteredConfig(), $connection);
}

/**
* Returns filtered configuration to use in slaves/masters.
*
* @return array
*/
private function getFilteredConfig()
{
return array_diff_key($this->resolvedBaseSettings, array_flip($this->masterSlaveConfigIgnored));
}

/**
* Replaces key in array if it exists.
*
* @param array $array
* @param string $oldKey
* @param string $newKey
*
* @return array
*/
private function replaceKeyIfExists(array $array, $oldKey, $newKey)
{
if (!isset($array[$oldKey])) {
return $array;
}

$array[$newKey] = $array[$oldKey];
unset($array[$oldKey]);

return $array;
}
}
42 changes: 42 additions & 0 deletions src/EntityManagerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use InvalidArgumentException;
use LaravelDoctrine\ORM\Configuration\Cache\CacheManager;
use LaravelDoctrine\ORM\Configuration\Connections\ConnectionManager;
use LaravelDoctrine\ORM\Configuration\Connections\MasterSlaveConnection;
use LaravelDoctrine\ORM\Configuration\LaravelNamingStrategy;
use LaravelDoctrine\ORM\Configuration\MetaData\MetaData;
use LaravelDoctrine\ORM\Configuration\MetaData\MetaDataManager;
Expand Down Expand Up @@ -109,6 +110,11 @@ public function create(array $settings = [])
$driver
);

if ($this->isMasterSlaveConfigured($driver)) {
$this->hasValidMasterSlaveConfig($driver);
$connection = (new MasterSlaveConnection($this->config, $connection))->resolve($driver);
}

$this->setNamingStrategy($settings, $configuration);
$this->setCustomFunctions($configuration);
$this->setCacheSettings($configuration);
Expand Down Expand Up @@ -440,4 +446,40 @@ protected function registerMappingTypes(array $settings = [], EntityManagerInter
$manager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping($dbType, $doctrineType);
}
}

/**
* Check if master slave connection was being configured.
*
* @param array $driverConfig
*
* @return bool
*/
private function isMasterSlaveConfigured(array $driverConfig)
{
// Setting read is mandatory for master/slave configuration. Setting write is optional.
// But if write was set and read wasn't, it means configuration is incorrect and we must inform the user.
return isset($driverConfig['read']) || isset($driverConfig['write']);
}

/**
* Check if slave configuration is valid.
*
* @param array $driverConfig
*/
private function hasValidMasterSlaveConfig(array $driverConfig)
{
if (!isset($driverConfig['read'])) {
throw new \InvalidArgumentException("Parameter 'read' must be set for read/write config.");
}

$slaves = $driverConfig['read'];

if (!is_array($slaves) || in_array(false, array_map('is_array', $slaves))) {
throw new \InvalidArgumentException("Parameter 'read' must be an array containing multiple arrays.");
}

if (($key = array_search(0, array_map('count', $slaves))) !== false) {
throw new \InvalidArgumentException("Parameter 'read' config no. {$key} is empty.");
}
}
}
Loading