Symfony 2 : 다중 및 동적 데이터베이스 연결
저는 SF2를 처음 접했고 여러 데이터베이스에 대한 연결을 하나의 번들로 관리하는 방법이 궁금했습니다. 현재로서는 잘 작동하는 이 솔루션이 있지만 이것이 올바른 방법인지 모르겠습니다....
myBundle\Ressource\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: ~
그런 다음 BD 또는 다른 것으로 전환하기 위해 다음을 수행합니다.
$O_ressource= $this->get('doctrine')->getEntityManager('client');
$O_ressource= $this->get('doctrine')->getEntityManager('default');
여러분, 이것을 관리하는 것이 좋은 방법이라고 생각하십니까?
그리고 두 번째 질문은 다음과 같습니다.
동적 데이터베이스 연결을 설정하는 방법은 무엇입니까? 내 시스템에 100개의 데이터베이스가 있고 내 config.yml 파일에 모든 데이터베이스를 설정할 수 없다는 의미입니다. 그래서 데이터베이스를 즉석에서 변경할 수 있기를 원합니다.
도와 주셔서 감사합니다!
를 사용 ConnectionFactory
하면 연결에 연결된 이벤트 구독자(예: stofDoctrineExtensions)가 작동을 멈춥니다.
여기 내 방법이 있습니다. 나는처럼하는이 ConnectionFactory
빈 연결 및 EntityManager를 가지고있다. 작업하는 동안 연결 구성을 Reflections로 바꿉니다. SF 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)
}
}
업데이트 :
php5.4용으로 생성된 교리 2.2 / sf 2.3(선택 없음)에 대한 보다 우아한 솔루션(저는 새로운 배열 초기화 프로그램을 좋아합니다. D) 연결 래퍼라는 교리 기능을 사용할 수 있습니다. http://docs.doctrine-project.org/를 참조하세요. 프로젝트/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 [zulus@w3des.net]
*/
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')
]);
}
}
그리고 *Bundle 클래스에 새로운 컴파일러 클래스를 기록합니다.
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ConnectionCompilerPass());
}
그리고 그것이 전부입니다!
세션 속성을 기반으로 요청 시 연결이 생성됩니다.
데이터베이스를 전환하려면 다음을 사용하십시오.
$this->get('doctrine.dbal.dynamic_connection')->forceSwitch($dbname, $dbuser, $dbpass);
장점
- 더 이상 반성은 없다
- 주문형 제작
- 우아하고 강력한
단점
- 엔티티 관리자를 수동으로 정리하거나 이에 대한 특별 교리 이벤트를 만들어야 합니다.
- 훨씬 더 많은 코드
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',
));
이것은 간단한 예일 뿐이지만 시작하는 데 도움이 될 것입니다.
각 클라이언트에 대해 동일한 스키마를 가진 다른 데이터베이스가 필요하다는 동일한 요구 사항이 발생합니다. symfony 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);
}
ReferenceURL : https://stackoverflow.com/questions/6409167/symfony-2-multiple-and-dynamic-database-connection
'IT이야기' 카테고리의 다른 글
만료된 Facebook OAuth2 액세스 토큰을 새로 고치는 올바른 방법 (0) | 2021.10.21 |
---|---|
사용자에게 POST 데이터를 다시 보내라는 메시지를 표시하지 않고 POST 후 브라우저 창 다시 로드 (0) | 2021.10.21 |
git의 기록에서 제거하지 않고 분기를 닫는 방법 (0) | 2021.10.21 |
이전 버전과 호환되는 Android 코드 작성 (0) | 2021.10.20 |
Simplemembership을 사용하는 새로운 MVC 4 인터넷 템플릿의 역할 기반 인증 (0) | 2021.10.20 |