[RESOLU] Affichage listes déroulantes liées

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 13:31

Le problème vient du script changeIP.JS. Il attends le numéro de réseau alors qu'on lui envoi le nom du réseau... Enfin je pense que ça vient de là.

Mammouth du PHP | 19672 Messages

21 mars 2013, 14:38

Ça veut dire que c'est donc la première liste qui bafouille, celle des réseaux, pas celle des IP.

Donc on recommence mais au bon endroit cette fois : comment est construite la liste des réseaux et à partir de quoi au juste ? Si on regarde le tableau construit à la base, on en voit effectivement nulle part l'identifiant du réseau puisque ce nom sert d'index aux listes d'IP.

Il faut donc revoir la structure même de ce tableau,... ou bien en construire deux, un pour les réseaux, un autre pour les IP. Mais partons sur l'idée d'un tableau unique. Je peux te suggérer comme exemple la structure suivante :

Code : Tout sélectionner

array(2) { [0] => array(2) { ["reseau"] => array(2) { ["id"] => int(1) ["nom"] => string(4) "Test" } ["ips"] => array(10) { [0] => string(10) "172.30.0.1" [1] => string(10) "172.30.0.2" [2] => string(10) "172.30.0.3" [3] => string(10) "172.30.0.4" [4] => string(10) "172.30.0.5" [5] => string(10) "172.30.0.6" [6] => string(10) "172.30.0.7" [7] => string(10) "172.30.0.8" [8] => string(10) "172.30.0.9" [9] => string(11) "172.30.0.10" } } [1] => array(2) { ["reseau"] => array(2) { ["id"] => int(2) ["nom"] => string(5) "Test2" } ["ips"] => array(10) { [0] => string(11) "172.30.0.11" [1] => string(11) "172.30.0.12" [2] => string(11) "172.30.0.13" [3] => string(11) "172.30.0.14" [4] => string(11) "172.30.0.15" [5] => string(11) "172.30.0.16" [6] => string(11) "172.30.0.17" [7] => string(11) "172.30.0.18" [8] => string(11) "172.30.0.19" [9] => string(11) "172.30.0.20" } } }
Petites explications sur les différents niveaux de cette structure.
-1- Premier niveau, des indexes numériques correspondant à la clé primaire du réseau considéré
-2- Second niveau, deux éléments, d'abord le nom du réseau et ensuite la liste des IPs;
-3- Troisième niveau : pour le nom du réseau, un tableau avec l'identifiant du réseau et le nom du réseau, ici par exemple, 1 // Test et 2 // Test2, et pour les IPs, un tableau avec des indexes numériques automatiques.

Je te laisse mijoter ça, essaye de construire cette structure à partir du retour de la requête SQL en modifiant la boucle while. Ne t'inquiète pas de la suite pour le moment, si tu arrives à ça, la suite sera plus facile.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 15:12

Pour information, actuellement, ça donne ça :

Image

Bon, après avoir lu ton post, j'ai testé ça :
$query_reseau = $bdd->query("SELECT adresse_ip AS idd, RESEAUX.id_reseau AS idr, RESEAUX.nom_reseau AS inr FROM IP, RESEAUX WHERE IP.id_reseau = RESEAUX.id_reseau AND adresse_ip NOT IN (SELECT adresse_ip FROM IP_MAT) ORDER BY RESEAUX.nom_reseau, INET_ATON(adresse_ip)");
            
            /* Création du tableau PHP des valeurs récupérées */
$reseaux = array();
/* Pour ne pas écraser mes tableaux, je crée un témoin */
$temoin_r = null;
while(false !== ($ligne = $query_reseau->fetch()))
{
    /* Je vérifie si je suis toujours dans le même réseau, sinon je crée les tableaux nécessaires */
    if ($temoin_r != $ligne['idr'])
    {
        $temoin_r = $ligne['idr'];
        $nom_reseau = $ligne['inr'];
        $reseaux[$temoin_r] = array(
            'id' => $temoin_r,
            'reseau' => $nom_reseau
        );
    }
    /* J'ajoute l'adresse IP */    
    $reseaux[$temoin_r][] = $ligne['idd'];
}
/* Affichage de débogage à supprimer quand le  résultat sera satisfaisant */
echo("<pre>\n");
var_dump($reseaux);
echo("</pre>\n");
ça donne :

Code : Tout sélectionner

