2013-01-23 12 views
38

SymfonyのURLに基​​づいて異なるエンティティマネージャ/コネクションを使用するのはかなり簡単です。次のルーティング設定を使用すると、FOSUserBundle用の複数のエンティティマネージャ

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

および次のCookbookから入手できます。

How to work with Multiple Entity Managers and Connections

私のコントローラは、このようになります。

class UserController extends Controller 
{ 
    public function indexAction($connection) 
    { 

     $products = $this->get('doctrine') 
      ->getRepository('AcmeStoreBundle:Product', $connection) 
      ->findAll() 
     ; 
     .................. 

他のem/connection/databaseから製品情報を取得できます。

ここで、このようなものをルーティングに追加すると、

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

どのように私は簡単に接続変数で定義された接続を使用するようにログインを作ることができますか?

この設定では、各データベースに独自のユーザーログイン情報(fos_userテーブル)があると想定しています。

編集:更新されたルーティング情報

EDIT2:

私はここに完全に間違っている場合ので、私を許してください、しかし、まだPHP/symfonyの/教義を持つ新たなんです。私は手動で接続をFOS \ UserBundle \ Doctrine \ UserManagerに設定しようとしました。次は、コントローラでクラス

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

のコンストラクタで、私たちはそのために

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

を「テスト」にEMを変更するには、次の方法を使用することができ、私は次のようににコードを変更ObjectManagerではなくEntityManagerを使用します。

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

私のアプリは問題なく正常に動作します。

コントローラとのやり方から、この行にパラメータを追加して接続を変更しようとしましたが、それでもデフォルトの接続が使用されています。

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

他に何が欠けていますか?

+2

私はFOSUserBundleがそうするように設計されているとは思わない。プロジェクト自体に貢献するか、フォークを作成するかによって、機能を拡張できます。あるいは、異なる接続をサポートする独自のUserBundleを作成することもできます。 – Sgoettschkes

+1

@Sgoettschkes:私はあなたに完全に同意します。私はまだ自分の問題に対する解決策や回避策を見つけることができませんが、私がそうするときは、githubのプルリクエストではなく、ここでそれを共有します:) –

+1

あなたは適切なオブジェクトマネージャをUserManagerクラスのコンストラクタ(テスト用のもの)? –

答えて

11

ご覧のとおり、FOSUserBundleはEntityManagerを1つしか持てません。あなたは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> 

パラメータ%fos_user設定からそれを見ることができます。だから、コンストラクタにmodel_manager_name

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

として設定で指定されたmodel_manager_name%がgetRepositoryで二番目のパラメータを受け入れないのEntityManagerのインスタンスをしています。したがって、標準のFOSUserBundleは1つのデータベースでしか動作できません。


は、しかし、これは物語の終わりではない、それはsymfonyの:) 我々は異なるDB接続を使用することができるのUserManagerを書き出すことができます。この設定では、fos_user.user_managerはfos_user.user_manager.defaultです。 orm.xmlにあります。

このクラスをオーバーライドして、使用する接続の種類を決定するパラメータを追加できます。さらに、ManagerFactoryによって、目的のObjectManagerを取得できます。私は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% 

あなたのマネージャーにあなたのサービスを定義

を(あなたがより多くのデータベースを必要とする場合は、このサービスのためにあなたの工場を書くことができます)2 databesesのための簡単な例を書いた

/** 
* 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; 
} 

簡単なテスト

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

私は答えがとても大きかったと申します。何かが最後まで明確でない場合は、コードを貼り付けますgithub

1

FosUserBundleは複数のエンティティマネージャを持つことができません。

2つのデータベースを使用する最も簡単な方法は、SecurityControllerの 'checkLoginAction'をオーバーライドすることです。

<?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); 
      } 
     } 

} 
関連する問題