[Symfony] Connection à plusieurs bases de données

a marqué ce sujet comme résolu.
1
2
3
4
5
6
7
8
dynamic:
    driver:   %database_driver%
    host:     %database_host%
    port:     %database_port%
    dbname:   %database name%
    user:     %database_user%
    password: %database_password%
    charset:  UTF8

Salut à tous

Je voudrais me connecter à plusieurs base de données dynamiquement. j’ai lu ce tuto http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html et Ça marche comme il l’on expliqué.

Mais mon seul problème c’est de modifier la valeur de dbname directement à partir de mon Controller pour pouvoir me connecter à toutes mes bases de données.

Ça va faire bientôt 1 semaine que je suis sur ce problème. si vous avez des idées j’en ai vraiment besoin

+0 -0

Bonsoir @motet-a

Je développe un site capable d’enregistrer des commandes, une commande se compose de produit, d’un magasin, d’un fournisseur.

Chaque société possède sa propose base de donnée, Une base de donnée master contient la liste des société avec la base sur laquel il faut pointé.

Je souhaite avoir 2 modèle de base de donnée à proposer au société, le modèle A est un modèle avec des tables classique, le second modèle B provient d’un ERP, donc les tables sont différentes.

Voilà pourquoi je souhaite une utilisation dynamique, si la société X utilise le modèle B, alors j’utilise les entités prévu pour cette société.

Salut !

Tu n’es quand même pas en train de dire que chaque société a sa propre structure de base de données  ?!

Sincèrement, je trouve que ça sent très mauvais. Tu peux, à la rigueur, récupérer une connexion particulière ou un EntityManager spécifique selon l’entreprise qui utilise ton application, mais si en plus tu dois adapter tes entités, ça ne va pas être une partie de plaisir, ou alors je risquerais de te considérer comme un peu masochiste  :-°

Dans ce genre de cas, je pense que je ferais plutôt des passerelles avec des webservices entre ton application et celle des clients. Si le client décide de changer quelque chose de son côté, tu n’as pas à revoir tout ton code, mais juste la partie qui adapte les données chez lui.

+1 -0

Non, j’ai du mal me faire comprendre.

Je propose 2 structures, les entreprises ont le choix d’utiliser soit la structure A, soit la structure B.

Chaque société possède sa propre base de donnée, en utilisant la structure définit. Je trouve sa logique qu’elle possède leurs propre base de donnée. Donc un exemple pour mieux comprendre ce que j’ai actuellement mis en place, mais sa ne me plaît pas du tout.

Pour afficher la liste des produits : voici le contrôlleur, qui en fonction de la structure choisi, effectue la requete.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    public function buildOrderAction($provider, SessionInterface $session){
        $products = new ProductsProviderRepository($session->get('em'), $session->get('struct'));
        if($session->get('struct') == 1){
            $products = $products->findByidProvider($provider);
            dump($products);
        }else{
            $products = $products->findProduct();
            dump($products);
        }

        return $this->render('creation/create_order.html.twig',[
            'products' => $products
        ]);
    }

le fichier ProductsProviderRepository

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class ProductsProviderRepository
{
    private $connectionParams;
    private $config;
    private $structure;

    public function __construct($dbname,$structure)
    {
        $config = new \Doctrine\DBAL\Configuration();
        $this->structure = $structure;
        $this->connectionParams = array(
            'dbname' => $dbname,
            'user' => 'root',
            'password' => '',
            'host' => '127.0.0.1',
            'driver' => 'pdo_mysql',
        );
        $this->conn = \Doctrine\DBAL\DriverManager::getConnection($this->connectionParams, $config);
    }

    public function findByidProvider($provider){
        if($this->structure == 1) {
            $qb = new QueryBuilder($this->conn);
            $qb->select('t.id', 't.price', 'p.ref', 'p.name', 'p.description', 'p.picture')
                ->from('products_provider', 't')
                ->where('t.num_prov = :id_provider')
                ->innerJoin('t', 'products', 'p', 't.num_product = p.ref')
                ->setParameter(':id_provider', $provider);
            return $qb->execute()->fetchAll();
        }
    }

    public function findProduct(){
        $qb = new QueryBuilder($this->conn);
        $qb->select('p.column2 AS id','p.column4 AS name','pri.column7 AS price')
            ->innerJoin('p','price','pri','p.column2 = pri.column3')
            ->from('products', 'p');
        return $qb->execute()->fetchAll();
    }

}

