Mapping entities across 2 (or more) databases - symfony

Context
I'm developing a website where I have to use data from two distinct databases (one local with full access, one external on read only).
One of "local" entities needs mapping to an "external" entity.
The external entity won't have its data changed since I can't persist these to the DB anyway.
Question
Is there a way to mark this mapping so that the external entity is pulled along when I retrieve the local entity ?

Short answer, No.
You can setup multiple database connections and use the same entity classes for both of them. But a single entity will not be able to have properties that map to different databases. You may have reference fields on there but those will need to just be keys that you can use to look them up using the other connection. For example imagine the following setup:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: '%database_driver%'
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
customer:
driver: '%database_driver2%'
host: '%database_host2%'
port: '%database_port2%'
dbname: '%database_name2%'
user: '%database_user2%'
password: '%database_password2%'
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
AcmeBundle: ~
customer:
connection: customer
mappings:
AcmeBundle: ~
Both managers will use the entity classes in the AcmeBundle. Then you can do something like
public function someControllerAction(){
// Get customer from the default connection
$customer = $this->getDoctrine()
->getManager() // If no value is provided the default is implied
->getRepository('AcmeBundle:Customer')
->findOneBy([
'id'=>12
]);
// Get the customers details from another connection
$customerDetails = $this->getDoctrine()
->getManager('customer')
->getRepository('AcmeBundle:CustomerDetails')
->findOneBy([
'customer_details_id' => $customer->getDetailsId()
]);
...
}

Related

Symfony wrong persist database working with two entity managers

I have the same symfony app deployed in two servers.
I use two entity managers, one called defaul with a connection on "local" database and the other called online on the "remote" database
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '%database_host%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
charset: UTF8
online:
driver: pdo_mysql
host: '%database_host2%'
port: '%database_port2%'
dbname: '%database_name2%'
user: '%database_user2%'
password: '%database_password2%'
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: default
entity_managers:
default:
dql:
string_functions:
GROUP_CONCAT: AppBundle\DQL\GroupConcatFunction
connection: default
mappings:
LexikTranslationBundle: ~
AppBundle: ~
LilWorksStoreBundle: ~
online:
connection: online
mappings:
AppBundle: ~
LilWorksStoreBundle: ~
I copy some entities from the remote database to the local app within a service. My service get the two entity managers
services:
app.syncro:
class: AppBundle\Service\Syncro
arguments: ['#doctrine.orm.default_entity_manager','#doctrine.orm.online_entity_manager']
I clone the remote entity and I try to persist it in my local
$user = $this->emRemote->getRepository("AppBundle:User")->find(1);
$clonedUser = clone $user;
$this->emLocal->persist($clonedUser->cloneUser());
$this->emLocal->flush();
The flush don't persist in the local database but try to persist in the distant.
Is something in my configuration doesn't works? Maybe my entity still have the remote database name stored in proxy?

How to create a Second database connection with Symfony2?

I'm trying to connect a second database to my project in Symfony2. First, I added into parameters.yml some parameters to create the connection.
Then, I edited my config.yml, and now looks like:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
circutor3:
driver: pdo_sqlsrv
host: "%database_host_circutor3%"
port: "%database_port_circutor%"
dbname: "%database_name_circutor%"
user: "%database_user_circutor3%"
password: "%database_password_circutor3%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
Finally, I tried to get connected, using the following code in my controller:
$em = $this->getDoctrine()->getManager('circutor3');
And, the error returned by Symfony2:
Doctrine ORM Manager named "circutor3" does not exist.
The circutor3 makes connection to a database, external to my system, so I don't need to create entities or objects. I only need to execute some SELECT to get information and store it using an array.
Is creating a typical mysqli connection the best way to solve my problem?
I don't know how to solve this with Symfony.
Thank you in advance.
you could access to the database connection in the controller as follow:
$connection = $this->getDoctrine()->getConnection('circutor3');
then use the connection as:
$stmt = $connection->prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
Some help here and here
Hope this help
According to Symfony documentation (http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html), you only defined a connection, not an entity manager :
You have to create an entity_manager for each connection.
orm:
default_entity_manager: default
entity_managers:
default:
...
circutor3:
connection: circutor3
mappings:
AppBundle: ~

