Boucle 12mois à partir d'un mois donnée

Rechercher

Boucle 12mois à partir d'un mois donnée

Par Eladan  -  15 reponses  -  Le 09/03/2015 13:03  -  Editer  - 

Bonjour,

Je suis novice en php, j'ai réussi à créer une fonction qui me crée un calendrier avec en paramètre l'année et le mois.
J'arrive à le faire boucler pour l'avoir comme je veux, CAD un tableau 4x4 affiché sur la page principale.

Le seul hic qui me reste est que mon tableau ne boucle que jusqu'à la fin de l'année en cours au lieu de faire les 12 mois...
Exemple : je commence en Avril, il va me créer 9 tableaux, soit jusque Décembre, alors qu'il devrait continuer jusque Mars de l'année suivante.

Voici la fonction que j'utilise pour générer le tableau sachant qu'outre la partie "graphique" que j'ai dans la page principale, même la ligne « <pre><?php print_r($dates); ?></pre> » s'arrête au mois de Décembre.
Je pense que le problème vient de l'indentation de la nouvelle année, remise à Janvier du mois et année +1, mais je ne sais pas comment le corriger.

La page fonction :

    class myDate  
    {  
        private $days = array('Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche');  
        public function getAll($month, $year)  
        {  
            $r = array();  
            $date = strtotime($year . '-' . $month . '-01');  
            //Boucle sur 12 mois  
            for($i = 1, $mm = $month, $yy = $year; $i < 13; $i++, $mm++)  
            {  
                $countit = 0;  
                //Arrivé en Décembre, on remet le mois à Janvier pour parcourir les 12 mois et on incrémente l'année  
                if($mm > 12)  
                {  
                    $mm = 1;  
                    $yy++;  
                    $date = strtotime($yy . '-' . $mm . '-01');  
                }  
                while(date('n', $date) == $mm)  
                {  
                    $countit = $countit + 1;  
                    //Ce que je veux >> $r[ANNEE][MOIS][JOUR] = JOUR DE LA SEMAINE  
                    $y = date('Y', $date);  
                    $m = date('n', $date);  
                    $d = date('j', $date);  
                    $n = date('N', $date);  
                    $r[$y][$m][$d] = $n;  
                    //Rajoute 1 jour à la date  
                    $date = strtotime(date('Y-m-d', $date) . ' +1 DAY');  
                }  
                echo "itération = " . $countit . " ";  
            }  
            return $r;  
        }  
    }
 

Réponses apportées à cette discussion

Par Eladan  -  Le 09/03/2015 13:29  -  Haut de page  - 

Désolé pour le format du code :(
Je trouve pas "modifier" pour le corriger.
Si quelqu'un à une idée pour le code, je suis preneur.

Merci d'avance

 
Par Cyrano  -  Le 09/03/2015 13:43  -  Haut de page  - 

Salut,
pour la mise en forme, pas de soucis, j'ai corrigé.

Par contre, il doit manquer un bout de ton code. Je signale que j'ai corrigé un autre point au passage : la syntaxe que tu as utilisé pour ta classe est en PHP4 et non en PHP5. Note donc la manière de déclarer des variables dans une classe et l'ajout d'un niveau de visibilité pour la méthode getAll.
Autre détail, le mot « date » est un mot réservé de PHP, j'ai donc renommé la classe myDate au lieu de Date pour être sûr que ça ne risque pas de créer un conflit.

Je ne vois pas dans ton code la ligne que tu indiques : il manque la partie où tu utilises cette classe : ajoute ça et on devrait débusquer plus facilement ce qui cloche.

 
Par Eladan  -  Le 09/03/2015 16:26  -  Haut de page  - 

Tout d'abord merci de m'aider.
Pour le coup de la déclaration de classe, je suis pas doué la dedans. Je préfère le style procédurale (je trouve plus clair mais surement parce que j'y suis pas encore habitué ^^)
Heu par contre comment tu as mis le code correctement car si je met la page principale, ça sera pareil niveau présentation.

j'ai essayé de mettre entre [ code]texte[ /code] mais non, ça risque d'être bien galère à déchiffrer si il y a pas les tabulations.

 
Par Cyrano  -  Le 09/03/2015 16:39  -  Haut de page  - 

Salut,
pour la mise en forme, il faut utiliser la syntaxe Markdown, il y a un lien vers la documentation juste au dessus de la zone de saisie lorsque tu postes.

Sommairement, pour un titre de paragraphe, on met un # en début de ligne et un espace avant le libellé du titre, deux # pour un titre de second niveau, trois # pour un troisième niveau etc.. Pour du code, laisse d'abord une ligne vide et ensuite décale tout le code de 4 espace vers la droite, puis à nouveau une ligne vide. Pour te faciliter la vie pour créer ce décalage, utilise un éditeur de code genre Notepad++, sélectionne tout ton code et fais une tabulation (ou deux selon le nombre qui est défini dans la configuration de Notepad++

Enfin, tu parles de procédural mais le code que tu as montré, c'est une classe, donc de la POO. Note bien que ce n'est pas plus compliqué, je dirais même que ça peut notablement améliorer les choses, en particulier sur le long terme.

 
Par Eladan  -  Le 09/03/2015 17:26  -  Haut de page  - 

Salut,
La génération du calendrier est une vidéo que j'ai trouvé sur le net. N'ayant pas vraiment compris/réussi à la transcrire en procédurale, je l'ai remise tel quelle en essayant de comprendre un maximum.

Pour le code de la page principale. Désolé j'ai pas remis myDate car je dois en rater, il me met des erreurs partout :(

La page principale

<body><?php
include('menu.php');
include('connexion.php');
include('fonction.php'); ?>
<center><?php
$date = new date();
$year = date('Y');
$month = date('n');
$dates = $date->getAll($month, $year);

$dates = current($dates); ?>
<table border="0" bordercolor="#FFFFFF">
    <tr><td>&nbsp;</td></tr>
    <tr><?php
        $months = array('','Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre');
        $returnligne = 0;

        //Parcours les mois de l'année
        foreach($dates as $m=>$days){
            //Gestion du mois pour la comparaison période/réservation
            if($m <= 9) $mois = '0'.$m; else $mois = $m;
            //Incrémentation du mois pour retour à la ligne
            $returnligne = $returnligne + 1; ?>
        <td align="left" valign="top"><?php echo $months[$m]." ".$year; ?>
            <table align="center" border="1" bordercolor="#FF0000" cellpadding="2" cellspacing="0">
                <thead>
                    <tr><?php
                        foreach($date->days as $d){
                        //Affiche les jours de la semaine ?>
                        <th align="center" valign="middle" bgcolor="#A9B4B3"><?php echo substr($d, 0, 2); ?></th><?php
                        } ?>
                    </tr>
                </thead>
                <tbody>
                    <tr><?php
                        //Récupère la valeur du dernier jour du mois
                        $end = end($days);
                        //Parcours les jours de la semaine
                        foreach($days as $d=>$w){
                            //Gestion du jour pour la comparaison période/réservation
                            if($d <= 9) $jour = '0'.$d; else $jour = $d;
                            //Met le premier du mois au bon jour de semaine
                            if($d == 1){
                                if($w != 1){ ?>
                        <td colspan="<?php echo $w-1; ?>"></td><?php
                                }
                            }
                            //Récupère la date du jour pour afficher le fond de couleur selon la période (hiver ou pleine) et la réservation
                            $concatenation = $year.'-'.$mois.'-'.$jour;
                            $periodHivD = "";
                            $periodHivF = "";
                            $periodPleinD = "";
                            $periodPleinF = "";
                            $periodeResD = "";
                            $periodeResF = "";
                            //On recupère les dates stockées dans la table Calendrier et période
                            $sql = "SELECT * FROM Periode";
                            $sql2 = "SELECT * FROM Calendrier";
                            $req = mysqli_query($db, $sql) or die('Erreur SQL !<br>'.$sql.'<br>'.mysqli_error());
                            $req2 = mysqli_query($db, $sql2) or die('Erreur SQL !<br>'.$sql2.'<br>'.mysqli_error());
                            // on fait une boucle qui va remplir les périodes
                            while($data = mysqli_fetch_assoc($req)) 
                            {
                                $periodHivDYearBefore = ($year-1).'-'.$data['DateDebutH'];
                                $periodHivD = $year.'-'.$data['DateDebutH'];
                                $periodHivF = $year.'-'.$data['DateFinH'];
                                $periodHivFYearNext = ($year+1).'-'.$data['DateFinH'];
                                $periodPleinD = $year.'-'.$data['DateDebutP'];
                                $periodPleinF = $year.'-'.$data['DateFinP'];
                            }
                            $pass = 0;
                            // on fait une boucle qui va remplir les réservations
                            while(($data2 = mysqli_fetch_assoc($req2)) && ($pass == 0))
                            {
                                $periodeResD = $data2['DateDebutR'];
                                $periodeResF = $data2['DateFinR'];
                                if(strtotime($concatenation) >= strtotime($periodeResD) && strtotime($concatenation) <= strtotime($periodeResF)) $pass = 1;
                            }
                            // on libère la mémoire
                            mysqli_free_result($req);
                            mysqli_free_result($req2);

                            //Date jour entre début hiver dernier et fin hiver de l'année
                            if(strtotime($concatenation) >= strtotime($periodHivDYearBefore) && strtotime($concatenation) <= strtotime($periodHivF)){
                        ?><td align="center" valign="middle" bgcolor="#0099FF"><?php echo $d; ?></td><?php }
                            //Date jour entre début période pleine et fin période pleine de l'année
                            elseif(strtotime($concatenation) >= strtotime($periodPleinD) && strtotime($concatenation) <= strtotime($periodPleinF)){
                        ?><td align="center" valign="middle" bgcolor="#008000"><?php echo $d; ?></td><?php }
                            //Date jour entre début hiver de l'année et fin hiver de l'année suivante
                            elseif(strtotime($concatenation) >= strtotime($periodHivD) && strtotime($concatenation) <= strtotime($periodHivFYearNext)){
                        ?><td align="center" valign="middle" bgcolor="#0099FF"><?php echo $d; ?></td><?php }
                            //Date jour entre début et fin de la réservation
                            elseif(strtotime($concatenation) >= strtotime($periodeResD) && strtotime($concatenation) <= strtotime($periodeResF)) {
                        ?><td align="center" valign="middle" bgcolor="#F20000"><?php echo $d; ?></td><?php }
                            else { ?><td align="center" valign="middle"><?php echo $d; ?></td><?php }

                            //Saut de ligne arrivé à la fin de la semaine
                            if($w == 7){ ?>
                    </tr><tr><?php
                            }
                        }
                        //On termine le tableau avec 7 colonnes
                        if($end != 7){ ?>
                        <td colspan="<?php echo 7-$end; ?>"</td><?php
                        } ?>
                    </tr>
                </tbody>
            </table><?php
            //Saut de ligne arrivé tous les 4 mois
            if(($returnligne == 4) || ($returnligne == 8)){ ?>
        </td>
    </tr><tr><?php
            } 
        } ?>
        </td>
    </tr>
</table>
<pre><?php print_r($dates); ?></pre>
</body>

J'espère ne pas me planter ce coup ci ^^
Je m'excuse si le code est un capharnaüm absolu.
PS : zut manque le code couleur pour une "meilleure" compréhension.

 
Par Cyrano  -  Le 09/03/2015 17:50  -  Haut de page  - 

Le problème, ce n'est pas le capharnaüm, c'est que tu en comprennes ou non le fonctionnement.

Ce type de code, dans le métier, on appelle ça du code « spaghetti » parce qu'on y mélange aussi bien le PHP, le HTML, le SQL, etc.. et en fait un peu de tout. Pour la maintenance à long terme, c'est une vraie catastrophe parce que c'est un peu illisible.

Mais bon, si tu es ici, je présume que tu cherches quand même à apprendre un peu, donc au fil du temps, tu apprendras à séparer tout ça pour obtenir le même résultat mais en te facilitant très notablement le boulot. C'est toute la différence entre procédural et POO.

Partant de là, il faut déterminer ce que tu veux obtenir : un tableau de douze mois, mais ne commençant pas obligatoirement en Janvier. Pour te simplifier l'existence, il faudrait déjà que tu aies une maquette HTML du résultat attendu : en observant cette maquette, tu pourras sans doute remarquer que tu n'as qu'une partie du tableau que tu dois construire dynamiquement. Dans cette partie dynamique, tu as différents éléments et des règles particulières à observer pour que l'affichage corresponde à ce que tu attends.

Dans ce que je peux voir de ton code, je vois pas mal de ménage à faire et de code à déplacer pour éviter des exécutions en boucle totalement inutiles. Mais ce détail mis à part, est-ce que tu comprends globalement ce que fait ce code ?

 
Par Eladan  -  Le 09/03/2015 20:04  -  Haut de page  - 

Pour ce que je veux obtenir, c'est exactement ça : un tableau de douze mois, mais ne commençant pas obligatoirement en Janvier.
J'arrive à le faire commencer au mois courant mais je n'arrive pas à lui faire exécuter les 12 mois.
En fait non, il fait bien les 12 mois car dans ma page fonction, la ligne suivante echo "itération = " . $countit . " "; parcours bien 12 mois et pour chaque mois, le nombre de jour en fonction du mois et de l'année parcouru.
Ex : je commence en Mars 2015 et il va bien jusque Février 2016 avec 29 jours pour Février car c'est une année bissextile.
En plus quand je lui dit de commencer en Janvier, il m'affiche bien l'ensemble de l'année.

En revanche, pour la maquette HTML, elle est déjà présente. J'ai mon tableau qui ouvre 4 colonnes au terme duquel il passe à la ligne pour la lisibilité du tableau.
Ou alors j'ai pas compris ce que tu entends par la.

Pour le code :
- je crée un tableau général pour avoir les 12 mois avec le format 4 colonnes (mois) par ligne ;
- dans chaque <td> alias mois du tableau initial, je crée un nouveau tableau qui liste les jours présents pour le mois en question ;
- ma page fonction incrémente un tableau à 3 dimensions qui permet au 2ème tableau de savoir quel jours de la semaine commence le mois, combien il y a de jours dans le mois, etc.
Si j'ai copié le code orienté objet, c'est principalement parce que je n'arrivais pas à faire la même chose sans.
J'arrivais à incrémenter le tableau $r mais je n'arrivais pas à trouver comment le lire pour faire des boucles avec.
ex: pour l'année (1ère dimension), tu parcours tous les mois (2ème dimension) et pour chaque mois, tu parcours tous les jours (3ème dimension) sachant que pour une année précise, un mois précis, un jour précis, c'est égal à un jour de la semaine.
Pour la date 2015-03-01 tu es dimanche.
Pour la date 2015-03-02 tu es lundi.
etc.

Ça il le fait correctement car j'ai bien l'affichage comme je le souhaite.
Par contre je n'arrive pas à comprendre pourquoi il ne va pas plus loin que Décembre de l'année en cours.
Est-ce parce que j'initialise pas correctement ma fonction getAll pour la transition Décembre-Janvier et année 2015-1016 ?
Est-ce parce que dans ma page principale, mon 1er foreach (foreach($dates as $m=>$days){) qui récupère le mois en cours $m, il ne sait pas faire je vais de 4 à 12 puis de 1 à 3 ?

Je penche plus sur la deuxième hypothèse car sinon ma boucle itération, présente dans la page fonction, ne saurait pas me donner l'ensemble des mois avec le nombre exact de jours pour chacun mais ça ne m'aide pas à corriger le problème.

Est-ce que ça répond à ta question ?
Désolé du temps de réponse, je travaillais dessus et je pensais pas que tu serais aussi réactif.
Merci encore ^^

PS : ta phrase "je vois pas mal de ménage à faire et de code à déplacer pour éviter des exécutions en boucle totalement inutiles."
Je présume que tu parles, entre autre, de ma 1ère requête SQL qui n'a pas besoin de se faire pour chaque mois vu que ces données là sont toujours les mêmes.
Donc de déplacer cette section en dehors du for ?

 
Par Cyrano  -  Le 09/03/2015 21:36  -  Haut de page  - 

À priori, tu boucles sur un tableau de données.
Comme je n'ai pas la base de données correspondante, je ne sais pas à quoi correspondent ces autres données.

Mais au moins pour la base de départ, tu as une ligne dont il faudrait vérifier le contenu :

$dates  = $date->getAll($month, $year);
echo('<pre>'. PHP_EOL);
print_r($dates);
echo("</pre>". PHP_EOL);

Rajoute les trois lignes en dessous de celle que j'ai copiée ici et fais voir le résultat.

 
Par Eladan  -  Le 09/03/2015 21:54  -  Haut de page  - 

Dans ma BDD, je n'utilise que 2 tables :
- Calendrier qui stock une date de début et une date de fin pour la réservation ;
- Periode qui stock une chaine sous le format 'm-d' pour les périodes de l'année. CAD période hivernale ou période pleine.

Avec tes 3 lignes, j'ai un tableau du type :

Array
(
    [2015] => Array
        (
            [4] => Array
                (
                    [1] => 3
                    [2] => 4
                    [3] => 5
                )
            [5] => Array
                (
                    [1] => 5
                    [2] => 6
                )
            [12] => Array
                (
                    [1] => 2
                    [2] => 3
                )
        )
    [2016] => Array
        (
            [1] => Array
                (
                    [1] => 5
                    [2] => 6
                )

            [2] => Array
                (
                    [1] => 1
                    [2] => 2
                )

            [3] => Array
                (
                    [1] => 2
                    [2] => 3
                )
        )

J'ai pas tout mis mais le 2ème Array comprend bien tous les mois et le 3ème Array tous les jours.
C'est le même type de tableau qu'avec mon <pre><?php print_r($dates); ?></pre> à la fin de ma page principale sauf que celui ci fait bien les 12 mois.

 
Par Cyrano  -  Le 10/03/2015 06:40  -  Haut de page  - 

Ok, je viens de capter : c'est ton utilisation de current() qui bousille ton système. La ligne juste après. Surtout que tu fais un truc pas très orthodoxe : tu redéfinis ta variable $dates avec une partie de $date. Résultat, le reste est perdu.

Le résultat, c'est que tu ne boucles que sur les mois de l'année en cours, le reste a été perdu. Pour vérifier ça, fais la chose suivante :

$dates  = $date->getAll($month, $year);
echo('<pre>'. PHP_EOL);
print_r($dates);
echo("</pre>". PHP_EOL);
$dates  = current($dates);
echo('<pre>'. PHP_EOL);
print_r($dates);
echo("</pre>". PHP_EOL);

Fais exécuter ça et compare les deux résultats.

 
Par Eladan  -  Le 10/03/2015 12:25  -  Haut de page  - 

J'y ai pensé au réveil (vers 5H30 -_-)
J'ai mis la ligne $dates = current($dates); en commentaire et j'ai relancé le script, il ne m'a affiché que les 10 ou 12 premiers jours du 1er mois passé en paramètre...

Après c'était au réveil, j'ai peut être raté un truc.
Je fais ça en rentrant et je te tiens au courant.
New vers 15H00 donc.

Donc c'est bien ça.
Avant cette ligne, il me fait bien les 12 Array et le passage de l'année.
Après il s'arrête au mois de Décembre.

Par contre si je supprime la ligne, je n'ai plus qu'un tableau qui parcours 12 lignes sans retour à la ligne au dimanche.
il me met :
2015
Lu Ma Me Je Ve Sa Di
4 5 6 7 8 9 10 11 12

Il remplace les jours par les mois (vu qu'en paramètre, j'ai commencé en Avril)
J'en reviens au point initial à savoir que je ne sais pas comment retranscrire en code ce que liste naturellement la fonction print_r

 
Par Eladan  -  Le 11/03/2015 18:31  -  Haut de page  - 

Bonjour,

Je n'arrive pas à faire une boucle qui comprend l'année.
Quand j'écris :

    foreach($dates as $y=>$months){
    echo "Année = ".$y."<br>";
    foreach($dates as $m=>$days){
        echo "Mois = ".$m." - ";
    }
}

Il me sort ça :
Année = 2015
Mois = 2015 - Mois = 2016 - Année = 2016
Mois = 2015 - Mois = 2016 -

Est-ce que quelqu'un pourrais me dire ce que font exactement ces 3 boucles :
1 - foreach($dates as $m=>$days){
2 - foreach($date->days as $d){
3 - foreach($days as $d=>$w){

Je pense que :
1 - pour chaque élément (mois) de ma variable $dates, il assigne un index (clé qui est le numéro du mois) et affiche les jours associés ;
2 - pour chaque jours de la semaine de mon tableau days, j'affiche le numéro associé ;
3 - pour chaque élément (jours) de mon tableau days, il assigne un index (clé qui est le numéro du mois) et affiche le numéro de la semaine associé.

Est-ce que c'est bien ça ?

 
Par Cyrano  -  Le 11/03/2015 18:45  -  Haut de page  - 

Salut,
en fait, tu commets une erreur de débutant assez classique, mais il te manque un élément dans tes connaissances. On va combler ça.

Fonctionnement d'une boucle foreach

Lorsqu'on crée une boucle foreach sur un tableau multi-dimensionnel, on va pouvoir isoler les clés de leurs contenu et traiter individuellement ce contenu en utilisant éventuellement les clés.

Prenons un exemple avec un tableau basique :

$monTableau = array(
    0 => 'a',
    1 => 'b',
    2 => 'c'
);

Construisons maintenant une boucle :

foreach($monTableau as $cle => $valeur)
{
    //...
}

Dans la boucle, on ba faire le tour de chacune des lignes : à chaque tour, on identifie la clé et la valeur correspondante. Cette valeur peut être scalaire ou bien être un tableau voire même un objet.

Transformons un peu le tableau :

$monTableau = array(
    0 => 'a',
    1 => 'b',
    2 => array(
        0 => 'ca',
        1 => 'cb',
        2 => 'cc'
    )
);

Lors du troisième tour, on a plus une valeur scalaire mais un tableau indexé. Ce qu'ion peut faire comme traitement là-dessus, c'est exactement la même chose que pour le tableau de base. il faut donc pointer sur le bon élément :

foreach($monTableau as $cle => $valeur)
{
    if(is_array($valeur))
    {
        foreach($valeur as $cle2 => $valeur2)
        {
            //....
        }
    }
}

Je te laisse mijoter tout ça, tu devrais trouver la réponse à ton problème, sinon, reviens demander ;)

 
Par Eladan  -  Le 12/03/2015 17:02  -  Haut de page  - 

Bonjour,

En effet, une erreur de débutant comme tu dis. Je confondais le tableau avec ça valeur.
Du coup deux petites boucles comme ceci et c'est bon, tout fonctionne ^^

foreach($dates as $y=>$tabmois)
{
    foreach($tabmois as $m=>$days)
    {
        //...
    }
}

Je te remercie beaucoup Cyrano, j'aurai pu galérer encore longtemps là dessus sans ton aide.

Il me reste un dernier petit problème (certainement du même acabit que les déclarations de tableau en PHP5) mais qui n'a pas rapport avec mes boucles, il vaut mieux que je crée un autre sujet je présume ?

 
Par Cyrano  -  Le 12/03/2015 17:41  -  Haut de page  - 

Content que tu aies finalement découvert par toi-même ;)

Pour l'autre sujet, ce serait mieux en effet d'ouvrir un nouveau sujet, ça facilitera pour ceux qui auraient à chercher sur un point particulier qu'ils n,aboutissent pas dans un mélange des genres indésirable.

 

Ajouter une réponse à la discussion

Seuls les membres connectés sont autorisés à poster dans les forums !

Identifiez-vous
Join |  ID/MDP? |