我正在构建一个symfony2应用程序,该应用程序可根据用于访问网站的域进行配置。 为了便于解决这个问题,我们假设数据库中有一个包含主机名和进一步配置的“域”实体。 考虑一下小的模板差异,页眉/页脚的一些差异。提供的产品有所不同。 可用的路线不会有所不同。
有两个地方我需要这个Domain对象。 *在Controller :: action中 *在基本模板中(即使控制器不需要它) 我不会在其他地方需要它,如果我这样做,我可以简单地从控制器传递它。
在没有产生太多开销的情况下获取此对象的最佳方法和在我们实际不需要它时不会获取它。
到目前为止我得到的一些想法: *我可以覆盖ControllerResolver并根据Request对象确定Domain对象。虽然我似乎没有访问ServiceContainer那里。 *我可以在BaseController中添加一些方法,当我在Controller:Action时,它可以为我检索域。 *为了在模板中使用,我可以创建一个添加全局变量的TwigExtension。但它需要访问Request对象或RequestStack。此外,这只会帮助我在模板中,我可能会做两次相同的事情。
有什么建议可能是一个好方法吗?
答案 0 :(得分:2)
不知道这是否是最佳解决方案,但到目前为止对我来说效果很好。
由于域信息取决于请求,因此它不是服务,因此不要尝试将其注入服务中,否则您将头痛不已。设置域信息的最自然的地方是请求,并允许控制器读取此信息以与服务进行交互。
因此,您可以设置一个内核事件侦听器,它从数据库中读取信息并设置domain
Request属性,如下所示:
<?php
namespace Acme\SiteBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Doctrine\ORM\EntityRepository;
class DomainSubscriber implements EventSubscriberInterface
{
protected $domainRepository;
public static function getSubscribedEvents()
{
return array(
KernelEvents::REQUEST => 'onKernelRequest'
);
}
public function __construct(EntityRepository $domainRepository)
{
$this->domainRepository = $domainRepository;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
// Console/CLI commands don't have Domain info
if ($request === null)
return;
$domain = $this->domainRepository->find($request->getHost());
if ($domain === null)
throw new \RuntimeException(sprintf("Cannot find domain %s", $request->getHost()));
$request->attributes->set('domain', $domain);
}
}
必须使用以下内容在services.yml
(或XML)中注册:
acme_site.manager:
class: Doctrine\ORM\EntityManager
factory_service: doctrine
factory_method: getManager
acme_site.domain_repository:
class: Doctrine\ORM\EntityRepository
factory_service: acme_site.manager
factory_method: getRepository
arguments:
- 'AcmeSiteBundle:Domain'
acme_site.domain_subscriber:
class: Acme\SiteBundle\EventListener\DomainSubscriber
arguments:
- "@acme_site.domain_repository"
tags:
- { name: kernel.event_subscriber }
在您的控制器中,您现在只需执行以下操作即可访问数据:
public function someAction(Request $request) {
$domain = $request->attributes->get('domain');
$domain->getWhatever();
}
在Twig中,您始终可以通过以下方式访问请求:
{% set domain = app.request.attributes.get('domain') %}
whatever: {{ domain.whatever }}
希望这有帮助!
免责声明:代码被复制粘贴然后进行编辑,因此可能包含一些小错误。
注意:如果您确实需要在服务中注入请求,那么我建议您阅读有关RequestStack
(Symfony 2.4+)的文档,或使用setRequest
方法并处理container scopes