8768 sujets

Développement web côté serveur, CMS

Bonjour,

je me perd un peu sur une requête sql que je dois effectuer.. Et avant de me perdre encore un peu plus, je sollicite votre aide Smiley smile ..

Concrètement, la page sert à calculer un prix selon divers critères..

Dans un premier temps je sélectionne un produit dans un menu déroulant..

Chaque produit à des options (accessoires).

via un jquery post, je récupère la liste de ces options depuis ma bdd, et affiche une liste de checkbox pour que le visiteur puisse sélectionner les options de son choix.

Et c'est là que je bloque.. au moment où le visiteurs clic sur une option, j'envoie une nouvelle requête pour recalculer l'ensemble.. mais je n'arrive pas à formuler ma requête

Sachant que ma liste de checkbox est variable selon le produit et qu'elles ont toutes un ID unique.
voici par exemple le contenu d'une requete :

id_accessoire[] 2
id_accessoire[] 3
id_accessoire[] 6
id_type 1

en gros je dois lui dire

sélectionner prix du produit de base dans la table type + prix des options sélectionnées dans la table accessoires.

Dans ma bdd j'ai ma
table type qui correspond aux produits avec un id_type unique. Le prix de base y est enregistré dans une colonne Smiley price .

table accessoires dans laquelle j'ai chaque accessoire, avec un id_accessoires + un id_type pour faire la liaison.

je pense qu'il y a une histoire de jointure si j'ai bien compris pour interroger les deux tables.. Mais surtout je ne comprend pas comment envoyer un where id_accessoire = x or id_accessoire = y or ..... selon le nombre d'éléments de ma requête..

J'espère être compréhensible ^^
Première partie de mon problème résolu je pense en tout cas, grâce à

if( count($_POST[id_accessoire]) > 0 ) { $id_accessoire = implode( ' OR id_accessoire=', $_POST[id_accessoire] ); }  
Hello,

Je pense que ta requête SQL devrait ressembler à quelque chose comme ça :


select sum(price) as price 
from accessoires
where id_type = 6789
and id_accessoire in (1, 2, 3, 4, 5)


En d'autres termes in est nettement plus approprié qu'une série de or.

Peut-être devrais-tu indiquer le prix de base en tant qu'accessoire obligatoire dans la table accessoires (p.ex. avec un id_accessoire=0), ça t'éviterais de faire deux requêtes ou une union.

Et sinon du point de vue interface utilisateur, ça ne me paraît pas très pertinent de faire un aller-retour serveur avec une requête à chaque fois qu'une option est cochée ou décochée. Il serait sans doute plus malin d'envoyer une seule fois toute la liste des accessoires avec leur prix lorsque le type est sélectionné, et simplement laisser javascript refaire le calcul à chaque fois qu'une case change d'état. De toute façon quelque soit la méthode, tu devras vérifier la commande finale et refaire le calcul côté serveur une fois que l'utilisateur valide définitivement.
La seule grande objection que je vois pour ne pas le faire, c'est si tu as des milliers d'accessoires possibles par type, ou si la logique est vraiment complexe (p.ex. le prix de A dépend du prix de B qui lui-même dépend si C est sélectionné ou pas) auquel cas transmettre toute la liste ou encoder toute la logique dans un format compact est peut-être trop couteux.

P.S. Attention avec les codes du genre implode(',',$_POST['truc']) à glisser dans in; les injections SQL ne sont pas loin et on ne peut pas facilement utiliser les requêtes préparées avec in.
QuentinC a écrit :
Hello,

Je pense que ta requête SQL devrait ressembler à quelque chose comme ça :


select sum(price) as price 
from accessoires
where id_type = 6789
and id_accessoire in (1, 2, 3, 4, 5)


En d'autres termes in est nettement plus approprié qu'une série de or.

Peut-être devrais-tu indiquer le prix de base en tant qu'accessoire obligatoire dans la table accessoires (p.ex. avec un id_accessoire=0), ça t'éviterais de faire deux requêtes ou une union.

Et sinon du point de vue interface utilisateur, ça ne me paraît pas très pertinent de faire un aller-retour serveur avec une requête à chaque fois qu'une option est cochée ou décochée. Il serait sans doute plus malin d'envoyer une seule fois toute la liste des accessoires avec leur prix lorsque le type est sélectionné, et simplement laisser javascript refaire le calcul à chaque fois qu'une case change d'état. De toute façon quelque soit la méthode, tu devras vérifier la commande finale et refaire le calcul côté serveur une fois que l'utilisateur valide définitivement.
La seule grande objection que je vois pour ne pas le faire, c'est si tu as des milliers d'accessoires possibles par type, ou si la logique est vraiment complexe (p.ex. le prix de A dépend du prix de B qui lui-même dépend si C est sélectionné ou pas) auquel cas transmettre toute la liste ou encoder toute la logique dans un format compact est peut-être trop couteux.

