在Controller构造函数Symfony上加载容器服务

时间:2015-03-27 07:26:18

标签: php symfony

有没有办法在Controller构造函数中加载容器服务,比如

class PostController extends Controller
{

    protected $breadcrumb;

    public function __construct()
    {
        //initializing breadcrumb
        $breadcrumbs = $this->get("white_october_breadcrumbs");
        $breadcrumbs->addRouteItem("Dashboard", "adminPage");
        $breadcrumbs->addRouteItem("Post", "postPage");
        $this->breadcrumb = $breadcrumbs;
    }
//..
}

4 个答案:

答案 0 :(得分:2)

您正在扩展Symfony\Bundle\FrameworkBundle\Controller\Controller类,它通过setter注入(方法container)而不是构造函数参数注入setContainer

当您在__construct()时,您还没有$container。因此,您的解决方案是覆盖setContainer方法(在构造控制器之后由服务容器调用)并将您的逻辑放在那里(而不是__construct())。

class PostController extends Controller
{

    protected $breadcrumb;

    public function setContainer(ContainerInterface $container = null)
    {
        parent::setContainer($container);
        $breadcrumbs = $container->get("white_october_breadcrumbs");
        $breadcrumbs->addRouteItem("Dashboard", "adminPage");
        $breadcrumbs->addRouteItem("Post", "postPage");
        $this->breadcrumb = $breadcrumbs;
    }

}

需要更多工作的其他解决方案是define your controller as a service并将其设置为container作为构造函数参数

答案 1 :(得分:2)

是的,这可以通过Controller as a Service实现。但是,注入Container被认为是一个不好的例子。如果您想获得服务white_october_breadcrumbs,您可以在控制器服务定义中注入它;如果你使用yaml:

service:
    class: app.controller.my_controller
    arguments:
        - "@white_october_breadcrumbs"
public function __construct(Breadcrumbs $breadcrumbs)
{
    $this->breadcrumbs = $breadcrumbs;
}

这是一个更好的解决方案,因为您不希望您的应用程序尽可能依赖于容器。

考虑到您希望在多个页面上使用此解决方案,另一种解决方案是在动作上使用事件侦听器甚至自定义注释来动态添加面包屑。但不建议初学者使用。

答案 2 :(得分:0)

  

在Controller构造函数上加载容器服务,Symfony

唐'吨。您的服务的生命周期是什么?如果调用控制器的操作,您想要初始化一些面包屑吗?子请求怎么样?控制器的创建顺序是什么?

<强> 1。中央配置:

  1. 创建一个配置图(例如以yml为单位),其中控制器类名为键,面包屑为值(例如,路径数组)
  2. 创建BreadcrumbBuilder服务,注入配置
  3. 为您的观点创建BreadcrumbProvider独立服务和twig-extension
  4. 创建并注册BreadcrumbRequestListener http://api.symfony.com/2.7/Symfony/Component/HttpKernel/Event/FilterControllerEvent.html侦听器,注入BreadcrumbBuilder,`BreadcrumbProvider
  5. 根据getController() - 可调用(样本A)
  6. 创建面包屑
  7. 直接在树枝上访问面包屑
  8. 样品A:

    $controller = $event->getController();
    if(\is_array($controller)) {
      $clazz = \get_class($controller[0]);
      $breadcrumbs = $this->breadcrumbBuilder->build($clazz);
      $this->breadcrumbProvider->setBreadcrumbs($breadcrumbs);
    }
    

    <强> 2。或者是开放式封闭式控制器,因此您无需更改中央配置,只需添加控制器:

    1. 让每个提供面包屑的控制器都是BreadcrumbProviderInterface实现getBreadcrumb(),返回创建面包屑所需的一些数据
    2. 还创建一个BreadcrumbRequestListener,检查该界面并存储可通过树枝访问的参考(样本B)
    3. 样本B:

      $controller = $event->getController();
      if(\is_array($controller) && $controller[0] instanceof BreadcrumbProviderInterface) {
        $this->breadcrumbs->setCurrentProvider($controller[0]);
      }
      

      第3。其他想法:

      • 通过在request_stack上拥有控制器和操作的$request->attributes->get('_controller');来请求面包屑。您可以使用主要请求或遍历所有控制器中的所有面包屑
      • 基础控制器类

答案 3 :(得分:0)

我遇到了类似的情况。在这里我的场景: 我有一个第三方包类,在vendor/my-vendor/my-third-party-bundle/Resources/config/services.xml中声明为服务,我想在src/AppBundle/Controller/MyController注入。命名空间设置正确,当我从上面的控制器的某个操作方法中从容器中获取第三方bundle类时,一切正常。例如: class MyController extends Controller { public function myAction() { // ... $myThirdPartyBundleService = $this->container ->get('my_third_party_bundle_service.class'); // ... } } 我试过的是将控制器声明为服务,遵循官方(Symfony docs)[http://symfony.com/doc/current/cookbook/controller/service.html],因为我在控制器中多次使用该服务。 似乎是MyThirdPartyBundle\DependencyInjection\MyThirdPartyBundleExtension::load()我有服务构建。我还尝试将die('my-third-party-bundle');置于load()方法中,并在MyAppBundle\Controller\MyControlle::__construct()中尝试die('controller')只是为了查看哪一个首先加载。正如我所料,首先返回的结果是来自第三方捆绑的结果。我还在die('my_app_bundle');中尝试了MyAppBundle\DependencyInjection\MyAppBundleExtension::load();。在我尝试时,结果取决于在AppKernel中声明包的顺序。所以我在MyAppBundle之前更改了MyThirdPartyBundle。我仍然没有得到理想的结果,而是取而代之的是NULL。在这一点上,我的第三方包的类似乎还没有构建。我没有太多时间来检查为什么会发生这种情况,但我怀疑原因是容器的配置构建。所以我能做的最简单快速的事情就是覆盖MyAppBundle控制器中的Symfony \ Component \ DependencyInjection \ ContainerInterface :: setContainer()```。它不是解决问题的最优雅方式,但它有效。我认为正确的方法是将控制器声明为服务,但似乎它在我的情况下不起作用。