2013-06-15 3 views
25

w moich usług konstruktoraJak dać pojemnik jako argument do usług

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

mijam EntityManager i securityContext jako argument. także mój services.xml jest tutaj

<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" /> 

ale teraz chcę użyć kontenera w usługach takich jak

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

jak mogę przejść pojemnik do usług?

+0

Dlaczego nie można dodać 'fos_user_profile_edit' jako argument? jeśli nie jest to wymagane, możesz użyć zastrzyku ustawiającego. Myślę, że powinieneś mieć bardzo dobry powód do wstrzyknięcia pojemnika na usługi. Sprawię, że twój kod nie będzie przenośny – Rocco

Odpowiedz

39

Dodaj:

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

A w swojej klasie słuchacza:

use Symfony\Component\DependencyInjection\ContainerInterface; 

//... 

public function __construct(ContainerInterface $container, ...) { 
+0

dzięki! to dobrze działa! – whitebear

+1

technicznie powinieneś użyć __construct (ContainerInterface $ container, ..), ponieważ prawdopodobnie nie używasz żadnych funkcji nie zdefiniowanych w interfejsie kontenera. –

+0

To mi pomogło. dzięki –

55

To proste, jeśli usługa rozciąga 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 ] ] 
+0

Lepiej zacytować '@ service_container'. Ponieważ w przeciwnym razie wystąpi wyjątek ('Zarezerwowany wskaźnik" @ "nie może uruchomić zwykłego skalarnego, musisz podać wartość skalarną w linii 22 (w pobliżu" - [setContainer, [@service_container]] ").'). Powiązany numer: http://stackoverflow.com/questions/34454834/symfony2-phpunit-yaml-parse-error –

+1

Musiałem dodać: 'protected $ container; \t funkcja publiczna __construct ($ container) { $ this-> container = $ container; } 'i zamiast' calls: - [setContainer, [@service_container]] 'Użyłem' argumentów: ['@service_container'] 'w services.yml , aby działało to w Symfony 2.8. Poza tym wszystko działa dobrze. Dzięki. – Strabek

5

Jeśli wszystkie twoje usługi to ContainerAware, proponuję utworzyć klasę BaseService, która będzie zawierać wszystkie popularne kody z innymi usługami.

1) Tworzenie klasy Base\BaseService.php:

<?php 

namespace Fuz\GenyBundle\Base; 

use Symfony\Component\DependencyInjection\ContainerAware; 

abstract class BaseService extends ContainerAware 
{ 

} 

2) zarejestrować tę usługę jako abstrakcyjne w swojej services.yml

parameters: 
    // ... 
    geny.base.class: Fuz\GenyBundle\Base\BaseService 

services: 
    // ... 
    geny.base: 
     class: %geny.base.class% 
     abstract: true 
     calls: 
      - [setContainer, [@service_container]] 

3) Teraz, w innych usługach, rozszerza klasę BaseService zamiast ContainerAware:

<?php 

namespace Fuz\GenyBundle\Services; 

use Fuz\GenyBundle\Base\BaseService; 

class Loader extends BaseService 
{ 
    // ... 
} 

4) Wreszcie, możesz użyć opcji parent w deklaracji usług.

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

wolę ten sposób z kilku powodów:

  • istnieje zgodność między kodem a config
  • tego uniknąć powielania zbyt dużo config dla każdej usługi
  • masz klasę bazową dla każdej usługi bardzo pomocne dla wspólnego kodu
14

Jest 201 6, możesz użyć cechę, która pomoże ci rozszerzyć tę klasę o wiele bibliotek.

<?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())) { 
      // e.g. 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); 
    } 
} 

Twój obiekt, który będzie usługą.

namespace AppBundle\Utils; 

use iBasit\ToolsBundle\Utils\Lib\Container; 

class myObject 
{ 
    use Container; 
} 

ustawienia usług

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

wywołać usługę w kontrolerze

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

z smf3 po prostu "użyj \ Symfony \ Component \ DependencyInjection \ ContainerAwareTrait;" –

+0

Nie jest dostarczany z funkcjami getUser(), getDoctrine, getParameter() ..., który jest dostarczany z kontrolerem. więc to ułatwi życie, ale na końcu oba mają taki sam rezultat. – Basit