Open mluggy opened 10 years ago
You can try changing $config in model.
The only way we we're able to solve this:
1) Extend MongoDB to update DB on each config:
class DatabaseDynamic extends \Purekid\Mongodm\MongoDB
{
/**
* @param string $name name
* @param array $config config
*/
protected function __construct($name, array $config)
{
$this->_name = $name;
$this->_config = $config;
/* Store the database instance */
static::$instances[$name] = $this;
}
/**
* Connect to MongoDB, select database
*
* @throws \Exception
* @return bool
*/
public function connect()
{
if ($this->_connection) {
return true;
}
$config = $this->_config['connection'];
$result = parent::connect();
$this->_config['connection'] = $config;
return $result;
}
/**
* Load instance
*
* @param string $name name
* @param array|null $config config
*
* @static
*
* @return MongoDB
*/
public static function instance($name = 'default', array $config = null)
{
if (!isset(static::$instances[$name])) {
if ($config === null) {
// Load the configuration for this database
$config = static::config($name);
}
static::$instances[$name] = new static($name, $config);
}
return static::$instances[$name];
}
public function updateConfigDB($db)
{
// Extract Db from connection
if (empty($this->_config['connection'])) {
throw new \Exception('No Config Specified In MongoDB');
}
$this->_config['connection']['database'] = $db;
}
/**
* @param string $db
*
* @throws \Exception
* @return null
*/
public function selectDB($db)
{
$this->updateConfigDB($db);
if (!$this->_connection) {
return;
}
$this->_db = $this->_connection->selectDB($db);
if (!$this->_db instanceof \MongoDB) {
throw new \Exception('Unable to connect to database :: $_db is ' . gettype($this->_db));
}
}
/**
* @param array $config config
*
* @return null
*/
public static function setConfig($config)
{
static::$config = $config;
}
/**
* @param string $block block
* @param array $config config
*
* @return null
*/
public static function setConfigBlock($block = 'default', $config = array())
{
static::$config[$block] = $config;
}
/**
* @param string $config_block config_block
*
* @throws \Exception
* @return array
*/
public static function config($config_block)
{
if (!empty(static::$config)) {
return static::$config[$config_block];
}
else {
throw new \Exception("database config section '{$config_block}' not exist!");
}
}
}
2) Extend Model to use DatabaseDynamic before any action
abstract class ModelDynamic extends \Purekid\Mongodm\Model
{
protected static $database = null;
/**
* Get database name
*
* @return string
*/
public static function databaseName()
{
$class = get_called_class();
$database = $class::$database;
return $database;
}
private function useDatabaseDynamicPrivate()
{
$this->_connection->selectDB(static::databaseName());
}
public static function useDatabaseDynamic()
{
static::connection()->selectDB(static::databaseName());
}
/**
* Model
*
* @param array $data data
* @param bool $mapFields map the field names
* @param bool $exists record exists in DB
*/
public function __construct($data = array(), $mapFields = false, $exists = false)
{
if ($mapFields === true) {
$data = static::mapFields($data, true);
}
if (is_null($this->_connection)) {
if (isset($this::$config)) {
$config = $this::$config;
} else {
$config = static::$config;
}
$this->_connection = DatabaseDynamic::instance($config);
}
$this->update($data, true);
if ($exists) {
$this->exist = true;
} else {
$this->initAttrs();
}
$this->initTypes();
$this->__init();
}
/**
* Mutate data by direct query
*
* @param array $updateQuery update query
* @param array $options options
*
* @throws \Exception
* @return boolean
*/
public function mutate($updateQuery, $options = array())
{
$this->useDatabaseDynamicPrivate();
return parent::mutate($updateQuery, $options);
}
/**
* Delete this record
*
* @param array $options options
*
* @return boolean
*/
public function delete($options = array())
{
$this->useDatabaseDynamicPrivate();
return parent::delete($options);
}
/**
* Save to database
*
* @param array $options options
*
* @return array
*/
public function save($options = array())
{
$this->useDatabaseDynamicPrivate();
return parent::save($options);
}
/**
* Retrieve a record
*
* @param array $criteria criteria
* @param array $fields fields
*
* @return Model
*/
public static function one($criteria = array(), $fields = array())
{
static::useDatabaseDynamic();
return parent::one($criteria, $fields);
}
/**
* Retrieve records
*
* @param array $criteria criteria
* @param array $sort sort
* @param array $fields fields
* @param int $limit limit
* @param int $skip skip
*
* @return Collection
*/
public static function find($criteria = array(), $sort = array(), $fields = array(), $limit = null, $skip = null)
{
static::useDatabaseDynamic();
return parent::find($criteria, $sort, $fields, $limit, $skip);
}
/**
* group
*
* @param array $keys keys
* @param array $query query
* @param mixed $initial initial
* @param mixed $reduce reduce
*
* @return mixed
*/
public static function group(array $keys, array $query, $initial = null, $reduce = null)
{
static::useDatabaseDynamic();
return parent::group($keys, $query, $initial, $reduce);
}
/**
* aggreate
*
* @param array $query query
*
* @return array
*/
public static function aggregate($query)
{
static::useDatabaseDynamic();
return parent::aggregate($query);
}
/**
* Distinct records
*
* @param string $key key distinct key
* @param array $criteria criteria
*
* @return string Records
*/
public static function distinct($key, $criteria = array())
{
static::useDatabaseDynamic();
return parent::distinct($key, $criteria);
}
/**
* Has record
*
* A optimized way to see if a record exists in the database. Helps
* the developer to avoid the extra latency of FindOne by using Find
* and a limit of 1.
*
* @link https://blog.serverdensity.com/checking-if-a-document-exists-mongodb-slow-findone-vs-find/
*
* @param array $criteria criteria
*
* @return boolean
*/
public static function has($criteria = array())
{
static::useDatabaseDynamic();
return parent::has($criteria);
}
/**
* Count of records
*
* @param array $criteria
*
* @return integer
*/
public static function count($criteria = array())
{
static::useDatabaseDynamic();
return parent::count($criteria);
}
/**
* Drop the collection
*
* @return boolean
*/
public static function drop()
{
static::useDatabaseDynamic();
return parent::drop();
}
/**
* Ensure index
*
* @param mixed $keys keys
* @param array $options options
*
* @return boolean
*/
public static function ensure_index($keys, $options = array())
{
static::useDatabaseDynamic();
return parent::ensure_index($keys, $options);
}
/**
* Return the connection
*
* @return MongoDB|null
*/
public function _getConnection()
{
$this->useDatabaseDynamicPrivate();
return $this->_connection;
}
/**
* Get Mongodb connection instance
*
* @return MongoDB
*/
protected static function connection()
{
$class = get_called_class();
$config = $class::$config;
return DatabaseDynamic::instance($config);
}
/**
* Get current database name
*
* @return string
*/
protected function dbName()
{
$dbName = "default";
$config = $this::$config;
$configs = DatabaseDynamic::config($config);
if ($configs) {
$dbName = $configs['connection']['database'];
}
return $dbName;
}
}
3) Accompany each Model with a new $database param
class Model extends ModelDynamic
{
/**
* @var string
*/
static $connection = 'default';
/**
* @var string
*/
static $database = 'core';
/**
* @var string
*/
static $collection = 'language';
/**
* @var array
*/
static $attrs = [
'name' => ['type' => 'string'],
'isActive' => ['type' => 'boolean', 'default' => false],
];
}
4) Connect through the new DatabaseDynamic block:
_\Model\DatabaseDynamic::setConfigBlock('default', [
'connection' => [
'hostnames' => '10.10.2.111:27017',
'database' => 'core'
]
]);
Changing all self:: to static or passing an optional $database name on every __call would have made this much simpler...
great package! is there an easy option to switch between different database using the same connection? preferably, have a $database complement $collection in the Model definition.