2013-06-15 10 views
25

nella mia servizi costruttoreCome dare contenitore come argomento per servizi

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

passo entityManager e SecurityContext come argomento. anche il mio services.xml è qui

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

ma ora, voglio usare il recipiente in servizi come

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

come posso passare il contenitore di servizi?

+0

Perché non si aggiunge 'fos_user_profile_edit' come argomento? se non è necessario puoi usare l'iniezione setter. Penso che dovresti avere una buona ragione per iniettare il contenitore dei servizi. Rendo il tuo codice non portatile – Rocco

risposta

39

Add:

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

E nella classe ascoltatore:

use Symfony\Component\DependencyInjection\ContainerInterface; 

//... 

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

grazie! Funziona bene! – whitebear

+1

tecnicamente, dovresti usare __construct (ContainerInterface $ container, ..) poiché probabilmente non stai usando alcuna funzione non definita nell'interfaccia del contenitore. –

+0

Questo mi ha aiutato. grazie –

55

E 'facile, se il servizio si estende 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

È meglio citare '@ service_container'. Perché altrimenti ci sarà l'eccezione lanciata ('L'indicatore riservato" @ "non può iniziare uno scalare semplice, è necessario citare lo scalare alla riga 22 (vicino a" - [setContainer, [@service_container]] ").'). Problema correlato: http://stackoverflow.com/questions/34454834/symfony2-phpunit-yaml-parse-error –

+1

Ho dovuto aggiungere: '$ protetto contenitore; \t public function __construct ($ container) { $ this-> container = $ container; } 'e invece di' calls: - [setContainer, [@service_container]] 'Ho usato' argomenti: ['@service_container'] 'in services.yml per farlo funzionare in Symfony 2.8. A parte questo, tutto funziona bene. Grazie. – Strabek

5

Se tutti i servizi sono ContainerAware, suggerisco di creare una classe BaseService che conterrà tutto il codice comune con gli altri servizi.

1) creare la classe Base\BaseService.php:

<?php 

namespace Fuz\GenyBundle\Base; 

use Symfony\Component\DependencyInjection\ContainerAware; 

abstract class BaseService extends ContainerAware 
{ 

} 

2) registrare questo servizio come astratta nel vostro services.yml

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

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

3) Ora, in altri servizi, si estende la classe BaseService invece di :

<?php 

namespace Fuz\GenyBundle\Services; 

use Fuz\GenyBundle\Base\BaseService; 

class Loader extends BaseService 
{ 
    // ... 
} 

4) Infine, è possibile utilizzare l'opzione parent nella dichiarazione dei servizi.

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

preferisco in questo modo per diversi motivi:

  • vi sia coerenza tra il codice e la configurazione
  • questo evita la duplicazione troppo configurazione per ogni servizio
  • di avere una classe di base per ogni servizio, molto utile per il codice comune
14

È 201 6, è possibile utilizzare il tratto che consente di estendere la stessa classe con più librerie.

<?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); 
    } 
} 

Il tuo oggetto, che sarà di servizio.

namespace AppBundle\Utils; 

use iBasit\ToolsBundle\Utils\Lib\Container; 

class myObject 
{ 
    use Container; 
} 

le impostazioni dei servizi

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

Chiamate il vostro servizio nel controllore

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

con smf3 solo "use \ Symfony \ Component \ DependencyInjection \ ContainerAwareTrait;" –

+0

Non viene fornito con getUser(), getDoctrine, getParameter() ... fornito con il controller. quindi questo renderà la vita più facile, ma alla fine entrambi hanno lo stesso risultato. – Basit

Problemi correlati