[RESOLU] Méthode, tables et stockage d'array

Petit nouveau ! | 6 Messages

09 mars 2021, 11:21

Bonjour à tous,

Je travaille dans une école de musique avec des professeurs qui chaque mois doivent déclarer pour chaque jour du mois :

- les heures complémentaires
- le motif de ses heures complémentaires
- nombre de déplacements
- nombre de déplacement exceptionnels

Une fois le formulaire rempli et validé pour le mois, je souhaiterai stocker ces données en base de données.

Au depart, j'étais parti à créer un tableau avec les dates du mois en ordonnée et des input pour chaque valeur afin de stocker un tableau converti en chaine de caractères dans ma base de données.

                                          

foreach ($dates as $value) {
 $date_Hora = date("d/m/Y", strtotime($value));
echo '<td date-sort="' . $value . '">' . $date_Hora . '</td>
<td><input name = "hor_comp[]" type="text"/></td>
<td><input name = "depla[]" type="text"/></td>
<td><input name = "motifs[]" type="text"/></td>
 </tr>';
}
 ?>

D'après que ce j'ai pu lire ce n'est pas une bonne méthode, Il apparait qu'il est conseillé de créer des tables plutôt que de stocker des array.
Le problème c'est que je ne vois le schema des tables étant donné que les mois ne possèdent pas le même nombre de jours.

Quelle serai pour vous la bonne démarche ?

Merci de votre aide

Avatar du membre
Mammouth du PHP | 1609 Messages

09 mars 2021, 13:46

Salut, je pense que ça manque un peu de détail mais avec ce que tu as énoncé, à priori 2 tables.

Une table "professeur", par exemple :
- id (clé primaire)
- prenom (varchar 50)
- nom (varchar 50)

Une table "declaration", par exemple :
- id (clé primaire)
- professeur_id (clé étrangère)
- date (datetime)
- heures_complementaires (int)
- motif_heures_complementaires (text)
- nombre_deplacements (int)
- nombre_deplacements_exceptionnels (int)

Les professeurs pourraient renseigner ces déclarations jour par jour en choisissant la date du jour concerné en plus de renseigner les autres champs.

Tu peux rester sur l'idée du tableau avec une ligne par jour et les inputs en colonnes, dans ce cas ajoute un input hidden name="date[]" avec la date du jour à chaque ligne et quand tu traites la soumission du formulaire, boucle sur les tableaux de données et fait un insert dans la table "declaration" pour chaque jour renseigné.
Développeur web depuis + de 20 ans

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

09 mars 2021, 14:06

Effectivement, il est préférable dans ta base de données de créer des tables et des champs permettant de qualifier les informations qu'ils contiennent. Tu peux ainsi utiliser toute la puissance du moteur de la bdd pour tes recherches (trouver toutes les heures sup à une date données, trouver tous les professeurs qui ont travaillé tel jour, calculer le nombre de déplacement exceptionnels du mois...).
Si tes données sont toutes regroupées dans un tableau que tu consignes en l'état en base, ces informations ne serait pas facilement exploitable (il faudrait lire tous les tableaux de ta base en php pour aller vérifier s'il y en a un qui concerne le 9 mars, alors qu'une requête te retournerait le résultat immédiatement :))

La suggestion de Saian est bonne. En complément je dirais juste que l'idée n'est pas de stocker un enregistrement pour chaque date, mais de ne conserver que celles pour lesquelles une information a été renseignée. Il y aura donc des "trous" dans ta table, mais c'est tout à fait normal (pas la peine de stocker une date pour dire qu'un professeur n'a pas travaillé le dimanche, l'absence de date a le même résultat et consomme moins de place ;))

Ainsi côté navigateur, tu peux facilement créer un formulaire qui demande à l'utilisateur de sélectionner une date et de remplir les informations correspondante et tu enregistres au fur et à mesure. C'est le plus simple, mais peut être pas le plus pratique à utiliser puisqu'il faut saisir date après date.

