Как предоставить контейнер в качестве аргумента для сервисов

в моем конструкторе сервисов

public function __construct( EntityManager $entityManager, SecurityContextInterface $securityContext) { $this->securityContext = $securityContext; $this->entityManager = $entityManager; 

Я передаю entityManager и securityContext в качестве аргумента. также мои services.xml здесь

  <service id="acme.memberbundle.calendar_listener" class="Acme\MemberBundle\EventListener\CalendarEventListener"> <argument type="service" id="doctrine.orm.entity_manager" /> <argument type="service" id="security.context" /> 

но теперь я хочу использовать контейнер в таких сервисах, как

 $this->container->get('router')->generate('fos_user_profile_edit') 

как я могу передать контейнер в сервисы?

Добавить:

 <argument type="service" id="service_container" /> 

И в вашем классе слушателя:

 use Symfony\Component\DependencyInjection\ContainerInterface; //... public function __construct(ContainerInterface $container, ...) { 

Это легко, если сервис расширяет ContainerAware

 use \Symfony\Component\DependencyInjection\ContainerAware; class YouService extends ContainerAware { public function someMethod() { $this->container->get('router')->generate('fos_user_profile_edit') ... } } 

service.yml

  your.service: class: App\...\YouService calls: - [ setContainer,[ @service_container ] ] 

Это 2016 год , вы можете использовать черту, которая поможет вам расширить один класс с несколькими библиотеками.

 <?php namespace iBasit\ToolsBundle\Utils\Lib; use Doctrine\Bundle\DoctrineBundle\Registry; use Symfony\Component\DependencyInjection\ContainerInterface; trait Container { private $container; public function setContainer (ContainerInterface $container) { $this->container = $container; } /** * Shortcut to return the Doctrine Registry service. * * @return Registry * * @throws \LogicException If DoctrineBundle is not available */ protected function getDoctrine() { if (!$this->container->has('doctrine')) { throw new \LogicException('The DoctrineBundle is not registered in your application.'); } return $this->container->get('doctrine'); } /** * Get a user from the Security Token Storage. * * @return mixed * * @throws \LogicException If SecurityBundle is not available * * @see TokenInterface::getUser() */ protected function getUser() { if (!$this->container->has('security.token_storage')) { throw new \LogicException('The SecurityBundle is not registered in your application.'); } if (null === $token = $this->container->get('security.token_storage')->getToken()) { return; } if (!is_object($user = $token->getUser())) { // eg anonymous authentication return; } return $user; } /** * Returns true if the service id is defined. * * @param string $id The service id * * @return bool true if the service id is defined, false otherwise */ protected function has ($id) { return $this->container->has($id); } /** * Gets a container service by its id. * * @param string $id The service id * * @return object The service */ protected function get ($id) { if ('request' === $id) { @trigger_error('The "request" service is deprecated and will be removed in 3.0. Add a typehint for Symfony\\Component\\HttpFoundation\\Request to your controller parameters to retrieve the request instead.', E_USER_DEPRECATED); } return $this->container->get($id); } /** * Gets a container configuration parameter by its name. * * @param string $name The parameter name * * @return mixed */ protected function getParameter ($name) { return $this->container->getParameter($name); } } 

Ваш объект, который будет обслуживать.

 namespace AppBundle\Utils; use iBasit\ToolsBundle\Utils\Lib\Container; class myObject { use Container; } 

Настройки вашего сервиса

  myObject: class: AppBundle\Utils\myObject calls: - [setContainer, ["@service_container"]] 

Позвоните в службу поддержки

 $myObject = $this->get('myObject'); 

Если все ваши услуги ContainerAware , я предлагаю создать класс BaseService, который будет содержать весь распространенный код с вашими другими сервисами.

1) Создайте класс Base\BaseService.php :

 <?php namespace Fuz\GenyBundle\Base; use Symfony\Component\DependencyInjection\ContainerAware; abstract class BaseService extends ContainerAware { } 

2) Зарегистрируйте эту услугу как абстрактный в своих services.yml

 parameters: // ... geny.base.class: Fuz\GenyBundle\Base\BaseService services: // ... geny.base: class: %geny.base.class% abstract: true calls: - [setContainer, [@service_container]] 

3) Теперь, в ваших других сервисах, расширяет класс BaseService вместо ContainerAware :

 <?php namespace Fuz\GenyBundle\Services; use Fuz\GenyBundle\Base\BaseService; class Loader extends BaseService { // ... } 

4) Наконец, вы можете использовать parent вариант в объявлении своих сервисов.

 geny.loader: class: %geny.loader.class% parent: geny.base 

Я предпочитаю этот путь по нескольким причинам:

  • существует согласованность между кодом и конфигурацией
  • это позволяет избежать дублирования слишком большого количества конфигураций для каждой службы
  • у вас есть базовый класс для каждого сервиса, очень полезный для общего кода