Symfony, Doctrine, Configuration and the Symfony Cache

868 Views Asked by At

I have a Symfony application that shares the same codebase for many DBs.

It's quite typical, I have a single database for each "instance" (or "account") of my application, which is a simple medical appointments tool. I need to keep this architecture as is.

However, we are migrating from Symfony 2.8 to Symfony 4. Before Symfony 4, I had to create a "pseudo-prod" Symfony environment for each DB, because Symfony (with Doctrine) is very tied to having a single DB specified by the config, and even using env vars like SYMFONY__DATABASE__NAME, the database connection properties get hardcoded into the cache, so I needed to create a different environment for each app instance, hence creating a cache dir for each account, which is far from ideal.

Will the new env vars features from Symfony 4 make dynamic DB connection more feasible in a "native" manner?

Should I use another method to achieve this? (for example, creating a custom connection factory, etc)

I would like to have a single cache for my prod environment, and let the connection parameters be dynamic.

Any ideas appreciated. Thanks!

Note:

This is NOT a duplicate of: Using Relationships with Multiple Entity Managers

I am already using multiple entity managers, it has nothing to do with that.

1

There are 1 best solutions below

5
dbrumann On

Setting up your application for different hosts with Symfony 4 should be straight forward. You can just provide the DATABASE_URL as environment variable to each host, e.g. with nginx:

server {
    server_name domain.tld www.domain.tld;
    root /var/www/project/public;
    location / {
        try_files $uri /index.php$is_args$args;
    }
    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php7.1-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        fastcgi_param DATABASE_URL "mysql://db_user:db_pass@host:3306/db_name";

        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;

        internal;
    }
    location ~ \.php$ {
        return 404;
    }
    error_log /var/log/nginx/project_error.log;
    access_log /var/log/nginx/project_access.log;
}

The import bit is fastcgi_param DATABASE_URL ....

By default all instances will use the same cache dir, which is probably not what you want. Imagine customer A seeing customer B's data, because it's pulled from cache and B accessed it first.

A way around this is to modify src/Kernel.php to factor in some other env variable, the project's base name or some other info identifying each host and append that to the cache base directory defined in getCacheDir. By default it looks like this:

public function getCacheDir(): string
{
    return dirname(__DIR__).'/var/cache/'.$this->environment;
}

You could also use Symfony's built in cache component to specify different app.caches per host instead. This way you can possibly reuse the system cache responsible for caching the container, annotations, validations, etc.

You can find the cache configuration in your config/packages/framework.yml under framework.cache. See: https://speakerdeck.com/dbrumann/caching-in-symfony-an-overview?slide=37