web-dev-qa-db-fra.com

Comment puis-je accéder à un service en dehors d'un contrôleur avec Symfony2?

Je construis un site qui s'appuie beaucoup sur une API tierce; j'ai donc pensé qu'il serait judicieux de conditionner le wrapper de l'API en tant que service. Cependant, je commence à trouver des cas où il serait utile d'y accéder en dehors d’un contrôleur tel que dans un référentiel d’entités. Il est également utile d’être en mesure d’obtenir un accès aux valeurs de configuration en dehors d’un contrôleur (comme dans un référentiel d’entités).

Quelqu'un peut-il me dire si cela est possible et si non existe-t-il une approche suggérée pour faire ce genre de chose?

merci pour toute aide

51
pogo

La distribution Symfony repose fortement sur l’injection de dépendance. Cela signifie que généralement, les dépendances sont injectées directement dans votre objet via le constructeur, les setters ou par d'autres moyens (comme la réflexion sur les propriétés). Votre service d'encapsulation d'API est alors une dépendance pour les autres objets de votre application.

Cela étant dit, il serait assez difficile d'injecter ce service dans le constructeur d'un référentiel d'entités car il nécessite déjà d'autres paramètres et je pense qu'il ne serait pas possible de les injecter en raison de la façon dont nous demandons le référentiel d'une entité.

Ce que vous pouvez faire est de créer un autre service qui sera chargé de faire le travail que vous étiez sur le point de faire dans le référentiel d’entités. De cette façon, vous pourrez injecter le gestionnaire d'entités, qui sera utilisé pour extraire le référentiel d'entités, votre service personnalisé ainsi qu'un autre service contenant vos valeurs de configuration (il existe d'autres moyens de partager des valeurs de configuration).

Dans mon cas d'utilisation, j'utilise un service d'assistance Facebook qui englobe les appels de l'API Facebook. Ce service est ensuite injecté où j'en ai besoin. Mon référentiel d'entités est uniquement responsable des appels à la base de données, il ne reçoit donc que les arguments dont il a besoin et non la dépendance entière. Ainsi, il ne recevra pas l'assistant mais uniquement les arguments nécessaires pour effectuer une demande, par exemple un identifiant d'utilisateur Facebook. À mon avis, c'est la façon de le faire car je pense que le référentiel d'entités ne devrait pas avoir de dépendances sur de tels objets auxiliaires.

Voici un petit exemple utilisant YAML comme configuration:

# app/config/config.yml
services:
  yourapp.configuration_container:
    class: Application/AcmeBundle/Common/ConfigurationContainer
    # You could inject configurations here      

  yourapp.api_wrapper:
    class: Application/AcmeBundle/Service/ApiWrapperService
    # Inject other arguments if needed and update constructor in consequence    

  yourapp.data_access:
    class: Application/AcmeBundle/Data/Access/DatabaseAccessService
    arguments: 
      entityManager: "@doctrine.orm.entity_manager"
      apiWrapperService: "@yourapp.api_wrapper"
      configuration: "@yourapp.configuration_container"

# Application/AcmeBundle/Common/ConfigurationContainer.php
public ConfigurationContainer
{
   public function __construct()
   {
       // Initialize your configuration values or inject them in the constructor
   }
}        

# Application/AcmeBundle/Service/ApiWrapperService.php
public ApiWrapperService
{
   public function __construct()
   {
       // Do some stuff
   }
}

# Application/AcmeBundle/Data/Access/DatabaseAccessService.php
public DatabaseAccessService
{
    public function __construct(EntityManager $entityManager, ApiWrapperService $apiWrapperService, ConfigurationContainer $configuration)
    {
        ...
    }
}

Le signe at (@) dans le fichier config.yml signifie que Symfony doit injecter un autre service dont l'identifiant est défini après le signe ar, et non une simple chaîne. Comme je l'ai dit précédemment, pour les valeurs de configuration, il existe d'autres moyens d'atteindre le même objectif, comme utiliser des paramètres ou une extension de paquet. Avec une extension de bundle, vous pouvez définir les valeurs de configuration directement dans le fichier config.yml et votre bundle les lira.

En conclusion, cela devrait vous donner l’idée générale des services d’injection. Voici une petite liste de documentation sur le sujet. Beaucoup de liens utilisent la définition du service XML au lieu de la définition YAML, mais vous devriez pouvoir les comprendre assez facilement.

  1. Symfony Official DI
  2. Articles de Fabien Potencier sur DI
  3. Articles de Richard Miller sur DI (Consultez son blog pour les autres articles de DI)

Notez que la configuration que je vous donne fonctionne pour Beta1 de Symfony2. Je n'ai pas encore mis à jour la version bêta2, il est donc possible que certains éléments ne fonctionnent pas comme dans la version bêta2.

J'espère que cela vous aidera à définir une solution finale à votre problème. N'hésitez pas à poser d'autres questions si vous souhaitez des éclaircissements ou autre chose.

Cordialement, .__ Matt

74
Matt

Je voudrais envelopper ce genre de comportement dans un service Symfony (comme un gestionnaire) . Je n'injecterais aucun paramètre ni aucune logique dans les référentiels d'entités, car ils devraient principalement être utilisés pour récupérer des données à l'aide de requêtes de gestionnaire d'objets . Je mettrais la logique dans les services et si le service nécessite un accès à la base de données, il appellera le référentiel d'entités pour récupérer les données.

0
shacharsol