Symfony 2在控制器之间共享数据

Car*_*ham 2 php controller symfony twig

我已经开始使用Symfony 2创建一个项目.我需要在所有控制器之间共享数据.

我添加了一个扩展symfony\controller的基本控制器,我的每个控制器都扩展了这个基本控制器

class BaseController extends Controller

class HomeController extends BaseController
Run Code Online (Sandbox Code Playgroud)

这个基本控制器将用于分配全局树枝变量(我知道我可以在配置中执行此操作,但某些变量将从其他配置文件和数据库中获取).

所以我认为我可以引用容器,因为Controller是容器感知的,但是我不是在使用函数(来自构造函数).

public function __construct ()
Run Code Online (Sandbox Code Playgroud)

我看到人们提到将容器作为参数传递并提及服务但我已经看过了,无法弄明白.我想要实现的就是:

public function __construct (Container $container) {
    $container->get('twig').addGlobal('foo');
}
Run Code Online (Sandbox Code Playgroud)

Cer*_*rad 6

这是Symfony 2新手的常见绊脚石.控制器/容器问题已被问过数百次,因此您并不孤单(提示).

为什么控制器构造函数代码不起作用?

首先查看vendor/symfony ... FrameworkBundle/Controller/Controller.php.嗯.那里没有构造函数,所以容器来自哪里?我们看到Controller扩展了ContainerAware.这似乎很有希望.我们看看ContainerAware(命名空间有助于找到文件的位置),再一次,没有构造函数.但是有一个setContainer方法,所以我们可以假设在调用构造函数之后将容器注入控制器.在基于依赖注入的框架中很常见.

所以现在我们知道构造函数代码失败的原因.容器尚未注射.愚蠢的设计吧?时间不同的框架?并不是的.让我们面对它,必须让所有控制器扩展一个基本控制器只是为了得到一些树枝变量设置并不是真正的最佳设计.

在执行控制器操作之前执行代码的Symfony方法是创建一个控制器事件监听器.它看起来像这样:

namespace Cerad\Bundle\CoreBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerAware;

use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ModelEventListener extends ContainerAware implements EventSubscriberInterface
{   
    public static function getSubscribedEvents()
    {
        return array(KernelEvents::CONTROLLER => array(
            array('doTwig', 0), // 0 is just the priority
        ));
    }
    public function doTwig(FilterControllerEvent $event)
    {
        // Ignore sub requests
        if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) return;

        $this->container->get('twig')->addGlobal('foo');
    }
}
// This goes in services.yml

parameters:
    cerad_core__model_event_listener__class: 
        Cerad\Bundle\CoreBundle\EventListener\ModelEventListener

services:
    cerad_core__model_event_listener:
        class:  '%cerad_core__model_event_listener__class%'
        calls:
            - [setContainer, ['@service_container']]
        tags:
            - { name: kernel.event_subscriber }
Run Code Online (Sandbox Code Playgroud)

所以现在我们拥有所需的功能而无需基本控制器类.

另请注意,可以通过事件访问控制器.由于已创建控制器但尚未调用操作方法,因此可以调用控制器方法或将数据直接注入控制器.这很少需要.在大多数情况下,您可以向请求对象添加其他信息,然后将其注入控制器的操作方法.

一旦您对听众和服务感到满意,这真的是一个很好的设计.