为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
米脂 2021-11-05 15:50:29
我已经设置了一个 symfony 项目。我所有的数据库连接都在app/.env.这是我在 .env 文件中配置的方式:DATABASE_URL=mysql://root@127.1.0.1:3306/abcdefg现在我想使用像 config.php 这样的 .php 文件,我可以在其中存储数据库配置的值,并且应用程序也应该使用相同的文件,而不是从 .env 文件中获取值。这是根据应用程序 URL 连接不同的数据库。所以数据库名称取决于 URL。为了使其动态化,我想使用 PHP 文件而不是 .env 文件。
查看完整描述

2 回答

?
拉丁的传说

TA贡献1789条经验 获得超8个赞

(我假设您使用的是 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:

    - { resource: my_config.php }

清除缓存。

检查这些参数是否已加载到容器中 - 例如通过运行以下命令:

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"]

 ------------------------- -------------------

如果上述步骤有效,那么您可以在应用程序中使用容器中的参数。


重要警告:如果您将安全凭证存储在此类 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”:


<?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}");

    }

}

现在让我们在 services.yaml 中设置装饰:


(您可以在此处阅读有关装饰服务的更多信息: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%'


并'db_credentials_per_site'在“config/my_config.php”中添加参数 - 如您所见,它被注入到MyConnectionFactory上面:


$container->setParameter('db_credentials_per_site', [

    'blue_site' => [

        'url' => 'mysql://user1:pass1@127.0.0.1:3306/dbname-blue',

    ],

    'red_site' => [

        'url' => 'mysql://user2:pass2@127.0.0.1:3306/dbname-red',

    ],

]);

我们还需要一件事来支持 CLI 命令中的此功能 - 我们需要'--site'为每个命令添加选项。如您所见,它正在被读取\App\Doctrine\MyConnectionFactory::getSiteNameFromRequestOrCommand。对于将使用数据库连接的所有命令,这将是强制性的:


在 services.yaml 中:


    App\EventListener\SiteConsoleCommandListener:

        tags:

            - { name: kernel.event_listener, event: console.command, method: onKernelCommand, priority: 4096 }

创建新文件“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);

    }

}

现在我们准备测试它是否有效:


当你调用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


查看完整回答
反对 回复 2021-11-05
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

最后,我为解决此问题所做的工作是对@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:

    dbal:

        # configure these for your database server

        driver: 'pdo_mysql'

        server_version: '5.7'

        charset: utf8mb4

        default_table_options:

            charset: utf8mb4

            collate: utf8mb4_unicode_ci


        url: '%env(resolve:DATABASE_URL)%'

    orm:

        auto_generate_proxy_classes: true

        naming_strategy: doctrine.orm.naming_strategy.underscore

        auto_mapping: true

        mappings:

            App:

                is_bundle: false

                type: annotation

                dir: '%kernel.project_dir%/src/Entity'

                prefix: 'App\Entity'

                alias: App

现在,我添加了以下行以将我新创建的“my_config.php”文件导入到“doctrine.yaml”,如下所示:


imports:

    - { resource: my_config.php }

然后对这样的代码进行了一些更改:(仅在 url 行中添加了“'%my_param%'”)


imports:

    - { resource: my_config.php }


doctrine:

    dbal:

        # configure these for your database server

        driver: 'pdo_mysql'

        server_version: '5.7'

        charset: utf8mb4

        default_table_options:

            charset: utf8mb4

            collate: utf8mb4_unicode_ci


        url: '%my_param%'

    orm:

        auto_generate_proxy_classes: true

        naming_strategy: doctrine.orm.naming_strategy.underscore

        auto_mapping: true

        mappings:

            App:

                is_bundle: false

                type: annotation

                dir: '%kernel.project_dir%/src/Entity'

                prefix: 'App\Entity'

                alias: App

这解决了我的问题。


查看完整回答
反对 回复 2021-11-05
  • 2 回答
  • 0 关注
  • 172 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信