Correction des devoirs ;)

Bonjour @ tous,

Maintenant que je suis bien plus à l’aise avec le HTML / CSS / Jquery grâce à Jeedom qui m’a servi de TP, je m’attaque au PHP depuis quelques jours. :nerd_face: :exploding_head:

J’ai pondu un bout de code à utiliser dans un scénario pour récupérer automatiquement la prochaine tâche chronologique programmée via un bloc « A » par les scénarios passés en paramêtre:

/* Permet de récupérer la date et l'heure du prochain évènement programmé dans un scénario (bloc "A"). 
Catte valeur est stockée dans une variable nommée "NextProg#ID_du_SCENARIO" - exemple: variable(NextProg31). */

$Scenarios_IDS = array(7,21,28,31,35,39); // ID du ou des scénario(s) à surveiller séparés par une virgule.

/*****************************************************************/
if (!empty($Scenarios_IDS)) {
foreach($Scenarios_IDS as $Scenario_ID) {
if (is_object(scenario::byId($Scenario_ID))) {
  $crons = cron::searchClassAndFunction('scenario', 'doIn', '"scenario_id":'.$Scenario_ID.',');
  if ($crons) {
  $a[$Scenario_ID] = $crons;}
   else { $scenario->setLog($nom.'Aucun bloc "A" programmé dans le scénario n°'.$Scenario_ID); 
     $scenario->setData('NextProg'.$Scenario_ID,'Pas de programmation');}
 } else { $scenario->setLog('Le scénario n°'.$Scenario_ID.' n\'existe pas'); 
        $scenario->setData('NextProg'.$Scenario_ID,'Le scénario n°'.$Scenario_ID.' n\'existe pas');
 }} 

  foreach($a as $key=>$value) {
    foreach($value as $data) {
      $b[$key][] = $data->getNextRunDate();
      sort($b[$key]);
      }}
  
  foreach ($b as $cle=>$test) {    
  $sID = $cle; $e = $test[0]; $nom = scenario::byId($cle)->getName();
  $d = explode(" ",$e);
  $jour = $d[0]; $heure = $d[1];
  $time = substr($heure,0,-3); 
  $tod = date("Y-m-d"); 
  $tom = date('Y-m-d', strtotime('+1 day'));
  $date = 'le '.strftime('%d/%m/%Y',strtotime($jour));
//  $prog = strftime("%M %H %d %m *",strtotime($e)+60);
//  $arr[] = $prog; $arr = array_unique($arr);
    
  if ($jour == $tod)  $day = 'Aujourd\'hui';
  else if ($jour == $tom)  $day = 'Demain';
  else $day = $date;

$result = $day.' à '.$time;
$scenario->setData('NextProg'.$sID,$result);
$scenario->setLog($nom.'('.$sID.'): '.$result);
  }
  
 /*   if ($scenario->getMode() != 'schedule') $scenario->setMode('schedule');
	$scenario->setSchedule($arr);
    $scenario->save();
    $y = print_r($arr,true);
    $scenario->setLog('Programmation pour MAJ: '.$y);
*/    
} else $scenario->setLog('Veuillez renseigner la ligne $Scenarios_IDS au début du code');

ça fonctionne mais je n’ai aucune idée de savoir si c’est la bonne approche ou la bonne manière de faire.

Si un développeur confirmé a l’occasion d’y jeter un œil et de me faire un retour, ça m’aiderait beaucoup :innocent:

Salut,
Au-delà du contenu qui est difficile à lire sur smartphone, je passerais un coup de beautifier sur le code et je commenterais davantage.
Pour le reste, je regarderais sur grand écran ce soir si tu veux.

Yes une ligne de code / une ligne de commentaire @mich0111 a raison.

Je ne suis pas d’accord, je ne met jamais de commentaire.
La ligne de code doit être suffisamment explicite pour être lue telle quel.
Et si un bloc de code est trop grand c’est qu’il faut découper. Il ne devrait en principe pas être nécessaire de lire chaque ligne de code pour comprendre, le nom des méthodes et l’orchestration doivent être suffisante.

