设置侦听器和控制器中可访问的全局变量的建议方法是什么?

时间:2014-10-08 17:49:07

标签: symfony dependency-injection listeners

背景

我正在使用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());
            }
        }
    }
}

大问题

我不想在我的模型中引入一个破坏依赖注入的错误解决方案。那么,您在哪里存储环境变量,您需要在许多不同的控制器和监听器中访问

1 个答案:

答案 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。