Connexion dynamique à la base de données symfony2
Mon projet symfony2 a une base de données principale et de nombreux enfants les bases de données. Chaque enfant de la base de données est créé pour chaque utilisateur, la base de données d'informations d'identification sont stockées dans la base de données principale. Lorsque les connexions de l'utilisateur, l'utilisateur spécifiques de la base de données d'informations d'identification sont extraits de la base de données principale et l'enfant de connexion de base de données, idéalement, devrait être établi.
J'ai googlé pour la même chose, et je suis tombé sur un certain nombre de solutions et enfin:
#config.yml
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: maindb
user: root
password: null
host: localhost
dynamic_conn:
dbname: ~
user: ~
password: ~
host: localhost
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
auto_mapping: true
dynamic_em:
connection: dynamic_conn
auto_mapping: true
J'ai créé une connexion par défaut pour se connecter à la base de données principale et d'une connexion vide pour l'enfant de la base de données, de la même façon, j'ai créé les gestionnaires de l'entité.
Puis j'ai créé par défaut de l'écouteur d'événement et ajouté le code suivant à la "onKernelRequest':
public function onKernelRequest(GetResponseEvent $event) //works like preDispatch in Zend
{
//code to get db credentials from master database and stored in varaiables
....
$connection = $this->container->get(sprintf('doctrine.dbal.%s_connection', 'dynamic_conn'));
$connection->close();
$refConn = new \ReflectionObject($connection);
$refParams = $refConn->getProperty('_params');
$refParams->setAccessible('public'); //we have to change it for a moment
$params = $refParams->getValue($connection);
$params['dbname'] = $dbName;
$params['user'] = $dbUser;
$params['password'] = $dbPass;
$refParams->setAccessible('private');
$refParams->setValue($connection, $params);
$this->container->get('doctrine')->resetEntityManager('dynamic_em');
....
}
Le code ci-dessus définit l'enfant paramètres de base de données et réinitialise le dynamic_em gestionnaire d'entités.
Quand je fais la suivre dans le contrôleur, il fonctionne très bien et les données si extrait de l'enfant de la base de données.
$getblog= $em->getRepository('BloggerBlogBundle:Blog')->findById($id); //uses doctrine
Mais, lorsque j'utilise le contexte de sécurité comme indiqué dans le code suivant, j'obtiens une erreur "PAS de BASE de données SÉLECTIONNÉ".
$securityContext = $this->container->get('security.context');
$loggedinUserid = $securityContext->getToken()->getUser()->getId();
Comment puis-je configurer la connexion à la base de façon dynamique et l'utilisation de contexte de sécurité ainsi?
Mise à JOUR:-
Après beaucoup de temps passé sur l'essai et l'erreur, et de googler autour, j'ai réalisé que security.context
est définie avant l'exécution de onKernelRequest
. Maintenant, la question est comment à injecter la connexion de base de données les informations dans la sécurité.contexte, et où à injecter?
Nous devons arriver à un point où la DBAL et le contexte de sécurité est définie et d'émission de jeton de sécurité est créé, et nous pouvons manipuler la base de données détails de la connexion.
Par conséquent, que la personne en suivant le lien indiqué, j'ai modifié le code, c'est exactement ce que je voudrais faire.
http://forum.symfony-project.org/viewtopic.php?t=37398&p=124413
Qui me laisse le code suivant ajouter à mon projet:
#config.yml //remains unchanged, similar to above code
Une passe de compilateur est créé comme suit:
//src/Blogger/BlogBundle/BloggerBlogBundle.php
namespace Blogger\BlogBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Blogger\BlogBundle\DependencyInjection\Compiler\CustomCompilerPass;
class BloggerBlogBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new CustomCompilerPass());
}
}
La passe de compilateur est comme suit:
# src/Blogger/BlogBundle/DependencyInjection/Compiler/CustomCompilerPass.php
class CustomCompilerPassimplements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$connection_service = 'doctrine.dbal.dynamic_conn_connection';
if ($container->hasDefinition($connection_service))
{
$def = $container->getDefinition($connection_service);
$args = $def->getArguments();
$args[0]['driverClass'] = 'Blogger\BlogBundle\UserDependentMySqlDriver';
$args[0]['driverOptions'][] = array(new Reference('security.context'));
$def->replaceArgument(0, $args[0]);
}
}
}
La classe du pilote de code est comme suit:
# src/Blogger/BlogBundle/UserDependentMySqlDriver.php
use Doctrine\DBAL\Driver\PDOMySql\Driver;
class UserDependentMySqlDriver extends Driver
{
public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{
$dbname = ..... //store database name in variable
$params['dbname'] = $dbname;
return parent::connect($params, $username, $password, array());
}
}
Le code ci-dessus ont été ajoutés à mon projet, et je suppose que c'est le travail réel autour de mon problème.
Mais maintenant j'ai l'erreur suivante:
ServiceCircularReferenceException: référence Circulaire détecté pour
service de sécurité".contexte", chemin d'accès: "profiler_listener -> profiler ->
de sécurité.contexte -> sécurité.l'authentification.manager ->
fos_user.user_provider.username_email -> fos_user.user_manager ->
la doctrine.orm.dynamic_manager_entity_manager ->
la doctrine.dbal.dynamic_conn_connection".
Comment puis-je obtenir mon code de travail? Je pari que je fais quelque chose de mal ici, et je vous serais reconnaissant de toute l'aide et des indices.
source d'informationauteur
Vous devez vous connecter pour publier un commentaire.
Ici, vous devez mettre en place votre propre logique sur votre propre, votre propre entreprise.
Prendre un coup d'oeil à la documentation de Doctrine sur "comment créer un gestionnaire d'entité".
Puis créer un service avec un clair de l'API:
Vous ne pouvez pas le faire par défaut DoctrineBundle, il n'est pas utilisable pour les fonctions dynamiques.
Et de le déclarer en tant que service.
J'aimerais proposer la solution à votre problème.Vous pouvez utiliser PhpFileLoader pour définir dynamiquement les paramètres de votre config.yml.
Extrait vous principal de la base de données les paramètres de connexion dans le fichier séparé:
Créer un nouveau script PHP (dire DynamicParametersLoader.php) qui permettra d'injecter de nouveaux paramètres dans l'application conteneur. Je pense que vous ne pouvez pas utiliser votre application symfony dans ce script, mais vous pouvez lire db principaux pouvoirs de variable $container. Comme suit:
Maintenant, vous devez dire à Symfony au sujet de votre script et de nouveaux paramètres.fichier yml:
À cette étape, vous pouvez utiliser librement injecté paramètres en vous config:
Il ya une très bonne solution à l'aide d'un écouteur d'événement posté ici:
Symfony2, Dynamique Connexion DB/Début de l'override de la Doctrine de Service