P.S. Attention avec les codes du genre implode(',',$_POST['truc']) à glisser dans in; les injections SQL ne sont pas loin et on ne peut pas facilement utiliser les requêtes préparées avec in.



Merci pour ce point de vue très intéressant..

Tu me fais peur avec ces histoires d'injection... Je suis pas sûr d'en connaitre le risque.. Mais si j'ai bien compris, tu me dis que c'est mieux d'utiliser "IN" mais qu'il y a des risques d'injection à cause de implode..? Mais plus besoin de implode si IN fonctionne il me semble.. faut que je test ça Smiley smile

J'ai fini par faire deux requêtes, l'une pour interroger la table type et récupérer le prix de base (sachant que celui-ci dépend également d'un autre paramètre (j'ai deux prix de base dans cette table))

Effectivement je pourrais sans doute économiser un certain nombre de requête en récupérant directement la liste de tous les accessoires et calculer la somme en javascript.. Mais en fait je voulais tout faire sur une seule page avec une mise à jour automatique du prix..

Je n'ai pas beaucoup d'accessoires, peut-être 4 ou 5 par type.

(Je comprends pas trop le select sum(price) as price)

Donc actuellement,

j'ai une requête sur un dropdown catégorie pour récupérer la liste des produits (type)
une requête sur le dropdown produit pour afficher les accessoires
une requête pour afficher le prix 1 ou le prix 2
+ 0 à 4 requête selon le nombre d'accessoires sélectionnés.

donc j'ai minimum 3 requêtes, et je peux en avoir jusqu'à 7 ou 8.

ça semble exagéré ? Même si c'est des petites requêtes de 3Bytes ? et environ 50 à 100ms de temps de réponse?

J'ai aucune idée de l'impact que ça peut avoir à grande échelle..

Mais il est vrai que je pourrai économiser et arriver à 2 requêtes et tout traiter en javascript.. puis retraiter le formulaire complet à l'étape suivante.. mais est-ce rentable surtout pour le serveur ? Car l'utilisateur ne verra pas la différence je pense.. ou à peine..
a écrit :
Effectivement je pourrais sans doute économiser un certain nombre de requête en récupérant directement la liste de tous les accessoires et calculer la somme en javascript.. Mais en fait je voulais tout faire sur une seule page avec une mise à jour automatique du prix..

Ben, justement. Si tu récupères la liste de tous les accessoires une fois que le type est sélectionné, la mise à jour du prix sur la page lorsque les cases sont cochées et décochées peut être instantanée.

a écrit :
Donc actuellement,
j'ai une requête sur un dropdown catégorie pour récupérer la liste des produits (type)
une requête sur le dropdown produit pour afficher les accessoires
une requête pour afficher le prix 1 ou le prix 2
+ 0 à 4 requête selon le nombre d'accessoires sélectionnés.
donc j'ai minimum 3 requêtes, et je peux en avoir jusqu'à 7 ou 8.

Si c'est juste le prix total qui t'intéresse, tu peux récupérer la somme de tous les accessoirs en une seule fois et revenir à 3 ou 4 requêtes maximum, justement en faisant select sum(price) ... where id_accessoire in(...) à la place de select price ... where id_accessoire = ... quatre fois d'affilée.

a écrit :
ça semble exagéré ? Même si c'est des petites requêtes de 3Bytes ? et environ 50 à 100ms de temps de réponse?

En soi, 7 ou 8 requêtes, c'est pas dramatique, certains CMS en font facilement 3 ou 4 fois plus à chaque affichage de page (on se demande bien ce qu'ils font mais c'est comme ça). En fait, il faut surtout voir qu'à la vitesse où les gens sont suceptibles de cliquer sur les cases, il y a moyen de mettre le serveur à genoux rapidement si tu fais une requête par clic je pense.

Tu as tout à gagner de faire le calcul côté client en fait. Parce que s'il y a soudainement une absence momentannée de réseau et que le prix met 1sec à s'afficher, l'utilisateur va s'énerver, va cliquer 12 fois sur la case, ça fait 12 envois AJAX, 12*7=84 requêtes SQL, le serveur va finir par être ralenti.... et couic. J'ai pris le scénario catastrophe là, mais tu vois l'idée. De l'AJAX à chaque clic ça me paraît clairement être de l'overkill et de l'anti-optimisation.
Modifié par QuentinC (03 Apr 2014 - 17:35)
QuentinC a écrit :

Tu as tout à gagner de faire le calcul côté client en fait. Parce que s'il y a soudainement une absence momentannée de réseau et que le prix met 1sec à s'afficher, l'utilisateur va s'énerver, va cliquer 12 fois sur la case, ça fait 12 envois AJAX, 12*7=84 requêtes SQL, le serveur va finir par être ralenti.... et couic. J'ai pris le scénario catastrophe là, mais tu vois l'idée. De l'AJAX à chaque clic ça me paraît clairement être de l'overkill et de l'anti-optimisation.


