web-dev-qa-db-fra.com

Comment utiliser plusieurs bases de données de manière dynamique pour un modèle dans CakePHP

Ok, ma première question a été modifiée tellement de fois que j'ai choisi de la supprimer et de reformuler ma question. J'ai mis au point un petit projet de test avec différents noms de modèles afin de trouver une solution appropriée à mon problème.

Avertissement: Ne mélangez pas les bases de données avec tables

Motivation: J'ai séparé les données de l'utilisateur en plusieurs bases de données pour les problèmes juridiques et de performance.

Je travaille actuellement sur un projet CakePHP comportant plusieurs Username __ et dont Usera son propre base de données avec plusieurs tables _ (carsest un de ses les tables). Maintenant, je dois d'abord expliquer quelque chose:

Chaque Usera son propre base de données (et non une table, un base de données), de sorte que les noms de base de données sont les suivants.

  • [DATABASE] app(Ceci est la base de données principale de l'application)
    • [TABLE] users
    • [TABLE] permissions( Non pertinent pour cette question )
  • [DATABASE] app_user1 (User.id 1 est propriétaire de tout ce base de données)
    • [TABLE] cars(a table entièrement détenue par User.id 1)
  • [DATABASE] app_user2 (User.id 2 est propriétaire de tout ce base de données)
    • [TABLE] cars(un table entièrement détenu par User.id 2)
  • etc...

J'ai fait un petit dessin qui pourrait clarifier les base de données/table -finitions et leurs relations avec les modèles:

How to use multiple databases dynamically for one model in CakePHP

Le problème!!!

Je ne sais pas à quelle base de données se connecter jusqu'à ce que le Userse connecte. Username __'s et leurs bases de données sont créés de manière dynamique; je ne peux donc pas utiliser app/Config/database.php.

Donc j'écris actuellement une extension sur les classes Modelet ConnectionManagerpour contourner les comportements de base de la base de données de CakePHP. Donc, le modèle Carsait quelle base de données utiliser. Mais j'ai juste le sentiment que cela pourrait être fait plus facilement!

Donc, je suppose que tout se résume à une question:

_ {Y a-t-il un moyen plus facile de faire cela?!} _

Merci à tous ceux qui prendront le temps et les efforts nécessaires pour lire et comprendre mon problème!

15
Ariaan

Ce monsieur ( Olivier ) avait le même problème! (Il y a un an) Il a écrit une petite adaptation pour les Controllers! C'est assez petit et il s'avère que cela fonctionne dans 1.3 et 2.x .

Quoi qu’il en soit, c’est ma solution finale, que j’ai mise dans le app/Model/AppModel.php:

class AppModel extends Model
{
  /**
   * Connects to specified database
   *
   * @param String name of different database to connect with.
   * @param String name of existing datasource
   * @return boolean true on success, false on failure
   * @access public
   */
    public function setDatabase($database, $datasource = 'default')
    {
      $nds = $datasource . '_' . $database;      
      $db  = &ConnectionManager::getDataSource($datasource);

      $db->setConfig(array(
        'name'       => $nds,
        'database'   => $database,
        'persistent' => false
      ));

      if ( $ds = ConnectionManager::create($nds, $db->config) ) {
        $this->useDbConfig  = $nds;
        $this->cacheQueries = false;
        return true;
      }

      return false;
    }
}

Et voici comment je l'ai utilisé dans mon app/Controller/CarsController.php:

class CarsController extends AppController
{
  public function index()
  {
    $this->Car->setDatabase('cake_sandbox_client3');

    $cars = $this->Car->find('all');

    $this->set('cars', $cars);
  }

}

Je parie que je ne suis ni le premier ni le dernier avec ce problème. Donc, j'espère vraiment que cette information trouvera des personnes et la communauté CakePHP.

37
Ariaan

Je n'aime pas l'idée d'écrire le nom réel de la base de données dans le code. Pour plusieurs bases de données, vous avez le fichier database.php dans lequel vous pouvez définir autant de bases de données que nécessaire.

Si vous voulez "changer" de base de données pour un modèle spécifique à la volée , utilisez la méthode setDataSource . (voir ici )

Par exemple, si vous avez deux bases de données, vous pouvez les définir dans le fichier database.php comme "default" et "sandbox", à titre d'exemple.

Ensuite, dans votre code:

$this->Car->setDataSource('sandbox');

Le bac à sable est le nom de la configuration et le nom réel de la base de données n’est écrit qu’une fois dans le fichier database.php.

9
noamicko

Vous pouvez toujours interroger toutes les bases de données en utilisant la notation complète dans mysql. F.ex .: 

SELECT * FROM my_schema_name.table_name;

Façon de gâteau:

$db = $this->getDataSource();
$query = array(
    'fields' => array('*'),
    'table' => 'my_schema_name.table_name'
);
$stmt = $db->buildStatement($query, $this);
$result = $db->execute($stmt);
1
bancer

Dans votre database.php 

public $mongo = array(
    'datasource' => 'Mongodb.MongodbSource',
    'database' => 'database_name_mongo',
    'Host' => 'localhost',
    'port' => 27017,
);

Dans votre contrôleur, vous pouvez utiliser 

$this->Organisation->setDataSource('mongo');

puis appliquer une requête comme 

this->Organisation->find('all');
1
teju c

Ceci est un peuple de la réponse acceptée. Cela empêchera l'erreur si la nouvelle source de données a déjà existé:

public function setDatabase($database, $datasource = 'default')
{
    $newDatasource = $datasource . '_' . $database;
    try {
        // return the new datasource if it's already existed
        $db = ConnectionManager::getDataSource($newDatasource);
        $this->useDbConfig  = $newDatasource;
        $this->cacheQueries = false;
        return true;
    } catch (Exception $e) {
        // debug($e->getMessage());
    }

    $db  = ConnectionManager::getDataSource($datasource);
    $db->setConfig(array(
        'name'       => $newDatasource,
        'database'   => $database,
        'persistent' => false
    ));

    if ( $ds = ConnectionManager::create($newDatasource, $db->config) ) {
        $this->useDbConfig  = $newDatasource;
        $this->cacheQueries = false;
        return true;
    }

    return false;
}
0
ktran