3

我遵循了 Fabien Potiencier 的教程,关于如何在 Symfony 组件之上创建自己的框架。现在我需要一个方法。而且我想将依赖容器注入到我的所有控制器中,而不是将每个控制器都定义为服务。

在原始 Symfony2 框架中,所有控制器都扩展了Controller位于以下位置的类Symfony\Bundle\FrameworkBundle\Controller\Controller.php

namespace Symfony\Bundle\FrameworkBundle\Controller;

class Controller extends ContainerAware
{
   // ...
}

该类Controller扩展了ControllerAware该类,因此您可以在控制器中执行以下操作:

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class MyController extends Controller
{
   public function someAction()
   {
      $this->container->get('dependencie_xyz);
   }
}

所以我的问题是:我怎样才能在我的框架中完成同样的事情?

4

4 回答 4

3

我花了一段时间,但我终于弄清楚了 Symfony2 框架是如何做到的。在 SymfonyFrameworkBundle 中有一个自定义的 ControllerResolver,它在解析的控制器上调用 setContainer 方法。控制器必须是 ContainerAwareInterface 的一个实例。

简化版:

class ContainerAwareControllerResolver extends ControllerResolver
{
    private $container;

    public __construct(ContainerInterface $container)
    {
        $this->container = $container;
            parent::__construct();
    }

    public function getController(Request $request)
    {
        $controller = parent::getController($request);
        if($controller instanceof ContainerAware ){
            $controller->setContainer($this->container);
        }
    }
}

来源:

https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php

于 2013-03-12T15:53:58.747 回答
0

太简单了。下一个代码将为您提供帮助

namespace Symfony\Bundle\FrameworkBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Symfony\Component\DependencyInjection\ContainerAware as ContainerAware;

class TestService extends ContainerAware
{
   public function __construct(Container $container) {
      // in your example from official doc 'dependencie_xyz' is a name of service
      $this->setContainer($container); // call parent setContainer() method, for identifying container variable, from now you can access to ServiceContainer using $this->container variable
      $test_param = $this->container->getParameter('test_param'); // get test_param from config.yml
   }

}

在 service.yml

像这样写东西

services:
    test_service:
        class: Symfony\Bundle\FrameworkBundle\TestService
        arguments: ['@service_container']

并将服务容器作为参数发布

于 2013-09-02T12:10:47.030 回答
0

如果您没有在控制器上实现任何接口,您可以添加这种方式,它会起作用。这是对 c4pone 实现的一个小修改。

/**
* Description of ContainerAwareControllerResolver
*
* @author sbc
*/
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;

class ContainerAwareControllerResolver extends ControllerResolver {

private $container;

public function __construct(LoggerInterface $logger = null, ContainerInterface $container = null) {

    parent::__construct($logger);

    $this->container = $container;
}

protected function instantiateController($class) {

    $new_class = new $class();

    $new_class->setContainer($this->container);

    return $new_class;
}
于 2016-03-18T07:57:29.360 回答
-1

Controller 类扩展了 ControllerAware 类,因此您可以在 Controller 中执行以下操作:

好吧,这不是真的。如果我们看一下class的签名ContainerAware,我们会看到它添加了一个setContainer方法,因此我们可以设置容器。Symfony2 创造了Controller::get一种让生活更轻松的方法。

我们可以在源代码中看到他们是如何做到的:

/**
 * Gets a service by id.
 *
 * @param string $id The service id
 *
 * @return object The service
 */
public function get($id)
{
    return $this->container->get($id);
}

您可以将它放在您自己的Controller类中,并让您的所有控制器扩展该控制器类。

于 2013-02-18T19:15:16.733 回答