Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch between multiple databases #59

Open
mluggy opened this issue May 21, 2014 · 2 comments
Open

Switch between multiple databases #59

mluggy opened this issue May 21, 2014 · 2 comments

Comments

@mluggy
Copy link

mluggy commented May 21, 2014

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.

@purekid
Copy link
Owner

purekid commented May 21, 2014

You can try changing $config in model.

@mluggy
Copy link
Author

mluggy commented May 26, 2014

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!");
        }
    }
}
  1. 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;
    }
}
  1. 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],
    ];
}
  1. 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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants