我正在使用Symfony 2.5构建托管CMS,在一种情况下,我们会根据域检测到正确的站点帐户。当用户创建任何记录时,我们使用prePersist
自动将siteId
插入到数据库记录中(因此所有记录都与正确的帐户相关联)。但是将siteId
注入到作为服务加载的侦听器中是很复杂的。
我无法在配置参数中设置siteId
(因为它对每个站点都是动态的,而不是整个应用程序的设置值)。
我无法使用$container->setParameter('siteId', $siteId)
,因为控制器执行时无法修改参数。
事实上,我需要在我的项目中访问许多环境变量,这些变量不能轻易地手动注入。 Soi我想知道其他人推荐的解决方案,以及我的解决方案是否“好”。
我需要存储许多可在各种控制器,服务和监听器中访问的CMS环境变量。所以我创建了一个env
实体,我可以在其中存储这些值以供以后访问,并将其定义为服务,以便将其注入到侦听器中。
环境实体
namespace Gutensite\CmsBundle\Entity\Cms;
class Env {
private $siteId = 0;
public function getSiteId() {
return $this->siteId;
}
public function setSiteId($siteId) {
$this->siteId = $siteId;
return $this;
}
}
定义Service.yml
services:
#Define Env as a Service
gutensite_cms.env:
class: Gutensite\CmsBundle\Entity\Cms\Env
#Inject Env into a Listener
gutensite_cms.listener.entity_persist:
class: Gutensite\CmsBundle\EventListener\EntityPersistListener
arguments:
- "@gutensite_cms.env"
tags:
- { name: doctrine.event_listener, event: prePersist }
- { name: doctrine.event_listener, event: preUpdate }
添加siteId
namespace Gutensite\CmsBundle\EventListener;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Gutensite\CmsBundle\Entity\Cms\Env;
class EntityPersistListener
{
private $env;
public function __construct(Env $env) {
$this->env = $env;
}
public function prePersist(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if (method_exists($entity, 'setTime')) $entity->setTime(time());
if (method_exists($entity, 'setSiteId') && !$entity->getSiteId()) $entity->setSiteId($this->env->getSiteId());
}
public function preUpdate(LifecycleEventArgs $eventArgs)
{
$entity = $eventArgs->getEntity();
if (method_exists($entity, 'setTimeMod')) $entity->setTimeMod(time());
// Update the Parent View timeMod
$this->updateView($eventArgs);
}
public function updateView($eventArgs)
{
$em = $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();
$updatedEntities = $uow->getScheduledEntityUpdates();
foreach($updatedEntities AS $entity) {
$view = false;
if (method_exists($entity, 'getViewVersion')) {
$view = $entity->getViewVersion()->getView();
}
if (method_exists($entity, 'getView')) {
$view = $entity->getView();
}
if($view) {
$view->setTimeMod(time());
}
}
}
}
我不想在我的模型中引入一个破坏依赖注入的错误解决方案。那么,您在哪里存储环境变量,您需要在许多不同的控制器和监听器中访问?
答案 0 :(得分:1)
在我的应用中,内容在“组织”之间分开。用户可以属于其中的许多用户,并且可以在登录后在组织之间切换。因此,用户创建的所有实体都属于当前组织。为了确保每次添加新实体时我都不必显式设置它,我创建了一个监听器:
class BoundToOrganisationListener implements EventSubscriber {
(...)
public function getSubscribedEvents() {
return array(
Events::prePersist
);
}
public function prePersist(LifecycleEventArgs $args) {
$entity = $args->getEntity();
$em = $args->getEntityManager();
/* @var $em \Doctrine\ORM\EntityManager */
$classMetadata = $em->getClassMetadata(get_class($entity));
if (array_key_exists('organisation', $classMetadata->reflFields) && !$entity->getOrganisation()) {
$token = $this->securityContext->getToken();
if (empty($token)) {
} else if($organisationId = $this->getCurrentUserOrganisationId()) {
$organisation = $em->find('...:Organisation', $organisationId);
$entity->setOrganisation($organisation);
}
}
我将当前组织保留在User对象中(我也将其保存到数据库中),这样我就可以从security.context服务中获取当前的组织用户。
我还检查!$ entity-> getOrganisation(),以防我想通过手动为新用户设置一个不同于一个用户所在的组织(例如当我是管理员或其他什么时)实体。
我的建议是将siteId保持在会话中并将会话注入到确保新对象设置了正确的siteId的服务中。
要将siteId保存到会话,您可以使用sensio建议设置区域设置的相同机制
http://symfony.com/doc/current/cookbook/session/locale_sticky_session.html
您可以根据请求确定您的siteId。