无法访问扩展Symfony\Bundle\FrameworkBundle\Controller\Controller的控制器中的Symfony2容器 [英] Unable to access Symfony2 container in controller extending Symfony\Bundle\FrameworkBundle\Controller\Controller

查看:67
本文介绍了无法访问扩展Symfony\Bundle\FrameworkBundle\Controller\Controller的控制器中的Symfony2容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了 ,但我仍然感到困惑,因为几乎每次我尝试使用 $ this->容器时,事情似乎都无法正常工作。例如,我正在按照说明的说明在自定义包控制器中构建表单。

I've read every page of the "book" about service containers, and I'm still baffled because things seem to randomly not work nearly every time I try to use $this->container. For example, I'm building a form in my custom bundle controller following the instructions.

我的控制器照常扩展了基本控制器:

My controller extends the base controller as usual:

namespace Gutensite\ArticleBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Gutensite\ArticleBundle\Entity\Article;

class AdminEditController extends Controller
{

    public function indexAction() {


        $content = new Article();
        $form = $this->createFormBuilder($content)
             ->add('content', 'text');

        // same issue with the shortcut to the service which I created according the instructions
        // $form = $this->createForm('myForm', $myEntity)

        //...more code below...
    }
}

这会产生错误:

Fatal error: Call to a member function get() on a non-object in /vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php on line 176

如果我们在该行号上查看该文件,则会看到Symfony的代码:

If we look at that file at that line number we see Symfony's code:

public function createFormBuilder($data = null, array $options = array())
{
    return $this->container->get('form.factory')->createBuilder('form', $data, $options);
}

所以为什么是symfony自己的控制者,无法访问container-> get()函数?!

So WHY is symfony's own controller NOT able to access the container->get() function?!

我在做什么错了?

这些都一样行,我无法弄清楚为什么有时无法在自己的控制器中通过$ this-> container访问容器(如果扩展框架控制器,或者通过在构造中传递容器来引用它,等等)。 似乎随机...

Along these same lines, I can't figure out why sometimes I can't access the container via $this->container in my own controller (if extend the framework controller or if I reference it by passing it in the construct, etc). It seems random...

我正在构建一个CMS,该用户的路线(URL)存储在数据库中。因此,我定义了一条路由,该路由将所有请求定向到我的主CMS控制器:

I am building a CMS that has user's routes (URLs) stored in a database. So I have one route defined which directs all requests to my main CMS Controller:

gutensite_cms_furl:
# Match Multiple Paths (the plain / path appears necessary)
path:     /
path:     /{furl}
defaults: { _controller: GutensiteCmsBundle:Init:index }
# Allow / in friendly urls, through more permissive regex
requirements:
    furl: .*

InitController查找请求的URL并获取正确的Route实体,该路由实体指向一个View实体,该View实体定义了要为请求的特定页面类型加载的Bundle和Controller,例如 / Admin / Article / Edit 的路由指向与Article bundle和AdminEdit控制器关联的内容类型,然后为该内容类型创建一个新对象( Gutensite\ArticleBundle\Controller\AdminEditController.php )并执行所需的功能。然后将必要的变量注入到主ViewController中,该变量将传递到模板中以呈现到页面中。

The InitController looks up the requested URL and gets the correct Route entity which points to a View entity that defines which Bundle and Controller to load for specific page type being requested, e.g. the route for /Admin/Article/Edit points to content type that is associated with the Article bundle and AdminEdit controller, which then creates a new object for this content type (Gutensite\ArticleBundle\Controller\AdminEditController.php) and executes the required functions. This then injects the necessary variables back into the main ViewController which gets passed to the template to be rendered out to the page.

此主控制器扩展了symfony控制器,我已经确认可以在此控制器中访问容器,例如 $ this->容器-> get('doctrine')有效。

This main controller extends symfony controller and I have confirmed that the container is accessible in this controller, e.g. $this->container->get('doctrine') works.

// Gutensite\CmsBundle\Controller\InitController.php
namespace Gutensite\CmsBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Gutensite\CmsBundle\Entity;

class InitController extends Controller
{
    public function indexAction(Request $request, $furl)
    {
        // Confirm container is accessible (yes it is)
        $test = $this->container->get('doctrine');

        // Look up the View Entity based on the Route Friendly URL: $furl
        $viewController = $this->container->get('gutensite_cms.view');
        $viewController->findView($furl, $siteId);

        // Load the Requested Bundle and Controller for this View
    $path = $viewController->view->namespace_controller."\\".$viewController->view->controller;
    $content = new $path;
        // Execute the main function for this content type controller, which adds variables back into the $viewController to be passed to the template.
    $content->indexAction($viewController);

        return $this->render(
        $viewController->view->bundle_shortcut.'::'.$viewController->view->getTemplatesLayout(),
            array('view' => $viewController)
    );


    }
}



ViewController定义为全局服务:

FYI, the ViewController is defined as a global service:

services:
    gutensite_cms.view:
        class: Gutensite\CmsBundle\Controller\ViewController
        arguments: [ "@service_container" ]

然后下面是 Gutensite / CmsBundle / Controller / ViewController.php

namespace Gutensite\CmsBundle\Controller;
use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class ViewController
{

    protected $container;
    public $routing;
    public $view;

    public function __construct(Container $container) {
        $this->container = $container;
    }

    public function findView($furl, $siteId=NULL) {
        $em = $this->container->get('doctrine')->getManager();
        $this->routing = $em->getRepository('GutensiteCmsBundle:Routing\Routing')->findOneBy(
            array('furl'=>$furl, 'siteId'=>$siteId)
        );

        if(empty($this->routing)) return false;

        // If any redirects are set, don't bother getting view
        if(!empty($this->routing->getRedirect())) return FALSE;

        // If there is not view associated with route
        if(empty($this->routing->getView())) return FALSE;

        $this->view = $this->routing->getView();
        $this->setDefaults();
    }
}

返回 InitController。 php 我们检索了视图对象,并加载了正确的捆绑软件和控制器功能。在这种情况下,它加载了 Gutensite\ArticleBundle\Controller\AdminEditController.php,这是我们无法访问服务容器的地方。

Back in the InitController.php we retrieved the view object and loaded the right bundle and controller function. In this case it loaded `Gutensite\ArticleBundle\Controller\AdminEditController.php which is where we lose access to the service container.

namespace Gutensite\ArticleBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Gutensite\ArticleBundle\Entity\Article;

class AdminEditController extends Controller
{

    protected $request;

    public function __contstruct(Request $request) {
        $this->request = $request;
}


public function indexAction($view)
    {
    // TEST: Test if I have access to container (I do not)
    //$doctrine = $this->container->get('doctrine');

        // This loads createForm() function from the Symfony Controller, but that controller then doesn't have access to container either.
        $form = $this->createForm('view', $content);

    }
}



更具体的问题



所以我断定,如果您扩展Symfony Controller(它本身扩展了ContainerAware),则该对象将是知道容器的。但这显然不是事实。这就是我需要更好地理解的地方。我以某种方式假定必须手动注入容器,但是为什么呢?那是标准方法吗?

More Specific Question

So I ASSUMED that if you extend the Symfony Controller, which itself extends ContainerAware, that the object would be "aware of the container". But that evidently is not the case. And that is what I need to understand better. I assume somehow the container has to be injected manually, but why? And is that the standard method?

推荐答案

好。您认为仅创建对象ContainerAware会自动导致容器被注入的假设是错误的。 PHP new运算符对依赖项一无所知。依赖项注入容器的工作是自动注入东西。当然,您并没有使用容器来创建控制器。

Ok. Your assumption that merely making an object ContainerAware will automatically cause the container to be injected is incorrect. The PHP new operator does not know anything about dependencies. It's the job of the dependency injection container to take care of automatically injecting stuff. And of course your are not using the container to create your controllers.

易于修复:

$path = $viewController->view->namespace_controller."\\".$viewController->view->controller;
$content = new $path;
$content->setContainer($this->container);
$content->indexAction($request,$viewController);

我并不真正关注您的流量。在我看来,视图的东西有点倒退,但是我相信您可以看到将容器注入Symfony控制器的位置和方式。不要在依赖容器的控制器构造函数中做任何事情。

I don't really follow your flow. The view stuff seems kind of backwards to me but I trust you can see where and how the container is injected into a Symfony controller. Don't do anything in the controller's constructor which relies on the container.

=================================== =============================

===============================================================

不是使用new运算符,您可以使用服务容器。

Instead of using the new operator, you could use the service container.

$contentServiceId = $viewController->view->contentServiceId;
$content = $this->container->get($contentServiceId);
$content->indexAction($request,$viewController);

不是让您查看返回类名,而是让它返回服务ID。然后,您可以在services.yml中配置控制器,然后就可以使用了。此菜谱条目可能会有所帮助: http://symfony.com/doc/current /cookbook/controller/service.html

Instead of having you view return a class name, have it return a service id. You then configure your controller in services.yml and off you go. This cookbook entry might help a bit: http://symfony.com/doc/current/cookbook/controller/service.html

====================== =====================================

=============================================================

ContainerAware所做的所有事情就是使Symfony DependencyInjectContainer注入容器。而已。没什么。您可以考虑在这里阅读: http://symfony.com/doc/current/ components / dependency_injection / index.html 只是为了了解有关依赖注入和依赖注入器容器的全部基本知识。

All ContainerAware does is to make the Symfony DependencyInjectContainer inject the container. Nothing more. Nothing less. You might conside reading through here: http://symfony.com/doc/current/components/dependency_injection/index.html just to get basic idea of what dependency injection and dependency injector container are all about.

这篇关于无法访问扩展Symfony\Bundle\FrameworkBundle\Controller\Controller的控制器中的Symfony2容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