IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Symfony PHP Discussion :

Tentative d'injection de dépendances via un service


Sujet :

Symfony PHP

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2013
    Messages : 25
    Points : 15
    Points
    15
    Par défaut Tentative d'injection de dépendances via un service
    Bonjour,

    J'ai actuellement un Bundle Symfony2 qui a été écrit sans injection de dépendances, j'ai dans mon contrôleur les méthodes suivantes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    private function calulcateMaterial(Product $product, $tab = null, $percentage_field = null, $simulationMaterials = false)
        {
            $em = $this->getDoctrine()->getEntityManager();
     
            // Initialize array to 11 values set to 0
            if ($tab != null) {
                $m = $tab;
            } else {
                $m = array_fill(0, 11, 0);
            }
     
            foreach($product->getAssemblies() as $assembly) {
                foreach($assembly->getParts() as $part) {
     
                    if ($part->getParent() != null) {
                        $quantity = $part->getParent()->getQuantity();
     
                        $base = $part->getMaterial();
     
                        if ($base != null) {
     
                            if ($part->getParam2() != null) {
                                $val = $part->getParam1() * $part->getParam2();
                            } else {
                                $val = $part->getParam1();
                            }
     
                            // Simulation for parts
                            if ($percentage_field != null && !$simulationMaterials) {
                                $percentage = $part->getParent()->$percentage_field();
                                if ($percentage != null) {
                                    $val = $val * $percentage;
                                }
                            }
     
                            // Simulation for materials
                            if ($simulationMaterials) {
                                if ($part->getMaterial() != null) {
                                    $simulation = $em->getRepository('ArtoAcvBundle:SimulationMaterial')->findOneBy(array(
                                        'product'  => $product->getId(),
                                        'material' => $part->getMaterial()->getId()
                                    ));
     
                                    if ($simulation != null && $simulation->$percentage_field() != null) {
                                        $val = $val * $simulation->$percentage_field();
                                    }
                                }
                            }
     
                            $mul = $assembly->getQuantity() * $quantity * $val;
     
                            $m[0]  += $base->getRmd() * $mul;
                            $m[1]  += $base->getEd() * $mul;
                            $m[2]  += $base->getWd() * $mul;
                            $m[3]  += $base->getGwp() * $mul;
                            $m[4]  += $base->getOdp() * $mul;
                            $m[5]  += $base->getAt() * $mul;
                            $m[6]  += $base->getPocp() * $mul;
                            $m[7]  += $base->getAa() * $mul;
                            $m[8]  += $base->getWt() * $mul;
                            $m[9]  += $base->getWe() * $mul;
                            $m[10] += $base->getHwp() * $mul;
                        }
                    }
                }
            }
     
            return $m;
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    private function calculateAll(Product $product)
        {
            $tab = $this->calulcateMaterial($product);
            return $tab;
        }
    La méthode calculateAll est appelée dans une de mes actions, seulement toutes ces méthodes n'ayant rien à faire dans mon contrôleur, j'ai voulu les externaliser.

    J'ai donc créé un service Calculator qui va faire les calculs.

    Mon services.xml ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    <?xml version="1.0" encoding="UTF-8"?>
     
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
     
        <services>
            <service id='acv.calculator'
                     class='Arto\AcvBundle\Calculator\Calculator'>
                     <argument type="service" id="doctrine.orm.entity_manager"/>
                     <call method="calculateMaterial">
                          <argument type="service" id="acv.product"></argument>
                     </call>
            </service>
            <service id='acv.product'
                     class='Arto\AcvBundle\Entity\Product'
                     public='false'>
            </service>
        </services>
    </container>
    J'ai donc écrit dans calculateAll(Product $product) le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $calculator = $this->getCalculator();
    $tab = $calculator->calculateMaterial($product);
    Seulement dans cette méthode je récupère toujours un $product NULL.

    A priori, je ne l'ai pas initialisé dans ma balise <argument></argument> dans le services.xml.

    Mais je ne vois pas comment je peux passer ma variable $product de ma méthode calculateAll() vers le services.xml dynamiquement.

    Si quelqu'un comprend mon souci et veux bien m'aider/me dire ce que je fais mal.

    Merci

    Antoine

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 168
    Points : 219
    Points
    219
    Par défaut
    slt,

    tu as un getter ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $calculator = $this->getCalculator();
    Si tu veux récupérer un service il faut faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            $service = $this->get('mon_service');
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            $service = $this->container->get('mon_service')
    une config simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    <?xml version="1.0" ?>
     
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
     
        <parameters>
            <parameter key="mon_service.class">App\FrontendBundle\Service\MonService</parameter>
        </parameters>
     
        <services>
            <service id="mon_service" class="%mon_service.class%">
            </service>
        </services>
     
    </container>


    Maintenant si dans ta class MonService tu as une methode calculate, dans ton controller tu n'as plus qu'a faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            $data = array();
            $service = $this->container->get('mon_service');
            $result = $service->calculate($data);

    Ensuite on parlera de passer la Request a ton service.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur Web
    Inscrit en
    Octobre 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2013
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    Bonsoir et merci mais tout ça a priori je l'ai déja,

    J'ai en effet fait mon :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $calculator = $this->getCalculator();
    ou getCalculator me donne un accès à mon service.

    Je fais bien mon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $calculator->calculate($product)
    et en effet ça fait appel à la bonne méthode de la classe Calculator.

    $product est une entité Doctrine, après je pourrais très bien passer un $productId et reconstituer le $product dans mon Calculator.

    Mon souci est que je récupère toujours un $product NULL au lieu de récupérer le $product que je passe à ma méthode

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 168
    Points : 219
    Points
    219
    Par défaut
    Poses ton code sur un git ou autre que l'on puisse regarder, par ce que j'ai du mal a te suivre.

  5. #5
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Septembre 2009
    Messages
    875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Septembre 2009
    Messages : 875
    Points : 1 313
    Points
    1 313
    Par défaut
    Enfait les arguments de ton services que tu configures sont souvent les services que ton service va utiliser.
    Un service (de scope normal mais tu verras les scopes plus tard c'est plus avancé) est une seule instance de cette classe la qui est accessible par le container. Il est créé au moment de l'initialisation du container (de mémoire).


    Voici a quoi devrait ressembler ton service calculator, de mon point de vue:

    la config (déolé j'écrit en yml mais ca reste identique)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    parameters:
        calculator.class  : Path\To\Service\CalculatorService
     
    services:
        calculator:
            class: "%calculator.class%"
            arguments: [ "@doctrine.orm.entity_manager"]
    Ton service:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    class CalculatorService {
    
        private $em;
    
        public function __construct(EntityManagerInterface $em)
        {
            $this->em  = $em;
        }
    
       public function calculate(Product $product)
     
            // Initialize array to 11 values set to 0
            if ($tab != null) {
                $m = $tab;
            } else {
                $m = array_fill(0, 11, 0);
            }
     
            foreach($product->getAssemblies() as $assembly) {
                foreach($assembly->getParts() as $part) {
     
    /*  [...]  */
                                if ($part->getMaterial() != null) {
                                    $simulation = $this->em->getRepository('ArtoAcvBundle:SimulationMaterial')->findOneBy(array(
                                        'product'  => $product->getId(),
                                        'material' => $part->getMaterial()->getId()
                                    ));
    /* [...]  */
     
            return $m;
      }
    }
    Après je vois pas trop l'interet de deux boucles imbriquées foreach alors que tu peux aller chercher les parts directement avec une requete. En plus le nombre de requete que tu génères est anormal.
    Ducoup le plus propre ce serait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public function calculate($product_id)
     
            // Initialize array to 11 values set to 0
            // [...]
            $parts =  $this->em->getRepository('ArtoAcvBundle:Part')->getPartByProductJoinSimulation(); l
            foreach($parts  as $part) {
            /* [...]  */
    Cette requete $this->em->getRepository('ArtoAcvBundle:Part')->getPartByProductJoinSimulation(); est une requete personnalisée écrite dans ton repository, qui va chercher tous les parts des assembly reliés au produit. Essaye de faire une jointure vers simulation pour pas généré tes requetes au milieu d'une boucle $simulation = $this->em->getRepository('ArtoAcvBundle:SimulationMaterial')->findOneBy(

Discussions similaires

  1. [2.x] Questions sur les services et l'injection de dépendance
    Par bilbi dans le forum Symfony
    Réponses: 2
    Dernier message: 15/06/2012, 12h02
  2. Spring + TagSupport et injection de dépendance
    Par worldchampion57 dans le forum Spring Web
    Réponses: 2
    Dernier message: 26/02/2007, 09h01
  3. [VB.NET] accéder au registre via un service
    Par Golzinne dans le forum Windows Forms
    Réponses: 7
    Dernier message: 14/12/2006, 16h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo