IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

Multiple connection db avec symfony 4


Sujet :

Symfony PHP

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut Multiple connection db avec symfony 4
    Bonjour,

    Depuis quelques jours je me casse la tête pour trouver une solution à mon problème. Via certaines informations que je reçois je voudrais dans un event listener changer les informations de connexion à la base de données par défaut pour pouvoir aller sur la base de données correspondant au bon client.

    Mais je ne trouve pas de solution. Je pourrais créer toutes les connections dans le fichier de configuration mais j'aimerais que la connections soit faite dans l'event listener pour que dans le reste du code j'utilise doctrine normalement.

    c'est-à-dire avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $this->getDoctrine()->getManager()->getRepository(maClass::class)->findAll();
    donc ne pas mettre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $this->getDoctrine()->getManager('maConnextion')->getRepository(Maclass::class)->findAll();
    Il doit surement y avoir un moyen mais j'ai du passer à côté. Si vous pouviez m'aider ce serait cool.

  2. #2
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    Bonjour,

    Effectivement cette partie est intéressante mais ce n'est pas ce que je demande.

    Le problème dans le cas là c'est qu'il faut créer une connexion par base de données et si il y en a 100 ou 300 c'est juste ingérable de mettre tout dans le fichier de config.

    En plus pour avoir accès je dois faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $this->getDoctrine()->getManager('maConnextion1')->getRepository(Maclass::class)->findAll();
     
    $this->getDoctrine()->getManager('maConnextion2')->getRepository(Maclass::class)->findAll();
     
    $this->getDoctrine()->getManager('maConnextion3')->getRepository(Maclass::class)->findAll();
    Moi j'aimerais éviter les maConnexion1, maConnexion2 ...

    Je ne sais pas si je me fait bien comprend?

  4. #4
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Par défaut
    Ah ouais, j'ai mal lu ton message.

    C'est faisable si tu veux juste utiliser SQL avec une connexion, mais si tu veux avoir l'ORM en entier ça risque d'être compliqué je pense.

    - Les informations de L'ORM sont liées à la connexion en cours donc si tu changes de connexion tes entités ne seront plus reconnues.

    - Et même si tu parvenais à résoudre ce problème, pour accéder à ta nouvelle EntityManager comme tu le veux (sans nom à l'avance) il faut remplacer l'entitymanager par défaut dans le conteneur avec la nouvelle. Or si tu reçois les informations de connexion en cours de traitement, à ce moment là le conteneur est déjà compilé et mis en cache. Il te faudra donc remplacer l'entitymanager dans le conteneur, puis le re-construire / recompiler, vider le cache et le mettre en cache.

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    d'accord donc le plus simple c'est encore d'ajouter chaque connexion dans le fichier de config et de mettre à chaque fois le nom de la connexion dans getManager alors.
    Mais si j'ai 100 connexions ça ne risque pas d'être un problème? au niveau vitesse d'exécution par exemple?

    Dans la documentation de doctrine j'ai trouvé qu'on pouvait faire un entityManager comme ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    use Doctrine\ORM\Tools\Setup;
    use Doctrine\ORM\EntityManager;
     
    $paths = array('/path/to/entity/mapping/files');
     
    $config = Setup::createAnnotationMetadataConfiguration($paths);
    $dbParams = array('driver' => 'pdo_sqlite', 'memory' => true);
    $entityManager = EntityManager::create($dbParams, $config);
    je pourrais le créer comme ça et le fournir aux controllers via un event_listener qui serait attacher à l'event kernel.request. Je dois lui donner le chemin des entités donc je devrais pouvoir utiliser l'ORM comme je veux non?

    Le problème de ça c'est que j'ai pour le moment une erreur qui me dit:

    Class "App\Entity\Member" is not a valid entity or mapped super class.

    Après recherche j'ai trouvé sur un forum quelqu'un qui conseil de mettre un paramètre a false dans la méthode suivante

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode, null, null, false);
    Et je n'ai plus l'erreur mais une autre qui est

    Argument 1 passed to App\Repository\MemberRepository::__construct() must be an instance of Symfony\Bridge\Doctrine\RegistryInterface, instance of Doctrine\ORM\EntityManager given, called in /Users/Jeje/Sites/Project/Symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Repository/DefaultRepositoryFactory.php on line 68

    Qu'est ce que tu en penses? Est ce que cette piste est déjà une bonne piste et si oui comment je peux résoudre les deux erreurs correctement?

    Merci à toi pour ton aide

    PS: dans mon cas les entités sont toutes les mêmes d'une base de données à l'autre je suppose que je dois juste spécifier le même chemin dans la config à chaque fois?

    PS2: si j'utilise l'option wrapper_class dans le fichier de configuration et que je défini l'authentification moi même est ce que je ne règlerais pas le problème?

  6. #6
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Par défaut
    - Mettre le dernier paramètre à false signifie que l'annotation "@ORM\Entity" est reconnue; à true c'est "@Entity" qui est reconnue.

    - Vu que tu devras utiliser le conteneur comme un service locator - $this->getDoctrine()->getManager('database_XXX'), ça risque d'être lourd en effet mais pour être certain il faut profiler.

    - Pour le 2e problème, désolé je tourne en rond là-dessus et ne trouve pas de solutions (ou même de piste).

  7. #7
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    J'ai fini par trouver une solution.

    Alors déjà il y a une options dans la configuration de dbal qui est wrapper_class.
    Elle permet de créer une class personnaliser pour la connection à la base de données. Notre classe doit hériter de Doctrine\DBAL\Connection.
    Alors personnellement j'ai créé une classe et je n'ai modifié que le contructeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public function __construct(array $params, Driver $driver, Configuration $config = null, EventManager $eventManager = null)
        {
            // Code qui rend les infos dynamique
     
            parent::__construct($params, $driver, $config, $eventManager);
        }
    et dans la configuration vous avez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    doctrine:
        dbal:
            connections:
                default:
                    dbname: ~
                    host: '%env(DATABASE_HOST)%'
                    port: '%env(DATABASE_PORT)%'
                    user: '%env(DATABASE_USER)%'
                    password: '%env(DATABASE_PASSWORD)%'
                    charset: "UTF8"
                    wrapper_class: App\Service\DynamicConnection
    Moi je devais juste modifier le nom mais vous avez accès à toutes les informations dans la variable $params du constructeur.

    Petite information bonus:

    J'avais besoin du request mais on ne la pas directement dans la classe. Vous pouvez utiliser le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $request = Request::createFromGlobals();
    La dernière chose que je n'ai pas réussi à faire complètement est transmettre des paramètres global dans la classe.
    La seul façon que j'ai trouvé est via la configuration. On a l'options "options" qui prend une clé et une valeur mais pas de tableau malheureusement.

    Tsilefy je ne sais pas si tu as une idée pour le dernier point?

  8. #8
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Par défaut
    Quelles paramètres globaux par exemple?

  9. #9
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    Dans mon cas un tableau associatif.

  10. #10
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Par défaut
    J'ai pensé à une simple method injection depuis le conteneur, mais apparemment ça ne marcherait pas.

    Essaie la méthode compiler pass tel que décrit https://stackoverflow.com/questions/...ection-wrapper

    Remplace le conteneur en entier dans l'exemple par ton tableau, évidemment. Tu peux passer les arguments de la fonction appelée par addMethodCall directement ou par une référence à un paramètre du conteneur (préférable).

    Et cela suppose que tu connais le tableau à l'avance ou qu'il est défini quelque part (environnement...).

  11. #11
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    Bonjour,

    Désoler pour la réponse tardive.

    Alors oui je connais le tableau il est fixe.
    Je comprend pas bien ce qu'est CompilerPass et ce qui la manière donc il me permettra d'avoir accès dans ma classe à mon tableau?

  12. #12
    Membre Expert

    Profil pro
    Inscrit en
    Mai 2008
    Messages
    1 576
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 1 576
    Par défaut
    Et désolé pour la réponse tardive à la question tardive!

    En fait, c'est plus simple que je ne le pensais. La wrapper class est disponible en tant que service, tu peux donc t'en servir pour modifier les paramètres de connexion (ou passer n'importe quel tableau).

    - Plutôt que de simplement hériter de Doctrine\DBAL\Connection, copie aussi tout le code de Doctrine\DBAL\Connection dans ta classe. Ça te permettra d'avoir accès à toutes les propriétés privées de cette classe.

    - Ajoute cette méthode dans ta nouvelle classe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public function changeParams(array $params)
    {
        $this->_params = $params;
    }
    - Ajouter une méthode changeConnection(): bool, qui sera une copie exacte de connect(), mais sans ces ligne au début:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if ($this->_isConnected) {
          return false;
    }
    Maintenant, quelque part dans ton code, ici dans un contrôleur par exemple pour un test rapide mais de préference il faudrait le mettre dans un service, injecte la connexion par défaut, modifie les paramètres de connexion et lance une nouvelle connexion comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    /**
         * @Route("doctrine/test")
         */
        public function testDoctrine(Connection $connection)
        {
           $params = $connection->getParams();
     
           $params['url'] = "mysql://user:pass@127.0.0.1:3306/database";
           $params['host'] = "IP.IP.IP.IP";
           $params['user'] = "user";
           $params['password'] = "pass";
     
           $connection->setParams($params);
     
           $connection->changeConnection();
     
    //etc...
    Le gros inconvénient: comme tu vas complètement bypasser Doctrine\DBAL\Connection, si tu mets à jour Doctrine et qu'il y a des modifications dans cette classe, tu ne pourra pas profiter de ces modifications. Pour éviter ça, tu peux aussi ne réécrire que les parties qui te seront utiles, moi j'ai fait au plus court.

    Dis-moi si ça marche.

  13. #13
    Membre régulier
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2016
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2016
    Messages : 9
    Par défaut
    Salut merci pour tes conseils.

    Alors je n'ai pas testé car j'ai déjà mis tout ce que j'ai expliqué en place mais ça devrait fonctionner. Dans mon cas j'avais juste besoin de changer le nom de la base de données et ce que j'ai expliqué plus haut fonctionne en plus d'avoir les mises à jour. Mon tableau peut être dans le options de doctrine c'est pas trop un problème. Si j'ai besoin de plus j'essayerai ton idée.

    Un tout grand merci pour ton aide vraiment précieuse.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. CONNECTION ODBC avec DB POSTGRE
    Par wallior dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 01/08/2005, 16h59
  2. connection SYS avec oracle10g
    Par matana dans le forum Oracle
    Réponses: 4
    Dernier message: 02/06/2005, 17h55
  3. connection postgresl avec asp + pilote odbc
    Par tony_montana dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 26/01/2005, 16h25
  4. Réponses: 1
    Dernier message: 24/08/2004, 18h10
  5. Connection ADSL avec un routeur
    Par SebCBien dans le forum Réseau
    Réponses: 18
    Dernier message: 14/08/2004, 18h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo