2013-02-18 2 views
3

Я следовал руководству Fabien Potiencier, около how to create your own Framework on top of the Symfony Components. Теперь мне нужен способ. И я хочу ввести контейнер зависимостей ко всем моим контроллерам, не определяя каждый отдельный контроллер как службу.Создайте класс базового контроллера, который реализует ContainerAwareInterface

В оригинальной Symfony2 Framework все контроллеры расширяет 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); 
    } 
} 

Так что мой вопрос: Как я могу сделать то же самое в своей Framework?

ответ

3

Мне потребовалось некоторое время, но я, наконец, понял, как это работает в Symfony2 Framework. В SymfonyFrameworkBundle есть пользовательский контроллер, который вызывает метод 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

+0

Как вы зарегистрировали этот пользовательский контроллер? При попытке зарегистрировать ошибки возникают ошибки. –

-1

Контроллер класса расширяет ControllerAware класса, так что вы можете сделать что-то подобное в вашем контроллере:

Ну, это не так. Если мы посмотрим на the signature of the ContainerAware class, мы увидим, что это добавило метод setContainer, чтобы мы могли установить контейнер. Symfony2 создал метод Controller::get, чтобы облегчить жизнь.

Мы можем видеть, как они делают это in the source code:

/** 
* 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 классе, и пусть все ваши контроллеры продлить этот класс контроллера.

+0

Проблема не в методе get, проблема в том, как получить контейнер, введенный в мой контроллер. Я не знаю, как Symfony Framework решила это, не объявляя каждый контроллер как услугу.Кроме того, я не писал $ this-> get (""), но $ this-> container-> get ("") – c4pone

+0

Хотелось бы знать, почему кто-то ответил на этот вопрос ?? –

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

записи smthing как этот

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

и почтовой службы контейнера в качестве аргумента

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; 
} 
Смежные вопросы