Entity MetaData for Doctrine and multiple Entity Managers

I'm trying to setup an Sql Server connection for Doctrine in Symfony2.However I can not figure out how to setup some Entity Foo to be managed by the new Entity Manager.
I have seen this post in regards to managing Entities with multiple Entity Managers, however I don't know how to use it with different Entity Managers like this. What metadata should I use so I can handle some of My entities with the new Entity Manager?
You can put Foo entity to separate bundle i.e MyFooBundle (if you have single core/app bundle) and map the bundle to other entity manager.
Disable auto mapping and configure connections at config.yml then define the entity managers and mapping
doctrine:
dbal:
connections:
default:
driver: %database_driver%
host: %database_host%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
other:
driver: %database_driver_2%
host: %database_host_2%
dbname: %database_name_2%
user: %database_user_2%
password: %database_password_2%
charset: UTF8
orm:
entity_managers:
default:
connection: default
mappings:
FOSUserBundle: ~
AppBundle: ~
other:
connection: other
mappings:
MyFooBundle: ~

Symfony2 and Doctrine APC Cache

i have read the documentation of symfony2 in relation to the performance and I have realized the following steps.
Install APC 'php-apc' on my webserver and restart my webserver
Modify my doctrine configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
metadata_cache_driver: apc
result_cache_driver: apc
query_cache_driver: apc
Now if i call a action to retrieve all users from database i see in the information bar at the bottom that doctrine execute every time 114 queries. Why the queries not cached?
My action look like this:
$users = $this->getDoctrine()->getRepository('AppUserBundle:User')->findAll();
return $this->render('AppUserBundle:User:index.html.twig', array('users' => $users));
Doctrine doesn't cache query results by default. You have to explicitly point that you want to cache query using useResultCache method. For example, if you'd like to cache getting all users, write your own method in User repository class:
use Doctrine\ORM\EntityRepository;
class UserRepository extends EntityRepository
{
public function fetchAll()
{
$query = $this->createQueryBuilder('u')->getQuery();
return $query->useResultCache(true)->getResult();
}
}
The method may take additional arguments:
public function useResultCache($bool, $lifetime = null, $resultCacheId = null)
$bool - set to true if you want to cache query result
$lifetime - TTL of cached result in seconds
$resultCacheId - you can pass your own id, in case of null Doctrine will handle that

How can I specify the database to reverse engineer?

I'm following this guide on reverse engineering a database. The guide says it uses the paramters.yml file for the database parameters, but how can I override this? I have several connections listed in my config.yml, and I'd like to be able to choose one of them.
Use the --em parameter to specify which entity manager you want to use.
doctrine:mapping:convert [--filter="..."] [--force] [--from-database] [--extend[="..."]] [--num-spaces[="..."]] [--namespace[="..."]] [--em[="..."]] to-type dest-path
If you assign each Doctrine connection to its own Entity Manager, then you can specify the entity manager with the --em="entity_manager_name" flag. However, you will have to manually map each bundle to an entity manager. In the following example config, the other connection and entity manager are named customer
$ php app/console doctrine:mapping:convert yml ./src/Acme/CustomerBundle/Resources/config/doctrine/metadata/orm --em="customer" --from-database --force
config.yml
# Doctrine Configuration
doctrine:
dbal:
default_connection: default
connections:
default:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
customer:
driver: %database_driver2%
host: %database_host2%
port: %database_port2%
dbname: %database_name2%
user: %database_user2%
password: %database_password2%
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
AcmeDemoBundle: ~
AcmeStoreBundle: ~
customer:
connection: customer
mappings:
AcmeCustomerBundle: ~

Resources