Gestionnaire d’entités multiples pour FOSUserBundle

Si vous utilisez assez facilement Entity Manager / Connection basé sur l’URL dans Symfony. Avec la configuration de routage suivante

connection: pattern: /a/{connection} defaults: { _controller: AcmeTestBundle:User:index } 

et du livre de recettes suivant;

Comment travailler avec des gestionnaires d’entités multiples et des connexions

Mon contrôleur ressemblerait à ceci:

 class UserController extends Controller { public function indexAction($connection) { $products = $this->get('docsortingne') ->getRepository('AcmeStoreBundle:Product', $connection) ->findAll() ; .................. 

et je pourrai récupérer des informations sur les produits à partir de différents em / connexions / bases de données.

Maintenant, si j’ajoute quelque chose comme ça à mon routage;

 login: pattern: /a/{connection}/login defaults: { _controller: FOSUserBundle:Security:login } 

Comment puis-je facilement faire la connexion pour utiliser la connexion comme défini dans la variable de connexion ?

Cette configuration suppose que chaque firebase database possède ses propres informations de connexion utilisateur (la table fos_user).

Modifier: mise à jour des informations de routage

Edit2:

Je suis toujours nouveau avec PHP / Symfony / Docsortingne, donc s’il vous plaît pardonnez-moi si je me trompe complètement ici. J’ai essayé de définir manuellement la connexion à FOS \ UserBundle \ Docsortingne \ UserManager . Ce qui suit est le constructeur de la classe

 // use Docsortingne\Common\Persistence\ObjectManager; // public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, ObjectManager $om, $class) { parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer); $this->objectManager = $om; $this->repository = $om->getRepository($class); $metadata = $om->getClassMetadata($class); $this->class = $metadata->getName(); } 

Dans un contrôleur, nous pouvons utiliser la méthode suivante pour changer le em en ‘testing’

 $em = $this->get('docsortingne')->getManager('testing'); $repository = $this->get('docsortingne')->getRepository($class, 'testing') 

Pour cela, j’ai modifié le code pour utiliser EntityManager au lieu d’ObjectManager.

 // //use Docsortingne\Common\Persistence\ObjectManager; use Docsortingne\ORM\EntityManager; // public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, EntityManager $om, $class) { parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer); $this->objectManager = $om; $this->repository = $om->getRepository($class); $metadata = $om->getClassMetadata($class); $this->class = $metadata->getName(); } 

Mon application fonctionne correctement sans erreur.

De la façon dont cela fonctionne avec le contrôleur, j’ai essayé de changer la connexion en ajoutant un paramètre à cette ligne, mais il utilise toujours la connexion par défaut.

 $this->repository = $om->getRepository($class, 'testing'); 

Que puis-je manquer ici?

Comme vous pouvez le constater, FOSUserBundle ne peut avoir qu’un seul EntityManager. Vous pouvez le voir depuis les parameters orm.xml

  %fos_user.model_manager_name%  

Paramètre% fos_user.model_manager_name% spécifié dans les parameters comme model_manager_name

 fos_user: db_driver: ~ # Required user_class: ~ # Required firewall_name: ~ # Required model_manager_name: ~ 

Ainsi, dans le constructeur, il y a l’instance de EntityManager, qui n’accepte pas le deuxième paramètre dans getRepository. Par conséquent, le FOSUserBundle standard ne peut fonctionner qu’avec une seule firebase database.


Mais ce n’est pas la fin de l’histoire, c’est Symfony 🙂 Nous pouvons écrire UserManager, qui peut utiliser différentes connexions db. Dans le paramètre, voyez que fos_user.user_manager est une erreur fos_user.user_manager.default. Nous le trouvons dans orm.xml

      %fos_user.model.user.class%  

Nous pouvons remplacer cette classe pour append un paramètre supplémentaire qui déterminera le type de connexion que vous souhaitez utiliser. Par ailleurs, ManagerFactory vous permet d’obtenir le ObjectManager souhaité. J’ai écrit un exemple simple pour les deux bases de données (si vous avez besoin de plus de bases de données, vous pouvez écrire votre usine pour ce service)

définir vos services dans services.yml

 services: acme.user_manager.conn1: class: Acme\DemoBundle\Service\UserManager public: true arguments: - @security.encoder_factory - @fos_user.util.username_canonicalizer - @fos_user.util.email_canonicalizer - @docsortingne - 'conn1_manager' - %fos_user.model.user.class% acme.user_manager.conn2: class: Acme\DemoBundle\Service\UserManager public: true arguments: - @security.encoder_factory - @fos_user.util.username_canonicalizer - @fos_user.util.email_canonicalizer - @docsortingne - 'conn2_manager' - %fos_user.model.user.class% 

Votre manager

 /** * Constructor. * * @param EncoderFactoryInterface $encoderFactory * @param CanonicalizerInterface $usernameCanonicalizer * @param CanonicalizerInterface $emailCanonicalizer * @param RegistryInterface $docsortingne * @param ssortingng $connName * @param ssortingng $class */ public function __construct(EncoderFactoryInterface $encoderFactory, CanonicalizerInterface $usernameCanonicalizer, CanonicalizerInterface $emailCanonicalizer, RegistryInterface $docsortingne, $connName, $class) { $om = $docsortingne->getEntityManager($connName); parent::__construct($encoderFactory, $usernameCanonicalizer, $emailCanonicalizer, $om, $class); } /** * Just for test * @return EntityManager */ public function getOM() { return $this->objectManager; } 

et test simple

 /** * phpunit -c app/ src/Acme/DemoBundle/Tests/FOSUser/FOSUserMultiConnection.php */ class FOSUserMultiConnection extends WebTestCase { public function test1() { $client = static::createClient(); /** @var $user_manager_conn1 UserManager */ $user_manager_conn1 = $client->getContainer()->get('acme.user_manager.conn1'); /** @var $user_manager_conn2 UserManager */ $user_manager_conn2 = $client->getContainer()->get('acme.user_manager.conn2'); /** @var $om1 EntityManager */ $om1 = $user_manager_conn1->getOM(); /** @var $om2 EntityManager */ $om2 = $user_manager_conn2->getOM(); $this->assertNotEquals($om1->getConnection()->getDatabase(), $om2->getConnection()->getDatabase()); } } 

Je suis désolé que la réponse soit si grande. Si quelque chose n’est pas clair jusqu’à la fin, je mets le code sur github

FosUserBundle ne peut pas avoir plus d’un gestionnaire d’entités.

La méthode la plus simple que j’ai trouvée pour utiliser 2 bases de données consiste à remplacer le ‘checkLoginAction’ de SecurityController.

 request->get("_username")); $user = $this->container->get('fos_user.user_manager')->findUserByUsername($username); $userDB2 = ..... $password = \sortingm($request->request->get('_password')); if ($user) { // Get the encoder for the users password $encoder = $this->container->get('security.encoder_factory')->getEncoder($user); $encoded_pass = $encoder->encodePassword($password, $user->getSalt()); if (($user->getPassword() == $encoded_pass) || $this->checkSecondEM()) { $this->logUser($request, $user); return new RedirectResponse($this->container->get('router')->generate($this->container->get('session')->get('route'), $request->query->all() )); } else { // Password bad return parent::loginAction($request); } } else { // Username bad return parent::loginAction($request); } } }