L’autre problème avec le commentaire c’est que la personne qui le relis doit aussi lire le code pour d’assurer que ça correspond toujours…

Alors là, si c’est le cas, les règles du codage ont profondément changé.
Comme @olive, pour moi la norme c’est une ligne de code, un commentaire.
Ça ne veut pas dire pour autant que le commentaire duplique le code.
Ce ne doit pas être :
i++;
// J’incrémente le compteur i
Mais pourquoi je l’incrémente.
L’idée reste de faire en sorte que le code n’est pas écrit pour soi mais pour les autres, surtout les commentaires.
Après on est obligé à rien

Je pense que les règles et les standards ont profondément changé oui.
Mais bref c’est un débat sans fin, il y aura toujours differents avis sur la question.
tout ce que je peux dire c’est quand déjà / seulement 20 ans d’expériences je n’ai jamais eu un commentaire dans du code que j’ai du maintenir qui a servit. Jamais, au contraire car très souvent le commentaire n’a pas suivi les évolutions du code.

Ça c’est un vrai débat.
Le MCO du code.

Pour revenir à ton code:

1°) un petit coup de beautify pour mettre le code en forme
2°) mettre dans liste des scénarios des noms plutôt que des ids. Demain te ne te souviendras pas à quoi correspond 7, 21, 28 …
3°) Eviter les noms sans signification tels que $a[…] ou $b[ ] $value $e , $d leur préférer un nom qui précise davantage ce qu’est chaque variable. Dans 15 jours, tu sauras plus ce que sont $an $b, $e , etc…
4°) Fermer chaque if else avec des {}
ainsi préférer (qui est plus clair à mon sens)

if (condition) {
} else {
}

5°) Regrouper dasn une fonction par exemple; un traitement
ainsi

function calcul_date($cle) {
$sID = $cle; $e = $test[0]; $nom = scenario::byId($cle)->getName();
  $d = explode(" ",$e);
  $jour = $d[0]; $heure = $d[1];
  $time = substr($heure,0,-3); 
  $tod = date("Y-m-d"); 
  $tom = date('Y-m-d', strtotime('+1 day'));
  $date = 'le '.strftime('%d/%m/%Y',strtotime($jour));
//  $prog = strftime("%M %H %d %m *",strtotime($e)+60);
//  $arr[] = $prog; $arr = array_unique($arr);
    
  if ($jour == $tod)  $day = 'Aujourd\'hui';
  else if ($jour == $tom)  $day = 'Demain';
  else $day = $date;

return $day.' à '.$time;
}

Du coup la boucle devient

foreach ($b as $cle=>$test) {    
     $result = calcul_date($cle) .' à '.$time;
     $scenario->setData('NextProg'.$sID,$result);
     $scenario->setLog($nom.'('.$sID.'): '.$result);
  }

6°) Eviter les if else trop éloignés ( comprenant plein de lignes de code entre le test de la condition et le else
Préférer

if (empty($Scenarios_IDS)) {
   $scenario->setLog('Veuillez renseigner la ligne $Scenarios_IDS au début du code');
} else {
  // ici traitement des scénarios valides ...
}

Voici quelques remarques à mon avis !
Pour les commentaires, préciser des cas particuliers, mais préférer une bonne structuration du code qui doit parler par lui-même et de facto être compréhensible.
Mettre en avant la logique du traitement :
→ boucle
→ conditions,
→ fonctions qui regroupent du code assurant un but précis.

A+
Bernard

1 « J'aime »

Super !!! Merci énormément d’avoir pris le temps de regarder et de me faire une réponse si complète :nerd_face: :partying_face:

Tes conseils sont vraiment très utiles surtout le passage sur l’intégration d’une fonction qui était encore légèrement floue pour moi c’est bien plus clair maintenant.
Juste pour mon information, tant que la fonction n’est pas appelée elle n’est pas traitée dans le déroulé du code c’est bien ça ? par contre elle doit obligatoirement être déclarée avant l’appel ?

J’ai revu mon code en fonction de toutes vos remontées, ça donne ça:

/************************************************************************************************************
Permet de récupérer la date et l'heure du prochain évènement programmé dans un scénario (bloc "A"). 
Catte valeur est stockée dans une variable nommée "NextProg#ID_du_SCENARIO" - exemple: variable(NextProg31). 
/************************************************************************************************************/
$Scenarios_IDS = array(7, 21, 28, 31, 35, 39); // ID du ou des scénario(s) à surveiller séparés par une virgule.
/*************************************************************************************************************
 *************************************************************************************************************/
if (empty($Scenarios_IDS)) {
    $scenario->setLog('Veuillez renseigner la ligne $Scenarios_IDS au début du code');
} else { //Récupération des éléments crons par Scénario
    foreach($Scenarios_IDS as $Scenario_ID) {
        if (!is_object(scenario::byId($Scenario_ID))) {
            $scenario->setLog('Le scénario n°'.$Scenario_ID.' n\'existe pas');
            $scenario->setData('NextProg'.$Scenario_ID, 'Le scénario n°'.$Scenario_ID.' n\'existe pas');
        } else {
            $crons = cron::searchClassAndFunction('scenario', 'doIn', '"scenario_id":'.$Scenario_ID.',');
            if (!$crons) {
                $scenario->setLog($nom.'Aucun bloc "A" programmé dans le scénario n°'.$Scenario_ID);
                $scenario->setData('NextProg'.$Scenario_ID, 'Pas de programmation');
            } else { //crons triés par n° scénario
                $tabCrons[$Scenario_ID] = $crons;
            }
        }
    }
	//Création et triage prochains crons 
    foreach($tabCrons as $key => $value) {
        foreach($value as $data) {
            $nextRun[$key][] = $data->getNextRunDate();
            sort($nextRun[$key]);
        }
    }
	//Calcul date et heure prochain lancement
    function calcul_date($next) {
        $e = $next[0];
        $d = explode(" ", $e);
        $jour = $d[0];
        $heure = $d[1];
        $time = substr($heure, 0, -3);
        $tod = date("Y-m-d");
        $tom = date('Y-m-d', strtotime('+1 day'));
        $date = 'le '.strftime('%d/%m/%Y', strtotime($jour));

        if ($jour == $tod) $day = 'Aujourd\'hui';
        else if ($jour == $tom) $day = 'Demain';
        else $day = $date;

        return ($day.' à '.$time);
    }
	//Récupération des variables
    foreach($nextRun as $cle => $next) {
        $nom = scenario::byId($cle)->getName();
        $sID = $cle;
        $result = calcul_date($next);
        $scenario->setData('NextProg'.$sID, $result);
        $scenario->setLog($nom.'('.$sID.'): '.$result);
    }
}

Au premier abord c’est déjà bien plus lisible et beaucoup mieux structuré, encore merci à vous tous :kissing_heart:

Je n’ai plus qu’à coder jusqu’à plus soif pour continuer mon apprentissage…

Bonsoir,

C’est (à mon sens ) beaucoup mieux dans le sens de la lisibilité.

Une remarque, le corps de la fonction doit être en dehors du code
principal, ainsi :

voila un exemple de code principal illicite:

car la fonction calcul_date est à l’intérieur du code principal .

{
	//Création et triage prochains crons 
    foreach($tabCrons as $key => $value) {
        foreach($value as $data) {
            $nextRun[$key][] = $data->getNextRunDate();
            sort($nextRun[$key]);
        }
    }
	**//Calcul date et heure prochain lancement**
**    function calcul_date($next) {**
**        $e = $next[0];**
**        $d = explode(" ", $e);**
**        $jour = $d[0];**
**        $heure = $d[1];**
**        $time = substr($heure, 0, -3);**
**        $tod = date("Y-m-d");**
**        $tom = date('Y-m-d', strtotime('+1 day'));**
**        $date = 'le '.strftime('%d/%m/%Y', strtotime($jour));**

**        if ($jour == $tod) $day = 'Aujourd\'hui';**
**        else if ($jour == $tom) $day = 'Demain';**
**        else $day = $date;**

**        return ($day.' à '.$time);**
**    }**
	//Récupération des variables
    foreach($nextRun as $cle => $next) {
        $nom = scenario::byId($cle)->getName();
        $sID = $cle;
        $result = calcul_date($next);
        $scenario->setData('NextProg'.$sID, $result);
        $scenario->setLog($nom.'('.$sID.'): '.$result);
    }
}

Voilà le code licite :

{
|//Création et triage tableau prochains crons 
  foreach($tabCrons as $key => $value) {
   foreach($value as $data) { 
     $nextRun[$key][] = $data->getNextRunDate(); 
     sort($nextRun[$key]); 
     }
 } 
//Calcul date et heure prochain lancement 
 //Récupération des variables 
foreach($nextRun as $cle => $next) { 
   $nom = scenario::byId($cle)->getName(); 
   $sID = $cle; 
  $result = calcul_date($next); $scenario->setData('NextProg'.$sID, $result); 
  $scenario->setLog($nom.'('.$sID.'): '.$result); } }  // fin du code principal ... |

// ici début du code des différentes fonctions du programme ...

function calcul_date($next) { 
   $e = $next[0]; $d = explode(" ", $e); 
   $jour = $d[0]; $heure = $d[1]; 
   $time = substr($heure, 0, -3); 
   $tod =  date("Y-m-d"); $tom = date('Y-m-d', strtotime('+1 day')); 
   $date = 'le'.strftime('%d/%m/%Y', strtotime($jour)); 
   if ($jour == $tod) $day = 'Aujourd\'hui';
   else if ($jour == $tom) $day = 'Demain'; 
   else $day = $date; return ($day.' Ã  '.$time); 
}

A+
Bernard

1 « J'aime »

Modification effectuée !!

Encore une fois merci beaucoup pour ces précieux conseils qui m’aident beaucoup à avancer.

Si tu as d’autres recommandations n’hésites pas je suis preneur :slightly_smiling_face:

@+

Un truc qui me gêne encore moi c’est le if (!$crons) dans

if (!$crons) {
    $scenario->setLog($nom.'Aucun bloc "A" programmé dans le scénario n°'.$Scenario_ID);
    $scenario->setData('NextProg'.$Scenario_ID, 'Pas de programmation');
} 

je suppose que cela fonctionne mais en fait tu t’attends à ce que ce soit un array donc fait plutôt if (!is_array($cron)) parce que là n’importe quelle valeur pouvant être interprétée comme true ton test sera valide mais le code après va crash.

1 « J'aime »

Effectivement dans mes récentes et nombreuses lecture sur le PHP j’avais bien compris que ce n’était pas propre du tout le if (!$crons) {.

C’est comme les commentaires, par moment je les mets bien et quand je reviens sur le code je vire tout.

is_array n’est pas utilisable car il existe bien un tableau mais vide, du coup j’ai mis ça: if (empty($crons)) {

Merci @Mips :wink:

1 « J'aime »

Toujours à propos du style de codage du if, mon avis est qu’il faut éviter comme la peste la construction

if (condition) 
    instruction;

Les raisons sont multiples mais la principale est que dans un moment d’étourderie on va ajouter une instruction derrière et penser que comme elle est indentée sous la première elle fait partie d’un bloc.
J’ai participé à un logiciel libre (Moodle) où un simple

if (condition) 
    instruction;

ou

if (condition)  instruction;

Etait suffisante pour se faire rejeter un PR.
Le résultat c’est que même pour une instruction je mets toujours les { } et je ne m’en porte que mieux.

1 « J'aime »

Exactement !

c’est une de mes premières remarques ! voir le 4°

Oui @Bercolly me l’a dit dès le début :wink: …mais t’as bien fait d’insister car il restait des réfractaires que je viens de corriger :grimacing:

Merci !!

Edit: Je vois que vous êtes d’accord :wink:

Mon passé de prof m’a appris qu’il faut répéter :smile:
Et pour être honnête il y a bien des dizaines d’années je me suis fait piéger par un if sans les crochets et je me souviens encore comme j’ai galéré pour trouver le bug car on peut lire x fois le code sans voir le problème.

1 « J'aime »

C’est encore pire en python, que j’ai découvert avec jeedom aussi.
C’est puissant mais la syntaxe est à vomir, tout repose sur l’alignement du code.

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.