IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

Changer l'ordre d'une liste [MySQL]


Sujet :

PHP & Base de données

  1. #1
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 34
    Par défaut Changer l'ordre d'une liste
    Bonjour à tous,

    Ça fait un bon moment que je relis mon code, que je cherche sur Google et je ne trouve pas la réponse à mon problème.

    Je veux écrire un code qui me permette de réorganiser les éléments d'une liste grâce à une entrée dans une base SQL qui s'appelle user_order.

    PHP lit la BDD et organise ma liste par ordre croissant de user_order.
    Il reste à ajouter ou enlever 1 à ce user_order pour le faire descendre ou monter et à donner l'ancien user_order à l'annonce qui suit (si je descend) ou qui précède (si je monte) pour ne pas avoir deux fois le même user_order.

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?php
    // J'inclus un fichier qui contient le code pour se connecter à la base
    	include ('./includes/tools.php');
    // Je récupère le sens du changement (up ou down) dans une variable
    	$ordre = $_GET['ordre'];
    // Je récupère l'id de l'annonce à monter ou descendre
    	$id_annonces = $_GET['annonce'];
    // Je récupère son ordre d'origine dans la BDD
    	$order_brut = mysql_query("SELECT user_order FROM bakovitz_annonces WHERE id_annonces = '$id_annonces'");
    	$order_net = mysql_fetch_array($order_brut);
    // Je crée la nouvelle valeur que j'insérerai dans user_order plus loin dans le cas ou je descend l'annonce
    	$down = $order_net['user_order'] + 1;
    // Idem mais pour la monter
    	$up = $order_net['user_order'] - 1;
    	$ancien = $order_net['user_order'];
     
    	switch($ordre) {
    // Si on descend l'annonce on ajoute 1 à son user_order
    		case 'down' : mysql_query("UPDATE bakovitz_annonces SET user_order = '$down' WHERE id_annonces = '$id_annonces'");
    // On enlève 1 à son voisin du dessous pour qu'il prenne sa place
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$ancien' WHERE user_order = '$down'"); break;
    // L'inverse si on monte
    		case 'up' : mysql_query("UPDATE bakovitz_annonces SET user_order = '$up' WHERE id_annonces = '$id_annonces'");
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$ancien' WHERE user_order = '$up'"); break;
    	}
    ?>
    Le problème c'est que quand j'exécute le code (avec 2 annonces) seule l'annonce voisine change de user_order. J'ai donc deux annonces avec le même user_order.
    Si je veux monter celle du bas, seule sa voisine du haut change...

    Je suis sûr que c'est un truc évident de syntaxe ou quoi parce que la logique de mon code me paraît juste.

    Merci par avance pour vos éventuelles réponses !

  2. #2
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Par défaut
    il faut modifier TOUTES les lignes qui changent d'ordre, donc quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // deplacement de l'item a la position $order vers le haut (donc vers $order - 1):
    // * L'element a ($order -1) passe a la position $order
    // * L'element a $order passe a la position ($order - 1)
     
    // Utilisation d'un index "temporaire" pour deplacer l'element courant
    UPDATE table
    SET order = -1
    WHERE order = $order;
     
    // Deplacement de l'element precedent vers le bas
    UPDATE table
    SET order  = order + 1 // ou = $order si tu preferes ^^
    WHERE order = $order - 1
     
    // Positionnement de l'element courant a la place de l'element précédent
    UPDATE table
    SET order = $order - 1
    WHERE order = -1
    Idem pour le deplacement vers le bas.

  3. #3
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 34
    Par défaut
    Merci Fladnag mais je ne suis pas sûr de bien comprendre.

    Tu me proposes une solution directement en SQL au lieu de faire faire les calculs par PHP c'est ça ?

    Je ne comprend pas non plus la raison de l'existence de l'index temporaire puisque s'il n'est pas le premier de la liste il chevauchera à un moment sur un autre non ?

    Et enfin (ça fait beaucoup !) j'aurais bien aimé avoir un commentaire sur le code que j'avais écris dans un but didactique, pour pas dire oui oui sans comprendre.


  4. #4
    Membre Expert Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 023
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 023
    Par défaut
    En tout cas ici il me semble qu'il y a clairement un problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    case 'down' : mysql_query("UPDATE bakovitz_annonces SET user_order = '$down' WHERE id_annonces = '$id_annonces'");
    // On enlève 1 à son voisin du dessous pour qu'il prenne sa place
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$ancien' WHERE user_order = '$down'"); break;
    Car la première ligne définit l'order à $down de ta news.
    Mais ta 2e ligne modifie toutes les news qui ont l'order = $down donc à priori l'annonce que tu viens de modifier va être modifiée une 2e fois ? à moins que je me plante ^^ je crois qu'il faudrait que t'inverses les 2 requêtes.

  5. #5
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Par défaut
    Quel que soit l'ordre dans lequel tu execute les requetes, la 2eme va forcement modifier :
    * L'element qui n'a pas bougé
    * L'element qui a été mis a la nouvelle place avec la 1ere requete.

    C'est pour ca que j'utilise un "index temporaire" dans ma solution.

    Il faudrait pouvoir executer les 2 requetes UPDATE en meme temps pour faire ca en une seule requete, avec 2 ca me parait difficile... a moins de trouver une fonction qui pour X associe X-1 et pour X-1 associe X, et encore je ne suis pas sur que l'UPDATE fonctionnera correctement (et ca doit dépendre des bases de données)

    C'est le meme probleme que pour inverser 2 variables :

    $a=1;
    $b=2;

    comment faire en sorte que $a==2 et $b==1 ? en utilisant la variable temporaire $c
    $c=$a;
    $a=$b;
    $b=$c;

    (y a d'autres solutions pour ce cas là, mais c'était pour l'exemple ;o)

  6. #6
    Membre Expert Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 023
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 023
    Par défaut
    Je ne comprends pas trop l'utilisation de l'index temporaire.
    Ceci devrait suffire non ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $current = 4;
    case 'down' :
    if($current > 0)	{
    	mysql_query("UPDATE bakovitz_annonces SET user_order = user_order + 1 WHERE user_order = $current - 1");
    	mysql_query("UPDATE bakovitz_annonces SET user_order = user_order - 1 WHERE id_annonces = '$id_annonces'");
    }
     
    break;
    Il faut aussi ajouter des tests d'extrêmes dans tes switch, tu ne peux pas décrémenter l'ordre d'une news s'il est inférieur à 1, ni incrémenter l'ordre s'il il est égal à max(ordre). Il faut aussi penser à recréer les suites d'ordres lorsque tu supprimes une news pour garder un état cohérent ^^

  7. #7
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Par défaut
    Citation Envoyé par Djakisback Voir le message
    Je ne comprends pas trop l'utilisation de l'index temporaire.
    Ceci devrait suffire non ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $current = 4;
    case 'down' :
    if($current > 0)	{
    	mysql_query("UPDATE bakovitz_annonces SET user_order = user_order + 1 WHERE user_order = $current - 1");
    	mysql_query("UPDATE bakovitz_annonces SET user_order = user_order - 1 WHERE id_annonces = '$id_annonces'");
    }
     
    break;
    Non, regarde, par exemple :
    Tu veux déplacer l'element en position 3 vers le bas, donc :
    * Mettre l'element 3 (A) en position 4
    * Mettre l'element 4 (B) en position 3

    UPDATE ... set order=order+1 WHERE order=3
    Une fois que tu as executé cette requete, il y a DEUX elements qui ont la position 4, A et B
    Donc si tu fait :
    UPDATE ... set order=order-1 WHERE order=4, tu va bouger l'element A et l'element B, au final ils seront tout les deux en position 3

    Dans ton exemple, tu utilise $id_annonces, ce qui peut etre une solution. Bouger la position d'un element non pas par sa position mais par son id unique.
    Cependant, si tu fais cela, je suppose que l'$id_annonce que tu as est celle de l'element qui bouge (sur lequel l'utilisateur a réalisé l'action)

    Il faudrait donc quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT order ... WHERE id=$element_a_bouger
    UPDATE SET order=order+1 WHERE order=order-1 // on deplace l'element précédent d'une case vers le BAS
    UPDATE SET order=order-1 WHERE id=$element_a_bouger // on déplace l'element a bouger d'une case vers le HAUT
    L'utilisation d'index temporaire n'est utile que si on a pas l'ID de l'element mais juste sa position et qu'on ne souhaite pas faire une requete SELECT id ... WHERE order=... pour se remettre dans le 2eme cas

  8. #8
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 34
    Par défaut
    Citation Envoyé par Djakisback Voir le message
    En tout cas ici il me semble qu'il y a clairement un problème :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    case 'down' : mysql_query("UPDATE bakovitz_annonces SET user_order = '$down' WHERE id_annonces = '$id_annonces'");
    // On enlève 1 à son voisin du dessous pour qu'il prenne sa place
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$ancien' WHERE user_order = '$down'"); break;
    Ha oui ok j'ai compris ! Et du coup j'ai compris l'histoire de l'index temporaire.


    Citation Envoyé par Fladnag Voir le message
    comment faire en sorte que $a==2 et $b==1 ? en utilisant la variable temporaire $c
    $c=$a;
    $a=$b;
    $b=$c;[/CODE]
    Ça y est j'ai compris, c'est un peu comme l'énigme de la barque : http://www.jeux-maths.com/enigme/5,loup-chevre-chou.htm
    Je pensais avoir géré ce problème mais j'avais un peu trop la tête dedans...

    Citation Envoyé par Fladnag Voir le message
    Il faut aussi ajouter des tests d'extrêmes dans tes switch, tu ne peux pas décrémenter l'ordre d'une news s'il est inférieur à 1, ni incrémenter l'ordre s'il il est égal à max(ordre). Il faut aussi penser à recréer les suites d'ordres lorsque tu supprimes une news pour garder un état cohérent ^^
    Ça j'y avais pensé ! Pour les extrêmes je le fais directement au moment de générer la liste, je désactive les boutons concernés. Et ma fonction de suppression soustrait 1 à tous les éléments dont l'ordre est supérieur à celui de l'élément que l'on supprime.

    Je modifie mon code grâce à vos précieux conseils et je reviens cliquer sur Résolu. Merci beaucoup !

  9. #9
    Membre averti
    Inscrit en
    Juin 2008
    Messages
    34
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 34
    Par défaut
    Trop bon ça marche =)

    Pour les newbies comme moi voici donc le code final, commenté et fonctionnel (comme je débute aussi c'est sûrement pas optimisé mais ça fait une base quand même !) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    <?php
    // Récupérer les infos de connexion à la BDD
    	include ('./includes/tools.php');
    // Récupérer la valeur de $ordre (soit up soit down) et l'id de l'annonce à bouger
    	$ordre = $_GET['ordre'];
    	$id_annonces = $_GET['annonce'];
    // Trouver l'ordre actuel de l'annonce à bouger dans la BDD et le rendre lisible par php
    	$order_brut = mysql_query("SELECT user_order FROM bakovitz_annonces WHERE id_annonces = '$id_annonces'");
    	$order_net = mysql_fetch_array($order_brut);
    // Déclaration d'une variable down et d'une variable up contenant la nouvelle valeur d'ordre pour l'annonce à bouger
    	$down = $order_net['user_order'] + 1;
    	$up = $order_net['user_order'] - 1;
    // Selon la valeur (down ou up) de $ordre
    	switch($ordre) {
    // Si on a l'ordre de descendre l'annonce, on attribue donc le fameux id temporaire pour ne pas avoir de conflit dans les ordres
    		case 'down' : mysql_query("UPDATE bakovitz_annonces SET user_order = -1 WHERE id_annonces = '$id_annonces'");
    // On enlève 1 à l'annonce qui a la valeur visée pour qu'elle prenne libère sa place
    		mysql_query("UPDATE bakovitz_annonces SET user_order = user_order -1 WHERE user_order = '$down'");
    // On donne la valeur visée
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$down' WHERE id_annonces = '$id_annonces'"); break;
    // Pareil pour le cas où on monte
    		case 'up' : mysql_query("UPDATE bakovitz_annonces SET user_order = -1 WHERE id_annonces = '$id_annonces'");
    		mysql_query("UPDATE bakovitz_annonces SET user_order = user_order +1 WHERE user_order = '$up'");
    		mysql_query("UPDATE bakovitz_annonces SET user_order = '$up' WHERE id_annonces = '$id_annonces'"); break;
    	}
    ?>
    Le code pour réorganiser les ordres en cas de suppression d'une annonce :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    	include ('./tools.php');
    	$id_annonces = $_GET['annonce'];
     
    	$ordre_brut_annonce_supprimee = mysql_query("SELECT user_order FROM bakovitz_annonces WHERE id_annonces = '$id_annonces'");
    	$ordre_net_annonce_supprimee = mysql_fetch_array($ordre_brut_annonce_supprimee);
    	$ordre_brut_annonces = mysql_query("SELECT id_annonces, user_order FROM bakovitz_annonces");
     
    	while ($ordre_net_annonces = mysql_fetch_array($ordre_brut_annonces)) {
    		if ($ordre_net_annonces['user_order'] > $ordre_net_annonce_supprimee['user_order']) {
    			$new_order = $ordre_net_annonces['user_order'] - 1;
    			$id_annonce_modif = $ordre_net_annonces['id_annonces'];
    			mysql_query("UPDATE bakovitz_annonces SET user_order = '$new_order' WHERE id_annonces = '$id_annonce_modif'") or die (mysql_error());
    		}
    		else {
    		}
    	}
    		mysql_query("DELETE FROM bakovitz_annonces WHERE id_annonces = '$id_annonces'");
    ?>
    Et pensez aussi à tester les valeurs extrêmes pour ne pas les empêcher d'aller plus haut que 1 et plus bas que le plus grand ordre. Voici le code php et html qui génère ma liste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <?php
    include ('./includes/tools.php');
    $biggest_brut = mysql_query("SELECT id_annonces, user_order FROM bakovitz_annonces ORDER BY user_order DESC LIMIT 0 , 1");
    $biggest_net = mysql_fetch_array($biggest_brut);
    $smallest_brut = mysql_query("SELECT id_annonces, user_order FROM bakovitz_annonces ORDER BY user_order ASC LIMIT 0 , 1");
    $smallest_net = mysql_fetch_array($smallest_brut);
    ?>
    			<h1>G&eacute;rer les annonces :</h1>
    				<?php
    				$bakovitz_annonces_brut = mysql_query("SELECT id_annonces, icone_annonces, texte_annonces, user_order FROM bakovitz_annonces ORDER BY user_order");
    				$annonces = '';
     
    				while ($bakovitz_annonces_net = mysql_fetch_array($bakovitz_annonces_brut)) {
    					$id_annonces = $bakovitz_annonces_net['id_annonces'];
    					$icone_annonces = $bakovitz_annonces_net['icone_annonces'];
    					$texte_annonces = $bakovitz_annonces_net['texte_annonces'];
    					if ($bakovitz_annonces_net['user_order'] == $biggest_net['user_order']) {
    					$annonces .= '<div class="annonce"><div class="boutons"><a class="fauxbtn" href="index.php?page=creer_annonces&annonce=' . $id_annonces . '">Editer</a><a class="fauxbtn" href="./includes/action_suppr_annonces.php?annonce=' . $id_annonces . '">Suppr.</a><a class="up" href="index.php?page=action_ordonner_annonces&ordre=up&annonce=' . $id_annonces . '"></a><a class="down" href="#"></a></div><div class="icone_annonces"><img src="../images/layout/icone_annonces/' . $icone_annonces . '" /></div><div class="texte-annonces">' . $texte_annonces . '</div></div>';	
    					}
    					else if ($bakovitz_annonces_net['user_order'] == $smallest_net['user_order']) {
    					$annonces .= '<div class="annonce"><div class="boutons"><a class="fauxbtn" href="index.php?page=creer_annonces&annonce=' . $id_annonces . '">Editer</a><a class="fauxbtn" href="./includes/action_suppr_annonces.php?annonce=' . $id_annonces . '">Suppr.</a><a class="up" href="#"></a><a class="down" href="index.php?page=action_ordonner_annonces&ordre=down&annonce=' . $id_annonces . '"></a></div><div class="icone_annonces"><img src="../images/layout/icone_annonces/' . $icone_annonces . '" /></div><div class="texte-annonces">' . $texte_annonces . '</div></div>';	
    					}
    					else {
    					$annonces .= '<div class="annonce"><div class="boutons"><a class="fauxbtn" href="index.php?page=creer_annonces&annonce=' . $id_annonces . '">Editer</a><a class="fauxbtn" href="./includes/action_suppr_annonces.php?annonce=' . $id_annonces . '">Suppr.</a><a class="up" href="index.php?page=action_ordonner_annonces&ordre=up&annonce=' . $id_annonces . '"></a><a class="down" href="index.php?page=action_ordonner_annonces&ordre=down&annonce=' . $id_annonces . '"></a></div><div class="icone_annonces"><img src="../images/layout/icone_annonces/' . $icone_annonces . '" /></div><div class="texte-annonces">' . $texte_annonces . '</div></div>';
    					}
    				}
    				echo $annonces;
    				?>
    			<a href="index.php?page=creer_annonces" class="fauxbtn">Cr&eacute;er</a>

  10. #10
    Membre Expert Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 023
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 023
    Par défaut
    @Fladnag : ah oui effectivement je vois maintenant merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AJAX] Sauvegarder l'ordre d'une liste après modification par javascript
    Par Ashgenesis dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 07/02/2008, 15h54
  2. Changer l'ordre d'une liste
    Par ethno dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 03/01/2008, 12h19
  3. changer Option Selected d'une Liste
    Par Link45 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 24/05/2007, 12h04
  4. Réponses: 2
    Dernier message: 05/06/2006, 17h51
  5. Réponses: 1
    Dernier message: 20/04/2006, 09h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo