简体   繁体   English

访问实体存储库或Anywhere中的Symfony配置参数

[英]Access Symfony Config Parameter in Entity Repository or Anywhere

I have a whole lot of configuration settings that I would like to be able to access throughout my application. 我有很多配置设置,我希望能够在整个应用程序中访问。 For example, I have an entity repository with some custom queries. 例如,我有一个包含一些自定义查询的实体存储库。 I would like to have a global parameter that sets the default "limit" to something like 10 records unless I specifically change it. 我想有一个全局参数,将默认的“限制”设置为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();
    }

}

In my pre-Symfony life, I could easily set this in my parameters.yml: 在我之前的Symfony生活中,我可以在我的parameters.yml中轻松设置它:

cms.limit: 10

or create a constant for this in some app config file: 或者在某些应用配置文件中为此创建一个常量:

define('cms.limit', 10);

But in Symfony, if I use a parameter, how can I access that from my entity repository since the "container" is not available in an entity repository? 但是在Symfony中,如果我使用参数,我如何从实体存储库访问它,因为“容器”在实体存储库中不可用?

People say "pass it in as an argument" but honestly, that's just clutter and senseless work for every time I call the query. 人们说“将其作为一个参数传递”但老实说,每次调用查询时,这都是混乱和毫无意义的工作。 What's the point of having parameters if you can't access them! 如果您无法访问参数,那么有什么意义呢!

Others say you have to construct some global service model (which I haven't understood yet either and seems like a HUGE effort for just fetching parameters). 其他人说你必须构建一些全局服务模型 (我还没有理解它,似乎只是为了获取参数而付出巨大努力)。

So what is the "best" way to access global parameters like this in ANY context (including the one here)? 那么在任何上下文(包括这里的那个)中访问这样的全局参数的“最佳”方法是什么?

I don't want to access the kernel, but if that's the last resort, why is it "wrong" to get the parameter from the kernel like: 我不想访问内核,但如果这是最后的手段,为什么从内核获取参数是“错误的”,如:

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

I can't believe it is this hard to access global parameters. 我无法相信这很难访问全局参数。 I understand the idea of needing to be explicit about the dependencies. 我理解需要明确依赖关系的想法。 But in an application where the parameters will always be available, and you always want to use them as say a default, why isn't this standard and easy? 但是在一个参数永远可用的应用程序中,你总是希望将它们用作默认值,为什么这个标准不容易?


Update 更新

Per the answers below I have turned my ViewVersionRepository into a service (that is what you were suggesting right?). 根据下面的答案,我已将我的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();
    }

}

Add Service: 添加服务:

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%']]

This results in an error complaining about the factory_service definition: 这会导致抱怨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"?

Fortunately, if I change factory_service to the suggested doctrine.orm.cms_entity_manager it works. 幸运的是,如果我将factory_service更改为建议的doctrine.orm.cms_entity_manager它可以正常工作。 Can someone explain why? 有人可以解释原因吗?

But then I get another error related to a method in the repository not existing (because the repository is broken). 但后来我得到另一个与存储库中的方法不存在的错误(因为存储库已损坏)。 I thought that having the arguments in the service definition, means I needed to add a __construct($viewVersion) method to ViewVersionRepository to accept the arguments list. 认为在服务定义中使用参数意味着我需要向__construct($viewVersion)添加__construct($viewVersion)方法以接受参数列表。 But that resulted in a nasty error that broke the repository. 但这导致了一个令人讨厌的错误,打破了存储库。 So I removed that because evidently this must be in the default Symfony EntityRepository (how am I supposed to know that?). 所以我删除了它,因为显然这必须在默认的Symfony EntityRepository中(我应该怎么知道?)。 I did keep a custom setLimit() method for the passing the global parameters into the call. 我确实保留了一个自定义的setLimit()方法,用于将全局参数传递给调用。

So now the service works... but that seems like SUCH a ton of work, just to get access to global parameters that should function as a DEFAULT if no parameters are passed into the method. 所以现在服务工作......但是这看起来像是大量的工作,只是为了访问全局参数,如果没有参数传递给方法,它应该作为DEFAULT。

Why shouldn't we use a $GLOBAL or a constant from a config file in these sorts of situations where we are setting defaults? 为什么我们不应该在这些我们设置默认值的情况下使用配置文件中的$ GLOBAL或常量? This doesn't break the dependency model, the custom variables can still be passed into the method, only we have a global app wide default. 这不会破坏依赖模型,自定义变量仍然可以传递给方法,只有我们有一个全局应用程序范围的默认值。 I don't understand why that is frowned upon... 我不明白为什么这是不赞成的......

It's worth while to study and understand how to create a repository as a service. 学习和理解如何将存储库创建为服务是值得的。 Something like: 就像是:

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%']]

In your controller you would do: 在你的控制器中你会做:

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

See docs: http://symfony.com/doc/current/components/dependency_injection/factories.html 请参阅文档: http//symfony.com/doc/current/components/dependency_injection/factories.html

The effort expended in learning how to use services will repay itself many times over. 学习如何使用服务所花费的精力将多次回报自己。

I personally used a custom config class. 我个人使用自定义配置类。 You can import your config class wherever you need - entity, repository, controller etc. 您可以在任何需要的位置导入配置类 - 实体,存储库,控制器等。

To answer your question why "pass it as an argument" just study the dependency injection pattern. 要回答你的问题,为什么“将其作为论证传递”只是研究依赖注入模式。 It is really a flexible and cool way to solve many of the problems when you want to maintain your project for a longer time. 当您想要长时间维护项目时,它实际上是一种灵活而酷炫的方法来解决许多问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM