Dự án symfony2 của tôi có một cơ sở dữ liệu chính và nhiều cơ sở dữ liệu con. Mỗi cơ sở dữ liệu con được tạo cho mỗi người dùng, thông tin đăng nhập cơ sở dữ liệu được lưu trữ trong cơ sở dữ liệu chính. Khi người dùng đăng nhập, thông tin xác thực cơ sở dữ liệu người dùng cụ thể được lấy từ cơ sở dữ liệu chính và kết nối cơ sở dữ liệu con lý tưởng nên được thiết lập. Tôi googled cho cùng, và tôi đi accross một số giải pháp và cuối cùng đã làm như sau:Kết nối cơ sở dữ liệu động symfony2
#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
Tôi tạo ra một kết nối mặc định để kết nối với cơ sở dữ liệu chính và kết nối trống cho cơ sở dữ liệu con, tương tự như tôi đã tạo các trình quản lý thực thể. Sau đó, tôi đã tạo sự kiện mặc định nghe và thêm đoạn mã sau vào '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');
....
}
Đoạn mã trên thiết lập các thông số cơ sở dữ liệu con và reset bộ quản lý dynamic_em thực thể.
Khi tôi làm như sau trong một số bộ điều khiển, nó hoạt động tốt và dữ liệu nếu tìm nạp từ cơ sở dữ liệu con.
$getblog= $em->getRepository('BloggerBlogBundle:Blog')->findById($id); //uses doctrine
Tuy nhiên, khi tôi sử dụng ngữ cảnh bảo mật như được thấy trong mã sau, tôi gặp lỗi 'KHÔNG ĐƯỢC CHẤP NHẬN'.
$securityContext = $this->container->get('security.context');
$loggedinUserid = $securityContext->getToken()->getUser()->getId();
Làm cách nào để đặt kết nối cơ sở dữ liệu động và sử dụng ngữ cảnh bảo mật?
UPDATE: -
Sau nhiều thời gian dành cho thử và sai, và googling xung quanh, tôi nhận ra rằng security.context
được thiết lập trước khi thực hiện onKernelRequest
. Bây giờ câu hỏi là cách để chèn chi tiết kết nối cơ sở dữ liệu vào security.context và trong đó để tiêm?
Chúng tôi cần phải đến điểm mà bối cảnh bảo mật và DBAL được đặt và mã thông báo bảo mật được tạo và chúng tôi có thể thao tác chi tiết kết nối cơ sở dữ liệu.
Do đó, khi người trong liên kết sau đã nêu, tôi đã thực hiện thay đổi đối với mã của mình, vì đó chính xác là những gì tôi muốn thực hiện. http://forum.symfony-project.org/viewtopic.php?t=37398&p=124413
Điều này khiến cho tôi những đoạn mã sau thêm vào dự án của tôi:
#config.yml //remains unchanged, similar to above code
Một trình biên dịch vượt qua được tạo ra như sau:
// 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());
}
}
Trình biên dịch thông qua như sau:
# 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]);
}
}
}
Mã lớp trình điều khiển như sau:
# 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());
}
}
Mã trên đã được thêm vào dự án của tôi và tôi cho rằng đây là công việc thực tế xung quanh cho vấn đề của tôi.
Nhưng bây giờ tôi nhận được lỗi sau:
ServiceCircularReferenceException: Circular reference detected for service "security.context", path: "profiler_listener -> profiler -> security.context -> security.authentication.manager -> fos_user.user_provider.username_email -> fos_user.user_manager -> doctrine.orm.dynamic_manager_entity_manager -> doctrine.dbal.dynamic_conn_connection".
thế nào, tôi có thể nhận được mã của tôi để làm việc? Tôi đặt cược rằng tôi đang làm điều gì đó sai ở đây và tôi sẽ đánh giá cao bất kỳ gợi ý và giúp đỡ.
là mã bằng cách sử dụng 'security.context' chạy * trước *' cái sự kiện onKernelRequest'? một số phụ thuộc của security.context phải sử dụng 'dynamic_em' – arnaud576875
Mã security.context được thêm vào cùng một hành động trong đó mã getRespository được thêm vào. Do đó tôi giả định rằng onKernelRequest được thực hiện trước security.context. –
@ John Tôi vừa thử nghiệm nó với Sf 2.3.2 và giải pháp đầu tiên của bạn làm việc cho tôi. Tôi đã sử dụng một người đăng ký sự kiện để sửa đổi đối tượng kết nối. Bộ điều khiển sau này đã tìm nạp một hàng từ cơ sở dữ liệu "nô lệ" và tải người dùng hiện đang đăng nhập (đã sử dụng 'FOSUserBundle'). Bối cảnh bảo mật không được phổ biến trong giai đoạn điều phối sự kiện và ngay từ cái nhìn đầu tiên tôi nghĩ nó đơn giản là vấn đề thay đổi các ưu tiên của người nghe. Nếu bạn chưa biết nó thì có lẽ bạn có thể cho tôi biết bạn đang sử dụng phiên bản Symfony nào? – gilden