array(24) { [30]=> array(256) { ["id"]=> string(2) "30" ["reseau"]=> string(6) "BLABLA" [0]=> string(12) "192.168.56.1" [1]=> string(12) "192.168.56.2" [...]
Je suis pas loin, mais je n'arrive pas à créer un autre sous-tableau, dès que je teste, il me crée un autre tableau en-dessous et je n'ai aucun lien entre les 2.

Mammouth du PHP | 19672 Messages

21 mars 2013, 15:39

Mouais, tu pars de travers, mais ça vient en grande partie du fait que tu tentes de tout faire à la fois.

Ralentis un peu la manœuvre et réfléchis à ta structure.
  1. On a au départ un tableau $reseaux, ça, c'est la ligne :
    $reseaux = array();
  2. Notre tableau $reseau contient d'autres tableaux. Donc, à chaque fois qu'on arrive sur un nouveau réseau dans la liste retournée par la base de données, on va créer les structures. Ces structures comportent deux éléments : réseau et ips qui sont également deux tableaux
    $reseaux[] = array(
        'reseau' => array(),
        'ips' => array()
    );
    
  3. Dans un premier temps, on peut s'occuper du réseau, on verra les IP ensuite. On connait les informations sur le réseau, son identifiant et son nom, on peut donc les mettre en place, Le code précédent devient alors :
    $reseaux[] = array(
        'reseau' => array(
            'id' => $ligne['idr'],
            'nom' => $ligne['inr']
        ),
        'ips' => array()
    );
    
  4. Là, on réalise ensuite qu'on va avoir un problème pour pointer sur le bon index au moment d'ajouter les adresses IP. Quand on fait $tableau[] = $valeur, c'est le moteur PHP qui crée automatiquement un index numérique auto-incrémenté à partir de zéro. Sachant ça, on peut facilement récupérer cet index pour initialiser une variable qui nous servira pour ajouter les adresses IP.
    On peut donc faire :
    $numTableau = count($reseaux) -1;
  5. Tout ce qui précède (sauf le premier point) devra être axécuté uniquement si on arrive sur un réseau différent du tour précédent (ou si c'est le premier). C'est donc à ça que sert le témoin, donc ces éléments de code sont dans le « if() ».
    Notre boucle while à ce stade va ressembler à ceci :
    /* Création du tableau PHP des valeurs récupérées */
    $reseaux = array();
    /* Pour ne pas écraser mes tableaux, je crée un témoin */
    $temoin_r = null;
    while(false !== ($ligne = $query_reseau->fetch()))
    {
        /* Je vérifie si je suis toujours dans le même réseau, sinon je crée les tableaux nécessaires */
        if($temoin_r != $ligne['idr'])
        {
            $start++;
            $temoin_r = $ligne['idr'];
            $reseaux[] = array(
                'reseau' => array(
                    'id'  => $ligne['idr'],
                    'nom' => $ligne['inr']
                ),
                'ips' => array()
            );
            $numTableau = count($reseaux) -1;
        }
    }
  6. Il ne reste plus qu'à ajouter les adresses IP : où ? Dans leur propre sous-tableau. On va donc pointer dessus et ajouter les adresses :
    $reseaux[$numTableau]['ips'][] = $ligne['idd'];
    Note bien les index utilisés.
Si tu as bien suivi, tu devrais pouvoir terminer les détails, je te laisse faire, ajoute ensuite le var_dump et affiche le résultat pour vérifier que ça correspond au tableau attendu. N'essaye pas d'aller plus vite que la musique, réfléchis tranquillement en restant aussi logique que possible.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 16:22

Alors, j'ai modifié le code avec la partie que tu as posté. Au niveau de la boucle foreach pour l'affichage, j'ai entré ceci :
<select name="edit_reseau" style="text-align:center;" id="reseau" onchange="changeIP(tab,this.value);">
                                        <option value="vide">- - - Sélectionnez le réseau - - -</option>
                                        <?php
                                        
                                        /* Construction de la première liste : on se sert du tableau PHP */
                                        foreach ($reseaux as $nr => $value) {                                            
                                            ?>                                        
                                            <option style="text-align:center;" value="<?php echo($nr); ?>"><?php echo $value['reseau']['nom']; ?></option>
                                            <?php                                            
                                        }
                                        ?>
                                    </select>
Du coup, ça m'affiche bien le nom des réseaux 8-)

Par contre, la partie Adresse IP n'apparaît même plus, c'est un souci JS.
/* On sérialise le tableau obtenu pour traitement par JavaScript */
            $chaine = htmlspecialchars(serialize($reseaux), ENT_QUOTES);
            ?>
            <script type="text/javascript">
                /* <![CDATA[ */
                <!--
                /*
                 * Ici, on transmets la chaîne sérialisée à JavaScript pour la transformer en tableau indexé JavaScript 
                 */
                var tableau = new PhpArray2Js('<?php echo $chaine; ?>');
                var tab = tableau.retour();
                // -->
                /* ]]> */
Je pense que ça vient de cette partie, PhpArray2JS n'est pas fait pour le tableau qu'on a créé ? Car le blocIP n'apparaît même plus après la sélection du réseau :
<span style="text-align:center;" id="blocIP"></span><input type="hidden" name="recup_ip" id="recup_ip"/></td></tr>

Mammouth du PHP | 19672 Messages

21 mars 2013, 16:45

Ok, alors si c'est bon pour les réseaux, on va voir les IP.
Mais j'ai un doute : dans la liste des réseaux, tu n'as pas les identifiant en value des options mais l'index des tableaux. Corrige ça et passe à la suite.

Au lieu de passer par PhpArray2JS, tu vas utiliser une fonction native de PHP : json_encode(). Ça va présenter le coté on ne peut plus pratique de générer une chaine directement lisible en JavaScript. TU as vu le tableau qui s'affiche avec var_dump ? Là, ça va sortir quelque chose comme ceci :

Code : Tout sélectionner

string(355) "[{"reseau":{"id":1,"nom":"Test"},"ips":["172.30.0.1","172.30.0.2","172.30.0.3","172.30.0.4","172.30.0.5","172.30.0.6","172.30.0.7","172.30.0.8","172.30.0.9","172.30.0.10"]},{"reseau":{"id":2,"nom":"Test2"},"ips":["172.30.0.11","172.30.0.12","172.30.0.13","172.30.0.14","172.30.0.15","172.30.0.16","172.30.0.17","172.30.0.18","172.30.0.19","172.30.0.20"]}]"
Donc dans ton PHP, tu vas mettre :
var tab = <?php echo json_encode($chaine); ?>;
Et tu n'as plus besoin de l'étape intermédiaire avec la variable tableau.

Pour pointer sur les bons éléments, tu pourras alors écrire par exemple :
[javascript]
option = '<option val="'+ tab.ips[n] +'">'+ tab.ips[n] +'</option>\n';
[/javascript]
Essaye déjà comme ça, je n'ai pas trop de temps pour te donner plus de détails, mais pars de l'existant et si un point t'échappe, pose des questions.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 17:10

J'ai modifié pour les identifiants en value. Pour continuer, j'ai juste une petite question, je me sépare de arrayPHP2.js, ok ! Par contre, je garde bien changeIP.js, le code JS :

[javascript]option = '<option val="'+ tab.ips[n] +'">'+ tab.ips[n] +'</option>\n';[/javascript]

ça concerne bien ce fichier là ? Ou alors, je peux tout faire dans ma page PHP juste avec une balise script ?

Merci.

Mammouth du PHP | 19672 Messages

21 mars 2013, 17:21

wow ! attention aux mélanges des genres...

Un truc très important à comprendre dans ce type de développement, c'est qu'est-ce qui sert à quoi et où.
Le PHP s'exécute coté serveur, le JavaScript coté client (les comiques qui interviendraient pour me parler de Node.js sont invités à aller jouer sur un bord de falaise :mrgreen: )

Donc, il est important de comprendre tout aussi bien à quoi sert tel ou tel fichier. « arrayPHP2.js » sert à transformer un tableau envoyé par PHP pour le transformer en quelque chose de plus facilement lisible et utilisable en JavaScript coté client. Ta page est construite en PHP et doit comporter une liste issue d'une requête SQL. Le tuto date de pas mal de temps et depuis, il y a eu quelques évolutions en PHP : donc l'utilisation de json_encode se trouve beaucoup plus appropriée aujourd'hui. Pour info, JSON = JavaScript Object Notation (ou, en français, Notation Objet JavaScript) et c'est une manière de structurer des informations utilisée par beaucoup de langages dont PHP et JavaScript bien entendu, mais pas uniquement loin s'en faut.

En résumé, oui, ton fichier arrayPHP2.js peut sauter, mais surtout pas l'autre puisque ce dernier gère la mise à jour des listes.

C'est plus clair comme ça ?
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 17:24

Ok, merci pour les explications, c'est bien ce que j'avais compris alors! Mais je voulais être sûr avant de partir dans la recherche... :D

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 17:41

Je remets ma boucle :
foreach ($reseaux as $key => $value) {                                            
                                            ?>                                        
                                            <option style="text-align:center;" value="<?php echo $value['reseau']['id']; ?>"><?php echo $value['reseau']['nom']; ?></option>
                                            <?php                                            
                                        }
On est d'accord, elle est bonne ? le fichier changeIP.js reçoit bien l'id de mon réseau ? Là, rien ne se passe, je n'ai même pas un message d'erreur pour m'aiguiller... Y'a pas moyen d'activer un message d'erreur pour JS ??

Avant de la modifier, la fonction changeIP utilisait "idr", pareil pour les "option value".

Mammouth du PHP | 19672 Messages

21 mars 2013, 17:57

Non mais tu ne regardes pas au bon endroit : lorsque tu sélectionnes un réseau, tu es dans une liste qui existe depuis le serveur, elle a été générée en PHP.

Là, il s'agit de mettre à jour la liste des adresses IP, donc ça se passe coté client (dans ton navigateur) et c'est du JavaScript. La structure de ton tableau de données en JavaScript ayant un peu changé, il faut mettre à jour le code JavaScript, ne touche plus au PHP, ça n'est plus pertinent.

Utilise Firebug et la console pour identifier les erreurs s'il y en a et reviens avec le résultat.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 18:07

Ah bah voilà, nickel la console de firebug ! Je fais tellement peu de JS... Je hais tellement le JS...

J'ai bien une erreur et ça, dès le départ...

Code : Tout sélectionner

TypeError: tab[idr][1] is undefined [Stopper sur une erreur] var nbd = tab[ idr ][1].length;
Le fichier actuelle :

[javascript]/* On crée la fonction qui va construire la seconde liste déroulante */
function maj(ip)
{
document.getElementById("recup_ip").value = ip;
}

function changeIP(tab,ips)
{
if(ips != "vide")
{
/* On compte les ip de ce réseau */
var nbd = tab[ ips ][1].length;
var form_d = '<select name="ip" id="ip" style="text-align:center;" onchange="maj(this.value);">';
form_d += '<option value="" selected="selected">- - - Selectionnez l\'IP - - -</option>';
for(var j = 0; j < nbd; j++)
{
form_d += '<option val="'+ tab.ips[n] +'">'+ tab.ips[n] +'</option>\n';
}
form_d += '</select>';
}
else
{
form_d = "";
}
document.getElementById("blocIP").innerHTML = form_d;[/javascript]

On est vraiment obligé de compter les IP ? A partir du moment où on connait le réseau, on a juste à toutes les lister... Non ?

EDIT: De ce que je lis, aucun foreach pour JS... :?

Mammouth du PHP | 19672 Messages

21 mars 2013, 18:27

Relax, apprends donc à respirer tranquillement au lieu de sauter vainement aux conclusions sans t'arrêter sur les points importants.

Regarde ton message d'erreur :

Code : Tout sélectionner

tab[idr][1] is undefined
Ok, regardons ton code :
[javascript]//...
var nbd = tab[ ips ][1].length;
// ...[/javascript]
Donc, l'index « 1 » n'est pas bon : d'où sort-il ? C'est ça la question qu'il faut te poser.

Ensuite, oui, on est obligé de compter parce que la fonction si pratique de PHP foreach n'existe pas en JavaScript même s'il en existe une autre qui pourrait faire l'affaire. Mais on y reviendra au besoin plus tard.

Pour l'instant, concentrons nous sur ce bout de code : il te faut savoir exactement à quoi correspond chaque élément. Quelle méthode appelle cette fonction changeIP ?, et d'où sort-elle les paramètres qu'elle envoie ?
Quelle est la structure de ta variable « tab » ? => Est-il normal de pointer sur tab[ips][1] ?

Puisque tu as Firebug, tu vas t'en servir. Tu vas faire afficher la valeur des paramètres reçus par ta fonction changeIP en ajoutant deux petites ligne au début :
[javascript]function changeIP(tab,ips)
{
console.info(tab);
console.info(ips);
if(ips != "vide")
{
/* On compte les ip de ce réseau */
// ....[/javascript]
Recharge ta page, ouvre la console Firebug (F12), efface les messages déjà présents et sélectionne un réseau dans la liste, puis, observe ce qui se passe dans la console : tu devrais voir deux messages avec des informations : copie/colle-moi ça ici, on pourra avancer plus facilement en sachant de quoi on cause ;)
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

[Compte supprime]
Invité n'ayant pas de compte PHPfrance

21 mars 2013, 18:36

Je suis relaaaxxxxxxx !!! C'est juste que je hais le JS !! :mrgreen:

Je vais devoir bouger, je re-teste tout ça demain matin !!!! Merci pour tout !! :mrgreen:

Mammouth du PHP | 19672 Messages

21 mars 2013, 19:08

Il n'y a pas de raison valable pour haïr le JavaScript. C'est juste un langage avec une syntaxe un peu différente du PHP, mais fondamentalement, les principes de programmation sont les mêmes.

Ce qui est éventuellement difficile, c'est de sauter de l'un à l'autre sans se pélanger les médales :mrgreen: et je fais ça tous les jours. Je te montrerai pas le code de mon dernier fichier JavaScript, tu vas imploser :D

Ceci dit, c'est là qu'il faut réaliser qu'il est crucial de bien séparer les choses : on évite de mélanger tous les codes, ça évite bien des maux de tête, et on traite un problème à la fois.
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe: