Kazenone65
Kazenone65

Reputation: 13

How to set default database depending on subdomain in symfony 4.2

I recently started working with Symfony 4 and I'm looking forward to setting default database depending on subdomain.

It's about an application i need to deploy for multiple customers, and each one have their specific database.

i started working with connections like below. the idea would be to set once and for all the default connection with a variable from the env, but I don't know how.

Am I doing this the right way?

doctrine:
    dbal:
        default_connection: customer1
        connections:
        customer1:
            url: '%env(DATABASE_CUSTOMER1_URL)%'
            driver: 'pdo_mysql'
            server_version: '5.7'
            charset: utf8mb4
            default_table_options:
                charset: utf8mb4
                collate: utf8mb4_unicode_ci
        customer2:
            url: '%env(DATABASE_CUSTOMER2_URL)%'
            driver: 'pdo_mysql'
            server_version: '5.7'
            charset: utf8mb4
            default_table_options:
                charset: utf8mb4
                collate: utf8mb4_unicode_ci

Upvotes: 1

Views: 1185

Answers (4)

Pablo
Pablo

Reputation: 105

I've been there. You don't need to use separate connections, or environments. Adding a new environment would be adding a ton of cache files.

You can set environment variables at web server level depending in the subdomain, you can use VirtualDocumentRoot in apache, or just a server alias with wildcards in Nginx.

Define an environment variable for each subdomain in your webserver and you'll be able to use it in your config files.

Upvotes: 0

svince
svince

Reputation: 1

Did you try something like that ?

In your bootstrap :

// load all the .env files
//  (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
$d = new Dotenv(false);
$d->loadEnv(dirname(__DIR__).'/.env');
$s = dirname(__DIR__).'/.env.'.filter_input(INPUT_SERVER, 'SERVER_NAME');
if (is_readable($s) ) {
    $d->load($s);
}

And create different .env.server_name with

# your server_name database
DATABASE_URL=mysql://user:secret@localhost/mydb

Symfony Profiler

Upvotes: 0

Ludo
Ludo

Reputation: 512

Another way is to create separate environments and corresponding index_*.php files to which you point your webserver. Pretty much create 2 new copies of application entry index.php file - public/index_customer1.php and public/index_customer2.php. Inside you change environment which Symfony uses:

<?php
...
$kernel = new AppKernel('customer1', false); # or new AppKernel('customer2', false)
...
?>

And now you need to have separate configuration of Doctrine for both of these environments. In config/packages/customer1/config.yml:

imports:
    - { resource: '../prod/' } # imports default prod env config

doctrine: # specify different database connection for whole env
    dbal:
        default_connection: default
        connections:
            default:
                url: '%env(DATABASE_CUSTOMER1_URL)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4

and in config/packages/customer2/config.yml

imports:
    - { resource: '../prod/' }

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                url: '%env(DATABASE_CUSTOMER2_URL)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4

https://symfony.com/doc/master/configuration/environments.html

And you need to configure your webserver to point to different index.php, based on domain.

Upvotes: 1

Ludo
Ludo

Reputation: 512

You are on the right track from configuration point of view. But keep in mind those connections are not triggered by the subdomain of the HTTP request but are simply just connecting to different database server based on call in actual PHP code.

Your env DATABASE_CUSTOMER?_URL variable should be specifying connection to MySQL instance, something like 'mysql://user:secret@localhost/mydb'

And doctrine configuration YAML should be formatted a bit differently and should include EntityManager config.

doctrine:
    dbal:
        default_connection: customer1
        connections:
            customer1:
                url: '%env(DATABASE_CUSTOMER1_URL)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4
            customer2:
                url: '%env(DATABASE_CUSTOMER2_URL)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4

    orm:
        default_entity_manager: customer1
        entity_managers:
            customer1:
                connection: customer1
            customer2:
                connection: customer2                

https://symfony.com/doc/current/doctrine/multiple_entity_managers.html

You now can specify which Connection/EntityManager you want to use. You can differentiate between them eg. in your Controllers by http host.

    public function someAction(Request $request)
    {
        if ($request->getHttpHost() === 'customer2url.com') {
            $em = $this->getDoctrine()->getManager('customer2');
        } else {
            $em = $this->getDoctrine()->getManager();
        }
    }

or call repository

$this->getDoctrine()->getRepository(Entity::class, 'customer1')

Upvotes: 0

Related Questions