Tu peux aussi générer en php un tableau / calendrier avec toutes les dates du mois concerné (et ainsi boucher les "trous" des dates que tu n'aurais pas en base), et pour chacune, remplir avec l'info en base quand elle existe ou laisser la possibilité de remplir ou non les informations attendues. Avantage pour l'utilisateur, la saisie du mois se fait sur un seul écran. Et pour toi, tu récupères le formulaire complet côté php, mais tu n'enregistres en base que les dates pour lesquelles des informations ont été transmises.
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Petit nouveau ! | 6 Messages

09 mars 2021, 18:16

Bonjour Ryle et Saian ,
Tout d'abord merci pour votre aide et vos réponses rapides.
J'ai donc suivi vos conseils créer un tableau de saisie de tout le mois, le input caché pour les date et les tables correspondantes.

Il me faut maintenant traiter les tableaux et les insérer en n'incluant pas les input pour lesquels il n'y a pas de saisie.
Pouvez-vous m'aider à écrire ou tout du moins à commencer ?

Bien à vous,
Jeff
<?php

include_once("../inc/connexion.php");

if (isset($_POST["go"])) {
}
?>

<!-- <?php include('head.php'); ?> -->

<body>
    <!-- Page Wrapper -->
    <div id="wrapper">

        <form action="index.php" method="post" class="form-horizontal">
            <table>
                <thead>
                    <tr>
                    <th>Date</th>
                        <th>Hres Compl.</th>
                        <th>Motifs Hres Compl.</th>
                        <th>Deplacnts Prévus</th>
                        <th>Deplacnts Except.</th>
                        <th>Motifs Deplacnts Except.</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <?php
                        // for each day in the month
                        for ($i = 1; $i <=  date("t", strtotime("-1 month")); $i++) {
                            // add the date to the dates array
                            $dates[] = date('Y') . "-" . date("m", strtotime("-1 month")) . "-" . str_pad($i, 2, '0', STR_PAD_LEFT);
                        }

                        foreach ($dates as $value) {
                            $date_Hora = date("d/m/Y", strtotime($value));

                            echo '<td>' . $date_Hora . '<input name = "date[]" type="hidden" value=\"'.$value.'\" /></td>

                                      <td><input name = "hor_comp[]" type="text"/></td>
                                      <td><input name = "motifs_hr_comp[]" type="text"/></td>
                                      <td><input name = "depla[]" type="text"/></td>
                                      <td><input name = "depla_exc[]" type="text"/></td>
                                      <td><input name = "motifs_depla_exc[]" type="text"/></td>

                                </tr>';
                        }
                        ?>
                </tbody>
                <div>
                    <input type="submit" name="go" class="btn btn-primary" value="Valider">
                </div>
            </table>
        </form>
    </div>
</body>
</html>


Avatar du membre
Mammouth du PHP | 1609 Messages

09 mars 2021, 18:40

Un modèle pour t'aiguiller. En espérant que les champs vides soient bien transmis comme vide et pas simplement omis.
for ($i = 0; $i < count($_POST['date']); $i++) {
    $date = $_POST['date'][$i];
    $heuresComplementaires = $_POST['hor_comp'][$i];
    // etc
    if (/* au moins une variable non vide hormis la date */) {
        // insertion en bdd
    }
}
Développeur web depuis + de 20 ans

Petit nouveau ! | 6 Messages

10 mars 2021, 13:27

Bonjour Saian,

Grace à ton aiguillage mon insertion fonctionne dans la table de declaration en incluant simplement les saisies effectives.
Merci, c'est parfait ! Je suis réellement épaté par le temps que vous consacrez à aider les autres. J'espère réellement dans quelques temps lorsque mon niveau en php le permettra d'aider les autres ainsi.

J'avais une autre question.
Peux tu également me donner un aiguillage pour remplir à nouveau le formulaire avec les infos en bdd dans une autre page qui permettrai de modifier leur saisie.
J'ai récupéré les données avec ma requête sql et recréer le formulaire avec l'ensemble des dates.
J'ai tenté de boucler sur le tableau créer par la requête SQL pour remplir la value de mon input, mais évidemment il manque les données non saisies et je pense que je m'emmêle en mettant deux boucles.
<?php

include_once("connexion.php");

if (isset($_GET["id"])) {

    $id_prof = $_GET["id"];

    $query = $mysqli->query("SELECT * FROM `declaration` WHERE `id_profs` = $id_prof");
    $nb = $query->num_rows;
    if ($nb > 0) {
        $list = array();
        while ($row = $query->fetch_array()) {
            array_push($list, $row);
        }
        $nb = count($list);
    }
}

?>

<head>
    <style>
        table {
            border-collapse: collapse;
        }

        th,
        td {
            border: 1px solid black;
            padding: 10px;
        }
    </style>
</head>

    <body>
        <!-- Page Wrapper -->
        <div id="wrapper">

            <form action="index.php" method="post" class="form-horizontal">
                <!-- <input name = "" type="text"/>
        <input name = "hor_comp[]" type="text"/> -->
                <table id="myTable">
                    <thead>
                        <tr>
                            <th>Date</th>
                            <th>Hres Compl.</th>
                            <th>Motifs Hres Compl.</th>
                            <th>Deplacnts Prévus</th>
                            <th>Deplacnts Except.</th>
                            <th>Motifs Deplacnts Except.</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <?php
                            // for each day in the month
                            for ($i = 1; $i <=  date("t", strtotime("-1 month")); $i++) {
                                // add the date to the dates array
                                $dates[] = date('Y') . "-" . date("m", strtotime("-1 month")) . "-" . str_pad($i, 2, '0', STR_PAD_LEFT);
                            }

                            foreach ($dates as $value) {
                                $date_Hora = date("d/m/Y", strtotime($value));

                                echo '<td>' . $date_Hora . '<input name = "date[]" type="hidden" value="' . $value . '" /></td>';?>

                                     <?php echo '<td><input  name = "hor_comp[]" type="text" class ="txtCal1" '?>
                                     <?php 
                                        if (isset($list)) {
                                                for ($i = 0; $i < $nb; $i++) {
                                                $dateM = $list[$i]['hrs_compl'];
                                                echo  'value="'.$dateM.'" /></td>';
                                                     }
                                                }             
                                     ?>
                                      
                                      <?php echo '<td><input  name = "motifs_hr_comp[]" type="text" '?>
                                      <?php echo 'value="" /></td>'?>
                                      
                                      <?php echo '<td><input  name = "depla[]" type="text" class ="txtCal2" '?>
                                      <?php echo 'value="" /></td>'?>
                                      
                                      <?php echo '<td><input  name = "depla_exc[]" type="text" class ="txtCal3" '?>
                                      <?php echo 'value="" /></td>'?>
                                      
                                      <?php echo '<td><input  name = "motifs_depla_exc[]" type="text"  '?>
                                      <?php echo 'value="" /></td>'?>

                              <?php echo '</tr>'?>
                              <?php } ?>
                    </tbody>
                    <tfoot>
                        <tr>
                            <td>Total</td>
                            <td id="total_sum_value1"></td>
                            <td></td>
                            <td id="total_sum_value2"></td>
                            <td id="total_sum_value3"></td>
                            <td></td>
                        </tr>
                    </tfoot>
                    <div>
                        <input type="submit" name="go" class="btn btn-primary" value="Valider">
                    </div>
                </table>
            </form>
        </div>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script>
            $(document).ready(function() {

                function CalculSum(i) {
                    var textCal = ".txtCal" + i;
                    var total_sum_value = "#total_sum_value" + i;
                    var tableTxt = "#myTable " + textCal;

                    // document.write(tableTxt);

                    $("#myTable").on('input', textCal, function() {
                        var calculated_total_sum = 0;

                        $(tableTxt).each(function() {
                            var get_textbox_value = $(this).val();
                            if ($.isNumeric(get_textbox_value)) {
                                calculated_total_sum += parseFloat(get_textbox_value);
                            }
                        });
                        $(total_sum_value).html(calculated_total_sum);
                    });
                }

                $("#myTable").on('input', '.txtCal1', function() {
                    CalculSum(1)
                });

                $("#myTable").on('input', '.txtCal2', function() {
                    CalculSum(2)
                });

                $("#myTable").on('input', '.txtCal2', function() {
                    CalculSum(3)
                });
            });
        </script>

    </body>

    </html>

J’espère être assez clair

Merci de votre aide

Jeff

Avatar du membre
Mammouth du PHP | 1609 Messages

10 mars 2021, 13:32

Salut, alors ce que tu peux faire, c'est utiliser le même script pour construire le tableau. Tu récupères les données en base. Tu les indexes dans un array sur la date. Et comme ça dans la boucle de construction du tableau, tu regardes via la date si tu as des données et s'il y en a tu les injectes dans les inputs. J'espère être assez clair aussi. ^^

PS : si tu as des données, tu pourrais aussi poser l'id de la ligne en input hidden comme ça pour la mise à jour tu pourras l'utiliser pour la requête update. Après ça devrait passer aussi avec la date mais faudra d'abord vérifier si la ligne existe déjà ou pas pour savoir si tu dois faire un update ou un insert. Au final tu peux avoir une seule page qui va servir à l'insert et à l'update.
Développeur web depuis + de 20 ans

Petit nouveau ! | 6 Messages

10 mars 2021, 15:38

Je crois comprendre ce que tu proposes, mais j'ai du mal à l'écrire.

J'ai un tableau simple date[] qui contient l'ensemble des dates du mois et qui permet de créer le formulaire html avec tous les input.
Puis j'ai un autre tableau liste[] contenant des tableaux avec l'ensemble des saisies effectives donc sans les saisies à vide.

array(9) {

[0]=> array(20) {
[0]=> string(2) "30" ["id_decla"]=> string(2) "30" [1]=> string(1) "1" ["id_profs"]=> string(1) "1" [2]=> string(19) "2021-02-01 00:00:00" ["date"]=> string(19) "2021-02-01 00:00:00" [3]=> string(1) "1" ["hrs_compl"]=> string(1) "1" [4]=> string(0) "" ["motif_hrs_compl"]=> string(0) "" [5]=> string(1) "0" ["nbre_deplacnts"]=> string(1) "0" [6]=> string(1) "1" ["nbre_deplacnts_exc"]=> string(1) "1" [7]=> string(0) "" ["motifs_deplacnts_exc"]=> string(0) "" [8]=> string(1) "0" ["statut"]=> string(1) "0" [9]=> string(19) "2021-03-10 10:43:00" ["date_crea"]=> string(19) "2021-03-10 10:43:00" }

[1]=> array(20) {
[0]=> string(2) "31" ect....
if (isset($_GET["id"])) {

    $id_prof = $_GET["id"];

    $query = $mysqli->query("SELECT * FROM `declaration` WHERE `id_profs` = $id_prof");
    $nb = $query->num_rows;
    if ($nb > 0) {
        $list = array();
        while ($row = $query->fetch_array()) {
            array_push($list, $row);
        }
        $nb = count($list);
    }
}

var_dump($list);

// for each day in the month
for ($i = 1; $i <=  date("t", strtotime("-1 month")); $i++) {
    // add the date to the dates array
    $dates[] = date('Y') . "-" . date("m", strtotime("-1 month")) . "-" . str_pad($i, 2, '0', STR_PAD_LEFT);
}
Comment faut-il faire ensuite ? Faut-il comparer les tableaux ? En creer un autre ?

Merci de votre aide

Avatar du membre
Mammouth du PHP | 1609 Messages

10 mars 2021, 16:39

Tu récupères les données en base. Tu les indexes dans un array sur la date.

Comment indexer le tableau sur la date pour ensuite récupérer la déclaration lors de l'affichage. Bien entendu il faut s'assurer que le format de $row['date'] corresponde avec celui de $date. Le format peut être adapté avec la fonction date ou la classe DateTime, etc.
$query = $mysqli->query("SELECT * FROM `declaration` WHERE `id_profs` = $id_prof");
$declarations = [];
while ($row = $query->fetch_array()) {
    $declarations[$row['date']] = $row;
}

// boucle de création du tableau des inputs avec $dates contenant les dates du mois au même format que $row['date']
foreach ($dates as $date) {
    $declaration = $declarations[$date] ?? null;
    if ($declaration) {
        // ligne avec declaration
    } else {
        // ligne sans declaration
    }
}

Et au lieu de faire un if else tu peux plutôt dans les values faire du :
echo $declaration ? $declaration['nom_de_la_colonne'] : null;
Développeur web depuis + de 20 ans

Petit nouveau ! | 6 Messages

10 mars 2021, 19:06

Tout fonctionne parfaitement selon ce que tu m'as indiqué. J'ai bien l'ensemble des saisies et j'ai également ajouté l'id_declaration dans un input caché pour prévoir l'update.

Pour être sûr de bien comprendre le processus, peux tu me confirmer que tes lignes de code peuvent s'expliquer de cette façon :

foreach ($dates as $date) {
$declaration = $declarations[$date] ?? null;
// on cree la variable declaration si on vérifie que la date existe dans le tableau declarations sinon on la passe à null

if ($declaration)
//cette condition vérifie si declaration n'est pas null ? Est ce le même chose que : if (($declaration) != null)
....

Enfin peux tu me donner une piste pour différentier l'update de ligne existante et la saisie de ligne vide lors de la validation du formulaire ? Peut être une condition sur l'existence ou non d'un id_declaration.

Merci de ton aide

Avatar du membre
Mammouth du PHP | 1609 Messages

10 mars 2021, 19:27

$declaration = $declarations[$date] ?? null;
// on cree la variable declaration si on vérifie que la date existe dans le tableau declarations sinon on la passe à null
Oui c'est équivalent à un
$declaration = isset(declarations[$date]) ? $declarations[$date] : null;
donc s'il y a bien une déclaration à la date donnée, $declaration prend sa valeur, sinon $declaration est null.

if ($declaration)
//cette condition vérifie si declaration n'est pas null ? Est ce le même chose que : if (($declaration) != null)
Plutôt un
if ($declaration != null && $declaration != false && $declaration != '' && $declaration != 0)
peut être que j'en oublie, en fait la condition est true pour toute valeur n'étant pas évaluée comme false dans une condition.

Enfin peux tu me donner une piste pour différentier l'update de ligne existante et la saisie de ligne vide lors de la validation du formulaire ? Peut être une condition sur l'existence ou non d'un id_declaration.
Exactement une condition du type
if ($_POST['id_declaration'][$i])
ce qui me fait penser que lors de la création du tableau d'inputs, il faudrait que tu poses un input hidden id_declaration vide s'il n'y a pas de déclaration pour le jour sinon tu vas avoir des décalages sur $i.
Développeur web depuis + de 20 ans

Petit nouveau ! | 6 Messages

11 mars 2021, 10:48

Tout fonctionne parfaitement . Encore une fois un grand merci. J'ai beaucoup appris.