我有很多配置设置,我希望能够在整个应用程序中访问它们。例如,我有一个带有一些自定义查询的实体存储库。我想有一个全局参数,将默认的"限制"设置为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
学习如何使用服务所付出的努力将会得到成倍的回报。
我个人使用自定义配置类。你可以在任何你需要的地方导入你的配置类——实体、存储库、控制器等。
要回答为什么"将其作为参数传递"的问题,只需研究依赖注入模式即可。当你想长时间维护你的项目时,它确实是一种灵活而酷的方法来解决许多问题。