猿问

在 Symfony 中使用 config.php 和 Doctic.yaml 使用动态数据库名称

我已经设置了一个 symfony 项目。我所有的数据库连接都在app/.env.

这是我在 .env 文件中配置的方式:

DATABASE_URL=mysql://root@127.1.0.1:3306/abcdefg

现在我想使用像 config.php 这样的 .php 文件,我可以在其中存储数据库配置的值,并且应用程序也应该使用相同的文件,而不是从 .env 文件中获取值。

这是根据应用程序 URL 连接不同的数据库。所以数据库名称取决于 URL。

为了使其动态化,我想使用 PHP 文件而不是 .env 文件。


米脂
浏览 176回答 2
2回答

拉丁的传说

(我假设您使用的是 Symfony 4 或更高版本 - 但也应该在稍加修改的早期版本中工作)第 1 部分 - 从 php 加载容器参数像这样创建文件“config/my_config.php”:<?php$container->setParameter('my_param', 'something1');$elements = [];$elements[] = 'yolo1';$elements[] = 'yolo2';$container->setParameter('my_param_which_is_array', $elements);在您的 services.yaml 文件中,像这样导入“my_config.php”:imports:&nbsp; &nbsp; - { resource: my_config.php }清除缓存。检查这些参数是否已加载到容器中 - 例如通过运行以下命令:php bin/console debug:container --parameter=my_param&nbsp;----------- ------------&nbsp; Parameter&nbsp; &nbsp;Value&nbsp;----------- ------------&nbsp; my_param&nbsp; &nbsp; something1&nbsp;----------- ------------php bin/console debug:container --parameter=my_param_which_is_array&nbsp;------------------------- -------------------&nbsp; Parameter&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Value&nbsp;------------------------- -------------------&nbsp; my_param_which_is_array&nbsp; &nbsp;["yolo1","yolo2"]&nbsp;------------------------- -------------------如果上述步骤有效,那么您可以在应用程序中使用容器中的参数。重要警告:如果您将安全凭证存储在此类 php 文件(db 用户和密码等)中,请确保您没有将其与应用程序其余部分的代码一起添加到存储库中 - 因此将其添加到“.gitignore”中,类似于“ .env”被添加到那里。有关处理 symfony 参数的更多信息,请参阅https://symfony.com/doc/current/service_container/parameters.html(在代码片段上,单击“PHP”选项卡而不是“YAML”以查看 PHP 示例)第 2 部分 - 根据 url(host) 或 CLI 参数使用不同的数据库要动态选择数据库连接凭据,我们可以使用学说连接工厂。我们将'doctrine.dbal.connection_factory'使用修改后的版本装饰默认服务:创建新文件“src/Doctrine/MyConnectionFactory.php”:<?phpnamespace 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{&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* @var array&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; private $db_credentials_per_site;&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* @var ConnectionFactory&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; private $originalConnectionFactory;&nbsp; &nbsp; public function __construct($db_credentials_per_site, ConnectionFactory $originalConnectionFactory)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; $this->db_credentials_per_site = $db_credentials_per_site;&nbsp; &nbsp; &nbsp; &nbsp; $this->originalConnectionFactory = $originalConnectionFactory;&nbsp; &nbsp; }&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* Decorates following method:&nbsp; &nbsp; &nbsp;* @see \Doctrine\Bundle\DoctrineBundle\ConnectionFactory::createConnection&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = [])&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; $siteName = $this->getSiteNameFromRequestOrCommand();&nbsp; &nbsp; &nbsp; &nbsp; if (!isset($this->db_credentials_per_site[$siteName])) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new \RuntimeException("MyConnectionFactory::createConnection - Unknown site name: {$siteName}");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return $this->originalConnectionFactory->createConnection(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'url' => $this->db_credentials_per_site[$siteName]['url'],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $config,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $eventManager,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $mappingTypes&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; }&nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp;* @return string&nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; private function getSiteNameFromRequestOrCommand()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // If we are inside CLI command then take site name from '--site' command option:&nbsp; &nbsp; &nbsp; &nbsp; if (isset($_SERVER['argv'])) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $input = new ArgvInput();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $siteName = $input->getParameterOption(['--site']);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!$siteName) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new \RuntimeException("MyConnectionFactory::getSiteNameFromRequestOrCommand - You must provide option '--site=...'");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (string) $siteName;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // Otherwise determine site name by request host (domain):&nbsp; &nbsp; &nbsp; &nbsp; $request = Request::createFromGlobals();&nbsp; &nbsp; &nbsp; &nbsp; $host = $request->getHost();&nbsp; &nbsp; &nbsp; &nbsp; switch ($host) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 'my-blue-site.local.dev2':&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 'blue_site';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 'redsite.local.com':&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 'red_site';&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; throw new \RuntimeException("MyConnectionFactory::getSiteNameFromRequestOrCommand - Unknown host: {$host}");&nbsp; &nbsp; }}现在让我们在 services.yaml 中设置装饰:(您可以在此处阅读有关装饰服务的更多信息:https : //symfony.com/doc/current/service_container/service_decoration.html)&nbsp; &nbsp; App\Doctrine\MyConnectionFactory:&nbsp; &nbsp; &nbsp; &nbsp; decorates: doctrine.dbal.connection_factory&nbsp; &nbsp; &nbsp; &nbsp; arguments:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $db_credentials_per_site: '%db_credentials_per_site%'并'db_credentials_per_site'在“config/my_config.php”中添加参数 - 如您所见,它被注入到MyConnectionFactory上面:$container->setParameter('db_credentials_per_site', [&nbsp; &nbsp; 'blue_site' => [&nbsp; &nbsp; &nbsp; &nbsp; 'url' => 'mysql://user1:pass1@127.0.0.1:3306/dbname-blue',&nbsp; &nbsp; ],&nbsp; &nbsp; 'red_site' => [&nbsp; &nbsp; &nbsp; &nbsp; 'url' => 'mysql://user2:pass2@127.0.0.1:3306/dbname-red',&nbsp; &nbsp; ],]);我们还需要一件事来支持 CLI 命令中的此功能 - 我们需要'--site'为每个命令添加选项。如您所见,它正在被读取\App\Doctrine\MyConnectionFactory::getSiteNameFromRequestOrCommand。对于将使用数据库连接的所有命令,这将是强制性的:在 services.yaml 中:&nbsp; &nbsp; App\EventListener\SiteConsoleCommandListener:&nbsp; &nbsp; &nbsp; &nbsp; tags:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - { name: kernel.event_listener, event: console.command, method: onKernelCommand, priority: 4096 }创建新文件“src/EventListener/SiteConsoleCommandListener.php”:<?phpnamespace App\EventListener;use Symfony\Component\Console\Event\ConsoleCommandEvent;use Symfony\Component\Console\Input\InputOption;class SiteConsoleCommandListener{&nbsp; &nbsp; public function onKernelCommand(ConsoleCommandEvent $event)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; // Add '--site' option to every command:&nbsp; &nbsp; &nbsp; &nbsp; $command = $event->getCommand();&nbsp; &nbsp; &nbsp; &nbsp; $command->addOption('site', null, InputOption::VALUE_OPTIONAL);&nbsp; &nbsp; }}现在我们准备测试它是否有效:当你调用http://my-blue-site.local.dev2/something,则'blue_site'数据库credenatials将被使用。当你调用http://something.blabla.com/something,则'red_site'数据库credenatials将被使用。当您运行以下命令时,'blue_site'将使用数据库凭据:php bin/console app:my-command --site=blue_site当您运行以下命令时,'red_site'将使用数据库凭据:php bin/console app:my-command --site=red_site