Je vois.

Tu peux donc, comme mentionné plus haut, spécifier quel EntityManager tu appelles pour effectuer tes requêtes, c’est juste un paramètre à passer à $this->getDoctrine()->getManager( $ici ), ce sera déjà plus simple et propre que de recréer à la volée les connexions, je pense.


Je ne suis toujours pas convaincu de la possibilité d’avoir une base de données par client et que tu les utilises toutes directement avec un ORM. Ça me fait penser aux personnes qui imaginent faire une table par utilisateur. Je comprends la logique derrière, mais je n’y adhère pas quand même.

+0 -0

Non, je pense que tu n’as pas vraiment compris, :)

Si j’utilise $this->getDoctrine()->getManager( $ici ), sa suppose que ma base de donnée est connu dans le fichier config.yml de symfony, hors moi je récupère sa dans une base de donnée master, ce que tu me propose, c’est du statique, moi je veux du dynamique.

C’est une base de donnée par société, la base de donné Z souhaite gardée ces commandes dans sa propre base de donnée, je peux pas faire une base de donnée contenant toute les commandes des entreprises …

Pour faire simple, j’ai deux structures possible, en fonction de la structure choisi, si la structure est A : alors j’utilise les entitées X, Y et Z.

Si la structure est B : alors j’utilise les entitées I, J et K

+0 -0

Donc si je comprends bien, en plus d’avoir des structures différentes, les informations de connexion à la base de données des clients sont dans la base de données maître ? Si non, tu les renseignes comment ?

Edit

