(im assuming you are using Symfony version 4 or higher - but should also work in earlier versions with slight modifications)
Part 1 - loading container parameters from php
- Create file "config/my_config.php" like this:
<?php
$container->setParameter('my_param', 'something1');
$elements = [];
$elements[] = 'yolo1';
$elements[] = 'yolo2';
$container->setParameter('my_param_which_is_array', $elements);
- In your services.yaml file import "my_config.php" like this:
imports:
- { resource: my_config.php }
- Clear cache.
- Check if those parameters are loaded in container - for example by running following commands:
php bin/console debug:container --parameter=my_param
----------- ------------
Parameter Value
----------- ------------
my_param something1
----------- ------------
php bin/console debug:container --parameter=my_param_which_is_array
------------------------- -------------------
Parameter Value
------------------------- -------------------
my_param_which_is_array ["yolo1","yolo2"]
------------------------- -------------------
If above steps work then you can use your parameters from container in your application.
Important warning: If you will store security credentials in such php file (db user and password etc) then make sure you are not adding it to repository along with code of rest of your application - so add it to ".gitignore" similarily as ".env" is added there.
For more info about handling of symfony parameters see https://symfony.com/doc/current/service_container/parameters.html (on the code snippets click the "PHP" tab instead of "YAML" to see PHP examples)
Part 2 - using different database depending on url(host) or CLI parameter
To dynamically choose database connection credentials we can use a doctrine connection factory. We will decorate default service 'doctrine.dbal.connection_factory' with our modified version:
Create new file "src/Doctrine/MyConnectionFactory.php":
<?php
namespace App\Doctrine;
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\HttpFoundation\Request;
class MyConnectionFactory
{
/**
* @var array
*/
private $db_credentials_per_site;
/**
* @var ConnectionFactory
*/
private $originalConnectionFactory;
public function __construct($db_credentials_per_site, ConnectionFactory $originalConnectionFactory)
{
$this->db_credentials_per_site = $db_credentials_per_site;
$this->originalConnectionFactory = $originalConnectionFactory;
}
/**
* Decorates following method:
* @see \Doctrine\Bundle\DoctrineBundle\ConnectionFactory::createConnection
*/
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = [])
{
$siteName = $this->getSiteNameFromRequestOrCommand();
if (!isset($this->db_credentials_per_site[$siteName])) {
throw new \RuntimeException("MyConnectionFactory::createConnection - Unknown site name: {$siteName}");
}
return $this->originalConnectionFactory->createConnection(
[
'url' => $this->db_credentials_per_site[$siteName]['url'],
],
$config,
$eventManager,
$mappingTypes
);
}
/**
* @return string
*/
private function getSiteNameFromRequestOrCommand()
{
// If we are inside CLI command then take site name from '--site' command option:
if (isset($_SERVER['argv'])) {
$input = new ArgvInput();
$siteName = $input->getParameterOption(['--site']);
if (!$siteName) {
throw new \RuntimeException("MyConnectionFactory::getSiteNameFromRequestOrCommand - You must provide option '--site=...'");
}
return (string) $siteName;
}
// Otherwise determine site name by request host (domain):
$request = Request::createFromGlobals();
$host = $request->getHost();
switch ($host) {
case 'my-blue-site.local.dev2':
return 'blue_site';
case 'redsite.local.com':
return 'red_site';
}
throw new \RuntimeException("MyConnectionFactory::getSiteNameFromRequestOrCommand - Unknown host: {$host}");
}
}
Now lets setup the decoration in services.yaml:
(you can read more about decorating of services here: https://symfony.com/doc/current/service_container/service_decoration.html)
App\Doctrine\MyConnectionFactory:
decorates: doctrine.dbal.connection_factory
arguments:
$db_credentials_per_site: '%db_credentials_per_site%'
and add 'db_credentials_per_site' parameter in "config/my_config.php" - as you see it is injected to MyConnectionFactory above:
$container->setParameter('db_credentials_per_site', [
'blue_site' => [
'url' => 'mysql://user1:[email protected]:3306/dbname-blue',
],
'red_site' => [
'url' => 'mysql://user2:[email protected]:3306/dbname-red',
],
]);
We need one more thing to support this feature in CLI commands - we need to add '--site' option to each command. As you see it is being read in \App\Doctrine\MyConnectionFactory::getSiteNameFromRequestOrCommand. It will be mandatory for all commands that will use database connection:
in services.yaml:
App\EventListener\SiteConsoleCommandListener:
tags:
- { name: kernel.event_listener, event: console.command, method: onKernelCommand, priority: 4096 }
create new file "src/EventListener/SiteConsoleCommandListener.php":
<?php
namespace App\EventListener;
use Symfony\Component\Console\Event\ConsoleCommandEvent;
use Symfony\Component\Console\Input\InputOption;
class SiteConsoleCommandListener
{
public function onKernelCommand(ConsoleCommandEvent $event)
{
// Add '--site' option to every command:
$command = $event->getCommand();
$command->addOption('site', null, InputOption::VALUE_OPTIONAL);
}
}
Now we are ready to test if it works:
- when you call
http://my-blue-site.local.dev2/something then the 'blue_site' database credenatials will be used.
- when you call
http://something.blabla.com/something then the 'red_site' database credenatials will be used.
- when you run following command then
'blue_site' database credenatials will be used:
php bin/console app:my-command --site=blue_site
- when you run following command then
'red_site' database credenatials will be used:
php bin/console app:my-command --site=red_site
.envor the system environment is the suggested place for configuration in the latest Symfony versionsDATABASE_URLenvvar to your application, which will override .env. In Apache you would do this withSetEnv DATABASE_URL "mysql://..."and with nginx it would befastcgi_param DATABASE_URL "mysql://...". No need to touch any config files. If this does not help, please explain how aconfig.phpis supposed to solve your problem.