30秒到达战场

最后,我为解决此问题所做的工作是对@domis86 的答案进行了一些更改。在“app/config/packages/”中创建了一个名为“my_config.php”的文件。如下添加代码$container->setParameter('my_param', 'mysql://root@xxx.x.x.x:0000/'.$_SERVER['HTTP_HOST']);.env 文件中的凭据正在“app/config/packages/doctrine.yaml”中使用以前“doctrine.yaml”看起来像这样:doctrine:&nbsp; &nbsp; dbal:&nbsp; &nbsp; &nbsp; &nbsp; # configure these for your database server&nbsp; &nbsp; &nbsp; &nbsp; driver: 'pdo_mysql'&nbsp; &nbsp; &nbsp; &nbsp; server_version: '5.7'&nbsp; &nbsp; &nbsp; &nbsp; charset: utf8mb4&nbsp; &nbsp; &nbsp; &nbsp; default_table_options:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; charset: utf8mb4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collate: utf8mb4_unicode_ci&nbsp; &nbsp; &nbsp; &nbsp; url: '%env(resolve:DATABASE_URL)%'&nbsp; &nbsp; orm:&nbsp; &nbsp; &nbsp; &nbsp; auto_generate_proxy_classes: true&nbsp; &nbsp; &nbsp; &nbsp; naming_strategy: doctrine.orm.naming_strategy.underscore&nbsp; &nbsp; &nbsp; &nbsp; auto_mapping: true&nbsp; &nbsp; &nbsp; &nbsp; mappings:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; App:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; is_bundle: false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: annotation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir: '%kernel.project_dir%/src/Entity'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prefix: 'App\Entity'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; alias: App现在,我添加了以下行以将我新创建的“my_config.php”文件导入到“doctrine.yaml”,如下所示:imports:&nbsp; &nbsp; - { resource: my_config.php }然后对这样的代码进行了一些更改:(仅在 url 行中添加了“'%my_param%'”)imports:&nbsp; &nbsp; - { resource: my_config.php }doctrine:&nbsp; &nbsp; dbal:&nbsp; &nbsp; &nbsp; &nbsp; # configure these for your database server&nbsp; &nbsp; &nbsp; &nbsp; driver: 'pdo_mysql'&nbsp; &nbsp; &nbsp; &nbsp; server_version: '5.7'&nbsp; &nbsp; &nbsp; &nbsp; charset: utf8mb4&nbsp; &nbsp; &nbsp; &nbsp; default_table_options:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; charset: utf8mb4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collate: utf8mb4_unicode_ci&nbsp; &nbsp; &nbsp; &nbsp; url: '%my_param%'&nbsp; &nbsp; orm:&nbsp; &nbsp; &nbsp; &nbsp; auto_generate_proxy_classes: true&nbsp; &nbsp; &nbsp; &nbsp; naming_strategy: doctrine.orm.naming_strategy.underscore&nbsp; &nbsp; &nbsp; &nbsp; auto_mapping: true&nbsp; &nbsp; &nbsp; &nbsp; mappings:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; App:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; is_bundle: false&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: annotation&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir: '%kernel.project_dir%/src/Entity'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; prefix: 'App\Entity'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; alias: App这解决了我的问题。
随时随地看视频慕课网APP
我要回答