fos symfony doctrine2 fosuserbundle

symfony - login fosuserbundle



Administrador de entidades mĂșltiples para FOSUserBundle (2)

Para utilizar diferentes Entity Manager / Connection basado en URL en Symfony es bastante fácil. Con la siguiente configuración de enrutamiento

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

y del siguiente libro de cocina;

Cómo trabajar con múltiples administradores de entidades y conexiones

Mi controlador se vería algo como esto;

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

y podré obtener información del producto de diferentes em / connection / database.

Ahora, si agrego algo como esto a mi enrutamiento;

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

¿Cómo puedo hacer el inicio de sesión para usar la conexión como se define en la variable de conexión ?

Esta configuración supone que cada base de datos tiene su propia información de inicio de sesión de usuario (la tabla fos_user).

Editar: información de enrutamiento actualizada

Edit2:

Todavía soy nuevo con PHP / Symfony / Doctrine, así que por favor, perdónenme si estoy completamente equivocado aquí. Traté de configurar manualmente la conexión en FOS / UserBundle / Doctrine / UserManager . El siguiente es el constructor de la clase

// use Doctrine/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(); }

En un controlador, podemos usar el siguiente método para cambiar el em a ''testing''

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

Para eso cambié el código a lo siguiente para usar EntityManager en lugar de ObjectManager.

// //use Doctrine/Common/Persistence/ObjectManager; use Doctrine/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(); }

Mi aplicación funciona bien sin ningún error.

Por la forma en que funciona con el controlador, traté de cambiar la conexión agregando un parámetro a esta línea, pero todavía está usando la conexión predeterminada.

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

¿Qué más podría estar perdiendo aquí?


Como puede ver, FOSUserBundle puede tener solo un EntityManager. Puedes verlo desde la configuración orm.xml

<service id="fos_user.entity_manager" factory-service="doctrine" factory-method="getManager" class="Doctrine/ORM/EntityManager" public="false"> <argument>%fos_user.model_manager_name%</argument> </service>

Parámetro% fos_user.model_manager_name% especificado en la configuración como model_manager_name

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

Entonces en el constructor viene la instancia de EntityManager, que no acepta el segundo parámetro en getRepository. Por lo tanto, el FOSUserBundle estándar solo puede funcionar con una base de datos.

Pero este no es el final de la historia, es Symfony :) Podemos escribir UserManager, que puede usar diferentes conexiones de db. En el entorno, vea que fos_user.user_manager es un fos_user.user_manager.default. Lo encontramos en orm.xml

<service id="fos_user.user_manager.default" class="FOS/UserBundle/Doctrine/UserManager" public="false"> <argument type="service" id="security.encoder_factory" /> <argument type="service" id="fos_user.util.username_canonicalizer" /> <argument type="service" id="fos_user.util.email_canonicalizer" /> <argument type="service" id="fos_user.entity_manager" /> <argument>%fos_user.model.user.class%</argument> </service>

Podemos anular esta clase para agregar un parámetro adicional que determinará qué tipo de conexión desea usar. Además de ManagerFactory, puede obtener el ObjectManager deseado. Escribí un ejemplo simple para los dos databeses (si necesita más bases de datos puede escribir su fábrica para este servicio)

defina sus servicios en 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 - @doctrine - ''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 - @doctrine - ''conn2_manager'' - %fos_user.model.user.class%

Tu gerente

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

y prueba 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()); } }

Lamento que la respuesta fuera tan grande. Si algo no está claro hasta el final, puse el código en github


FosUserBundle no puede tener más de un administrador de entidades.

La forma más fácil que encontré de usar 2 bases de datos, es anular la ''checkLoginAction'' del SecurityController.

<?php //in myuserBunle/Controller/SecurityController.php class SecurityController extends BaseController { /** * check the user information */ public function checkLoginAction(Request $request){ $username = /trim($request->request->get("_username")); $user = $this->container->get(''fos_user.user_manager'')->findUserByUsername($username); $userDB2 = ..... $password = /trim($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); } } }