Tu as raison, même si bon, j'étais bien content d'avoir réussi à obtenir enfin mon prix affiché Smiley lol .. Faut bien admettre que c’était pas forcement la meilleure façon de faire.. Alors je vais refaire ça en espérant ne pas y passer 3 jours Smiley biggol
Bon pas si simple Smiley smile .

Pour le moment j'ai refais mes requête.. Mais je bloque sur un truc...

        public function GetFinalPrice()
        {

            $sql = "SELECT * FROM type WHERE id_type=$_POST[id_type]";
            mysql_query("SET NAMES UTF8");       
            $res = mysql_query($sql,$this->conn);
            $price = "0";
            $data = mysql_fetch_array($res);
            $price_functionnal = $data['price_functional'];
            $price_not_functionnal = $data['price_not_functionnal'];

//ici j'ai mes deux prix pour le produit sélectionné. Pour les accessoires, je fais la requête qui suit.. dont le résultat doit je suppose être mis dans un tableau vu que je peux en avoir plusieurs

            $sql = "SELECT * FROM accessoires WHERE id_type=$_POST[id_type]";
            mysql_query("SET NAMES UTF8");       
            $res = mysql_query($sql,$this->conn);

            $accessoires = array();

            while($row = mysql_fetch_array($res))
            {
                $accessoires[] = $accessoires;
            }

      

        }  


Et là je sais pas trop quoi en faire ou comment l'exploiter, une direction à me donner ? .. Si je fais un print_r($accessoires); vers mon contenu, j'obtiens:
Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) [3] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) ) [4] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) [3] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) ) ) [5] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) [3] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) ) [4] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) [3] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) [2] => Array ( [0] => Array ( ) [1] => Array ( [0] => Array ( ) ) ) ) ) ) )

Coté jquery j'ai tenté
 
            var id_type = $("select#modele option:selected").attr('value');
            $.post("get_final_price.php", {id_type:id_type}, function(data){

                 $.each(data, function(index, val) {
                     $("div#accessoires").push("<li id=' " + key + " '>" + val +"</li>");
                 });

            });


mais ça m'envoie une TypeError: invalid 'in' operand a
Modifié par esk57 (03 Apr 2014 - 22:34)
J'aime beaucoup cette ligne :

                $accessoires[] = $accessoires;

Smiley lol
Tu as dû avoir un petit moment d'absence !
Smiley lol


Je pense que tu voulais plutôt écrire :

                $accessoires[] = $row; 


P.S. Tu utilises l'ancienne API mysql. A l'occasion, pense à passer à PDO ou mysqli.
QuentinC a écrit :
J'aime beaucoup cette ligne :

                $accessoires[] = $accessoires;

Smiley lol
Tu as dû avoir un petit moment d'absence !
Smiley lol


Je pense que tu voulais plutôt écrire :

                $accessoires[] = $row; 




oh ! Smiley eek je crois que j'ai encore pas mal de moment d'absence à mon stade lool. Bon en tout cas ya du progrès, mon print_r me sort quelque chose Smiley smile .. Reste à voir comment récupérer ça avec jquery.. pour le moment rien de concluant.. Je me demande s'il faut envoyer ça en JSON...?

QuentinC a écrit :

P.S. Tu utilises l'ancienne API mysql. A l'occasion, pense à passer à PDO ou mysqli.


Oui c'est vrai.. Mais la plupart des tutos sont sur ce modèle.. et je commence à peine avec tout ça.. je vais essayer de convertir ça par la suite. Smiley smile
Modifié par esk57 (04 Apr 2014 - 00:25)
snif, je bloc complet..

dans les bout de code que je trouve, tous semble avec un tableau genre [value1,value2...]

Moi je récupère un tableau

Array ( [0] => Array ( [0] => 1 [id_type] => 1 [1] => 1 [id_accessoire] => 1 [2] => Boîte d’origine Smiley nom => Boîte d’origine [3] => 1 Smiley prix => 1 ) [1] => Array ( [0] => 1 [id_type] => 1 [1] => 2 [id_accessoire] => 2 [2] => Câbles et connecteur Smiley nom => Câbles et connecteur [3] => 3 Smiley prix => 3 ) [2] => Array ( [0] => 1 [id_type] => 1 [1] => 4 [id_accessoire] => 4 [2] => Kit Smiley nom => Kit [3] => 2 Smiley prix => 2 ) [3] => Array ( [0] => 1 [id_type] =>.............

mais rien à faire.. Je me dis que peut-être c'est un "format" de tableau particulier ? Et que je dois transformer en autre chose ?

edit:

Petite progression..

J'ai encodé mon array en JSON.
Récupéré avec jQuery..
Parser.
j'obtiens maintenant des "objets" et j'arrive à lire et extraire mes données Smiley smile


var newHTML = [];
$.each(data, function(index, value) {
    newHTML.push('<span>' + value[2] + '</span>');
});
$("div#accessoires").html(newHTML.join(""));

Modifié par esk57 (04 Apr 2014 - 03:17)