Doublon dans un array ?

Résolu
emrh Messages postés 439 Statut Membre -  
emrh Messages postés 439 Statut Membre -
Bonjour à tous,

J'ai du mal à comprendre les array ce qui fait que je n'obtiens pas ce que je veux
avec ma programmation...
Voici une requête qui fonctionne bien dans PhpMyAdmin :
SELECT contrats.facture, SUM(T.total) AS Total_facture
FROM (SELECT id_contrat,prix*quantites AS total FROM compositions) AS T
INNER JOIN contrats
ON contrats.id_contrat = T.id_contrat
WHERE contrats.facture <> 'NULL'
AND contrats.id_client =18
GROUP by contrats.facture


résultat obtenu :


Mais qui ne donne pas le résultat escompté en php :
// Récupération des factures du client sélectionné : 
      $requete_factures = $bdd->prepare('
        SELECT contrats.facture, contrats.date_facture, contrats.id_contrat
        FROM contrats
        WHERE contrats.id_client = :id_client
        AND contrats.etat = 3
        
        ORDER BY contrats.facture DESC');
      $requete_factures->execute(array('id_client' => $_GET['id_client']));
      $nbr_factures = $requete_factures->rowCount(); 


      // Calcul du total par facture :
      $requete_totaux_factures = $bdd->prepare("
          SELECT contrats.facture, SUM(T.total) AS Total_facture
          FROM (SELECT id_contrat,prix*quantites AS total FROM compositions) AS T
          INNER JOIN contrats
          ON contrats.id_contrat = T.id_contrat
          WHERE contrats.facture <> 'NULL'
          AND contrats.id_client = :id_client
          GROUP by contrats.facture");
      $requete_totaux_factures->execute(array('id_client' => $_GET['id_client']));
      $totauxparfactures = $requete_totaux_factures->fetchAll();


      // On stock les n° de factures et leurs totaux correspondant dans un array $total :
      $total_facture=array();
      foreach($totauxparfactures as $valeur) {
        $total_facture[$valeur['facture']] = $valeur['Total_facture'];
      }



<tbody>
   <?php
      while ($data_facture = $requete_factures->fetch()) { ?>
   <tr>
      <td>
         <?php
            echo $data_facture['facture']; ?>
      </td>
      <td class="td-gauche">
         <?php 
            $date_facture = date("d/m/Y", strtotime($data_facture['date_facture']));
            echo $date_facture;
            ?>
      </td>
      <td class="td-droite">
         <?php
            $total = $total_facture[$data_facture['facture']];
            echo number_format($total, 2, ',', ' ');?>
      </td>
   </tr>
   <?php }?>
</tbody>






Pourriez vous m'aider à résoudre ce double affichage des factures ?
D'avance merci !

Configuration: Linux / Chrome 99.0.4844.84

1 réponse

  1. jordane45 Messages postés 30427 Date d'inscription   Statut Modérateur Dernière intervention   4 831
     
    Bonjour,

    <?php
    // NB: Code à placer AU DEBUT de ton script PHP .. pas en plein milieu de ton code html comme 
    // il semble que ça soit le cas actuellement !!
    
    //---------------------------------------------------------------//
    //connexion à la bdd
    // A lire et à appliquer avant de poursuivre :
    // http://www.commentcamarche.net/faq/46512-pdo-gerer-les-erreurs
    //---------------------------------------------------------------//
    
    
    //---------------------------------------------------------------//
    // On va découper ton code en "fonctions"
    // ça le rendra plus lisible et plus facile
    // à maintenir ou à faire évoluer
    //---------------------------------------------------------------//
    
    function getNbFacturesById_Client($id_client){
      global $bdd;
      $sql = "SELECT count(*) AS NB
            FROM contrats
            WHERE contrats.id_client = :id_client
            AND contrats.etat = 3";
      try{
        $stmt = $bdd->prepare($sql);
        $stmt->execute(array(':id_client' => $id_client));
        $resultat = $stmt->fetchColumn(); // https://www.php.net/manual/fr/pdostatement.fetchcolumn.php
        return $resultat;
      }catch(Exception $e){
        echo "Erreur dans la requête " . $sql;
        echo $e->getMessage();
        exit;
      }
    }
    
    function getFacturesById_Client($id_client){
      global $bdd;
      $sql = "SELECT contrats.facture
                  , SUM(T.total) AS TOTAL_FACTURE
                  , DATE_FORMAT(contrats.date_facture, '%d/%m/%Y) as DATE_FACTURE_FR
              FROM (
                SELECT id_contrat,prix*quantites AS total FROM compositions
                ) AS T
              INNER JOIN contrats  ON contrats.id_contrat = T.id_contrat
              WHERE contrats.facture <> 'NULL'
              AND contrats.id_client = :id_client
              GROUP by contrats.facture";
      try{
        $stmt = $bdd->prepare($sql);
        $stmt->execute(array(':id_client' => $id_client));
        $resultat = $stmt->fetchAll(); //On retourne un Array du résultat
        return $resultat;
      }catch(Exception $e){
        echo "Erreur dans la requête " . $sql;
        echo $e->getMessage();
        exit;
      }
    }
    
    
    
    //---------------------------------------------------//
    // On récupère proprement les variables envoyées 
    // en $_POST / $_GET / $_SESSION ...  AVANT de les utiliser
    // pour cela, j'utilise l'écriture ternaire : https://blog.smarchal.com/operateur-ternaire-php#:~:text=L'op%C3%A9rateur%20ternaire%20est%20un,%5BTHEN%5D%20%3A%20%5BELSE%5D%3B
    //---------------------------------------------------//
    $id_client = !empty($_GET['id_client']) ? trim($_GET['id_client']) : NULL;
    
    // On récupère les données en bdd
    $nbFactures = getNbFacturesById_Client($id_client); // nombre de facture pour le client et en etat 3 ( tu ne t'en sers pas ? )
    $arrFactures = getFacturesById_Client($id_client); // array contenant la liste de tes factures
    
    
    ?>
    


    Et ensuite, dans ton code html, là où tu veux t'en servir :
    <tbody>
       <?php
         foreach( $arrFactures as $F ) {
        ?>
       <tr>
          <td>
            <?php
              echo $F['facture']; 
            ?>
          </td>
          <td class="td-gauche">
            <?php 
              echo $F['DATE_FACTURE_FR'];
            ?>
          </td>
          <td class="td-droite">
            <?php
              $total = $total_facture[$F['TOTAL_FACTURE']];
              echo number_format($total, 2, ',', ' ');
            ?>
          </td>
       </tr>
       <?php
       }
       ?>
    </tbody>
    


    1
    1. emrh Messages postés 439 Statut Membre 20
       
      Houlalalala ! C'est tout nouveau pour moi tout ça !
      Merci Jordan pour cette longue explication que je vais décortiquer pour comprendre comment tu codes
      et m'en inspirer...


      // NB: Code à placer AU DEBUT de ton script PHP .. pas en plein milieu de ton code html comme
      // il semble que ça soit le cas actuellement !!

      Non, non, je t'assure, mon code php est bien écrit en début de page et mon JavaScript en fin de page...
      D'ailleurs je me demande pourquoi écrire des fonctions en début de code (qui obligent l'utilisation de global $bdd; par exemple) si on peut récupérer au même endroit les variables d'URL (ou de formulaires) puis lancer les requêtes dans la foulée ?
      Tu dis que c'est pour la lisibilité et la maintenance alors que je pensais que des blocs d'instructions comme
      ça étaient tout aussi faciles à lire et maintenir :




      L'utilisation de $stmt est certainement plus pro et propre que $requete_totaux_factures
      mais quand on peine avec le code, il me semblait que c'était plus lisible d'utiliser des variables claires plutôt qu'abstraites. D'autre part, je suis souvant coincé par le nom de variables utilisées plus loin dans le code comme $facture, c'est pour ça que pour éviter des plantages j'utilise ce type de noms de requêtes...

      Je suis prêt à passer en pro mais je me demande quelle peut être l'utilité de rendre le code plus concis ? C'est comme l'écriture ternaire que j'ai utilisé une fois ou deux mais, par manque d'habitude, je la trouve moins simple à lire...
      C'est comme les foreach : ou les endif : qui ont fait disparaître les } ...ça doit être une question d'habitude !


      //connexion à la bdd .../... pdo-gerer-les-erreurs
      Ma page connexion.php me semblait correcte non ?



      SELECT count(*) AS NB...
      $nbr_contrats = $requete_contrats->rowCount(); me semblait pourtant pas mal pour le/les comptages...
      Tu me déconseilles son utilisation ?


      fetchColumn();
      Je vais jeter un œil là dessus, bien que j'ai toujours pensé que la doc de php.net s'adressait à des pros : elle m'est extrêmement difficile à lire et à comprendre... Mais j'ai bien conscience que je vais devoir y passer pour obtenir les
      résultats de plus en plus complexes que je souhaite obtenir (tout comme les FetchAll(PDO:: ...etc que je ne sais toujours pas utiliser !)
      0
    2. emrh Messages postés 439 Statut Membre 20
       
      - Du coup, tu utilises $stmt pour toutes tes requêtes ?
      Je peux donc appeler toutes les miennes $requete et n'utiliser qu'un seul closeCursor(); ?

      - J'ai corrigé ' dans DATE_FORMAT(contrats.date_facture, '%d/%m/%Y)

      - Pour quelle raison tu utilises des champs en majuscules comme DATE_FACTURE_FR et tu laisses les
      autres en minuscules ? Devrais-je pour des raisons de normalisation utiliser des majuscules pour le
      nom de mes champs en bdd ?

      - Comment lire en français cette ligne :
      $id_client = !empty($_GET['id_client']) ? trim($_GET['id_client']) : NULL;
      Voilà ce que je comprends :
      Variable id_client = SI (elle n'est pas vide) ALORS ???? supprimer les espaces de id_client ? SINON id_client n'existe pas


      - Toutes mes requêtes fonctionnent avec
      execute(array('id_client' => $_GET['id_client']));
      à quoi sert le : que tu ajoutes dans
      execute(array(':id_client' => $_GET['id_client']));
      1
    3. emrh Messages postés 439 Statut Membre 20
       



      :-)
      Merci JORDAN !!!
      0
    4. jordane45 Messages postés 30427 Date d'inscription   Statut Modérateur Dernière intervention   4 831 > emrh Messages postés 439 Statut Membre
       
      rowCount ne s'utilise pas avec une requête de type SELECT
      A la place, on fera une requête avec un count ou alors un fetchAll (sur lequel on fera un count en php )

      Pour ce qui est du découpage en fonctions ( fonctions que tu pourrais mettre dans un autre fichier et l'inclure dans les pages où tu en as besoin) c'est avant tout pour éviter de réécrire plusieurs fois le même code dans différentes pages.
      J'aurai pu aller encore plus loin ( ce que je fais souvent ) en découpant en CLASS ( histoire de passer à la notion d'objet )
      1
    5. jordane45 Messages postés 30427 Date d'inscription   Statut Modérateur Dernière intervention   4 831 > emrh Messages postés 439 Statut Membre
       

      - Du coup, tu utilises $stmt pour toutes tes requêtes ?
      Je peux donc appeler toutes les miennes $requete et n'utiliser qu'un seul closeCursor(); ?

      Oui bien sûr.
      A noter que le closeCursor n'est pas nécessaire en mysql.



      - Pour quelle raison tu utilises des champs en majuscules comme DATE_FACTURE_FR et tu laisses les
      autres en minuscules ? Devrais-je pour des raisons de normalisation utiliser des majuscules pour le
      nom de mes champs en bdd ?

      En BDD je nomme toujours mes tables et mes champs en minuscule.
      Par contre, dans les requête, lorsque je mets des ALIAS, là je les met en majuscule. ( ça me permet de différencier les champs qui proviennent directement de ma bdd avec ceux que j'ai éventuellement manipulé )
      Il n'y a aucune obligation à le faire.


      - Comment lire en français cette ligne :
      $id_client = !empty($_GET['id_client']) ? trim($_GET['id_client']) : NULL;
      Voilà ce que je comprends :
      Variable id_client = SI (elle n'est pas vide) ALORS ???? supprimer les espaces de id_client ? SINON id_client n'existe pas

      Tout à fait.



      - Toutes mes requêtes fonctionnent avec
      execute(array('id_client' => $_GET['id_client']));
      à quoi sert le : que tu ajoutes dans
      execute(array(':id_client' => $_GET['id_client']));

      Les deux points, c'est pour être conforme au "nommage" de la variable que tu mets dans tes requêtes
      WHERE contrats.id_client = :id_client
      


      A noter que tu n'utiliseras plus, désormais, $_GET['tavariable'] dans ton exécute ... mais tu auras, au préalable récupéré proprement la variable AVANT de l'utiliser.
      1