Symfony 3:无法从控制器内部访问容器
Symfony 3: cannot access the container from inside a controller
我正在将我的应用程序从 Symfony 2.8 迁移到 Symfony 3.3。
从我的控制器里面我有这个:
public function indexAction()
{
$email = new Email();
$form = $this->createForm(GetStartedType::class, $email, [
'action' => $this->generateUrl('get_started_end'),
'method' => 'POST',
]);
return [
'form' => $form->createView(),
];
}
但是我收到这个异常:
Call to a member function get() on null
我的控制器扩展 Symfony\Bundle\FrameworkBundle\Controller\Controller
:
/**
* {@inheritdoc}
*/
class DefaultController extends Controller
{
...
}
所以我可以访问容器。
在 Symfony 的代码中放置一些转储,我看到容器设置正确:
namespace Symfony\Component\DependencyInjection;
/**
* ContainerAware trait.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
trait ContainerAwareTrait
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* Sets the container.
*
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/
public function setContainer(ContainerInterface $container = null)
{
dump('Here in the ContainerAwareTrait');
dump(null === $container);
$this->container = $container;
}
}
这转储
Here in the ContainerAwareTrait
false
所以自动装配工作正常并设置容器。
但是在 ControllerTrait
我有这个:
trait ControllerTrait
{
/**
* Generates a URL from the given parameters.
*
* @param string $route The name of the route
* @param mixed $parameters An array of parameters
* @param int $referenceType The type of reference (one of the constants in UrlGeneratorInterface)
*
* @return string The generated URL
*
* @see UrlGeneratorInterface
*/
protected function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
{
dump('Here in the ControllerTrait');
die(dump(null === $this->container));
return $this->container->get('router')->generate($route, $parameters, $referenceType);
}
...
这是转储:
Here in the ControllerTrait
true
所以这里的 container
是 null
,这会导致错误。
谁能帮我解决这个问题?
为什么 container
为空?
如果有帮助,这是 services.yml
配置(Symfony 附带的默认配置):
# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
tags: ['controller.service_arguments']
此问题已作为问题发布在 Symfony's issue tracker。
S3.3 自动装配功能使得将控制器定义为服务变得更加容易。
将控制器定义为服务的通常动机是避免注入容器。换句话说,您应该显式注入控制器使用的每个服务。自动装配功能允许您使用操作方法注入,因此您不必在构造函数中注入一堆东西。
然而,基本的 Symfony 控制器 class 提供了一些使用大约 12 种不同服务的辅助功能。一次注射这些确实会很痛苦。我曾以为自动装配功能可能会为您解决这个问题,但我想不会。
因此,您基本上需要在服务定义中添加对 setContainer 的调用。类似于:
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
[[setContainer, ['@service_container']]]
tags: ['controller.service_arguments']
自动装配功能仍在开发中,因此如果 3.4/4.0 发生变化,我不会感到惊讶。
此问题已由 PR #23239 and is relased in Symfony 3.3.3 解决。
我正在将我的应用程序从 Symfony 2.8 迁移到 Symfony 3.3。
从我的控制器里面我有这个:
public function indexAction()
{
$email = new Email();
$form = $this->createForm(GetStartedType::class, $email, [
'action' => $this->generateUrl('get_started_end'),
'method' => 'POST',
]);
return [
'form' => $form->createView(),
];
}
但是我收到这个异常:
Call to a member function get() on null
我的控制器扩展 Symfony\Bundle\FrameworkBundle\Controller\Controller
:
/**
* {@inheritdoc}
*/
class DefaultController extends Controller
{
...
}
所以我可以访问容器。
在 Symfony 的代码中放置一些转储,我看到容器设置正确:
namespace Symfony\Component\DependencyInjection;
/**
* ContainerAware trait.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
trait ContainerAwareTrait
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* Sets the container.
*
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/
public function setContainer(ContainerInterface $container = null)
{
dump('Here in the ContainerAwareTrait');
dump(null === $container);
$this->container = $container;
}
}
这转储
Here in the ContainerAwareTrait
false
所以自动装配工作正常并设置容器。
但是在 ControllerTrait
我有这个:
trait ControllerTrait
{
/**
* Generates a URL from the given parameters.
*
* @param string $route The name of the route
* @param mixed $parameters An array of parameters
* @param int $referenceType The type of reference (one of the constants in UrlGeneratorInterface)
*
* @return string The generated URL
*
* @see UrlGeneratorInterface
*/
protected function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
{
dump('Here in the ControllerTrait');
die(dump(null === $this->container));
return $this->container->get('router')->generate($route, $parameters, $referenceType);
}
...
这是转储:
Here in the ControllerTrait
true
所以这里的 container
是 null
,这会导致错误。
谁能帮我解决这个问题?
为什么 container
为空?
如果有帮助,这是 services.yml
配置(Symfony 附带的默认配置):
# controllers are imported separately to make sure they're public
# and have a tag that allows actions to type-hint services
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
tags: ['controller.service_arguments']
此问题已作为问题发布在 Symfony's issue tracker。
S3.3 自动装配功能使得将控制器定义为服务变得更加容易。
将控制器定义为服务的通常动机是避免注入容器。换句话说,您应该显式注入控制器使用的每个服务。自动装配功能允许您使用操作方法注入,因此您不必在构造函数中注入一堆东西。
然而,基本的 Symfony 控制器 class 提供了一些使用大约 12 种不同服务的辅助功能。一次注射这些确实会很痛苦。我曾以为自动装配功能可能会为您解决这个问题,但我想不会。
因此,您基本上需要在服务定义中添加对 setContainer 的调用。类似于:
AppBundle\Controller\:
resource: '../../src/AppBundle/Controller'
public: true
[[setContainer, ['@service_container']]]
tags: ['controller.service_arguments']
自动装配功能仍在开发中,因此如果 3.4/4.0 发生变化,我不会感到惊讶。
此问题已由 PR #23239 and is relased in Symfony 3.3.3 解决。