I am about to start a project in doctrine symfony, but I have to make connection with multiple databases. One of them is an existing database (SQL SERVER) that cannot be mapped with ORM. Is there any possibility to connect with this db with another db that is NOT mapped in doctrine and work with controllers normally?
I develop a multi-database sf2 app with doctrine2 orm mapping.
We use intellectsoft-uk/MssqlBundle
Our configuration is:
config.yml
# Doctrine Configuration
doctrine:
dbal:
default_connection: acme_mysql
connections:
acme_mysql:
host: %acme_mysql_database_host%
port: %acme_mysql_database_port%
dbname: %acme_mysql_database_name%
user: %acme_mysql_database_user%
password: %acme_mysql_database_password%
charset: UTF8
acme_slqsrv:
driver: sqlsrv
driver_class: \Realestate\MssqlBundle\Driver\PDODblib\Driver
host: %acme_slqsrv%
port: %acme_slqsrv%
dbname: %acme_slqsrv%
user: %acme_slqsrv%
password: %acme_slqsrv%
charset: UTF8
orm: #optional if you want to map some entity in doctrine2
auto_generate_proxy_classes: %kernel.debug%
default_entity_manager: acme_mysql
entity_managers:
em_mysql:
connection: acme_mysql
mappings:
AcmeMysqlBundle: ~
em_sqlsrv:
connection: acme_sqlsrv
mappings:
AcmeSqlSrvBundle: ~
This configuration permit you to take a connection instance in a controller/service and use it for access database and execute stored procedures and so on...
Hope this help
Related
I used this documentation : https://symfony.com/doc/4.4/doctrine/multiple_entity_managers.html
So now I can create new databases named legacy and Project like this
doctrince.yaml:
doctrine:
dbal:
default_connection: legacy
connections:
legacy:
driver: pdo_mysql
host: "%env(database_host)%"
port: "%env(database_port)%"
dbname: "%env(database_name)%"
user: "%env(database_user)%"
password: "%env(database_password)%"
charset: UTF8
project:
driver: pdo_mysql
host: "%env(database_host_project)%"
port: "%env(database_port_project)%"
dbname: "%env(database_name_project)%"
user: "%env(database_user_project)%"
password: "%env(database_password_project)%"
charset: UTF8
orm:
default_entity_manager: legacy
entity_managers:
legacy:
connection: legacy
mappings:
Legacy:
is_bundle: false
type: annotation
dir: "%kernel.project_dir%/..."
prefix: '...'
alias: Legacy
project:
connection: project
auto_mapping: true
mappings:
Project:
is_bundle: false
type: annotation
dir: "%kernel.project_dir%/src/Entity"
prefix: 'App\Entity'
alias: Project
Now I have several Fixture classes all of them depend on each other and also some will create fixture for legacy and some will create for project.
Now my question is when I do:
php bin/console doctrine:fixtures:load --em=legacy
It runs the appfixtures of the project but not the of the bundle.
and then i get this error:
The class .. was not found in the chain configured namespaces ....
My question is now how can I load fixtures on multiple databases with multiple connections.
Thanks in advance.
You should read this doc : https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
I think it may solve your problem as this is exactly what you trying to do.
If you have to create a fixture for legacy just use :
$entityManager = $this->getDoctrine()->getManager('legacy');`
else if it is for project use
$entityManager = $this->getDoctrine()->getManager('project');`
Also, if you change doctrine.dbal.default_connection, entityManager will run against the defined connection.
So you can try to create group of fixtures.
And then run fixtures for project :
Edit config for test environment
#config/packages/test/doctrine.yaml
doctrine:
dbal:
default_connection: 'project'
Then run fixture for 'project' group
> php bin/console doctrine:fixtures:load --group=project
Then do the same thing for 'legacy'
I'm about to embark on using RDS with a master read/write and slave read-only setup.
I've read about the Doctrine MasterSlaveConnection type.
However, there will be some endpoints I create that I would like to use the read-only replica (most of my GET endpoints) and some will need to write data (PUT, PATCH, DELETE endpoints).
I'm also using API Platform.
What is the best way of achieving this in Symfony 4 and Doctrine 2?
What I have done in the past is to just use different connections.
Something like:
doctrine:
dbal:
default_connection: default
connections:
default:
# This is your Master
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
slave:
# This would be the slave
url: '%env(DATABASE_SLAVE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
slave:
connection: slave
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: Main
https://symfony.com/doc/current/doctrine/multiple_entity_managers.html
Then in your controllers or business logic you can either choose to use the default entity manager:
// Controller
$this->getDoctrine()->getEntityManager();
Or you can get the slave connection:
// Controller
$this->getDoctrine()->getEntityManager('slave');
If you need this to work just on all requests without having to create special actions for everything then your best bet is to decorate the Collection and Item DataProviders for doctrine.
https://symfony.com/doc/current/service_container/service_decoration.html
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/CollectionDataProvider.php
https://github.com/api-platform/core/blob/master/src/Bridge/Doctrine/Orm/ItemDataProvider.php
So basically you need to change what manager is chosen based on the $opperationName something like:
if($opperationName === 'GET'){
$manager = $this->managerRegistry->getManager('slave');
} else {
$manager = $this->managerRegistry->getManager();
}
You actually don't need to setup multiple entity managers, nor is it preferable as handling one entity with multiple entity managers is hard.
Using Doctrine 2.2, you can setup slaves/replicas directly from configuration without needing an extra entity manager:
See the config reference here:
https://www.doctrine-project.org/projects/doctrine-bundle/en/2.2/configuration.html#configuration-overview
Example:
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: '%env(DATABASE_DBNAME)%'
user: '%env(DATABASE_USER)%'
password: '%env(DATABASE_PASSWORD)%'
host: '%env(DATABASE_HOST)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
slaves:
ro_replica:
dbname: '%env(REPLICA_DBNAME)%'
user: '%env(REPLICA_USER)%'
password: '%env(REPLICA_PASSWORD)%'
host: '%env(REPLICA_HOST)%'
charset: utf8mb4
Thank you #Chase for the solution. You have made my day. Although it works for me in 'dev' environment I had a problem when switched to 'prod'. I was getting an error that an Entity can not be found. The solution came from this post - thanks #xabbuh. Basically I had to add default_entity_manager: name_of_default_em to doctrine.yml. Here is the copy of the code:
# config/packages/prod/doctrine.yaml
doctrine:
orm:
default_entity_manager: BOE <- add this line to let know prod about default em
auto_generate_proxy_classes: false
metadata_cache_driver:
type: service
id: doctrine.system_cache_provider
query_cache_driver:
type: service
id: doctrine.system_cache_provider
result_cache_driver:
type: service
id: doctrine.result_cache_provider
# ...
I have been using Symfony with Doctrine for some time, and up until now was able to configure Doctrine to connect to several databases on the same server (IP), through the config.yml.
But now I have a different scenario.
I am working on a case, that has multiple projects running on different IP adresses. I can connect with the database that runs locally on the machine that also hosts the main application, but now I need to connect to another database that's hosted on another server. So, to lay out this case:
Server Alpha. IP: 193.15.15.15, database name: "Foo"
Server Beta. IP: 193.15.15.16, database name: "Bar"
I have defined the user and password for each of these databases in my parameters.yml, so that is no biggie. I just would like to know if it's possible to connect to the (locally hosted) database on server Beta, while the application is on server Alpha.
Thanks in advance!
You should configure multiple entity managers and connections
On the file config.yml :
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: '193.15.15.15'
port: '%port_parameter_for_foo%'
dbname: 'Foo'
user: '%user_parameter_for_foo%'
password: '%pass_parameter_for_foo%'
charset: UTF8
customer:
driver: pdo_mysql
host: '193.15.15.16'
port: '%port_parameter_for_bar%'
dbname: 'Bar'
user: '%user_parameter_for_bar%'
password: '%pass_parameter_for_bar%'
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
BundleOnAlpha: ~
customer:
connection: beta
mappings:
BundleOnBeta: ~
The doc is more complete:
https://symfony.com/doc/3.4/doctrine/multiple_entity_managers.html
A symfony noob here. Been trying since morning to map entity/s of the database using Doctrine via console throws up no primary key error. The mysql server is a remote one which I unfortunately only have read access and I am not able to create a primary key. I did see a few questions on SO with the exact same issue but they were unanswered and old.
I tried https://medium.com/#joaoneto/solves-doctrine-orm-error-with-tables-without-primary-key-on-mysql-when-mapping-the-database-1ce740610b51
but again it throws up error regarding empty columns.
Call to a member function getColumns() on null
My doctrine.yaml. Obviously I altered the connection details.
doctrine:
dbal:
default_connection: default
connections:
# configure these for your database server
default:
driver: 'pdo_mysql'
host: 'localhost'
port: '3306'
dbname: 'symfony_test_db'
user: 'root'
password: ''
charset: utf8mb4
customer:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'sg3_symfony_db'
user: 'sguser'
password: 'password'
charset: UTF8
backoffice:
driver: 'pdo_mysql'
host: 'localhost'
port: '3306'
dbname: 'back_office'
user: 'backoffice_user'
password: 'password'
charset: UTF8
one:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'one_db'
user: 'one_user'
password: 'password'
charset: UTF8
staging:
driver: 'pdo_mysql'
host: 'xxx.xxx.xx.xxx'
port: '3306'
dbname: 'staging'
user: 'staginguser'
password: 'password'
charset: UTF8
# With Symfony 3.3, remove the `resolve:` prefix
#url: '%env(resolve:DATABASE_URL)%'
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
#auto_mapping: true
mappings:
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Main'
prefix: 'App\Entity\Main'
alias: Main
customer:
connection: customer
mappings:
Customer:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Customer'
prefix: 'App\Entity\Customer'
alias: Customer
backoffice:
connection: backoffice
mappings:
Backoffice:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Backoffice'
prefix: 'App\Entity\Backoffice'
alias: Backoffice
one:
connection: mt4
mappings:
One:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/One'
prefix: 'App\Entity\One'
alias: One
staging:
connection: staging
mappings:
staging:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity/Staging'
prefix: 'App\Entity\Staging'
alias: Staging
CLI command I use to map but fails.
php bin/console doctrine:mapping:convert --from-database annotation --force --em=one ./src/Entity/One/ --verbose
In this case, sometimes you need to walk around.
This error:
Table ____ has no primary key. Doctrine does not support reverse
engineering from tables that don’t have a primary key.
So.
Doctrine can not work on tables that have no primary key.
In MySQL, create tables without PK will always be a bad idea, but, in some cases (or legacy systems) that not have PKs on some tables, you still can use Doctrine as ORM.
However, by default (and I believe this will not change) if your database has tables without primary key Mapping simply will not work.
The more fast way to solve this is override the vendor class DatabaseDriver, in the namespace:
namespace Doctrine\ORM\Mapping\Driver;
On line 289, change:
if ( ! $table->hasPrimaryKey()) {
continue;
// throw new MappingException(
// "Table " . $table->getName() . " has no primary key. Doctrine does not ".
// "support reverse engineering from tables that don't have a primary key."
// );
}
To avoid any future problems, after mapping your database, return the settings to avoid any problems later.
Good luck!
Reference: Solves Doctrine ORM Error with tables without Primary Key on MySQL when mapping the database.
Not a very clean solution but for the moment I managed to do it by, exporting the schema of tables I need and recreating them on my local server. Forcing Pk's on the tables that did not have PK defined. This created entity class files instantly and worked like a charm.
I have MySQL cluster with master server and 4 slaves.
The site based on Symfony3, Doctrine is used as ORM and DBAL.
My config for Doctrine looks like this:
doctrine:
dbal:
default_connection: default
connections:
default:
dbname: "%default_db_master_name%"
host: "%default_db_master_host%"
port: "%default_db_master_port%"
user: "%default_db_master_user%"
password: "%default_db_master_password%"
charset: UTF8
driver: "%default_db_master_driver%"
logging: "%kernel.debug%"
profiling: "%kernel.debug%"
wrapper_class: AppBundle\Connection\AppMasterSlaveConnection
mapping_types:
enum: string
slaves:
slave1:
host: "%default_db_slave1_host%"
port: "%default_db_slave_port%"
dbname: "%default_db_slave_name%"
user: "%default_db_slave_user%"
password: "%default_db_slave_password%"
slave2:
host: "%default_db_slave2_host%"
port: "%default_db_slave_port%"
dbname: "%default_db_slave_name%"
user: "%default_db_slave_user%"
password: "%default_db_slave_password%"
I would like to add weights for slaves, because they hardware is not equal, some of them are more productive, some less.
Also I would like to inject memcache service (or inject params for creating cache service object) for putting temporarely dns which are overloaded by requests and give them chance to back to normal.
For example, I want to inject weight param for slaves following way:
slave1:
host: "%default_db_slave1_host%"
port: "%default_db_slave_port%"
dbname: "%default_db_slave_name%"
user: "%default_db_slave_user%"
password: "%default_db_slave_password%"
weight: "%default_db_slave1_weight%"
slave2:
host: "%default_db_slave2_host%"
port: "%default_db_slave_port%"
dbname: "%default_db_slave_name%"
user: "%default_db_slave_user%"
password: "%default_db_slave_password%"
weight: "%default_db_slave2_weight%"
When I add this option, I receive an error
InvalidConfigurationException in ArrayNode.php line 317:
Unrecognized option "weight" under "doctrine.dbal.connections.default.slaves.slave1"
I don't know how to do it. I have just one idea, transfer all these params via Driver options,something like this
logging: "%kernel.debug%"
profiling: "%kernel.debug%"
wrapper_class: AppBundle\Connection\AppMasterSlaveConnection
options:
slave1: 5
slave2: 25
slave3: 45
slave4: 25
cache: '%memcached_db%'
mapping_types:
enum: string
slaves:
slave1:
But it looks awful.
Help me please.