【问题标题】:How to load Symfony's config parameters from database (Doctrine)如何从数据库中加载 Symfony 的配置参数(Doctrine)
【发布时间】:2015-02-25 07:30:40
【问题描述】:

我没有对parameters.yml 中的参数进行硬编码,而是尝试从数据库中加载它们。并非parameters.yml中的所有参数都需要从数据库中加载一些,例如paypal的api详细信息

config.yml我已经导入了parameters.php

imports:
    - { resource: parameters.php }

如果我像下面那样在parameters.php 中添加静态信息,它就可以正常工作

$demoName = 'First Last';
$container->setParameter('demoName', $demoName);

但是我无法从数据库表中获取信息。我想我应该创建类并使用$em = this->getDoctrine()->getManager();,它应该可以工作,但它没有,我得到了

的错误

Notice: Undefined variable: paypal_data in /opt/lampp/htdocs/services/app/config/parameters.php (which is being imported from "/opt/lampp/htdocs/services/app/config/config.yml").

这是我所做的尝试如下,但代码似乎没有进入__construct()

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\ORM\Mapping as ORM;

class parameters extends Controller
{
    public $paypal_data;

    function __construct() {
        $this->indexAction();
    }

    public function indexAction(){

        $em = $this->getDoctrine()->getManager();
        $this->paypal_data = $em->getRepository('featureBundle:paymentGateways')->findAll();

    }

}
$demoName = 'First Last';
$container->setParameter('demoName', $demoName);
$container->setParameter('paypal_data', $this->paypal_data);

任何帮助将不胜感激。

【问题讨论】:

  • 您是否尝试将 $paypal_data 设置为 $this-paypal_data 的类范围?
  • 是的,我也试过了
  • 也许你需要实例化参数对象?
  • 这绝对行不通。控制器用于将请求转换为响应,而不是在任何需要逻辑的地方使用。解析配置时不能使用任何服务,这个阶段你还在配置容器,还不能使用。您对 PHP 中的 OO 也有一些误解。
  • 好吧,我确信我并没有试图实现以前没有做过的事情。我想要做的不是在 config.yml 中硬编码 paypal 凭据,只需允许用户在管理面板中定义它们,并且用户定义的任何值都可以在 config.yml 中使用它们

标签: php symfony


【解决方案1】:

你做错事了。您需要声明您的 CompilerPass 并将其添加到容器中。加载整个容器后...在编译时,您将可以访问其中的所有服务。

只需获取实体管理器服务并查询所需的参数并将它们注册到容器中。

分步说明:

  • 定义编译器通道:

    # src/Acme/YourBundle/DependencyInjection/Compiler/ParametersCompilerPass.php
    class ParametersCompilerPass implements CompilerPassInterface
    {
        public function process(ContainerBuilder $container)
        {
            $em = $container->get('doctrine.orm.default_entity_manager');
            $paypal_params = $em->getRepository('featureBundle:paymentGateways')->findAll();
            $container->setParameter('paypal_data', $paypal_params);
        }
    }
    
  • 在捆绑定义类中,您需要将编译器传递添加到您的容器中

    # src/Acme/YourBundle/AcmeYourBundle.php
    class AcmeYourBundle extends Bundle
    {
        public function build(ContainerBuilder $container)
        {
            parent::build($container);
    
            $container->addCompilerPass(new ParametersCompilerPass(), PassConfig::TYPE_AFTER_REMOVING);
        }
    }
    

【讨论】:

  • 感谢您的详细解答,我会尽快回复您
  • 添加构建功能后,我得到了错误Attempted to load class "ParametersCompilerPass" from namespace "ClickTeck\featuresBundle". Did you forget a "use" statement for another namespace?,所以我添加了use 语句并指向ParametersCompilerPass(),这导致我出现The autoloader expected class "ClickTeck\featuresBundle\DependencyInjection\Compiler\ParametersCompilerPass" to be defined in file "/opt/lampp/htdocs/services/src/ClickTeck/featuresBundle/DependencyInjection/Compiler/ParametersCompilerPass.php" 的另一个错误。
  • 找到了文件但类不在其中,类名或命名空间可能有错字。我似乎无法理解类型在哪里,我已经检查了文件名和班级
  • 如果您在数据库上进行了更改,则由于容器缓存而导致参数未更改,是否有解决此问题的方法?
  • 更新设置实体时清除缓存
【解决方案2】:

CompilerPass 的解决方案在我的 Symfony 4 中不起作用,它仅在控制器中起作用,但在 twig.yaml 文件中使用时不起作用:

param_name: '%param_name%'

由于我需要在侧边栏中使用这个参数,所以在所有页面中,从控制器传递它是不可行的。

这就是我所做的,这要归功于您可以将reference services 作为全局 Twig 变量。

我有一个服务,叫做设置,它直接从数据库加载设置,简化:

class Settings
{
    private Connection $db;

    public function __construct(EntityManagerInterface $em)
    {
        $this->db = $this->em->getConnection();
    }

    /**
     * Get a setting value. 
     * If the setting doesn't exist, return the default value specified as the second param
     */
    public function get(string $name, $default=''): string
    {
        $val = $this->db->executeQuery("SELECT `value` FROM `settings` WHERE `key`=?;", [$name])->fetchOne();
        // strict comparison is needed for cases when $val === '0'
        return $val !== false ? $val : $default;
    }

    /**
     * Set a setting value. 
     * If the setting doesn't exist, create it. Otherwise, replace the db value
     */
    public function set(string $name, ?string $value, string $description = '')
    {
        if(is_null($value)) {
            // Remove the key
            $this->db->executeQuery('DELETE FROM settings WHERE `key`=?;', [$name]);
            return;
        }

        $this->db->executeQuery('INSERT INTO settings (`key`, `type`, `value`, `description`) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE `type`=?, `value`=?, `description`=?;',
            [$name, $type, $value, $description, $type, $value, $description]);
    }

现在,我只是添加了config/packages/twig.yaml

twig:
    # ...
    globals:
        # ...
        settings: '@App\Service\Settings'

这太棒了,因为现在我可以从任何模板读取任何数据库设置:

{{ dump(settings.get('setting_name')) }}

我发布的设置类已简化,它仍然可以改进,例如,如果您多次请求相同的设置,可以避免再次进行相同的查询,但这很简单(将获取的密钥存储在 private $fetched数组),或 warmup(array $keys) 方法通过单个查询获取许多设置 ("SELECT key, value FROM settings WHERE key IN (?);", [$toFetch], [Connection::PARAM_STR_ARRAY])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 2014-06-25
    • 1970-01-01
    • 2011-10-19
    相关资源
    最近更新 更多