Doublon dans un array ?

Résolu/Fermé
emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 - 9 avril 2022 à 17:21
emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 - 10 avril 2022 à 16:55
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

jordane45 Messages postés 38144 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 21 avril 2024 4 650
Modifié le 9 avril 2022 à 19:19
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
emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 20
Modifié le 10 avril 2022 à 09:43
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
emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 20
Modifié le 10 avril 2022 à 10:12
- 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
emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024 20
10 avril 2022 à 10:20



:-)
Merci JORDAN !!!
0
jordane45 Messages postés 38144 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 21 avril 2024 4 650 > emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024
10 avril 2022 à 11:46
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
jordane45 Messages postés 38144 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 21 avril 2024 4 650 > emrh Messages postés 427 Date d'inscription mardi 9 décembre 2014 Statut Membre Dernière intervention 9 avril 2024
10 avril 2022 à 11:52

- 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