在实体存储库或任何地方访问Symfony配置参数


Access Symfony Config Parameter in Entity Repository or Anywhere

我有很多配置设置,我希望能够在整个应用程序中访问它们。例如,我有一个带有一些自定义查询的实体存储库。我想有一个全局参数,将默认的"限制"设置为10条记录,除非我特别更改它。

class ViewVersionRepository extends EntityRepository {
    /**
     * Get all the versions for the specified view id, ordered by modification time.
     * @param integer $id
     * @param integer $limit
     * @param integer $offset default 0
     * @return array
     */
    public function findByViewIdLimit($id, $limit = NULL, $offset = 0) {
        // this won't work because we don't have access to the container... ;(
        $limit = ($limit != NULL) ? $limit : $this->container->getParameter('cms.limit');
        return $this->createQueryBuilder('v')
            ->where('v.viewId = :id')
            ->orderBy('v.timeMod', 'DESC')
            ->setParameter('id', $id)
            ->setFirstResult($offset)
            ->setMaxResults($limit)
            ->getQuery()
            ->getResult();
    }
}

在symfony出现之前,我可以很容易地在parameters.yml:

中设置它。
cms.limit: 10

或者在应用配置文件中创建一个常量:

define('cms.limit', 10);

但是在Symfony中,如果我使用一个参数,我怎么能从我的实体存储库访问,因为"容器"在实体存储库中不可用?

人们说"传递它作为一个参数",但老实说,这只是混乱和无意义的工作,每次我调用查询。如果不能访问参数,那么拥有参数有什么意义?

其他人说你必须构建一些全局服务模型(我还没有理解,似乎只是获取参数是一个巨大的努力)。

那么在任何上下文中(包括这里)访问这样的全局参数的"最佳"方式是什么?

我不想访问内核,但如果这是最后的手段,为什么从内核中获取参数是"错误的",如:

global $kernel;
$assetsManager = $kernel->getContainer()->get('acme_assets.assets_manager');‏

我真不敢相信访问全局参数这么难。我理解需要明确依赖关系的想法。但在应用程序中,参数总是可用的,并且您总是希望使用它们作为默认值,为什么这不是标准和简单的呢?


更新

根据下面的答案,我已经把我的ViewVersionRepository变成了一个服务(这就是你建议的对吗?)。

class ViewVersionRepository extends EntityRepository

{

    // do not evidently need to set $this->viewVersion either
    // protected $viewVersion;
    protected $limit;
    /**
     * Allow limit to be set by parameter, injected by service definition
     * @param $limit
     */
    public function setLimit($limit) {
        $this->limit = $limit;
    }

    /**
     * Get all the versions for the specified view id, ordered by modification time.
     * @param integer $id
     * @param integer $limit default from global parameter
     * @param integer $offset default 0
     * @return array
     */
    public function findByViewIdLimit($id, $limit = NULL, $offset = 0) {
        $limit = (!empty($limit)) ? $limit : $this->limit;
        return $this->createQueryBuilder('v')
            ->where('v.viewId = :id')
            ->orderBy('v.timeMod', 'DESC')
            ->setParameter('id', $id)
            ->setFirstResult($offset)
            ->setMaxResults($limit)
            ->getQuery()
            ->getResult();
    }
}

添加服务:

gutensite_cms.view_version_repository:
    class: Gutensite'CmsBundle'Entity'View'ViewVersionRepository
    factory_service: 'doctrine.orm.default_entity_manager'
    factory_method: 'getRepository'
    arguments:
        - 'Gutensite'CmsBundle'Entity'View'ViewVersion'
    calls:
        - [setLimit, ['%cms.limit.list.admin%']]

这会导致报错factory_service定义:

You have requested a non-existent service "doctrine.orm.default_entity_manager". Did you mean one of these: "doctrine.orm.cms_entity_manager", "doctrine.orm.billing_entity_manager"?

幸运的是,如果我将factory_service更改为建议的doctrine.orm.cms_entity_manager,它可以工作。有人能解释一下为什么吗?

但随后我得到另一个与存储库中不存在的方法相关的错误(因为存储库被破坏了)。我认为在服务定义中有参数,意味着我需要添加一个__construct($viewVersion)方法到ViewVersionRepository来接受参数列表。但这导致了一个严重的错误,破坏了存储库。所以我删除了,因为显然这必须在默认的Symfony EntityRepository(我怎么知道?)。我保留了一个自定义setLimit()方法,用于将全局参数传递到调用中。

所以现在服务工作了…但这似乎是一项繁重的工作,只是为了访问全局参数,如果没有参数传递到方法中,全局参数应该作为默认值。

为什么我们不应该使用$GLOBAL或配置文件中的常量在这些情况下,我们正在设置默认值?这不会破坏依赖模型,自定义变量仍然可以传递到方法中,只是我们有一个全局的应用范围默认值。

研究和理解如何将存储库创建为服务是值得的。比如:

view_version_repository:
    class:  My'SomeBundle'Entity'ViewVersionRepository
    factory_service: 'doctrine.orm.default_entity_manager'
    factory_method:  'getRepository'
    arguments:  
        - 'My'SomeBundle'Entity'ViewVersion'
    calls:
         - [setLimit, ['%limit_parameter%']]

在你的控制器中你可以这样做:

$viewVersionRepository = $this->container->get('view_version_repository');

参见docs: http://symfony.com/doc/current/components/dependency_injection/factories.html

学习如何使用服务所付出的努力将会得到成倍的回报。

我个人使用自定义配置类。你可以在任何你需要的地方导入你的配置类——实体、存储库、控制器等。

要回答为什么"将其作为参数传递"的问题,只需研究依赖注入模式即可。当你想长时间维护你的项目时,它确实是一种灵活而酷的方法来解决许多问题。