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

2022-01-22 00:00:00 php symfony controller twig

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

I have started to create a project using Symfony 2. I need to share data between all controllers.

我添加了一个扩展 symfonycontroller 的基本控制器,并且我的每个控制器都扩展了这个基本控制器

I have added a base controller which extends symfonycontroller and each of my controllers extends this base controller

class BaseController extends Controller

class HomeController extends BaseController

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

This base controller will be used for things like assigning global twig variables ( I know I can do this in the config but some of the variables will be gotten from other config files and database ).

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

So I thought I could reference container since Controller is container aware, however it isn't at the point I am using the functions (from constructor).

public function __construct ()

我看到有人提到将容器作为参数传递并提到服务,但我看过并无法弄清楚.我想要实现的是:

I have seen people mention passing the container in as a parameter and mention services but I have had a look and cannot figure it out. All I want to achieve is this:

public function __construct (Container $container) {
    $container->get('twig').addGlobal('foo');
}

推荐答案

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

This is a common stumbling block to Symfony 2 newbies. The controller/container question has been asked hundreds of time before so you are not alone(hint).

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

Why doesn't your controller constructor code work?

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

Start by looking under vendor/symfony...FrameworkBundle/Controller/Controller.php. Hmm. No constructor there so where the heck is the container coming from? We see that Controller extends ContainerAware. That seems promising. We look at ContainerAware (the namespace helps to find where the file is) and once again, no constructor. There is however a setContainer method so we can assume that the container is injected into the controller after the constructor is called. Quite common in a dependency injection based framework.

所以现在我们知道为什么构造函数代码失败了.容器尚未注入.愚蠢的设计对吧?是时候换一个框架了?并不真地.让我们面对现实吧,必须让所有控制器扩展一个基本控制器只是为了设置一些树枝变量并不是最好的设计.

So now we know why the constructor code fails. The container has not yet been injected. Stupid design right? Time for a different framework? Not really. Let's face it, having to have all your controllers extend a base controller just to get some twig variables set is not really the best design.

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

The Symfony way to execute code before the controller action is executed is to make a controller event listener. It will look something like this:

namespace CeradBundleCoreBundleEventListener;

use SymfonyComponentDependencyInjectionContainerAware;

use SymfonyComponentHttpKernelHttpKernel;
use SymfonyComponentHttpKernelKernelEvents;
use SymfonyComponentHttpKernelEventFilterControllerEvent;

use SymfonyComponentEventDispatcherEventSubscriberInterface;

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: 
        CeradBundleCoreBundleEventListenerModelEventListener

services:
    cerad_core__model_event_listener:
        class:  '%cerad_core__model_event_listener__class%'
        calls:
            - [setContainer, ['@service_container']]
        tags:
            - { name: kernel.event_subscriber }

所以现在我们有了所需的功能,而不需要基本控制器类.

So now we have the desired functionality without the need for a base controller class.

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

Notice also that the controller can be accessed through the event. Since the controller has been created but the action method not yet called, you could call controller methods or inject data directly into the controller. This is seldom needed. In most cases, you would add additional information to the request object which then gets injected into the controller's action method.

一旦您对听众和服务感到满意,这确实是一个不错的设计.

It's really a nice design once you get comfortable with listeners and services.

相关文章