Connect to Multiple Databases on Different Servers - php

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

Related

An exception occurred in driver: SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it. - error in Symfony

I'm trying to connect to my aws rds database with symfony. But I constantly get an error: An exception occurred in driver: SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it.". My security groups are open to all ports and here are my settings.
//services.yaml
parameters:
database_driver: pdo_mysql
database_host: '%env(RDS_HOSTNAME)%'
database_port: '%env(RDS_PORT)%'
database_name: '%env(RDS_DB_NAME)%'
database_user: '%env(RDS_USERNAME)%'
database_password: '%env(RDS_PASSWORD)%'
//doctrine.yaml
doctrine:
dbal:
# if the url option is specified, it will override the above config
default_connection: default
connections:
default:
dbname: '%env(RDS_DB_NAME)%'
user: '%env(RDS_USERNAME)%'
password: '%env(RDS_PASSWORD)%'
host: '%env(RDS_HOSTNAME)%'
driver: 'pdo_mysql'
port: 3306
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App
In .env you are the correct variables.
If someone has a fix, please provide it to me :)
I found the problem.
Currently, I'm a student and living in a student dorm. My dorm network is blocking the connection with an outside MySql server so that's why I repeatedly get this error.
The solution would be to use a non-public source of the internet or try to share internet from some other device. You could also use a VPN (make sure to test first because with some of them the same error ocurrs).

Symfony 4 Doctrine 2, Mapping entity, error table has no primary key,

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.

Create Entity Manager in Symfony3?

I have an existing entity in a Symfony3 project that I am trying to add an entity manager to. My doctrine.yml file looks like this
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: localhost
port: 3306
dbname: fullstackdb
user: root
password: root
charset: UTF8
lego:
driver: pdo_mysql
host: localhost
port: 3306
dbname: fullstackdb
user: root
password: root
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
auto_mapping: true
default:
connection: default
mappings:
lego:
connection: lego
mappings:
AppBundle: ~
However anytime I try to access this entity manager through php bin/console doctrine:database:create --connection=lego
, it says the manager does not exist! I'm not sure if I'm missing a step - the only thing I've done to create the manager is to make the yml file.
It doesn't show up when I run bin/console debug:container.
Grateful for any help!
1) You are using the same schema name (database name) on the same host in two different entity managers without schema_filters. This means that when you do an update to one of the entity managers it will attempt to delete the data of the other entity manager.
2) You are asking about a entity manager but in the command you are passing a connection.
3) Run php bin/console debug:container | grep doctrine
This will give you all the doctrine services. Update your question accordingly.
4) Provide the exact command and exact error you get so we can track it down to the origin
5) For a more information run the command in verbose mode adding -v at the end
6) Are you importing your doctrine.yml in your config.yml ?

Multiple connections and entity managers in a symfony 2 / 3 application

My multi-tenant-app uses a master database, that holds information about tenants (like name, etc.) and a app-specific database per tenant.
I configured a master and some_tenant connection and entity manager in the doctrine section inside config.yml.
This gives me access to the master database from a controller (eg. for validating and getting tenant information for some_tenant based on the subdomain some_tenant.my-app.com). And it lets me use a tenant-specific database and entity manager during the application life-cycle.
The doctrine section in my config looks like this:
doctrine:
dbal:
default_connection: 'master'
connections:
master:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
some_tenant:
driver: pdo_mysql
host: "%database_host_some_tenant%"
port: "%database_port_some_tenant%"
dbname: "%database_name_some_tenant%"
user: "%database_user_some_tenant%"
password: "%database_password_some_tenant%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
master:
connection: master
mappings:
BEMultiTenancyBundle: ~
some_tenant:
connection: some_tenant
mappings:
AppBundle: ~
Here comes the part, which I am unhappy with and cannot find a solution:
First of all, tenants will be more than 20. And it starts to get messy, altering the doctrine config this way.
Then there is another config file, called tenants.yml which holds more information like enabled/disabled app-features, tenant-specific themes, etc.
The file is loaded, validated using the Config Component, and a container parameter is set, so that tenants configurations are available app-wide.
I would like to store the database credentials also in that file.
I want to create connections and entity managers based on that config. One per each tenant, which can be used during the app life-cycle.
I need to have them available also at the console command bin/console doctrine:schema:update --em=some_tenant for updating each tenant's database schem and bin/console doctrine:schema:update --em=master for updating the master database scheme.
By now I guess, the only way to achieve this is to add configuration parameters to the doctrine section programmatically after the AppBundle is loaded, and before the doctrine registry is constructed with the given managers and connections.
But I cannot even find a point, where I could achive this.
Is there another way to get to point 1 and 2?
Even though there is a similiar question, which I am not sure if it is exactly about the same problem and is about 3 years old, I wanted to post this question with a bit more explanation.
The solution in comments is a straight way easy solution and it will work. The other solution I've ever meet is to dynamically replace tenant database credentails using some external conditions, i.e request HOST.
You can decorate or extend the connection factory with a service in a way, that having the request stack available (or providing the domain with ENV or console argument for other SAPI's) you can have the same entity manager (even default!) being configured on demand.
on a brief look this would look like
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Symfony\Component\HttpFoundation\RequestStack;
class DynamicConnectionFactory extends Factory
{
/** #var RequestStack */
private $requestStack;
public function __construct(array $types, RequestStack $stack)
{
parent::__construct($types);
$this->requestStack = $stack;
}
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array())
{
$host = $this->requestStack->getMasterRequest()->getHost();
$params = $this->replaceParamsForHost(array $params, $host);
return parent::createConnection($params, $config, $eventManager, $mappingTypes);
}
private function replaceParamsForHost(array $params, $host)
{
//do your magic, i.e parse config or call Memcache service or count the stars
return array_replace($params, ['database' => $host]);
}
}
I think that, To manage multi-tenant with symfony 2/3.
We can config auto_mapping: false for ORM of doctrine.
file: config.yml
doctrine:
dbal:
default_connection: master
connections:
master:
driver: pdo_mysql
host: '%master_database_host%'
port: '%master_database_port%'
dbname: '%master_database_name%'
user: '%master_database_user%'
password: '%master_database_password%'
charset: UTF8
tenant:
driver: pdo_mysql
host: '%tenant_database_host%'
port: '%tenant_database_port%'
dbname: '%tenant_database_name%'
user: '%tenant_database_user%'
password: '%tenant_database_password%'
charset: UTF8
orm:
default_entity_manager: master
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
master:
connection: master
auto_mapping: false
mappings:
AppBundle:
type: yml
dir: Resources/master/config/doctrine
tenant:
connection: tenant
auto_mapping: false
mappings:
AppBundle:
type: yml
dir: Resources/tenant/config/doctrine
After that, we cannot handle connection of each tenant by override connection info in request_listener like article: http://mohdhallal.github.io/blog/2014/09/12/handling-multiple-entity-managers-in-doctrine-the-smart-way/
I hope that, this practice can help someone working with multi-tenant
Regards,
Vuong Nguyen

Doctrine connection with db

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

Categories