2013-01-23 16 views
38

के लिए एकाधिक इकाई प्रबंधक सिम्फनी में यूआरएल के आधार पर अलग-अलग इकाई प्रबंधक/कनेक्शन का उपयोग करने के लिए काफी आसान है। निम्नलिखित रूटिंग कॉन्फ़िगरेशनFOSUserBundle

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

और निम्न कुकबुक से;

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() 
     ; 
     .................. 

और मैं विभिन्न एम/कनेक्शन/डेटाबेस से उत्पाद जानकारी प्राप्त करने में सक्षम हूं।

अब, अगर मैं अपने रूटिंग में ऐसा कुछ जोड़ता हूं;

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') 

कि के लिए करने के लिए उन्हें बदलने के लिए मैं कोड बदल के लिए निम्न का उपयोग कर सकते 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 को ऐसा करने के लिए डिज़ाइन किया गया है। आप या तो प्रोजेक्ट में योगदान करके या कांटा बनाकर कार्यक्षमता बढ़ा सकते हैं। या आप अलग-अलग कनेक्शन के लिए समर्थन के साथ अपना खुद का उपयोगकर्ता बंडल लिख सकते हैं। – Sgoettschkes

+1

@Sgoettschkes: मैं पूरी तरह से आपसे सहमत हूं। मैं अभी तक अपनी समस्या के समाधान/समाधान खोजने में सक्षम नहीं हूं, लेकिन जब मैं करता हूं, तो मुझे यकीन है कि अगर यह जिथूब पर पुल अनुरोध द्वारा नहीं किया गया है तो मुझे यह साझा करना होगा :) –

+1

क्या आपने उचित ऑब्जेक्ट मैनेजर को इंजेक्शन दिया है UserManager क्लास कन्स्ट्रक्टर (परीक्षण एक)? –

उत्तर

11

जैसा कि आप देख सकते हैं, FOSUserBundle में केवल एक EntityManager हो सकता है। आप 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% model_manager_name के रूप में सेटिंग्स में निर्दिष्ट

fos_user: 
    db_driver:   ~ # Required 
    user_class:   ~ # Required 
    firewall_name:  ~ # Required 
    model_manager_name: ~ 
तो निर्माता में

EntityManager, जो getRepository में दूसरा पैरामीटर स्वीकार नहीं करता है के कहने आता है। इसलिए, मानक FOSUserBundle केवल एक डेटाबेस के साथ काम कर सकता है।


लेकिन इस कहानी का अंत नहीं है, यह Symfony है :) हम UserManager, जो अलग-अलग db कनेक्शन का उपयोग कर सकते हैं बाहर लिख सकते हैं। सेटिंग में देखें कि fos_user.user_manager एक fos_user.user_manager.default है। हम इसे 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> 

में मिल हम एक अतिरिक्त पैरामीटर तय करेंगे कि कनेक्शन की किस तरह आप उपयोग करना चाहते जोड़ने के लिए इस वर्ग को ओवरराइड कर सकते हैं। प्रबंधक फैक्टरी द्वारा आगे आप वांछित ऑब्जेक्ट प्रबंधक प्राप्त कर सकते हैं। मैं दो databeses के लिए सरल उदाहरण लिखा था (यदि आप और अधिक डेटाबेस की जरूरत है तो आप इस सेवा के लिए अपने कारखाने में लिख सकते हैं)

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% 

आपका प्रबंधक में अपनी सेवाओं को परिभाषित

/** 
* 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 डेटाबेस का उपयोग करने का सबसे आसान तरीका है।

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

} 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^