Si jamais, les $ définissent un traitement particulier sur ce forum (c’est utilisé pour formater des formules mathématiques). Quand tu mentionnes du code en cours de phrase, encadre-le avec des `.

+0 -0

Tu as donc bien les informations de connexion quelque part. Pourquoi ne pas enregistrer uniquement le nom de l’EntityManager en base, et le déclarer dans les fichiers de configuration ?

Sinon, essaie de voir comment sont créés les EntityManagers afin de "monter d’un niveau" par rapport à la DBAL que tu utilises pour l’instant.

+0 -0

Oui, mais si je fais ceci :

1
$this->getDoctrine()->getManager('app1');

Le manager app1 n’existe pas, et la connexion n’est pas faite … Il faut peut être crée un service d’après ce que j’ai lu, mais je ne sais pas faire …

EDIT : J’avais réfléchie à l’idée de l’inscrire dans le fichier de config, mais si par la suite, une société souhaite utiliser le site, elle devrais donc me contacter pour que j’inscrive les informations de connexion. L’idée est de crée la base de donnée à l’inscription et de pouvoir l’utiliser directement

+0 -0

Tu risques d’en avoir bien besoin vu ce dans quoi tu te lances.  ^^

Et c’est pas très difficile de créer un service, au final c’est une manière de créer un objet (au niveau POO) sans devoir à chaque fois le construire. Dans les exemples que j’ai en tête, j’ai notamment les APIs pour les paiements. Ce sont souvent des classes qui demandent des paramètres particuliers à la construction, mais ces paramètres sont toujours les mêmes. Toi tu n’auras même pas vraiment ce cas-là, vu que tu risques plutôt d’avoir une méthode de ta classe-service qui te génère un EntityManager selon les paramètres que tu lui passeras, donc tu pourrais presque faire une classe avec une méthode statique.

EDIT : J’avais réfléchie à l’idée de l’inscrire dans le fichier de config, mais si par la suite, une société souhaite utiliser le site, elle devrais donc me contacter pour que j’inscrive les informations de connexion. L’idée est de crée la base de donnée à l’inscription et de pouvoir l’utiliser directement

subscribe

Que les données de connexion soient dans un fichier ou dans la base de données ne changent au final que le nombre d’étape (deux de plus, je dirais), mais à part ça tu dois d’abord renseigner les données de connexion et la structure avant de créer les tables.

+0 -0

Donc si j’ai bien compris, je dois crée un entitymanager qui lui initialisera la connexion sur le nom de la base de donnée que je lui passerai en paramètre.

Le problème, c’est que j’ai trouver aucun tuto pour crée un entity manager :(

Oui mais si c’est vraiment dynamique, l’utilisateur crée sa société, un script crée la base de donnée et les tables et c’est partie … Je ne fais pas uniquement réduire le nombre d’étape. L’utilisateur n’a pas accès au config.yml. Donc sa lui permet d’être autonome et de se passer de moi

+0 -0

C’est entre autres pour t’éviter ça que je te conseillais de renseigner les connexions dans les fichiers de configuration  ^^

Je ne sais pas le faire non plus, hein. Mais je pense qu’en allant regarder où sont utilisés les paramètres de config.yml relatifs aux bases de données, ce serait possible de voir comment c’est fait.

Il y a aussi la possibilité d’aller regarder l’API de Doctrine. Un bon endroit pour commencer serait les détails des classes EntityManager. Ça commence bien, le constructeur est protégé… Ben il faut aller voir si c’est pour forcer l’héritage, ou s’il y a un autre mécanisme.

Oui mais si c’est vraiment dynamique, l’utilisateur crée sa société, un script crée la base de donnée et les tables et c’est partie … Je ne fais pas uniquement réduire le nombre d’étape. L’utilisateur n’a pas accès au config.yml. Donc sa lui permet d’être autonome et de se passer de moi

subscribe

Et par-dessus le marché, les sociétés s’inscrivent elles-mêmes ?  o_O

Je te souhaite sincèrement bonne chance !

Edit

Au pire, il est peut-être imaginable de modifier le fichier config.yml avec l’application, mais ça devient assez poussé, là.

+0 -0

Provisoirement, dans un premier temps, je vais les déclarers dans le config.yml. En revanche, comment je peux dire que telle entity est pour la structure A, et telle entité est pour la structure B

Car j’ai un Bundle regroupant toute les entités, et si je tappe la commande doctrine:create:database, il me générer toute les entités.

Sauf erreur de ma part, on peut lier les entités à des EntityManagers précis. Mais note bien que suivant les relations entre tes entités, tu ne pourras pas forcément dire "là j’aimerais celle-ci et pas l’autre" parce que les deux sont liées.

Tu es toujours sûr de vouloir continuer sur cette voie ?

+0 -0

Ahahahahha, j’ai pas le choix mdr, je suis en stage est l’entreprise est roi … J’essai de mettre en place ce qu’il me demande.

Donc, sa veut dire que je crée 2 bundle, le premier pour la structure A, le deuxième pour la structure B, mais c’est ridicule, car les contrôlleurs sont les mêmes, les vues sont identiques … il va y’avoir duplication de code

Tu peux créer un bundle qui regroupe le code des deux structures, et par le truchement des MappedSuperclass, tu créés les classes avec les bonnes relations. Ou même tu as la structure maximale qui étend la minimale, plus de MappedSuperclass.

Mais pour le coup, tu vas devoir jouer avec des entités différentes pour des objets similaires, en plus des histoires d’EntityManagers…

Symfony Doctrine ORM n’est peut-être pas la solution qu’il te faudrait pour ce que tu as à faire.

+1 -0

Je demande pourtant pas la lune .

Pouvoir gérer des connexions de manière dynamique avec deux structures possible. Rien de bien compliquer à mon sens

Dois-je utiliser PDO ?, la solution que j’ai mise en place fonctionne, si tu re regarde le code plus haut, DBAL fait l’affaire mais j’aime pas le code

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte