2011-06-20 6 views
52

मैं एसएफ 2 के लिए काफी नया हूं और मैं सोच रहा था कि मैं एक बंडल में अलग-अलग डेटाबेस से कनेक्शन कैसे प्रबंधित कर सकता हूं। जो ठीक काम करता है - - क्षण के लिए मैं इस समाधान है myBundle \ Ressource में लेकिन अगर यह यह करने के लिए सही तरीका है मैं नहीं जानता ....सिम्फनी 2: एकाधिक और गतिशील डेटाबेस कनेक्शन

\ config \ config.yml:

doctrine: 
dbal: 
    default_connection:  default 
    connections: 
     default: 
      dbname:   SERVER 
      user:    root 
      password:   null 
      host:    localhost 
     client: 
      dbname:   CLIENT_134 
      user:    root 
      password:   null 
      host:    localhost 
orm: 
    default_entity_manager: default 
    entity_managers: 
     default: 
      connection:  default 
      mappings: 
       MyBundle: ~ 
     client: 
      connection:  client 
      mappings: 
       MyBundle: ~ 

और फिर, क्रम में बीडी या अन्य में से एक पर जाने के लिए मुझे क्या करना:

$O_ressource= $this->get('doctrine')->getEntityManager('client'); 
$O_ressource= $this->get('doctrine')->getEntityManager('default'); 

तो दोस्तों, आपको लगता है कि यह इस का प्रबंधन करने के लिए एक अच्छा तरीका है?

और मेरी दूसरी सवाल यह है:

कैसे गतिशील डेटाबेस कनेक्शन स्थापित करने के लिए? मेरा मतलब है कि मेरे सिस्टम में मेरे पास 100 डेटाबेस हैं और मैं उन्हें अपनी config.yml फ़ाइल में सेट नहीं कर सकता। तो मैं फ्लाई पर डेटाबेस को बदलने में सक्षम होना चाहता हूं।

सहायता के लिए धन्यवाद!

+0

"गतिशील डेटाबेस कनेक्शन," आप अपने नियंत्रक से एक DBAL संबंध बनाने का अर्थ यह है द्वारा? – Problematic

+3

हाँ, बिल्कुल! एक डेटाबेस से दूसरे डेटाबेस में बदलने में सक्षम हो, और इन डेटाबेस को config.yml फ़ाइल – Fish

+0

में घोषित नहीं किया जा सकता है getEntityManager symfony2 –

उत्तर

23

आप Symfony\Bundle\DoctrineBundle\ConnectionFactory पर गौर कर सकते, कंटेनर सेवा doctrine.dbal.connection_factory का उपयोग कर:

$connectionFactory = $this->container->get('doctrine.dbal.connection_factory'); 
$connection = $connectionFactory->createConnection(array(
    'driver' => 'pdo_mysql', 
    'user' => 'root', 
    'password' => '', 
    'host' => 'localhost', 
    'dbname' => 'foo_database', 
)); 

बस एक त्वरित उदाहरण है कि है, लेकिन यह मिलना चाहिए आप शुरू कर दिया।

+0

के नवीनतम संस्करण में बहिष्कृत है धन्यवाद, यह मेरी मदद करता है! मैं सोच रहा था कि पैरामीटर के मान को बदलने का कोई तरीका है जो मेरी कॉन्फ़िगरेशन फ़ाइल में परिभाषित है? उदाहरण के लिए: # एप्लिकेशन/config/config.yml पैरामीटर: my_mailer.class: एक्मे \ HelloBundle \ मेलर my_mailer.transport: sendmail सेवाएं: my_mailer: वर्ग:% my_mailer.class% तर्क: [% my_mailer.transport%] क्या मैं अपना मान बदल सकता हूं:% my_mailer.transport% – Fish

+0

कोड से या कॉन्फ़िगर फ़ाइल से बदलें? – Problematic

+0

इसे कोड से बदल रहा है। – Fish

49

यदि आप ConnectionFactory का उपयोग करते हैं, तो कनेक्शन से जुड़े आपके ईवेंट ग्राहक काम करना बंद कर देंगे, उदाहरण के लिए stofDoctrineExtensions।

यहां मेरी विधि है। मेरे पास ConnectionFactory के साथ खाली कनेक्शन और EntityManager है। काम करते समय मैं प्रतिबिंब द्वारा कनेक्शन कॉन्फ़िगरेशन को प्रतिस्थापित करता हूं। एस एफ 2.0.10 पर काम करता है;)

class YourService extends ContainerAware 
{ 

    public function switchDatabase($dbName, $dbUser, $dbPass) 
    { 
    $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_manager'); // for sure (unless you like broken transactions) 
    } 
} 

अद्यतन:

सिद्धांत 2.2 के लिए अधिक सुरुचिपूर्ण समाधान/एस एफ 2.3 (relection के बिना), php5.4 (मैं नई सरणी प्रारंभकर्ता प्यार के लिए बनाया: डी) हम कनेक्शन रैपर नामक सिद्धांत सुविधा का उपयोग कर सकते हैं, http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/portability.html

यह उदाहरण अस्थायी भंडारण कनेक्शन विवरण के लिए सत्र सेवा का उपयोग करें।

namespace w3des\DoctrineBundle\Connection; 

use Doctrine\DBAL\Connection; 
use Symfony\Component\HttpFoundation\Session\Session; 
use Doctrine\Common\EventManager; 
use Doctrine\DBAL\Events; 
use Doctrine\DBAL\Event\ConnectionEventArgs; 

/* 
* @author Dawid zulus Pakula [[email protected]] 
*/ 
class ConnectionWrapper extends Connection 
{ 

const SESSION_ACTIVE_DYNAMIC_CONN = 'active_dynamic_conn'; 

/** 
* @var Session 
*/ 
private $session; 

/** 
* @var bool 
*/ 
private $_isConnected = false; 

/** 
* @param Session $sess 
*/ 
public function setSession(Session $sess) 
{ 
    $this->session = $sess; 
} 

public function forceSwitch($dbName, $dbUser, $dbPassword) 
{ 
    if ($this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) { 
     $current = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN); 
     if ($current[0] === $dbName) { 
      return; 
     } 
    } 

    $this->session->set(self::SESSION_ACTIVE_DYNAMIC_CONN, [ 
     $dbName, 
     $dbUser, 
     $dbPass 
    ]); 

    if ($this->isConnected()) { 
     $this->close(); 
    } 
} 

/** 
* {@inheritDoc} 
*/ 
public function connect() 
{ 
    if (! $this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) { 
     throw new \InvalidArgumentException('You have to inject into valid context first'); 
    } 
    if ($this->isConnected()) { 
     return true; 
    } 

    $driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array(); 

    $params = $this->getParams(); 
    $realParams = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN); 
    $params['dbname'] = $realParams[0]; 
    $params['user'] = $realParams[1]; 
    $params['password'] = $realParams[2]; 

    $this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions); 

    if ($this->_eventManager->hasListeners(Events::postConnect)) { 
     $eventArgs = new ConnectionEventArgs($this); 
     $this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs); 
    } 

    $this->_isConnected = true; 

    return true; 
} 

/** 
* {@inheritDoc} 
*/ 
public function isConnected() 
{ 
    return $this->_isConnected; 
} 

/** 
* {@inheritDoc} 
*/ 
public function close() 
{ 
    if ($this->isConnected()) { 
     parent::close(); 
     $this->_isConnected = false; 
    } 
} 
} 

अगला अपने सिद्धांत विन्यास में इसे पंजीकृत:

पहले तो हम विशेष कनेक्शन आवरण बनाने के लिए

… 

connections: 
    dynamic: 
    driver: %database_driver% 
    host:  %database_host% 
    port:  %database_port% 
    dbname: 'empty_database' 
    charset: UTF8 
    wrapper_class: 'w3des\DoctrineBundle\Connection\ConnectionWrapper' 

और हमारे ConnectionWrapper ठीक से पंजीकृत है। अब सत्र इंजेक्शन।

पहले विशेष CompilerPass वर्ग बनाने के लिए:

namespace w3des\DoctrineBundle\DependencyInjection\CompilerPass; 

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Definition; 
use Symfony\Component\DependencyInjection\Reference; 

class ConnectionCompilerPass implements CompilerPassInterface 
{ 

/** 
* {@inheritDoc} 
*/ 
public function process(ContainerBuilder $container) 
{ 
    $connection = $container 
    ->getDefinition('doctrine.dbal.dynamic_connection') 
    ->addMethodCall('setSession', [ 
     new Reference('session') 
    ]); 
} 
} 

और हम * बंडल वर्ग में हमारे नए संकलक वर्ग रिकॉर्ड:

public function build(ContainerBuilder $container) 
{ 
    parent::build($container); 
    $container->addCompilerPass(new ConnectionCompilerPass()); 
} 

और वह अपने सभी!

सत्र गुणों के आधार पर कनेक्शन मांग पर बनाया जाएगा।

डेटाबेस जाने के लिए, बस का उपयोग करें:

$this->get('doctrine.dbal.dynamic_connection')->forceSwitch($dbname, $dbuser, $dbpass); 

लाभ

  1. कोई और अधिक प्रतिबिंब
  2. निर्माण की मांग पर
  3. सुरुचिपूर्ण और शक्तिशाली

नुकसान

  1. आप सफाई तो अपनी इकाई के प्रबंधक manualy के लिए, या इस
  2. के लिए विशेष सिद्धांत घटना बनाने के बहुत अधिक कोड
+1

dynamic_conn या dynamic_manager का उद्देश्य क्या है? क्या आप उनके उद्देश्य के बारे में और विस्तार कर सकते हैं? धन्यवाद –

+0

मेरे पास एप्लिकेशन है, जहां प्रत्येक क्लाइंट के पास अन्य क्लाइंट की तरह एक ही स्कीमा के साथ अपना डेटाबेस होता है। यह विधि मुझे पूर्व के लिए वास्तविक डेटाबेस पर स्विच करने की अनुमति देता है। सत्र विशेषाधिकार – zulus

+0

इस प्रतिक्रिया के लिए धन्यवाद। Http://knpuniversity.com/screencast/question-answer-day/symfony2- गतिशील- subdomains की सहायता से मैं दिए गए सबडोमेन –

0

मैं एक ही की आवश्यकता होगी, में चलाने के साथ विभिन्न डेटाबेस करना होगा प्रत्येक ग्राहक के लिए एक ही स्कीमा। सिमफनी 2.3 के बाद, विधि resetEntityManager के बहिष्करण के बाद, मैंने देखा कि कोड कनेक्शन बंद किए बिना और (पुरानी इकाई) प्रबंधक को रीसेट किए बिना अच्छी तरह से चलाया जाता है।

यह मेरा वर्तमान कार्यशील कोड है:

public function switchDatabase($dbName, $dbUser, $dbPass) { 
    $connection = $this->container->get(sprintf('doctrine.dbal.%s_connection', 'dynamic_conn')); 

    $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); 
} 
+0

मैं एक डैशबोर्ड सिस्टम का निर्माण कर रहा हूं जो विभिन्न डेटाबेस को एकीकृत करेगा जिससे सिम्फनी 3.0 के साथ उन डेटाबेस को प्रबंधित करने के लिए एक इंटरफ़ेस प्रदान किया जा सके। बात यह है कि सिद्धांतों को घोषित करने के लिए पैरामीटर.आईएमएल फ़ाइल का उपयोग किया जाता है और मैंने किसी को इस परिप्रेक्ष्य में इस धागे में निहित एक ही चीज़ को प्राप्त करने के बारे में बात नहीं की है। दस्तावेज़ इसे स्पष्ट नहीं कर रहे हैं क्योंकि मैंने उनको आजमाया है, मैं त्रुटियों पर ठोकर खा रहा हूं। क्या कोई सिम्फनी 3.0 के लिए समाधान प्रदान कर सकता है .... धन्यवाद। – Maximum86

+0

आप इस पोस्ट से कोड कॉपी करें http://stackoverflow.com/a/9291896/6345477 – alias

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

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