我有很多配置设置,我希望能够在整个应用程序中访问。例如,我有一个包含一些自定义查询的实体存储库。我想有一个全局参数,将默认的“限制”设置为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 service model(我还没有理解它,对于只是获取参数似乎是一项巨大的努力)。
那么在任何环境中(包括这里的那个)访问这样的全局参数的“最佳”方法是什么?
我不想访问内核,但如果这是最后的手段,为什么从内核获取参数是“错误的”,如:
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
则可行。 有人可以解释原因吗?
但后来我得到另一个与存储库中的方法不存在的错误(因为存储库已损坏)。我想在服务定义中包含参数意味着我需要向ViewVersionRepository添加__construct($viewVersion)
方法以接受参数列表。但这导致了一个令人讨厌的错误,打破了存储库。所以我删除了它,因为显然这必须在默认的Symfony EntityRepository中(我应该怎么知道?)。我确实保留了一个自定义的setLimit()方法,用于将全局参数传递给调用。
所以现在服务工作......但这看起来像很多工作,只是为了访问全局参数,如果没有参数传递给方法,它应该作为DEFAULT。
为什么我们不应该在这些我们设置默认值的情况下从配置文件中使用$ GLOBAL或常量?这不会破坏依赖模型,自定义变量可以仍然会传递给方法,只有我们有一个全局应用程序范围的默认值。我不明白为什么这是不赞成的......
答案 0 :(得分:8)
学习和理解如何将存储库创建为服务是值得的。类似的东西:
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');
请参阅文档:http://symfony.com/doc/current/components/dependency_injection/factories.html
学习如何使用服务所花费的精力将多次回报。
答案 1 :(得分:1)
我个人使用自定义配置类。您可以在任何需要的位置导入配置类 - 实体,存储库,控制器等。
要回答你的问题,为什么“将其作为论据传递”只是研究依赖注入模式。当你想长时间维护你的项目时,它真的是一种灵活而酷的方法来解决许多问题。