8791 sujets

Développement web côté serveur, CMS

Bonjour,
dernièrement j'ai modifier certaines donné dans ma bdd principal. J'ai créer une table contenant une liste de catégories. En 3 colonne: id, fr et en

Donc quand j'assigne une catégorie à un produit, j'utilise cette liste.

En faisant ce changement j'ai du corrigé certains code de mon site, dont mon formulaire de contact. Pour mon formulaire en français aucun problème. Mais pour celui en anglais c'est une autre histoire.

Donc, dans le dis formulaire, j'ai une liste déroulante qui doit afficher tous les produits de ma bdd. J'utilise les jointure pour faire la traduction des termes en anglais. Mais ça ne fonctionne pas...

voici mon code:
<select name="produit">
	<option value="">Choose product</option>
	<?php
	$recherche = "SELECT PROD.`produit`, C.`en`, C.`fr`
			FROM `produits` PROD
			LEFT JOIN `categories` C
			ON PROD.`categorie` = C.`en`
			LEFT JOIN `cameras` CAM
			ON CAM.`categorie` = C.`en`
			ORDER BY C.`en`";
	$requete = mysql_query($recherche);
	while($info = mysql_fetch_assoc($requete)) {
		if($info['categorie'] == "Cameras") {
			$q = "SELECT camera FROM cameras WHERE categorie='".$info['categorie']."' ORDER BY annee DESC";
		} else {
			$q = "SELECT produit FROM produits WHERE categorie='".$info['categorie']."'";
		}
		$q = mysql_query($q);
							
		echo '<optgroup label="'.$info['categorie'].'">';
		while($row = mysql_fetch_assoc($q)) {
			if($info['categorie'] == "Cameras") { $row['produit'] = $row['camera']; }
			if(!in_array($row['produit'], $removeArr)){
				echo '<option value="'.$row['produit'].'" '.(isset($formulaire) && $formulaire->produit == $row['produit']?'selected="selected"':"").'>'.$row['produit'].'</option>';	
			}
		}
		echo '</optgroup>';
	}
	?>
</select>

Modifié par juliesunset (11 Jan 2013 - 15:53)
Salut,
La condition de jointure doit être sur la clé primaire C.id et pas C.en (bizarre que ça marche en français, d'ailleurs, ou alors ta clé primaire est une chaîne égale à la chaîne fr).

En passant, il y aurait pas mal de choses à revoir dans ton code : requêtes imbriquées, module mysql_* obsolète, test if($info['categorie'] == "Cameras") qui ne passera jamais puisque tu ne sélectionnes pas la colonne 'categorie'. Juste en passant, hein.
ça fonctionne en français, parce que je n'ais pas besoin de faire de jointure.

Les noms de catégorie sont entré en français dans les tables "produits" et "cameras", à partir de la table "categories" dans laquelle il y a 3 colonnes, les id, les catégories en français (fr) et les mêmes catégories mais en anglais (en), d'où la raison pour laquelle j'ai besoin de faire une jointure pour le formulaire en anglais.

Donc il faut que je remplace les infos de la colonne "catégorie" de mes tables "produits" et "cameras" par celles de la colonne "en" de la table "categories".

J'ai changé "$info['categorie']" par "$info['en]"
là si j'écris:
$recherche = 
	"SELECT 
		PROD.`produit`,
		PROD.`categorie`,
		C.`en`
	FROM `categories` C
	LEFT JOIN `produits` PROD
		ON PROD.`categorie` = C.`en`
	ORDER BY C.`en` NOT IN ('Cameras'), C.`en`";

Étonnement ça fonctionne en partie. Les caméras sont bien affiché, mais pas le reste...

Seven tears a écrit :
requêtes imbriquées, module mysql_* obsolète

Alors on fait comment maintenant?
OK je viens de me souvenir,

Ça serais donc plutôt comme ça:
$recherche = 
	"SELECT 
		PROD.`produit`,
		PROD.`categorie`,
		C.`en`,
		C.`fr`,
	FROM `categories` C
	LEFT JOIN `produits` PROD
		ON PROD.`categorie` = C.`fr`
	ORDER BY C.`en` NOT IN ('Cameras'), C.`en`";

J'indique ainsi la colonne d'origine... mais ça ne fonctionne toujours pas correctement.

page enligne -http://www.spypoint.com/EN/contact.php
il faut cliquer sur "Technical Support" en premier pour voir apparaître le menu déroulant problématique.
Modérateur
Salut,

Ton souci est simple ! On est d'accord que tu as cette structure ?
http://img843.imageshack.us/img843/3241/juliesunset.png

Dans la table categories qui devrait être appelé langues au passage, deux enregistrements devraient être comme ?
INSERT INTO categories (name) VALUES('en'),VALUES('fr');

Dans la table produits, deux enregistrements devraient être comme ?
INSERT INTO produits (name,categorie_id) VALUES('un produit',2),VALUES('one product',1);


Alors ta requête finale pour sélectionner les enregistrements suivant une categorie est :

SELECT
	p.name AS name
FROM
	produits AS p,
	categories AS c
WHERE
	c.id = p.categorie_id
AND
	p.categorie_id = 1 #1 étant la langue spécifiée (là c'est l'Anglais suivant mon exemple)
Comme ça,
Donc table "categories"
upload/22504-categories.jpg
et table "produits"
upload/22504-produits.jpg
Le contenue de la colonne "categorie" de la table "produits" correspond à celui de la colone "fr" de la table "categories"

Désolé j'ai vraiment du mal à te suivre... ça fait un moment je suis là-dessus, je ne doit plus y voire très claire!
La table "produits" n'est pas bonne. La clef étrangère "categorie" doit pointer sur la clef primaire de la table "categories" :
1  | SDB-85 | 3 => ID de "détecteur de mouvement / motion detect"
...
43 | IRB-W  | 4 => ID de "éclairage infrarouge / infrared boster"


Donc pour la jointure :
select
  produits.id,
  produits.produit,
  categorie.en
from produits
left join categories
  on produits.categorie = categories.id


a écrit :
Alors on fait comment maintenant?

Pour tes requêtes imbriquées (pas imbriquées au sens SQL, mais dans le sens où tu refais une requête pour chaque enregistrement de la première) : là, tu multiplies inutilement le nombre de requêtes, donc les allers-retours vers MySQL, question performances c'est pas top, surtout que pour des produits de la même catégorie, la requête sera la même. A minima, il serait mieux de faire une requête sur toutes les catégories avant, et de filtrer ensuite en PHP.

Pour mysql_*, qui est obsolète depuis longtemps, préférer mysqli ou PDO.
Modérateur
Ta table categories est mal modélisée. Je vois de la redondance ce qui est très mauvais. Je vais faire une visualisations de tes tables et mettre en pratique mon intuition.

Je ne vois pas du tout l'intérêt du left join mise à part faire une rustine sur une base bancale.
Modifié par niuxe (10 Jan 2013 - 22:06)
Modérateur
La modelisation devrait ainsi :
http://img845.imageshack.us/img845/4408/juliesunset2.png

Un exemple de la table langues :

INSERT INTO langues (name) VALUES('en'),('fr');

Un exemple de la table categories (et là oui, ça prend tout son sens)

INSERT INTO categories (name,langue_id) VALUES('détecteur de mouvement',2),('motion detection',1);

Un exemple de la table produits:

INSERT INTO produits (name,categorie_id) VALUES('WRL',2); #dans le cas où la description du produit est en Français


la requête de sélection :

SELECT
	c.name AS categorie,
	p.name AS nom
FROM
	produits AS p,
	categories AS c,
	langues AS l
WHERE
	l.id = c.langue_id
AND
	c.id = p.categorie_id
AND
	l.id = 1 #1 étant la langue spécifiée (là c'est l'Anglais suivant mon exemple)

Dans la dernière conditionnelle :

#...
l.id = 1 

j'aurais pu tout à fait ecrire :

l.name = 'en'

;)
Modifié par niuxe (10 Jan 2013 - 22:12)
Je ne crois pas que ce soit ça. Ce n'est pas une catégorie qui est soit en FR, soit en EN, elle est dans les 2 langues. Et si tu fais 2 enregistrements pour 1 catégorie, tu es marron pour référencer cette catégorie dans les produits.
Sa structure produits-catégories était "bonne" à la clef étrangère près, et si le site n'évolue pas pour intégrer une 3è langue (compromis à faire sur les formes normales en début de projet).

L'inquiétude pour la suite serait plutôt du coté des caméras qui semblent être des produits mais sûrement avec des infos supplémentaires pour ne pas figurer dans produits. Julie nous en dira plus si besoin.
Modérateur
En complément de ce que j'ai écrit :

Beaucoup de personnes confondent une chose primordiale dans la définition de SGBDR. SGBDR veut dire :
système de gestion de base de données relationnelles. La définition de relationnelle est très mal comprise. Beaucoup pensent que ce sont les relations entres les différentes tables. Or c'est totalement faux. C'est une relation dans la table en elle même ! Tous les attributs (champs) de la table doivent être en relation direct avec la définition table elle même (pas de code postal dans la table produits....).

Pour reprendre une expression de William Kent :
william kent a écrit :

Chaque attribut qualifie la clef,
TOUTE la clef,
RIEN QUE la clef


La clef étant l'identifiant unique.
Modifié par niuxe (10 Jan 2013 - 22:29)
Modérateur
Seven tears a écrit :
Et si tu fais 2 enregistrements pour 1 catégorie, tu es marron pour référencer cette catégorie dans les produits.

Bah non, puisqu'une categorie est liée à une langue et un produit est lié à une catégorie. Là où tu pourrais dire quelque chose, alors il y aura 2 fiches pour chaque produits ? Oui, parce que nous avons deux langues Smiley cligne . En plus un nom de produit en Anglais n'aura peut être pas le même nom en Français. Pourtant ce sera le même produit. Je ne parle pas de la descrpition du produit puisque ce dernier sera dans la langue choisie.

Seven tears a écrit :
Sa structure produits-catégories était &quot;bonne&quot; à la clef étrangère près, et si le site n'évolue pas pour intégrer une 3è langue (compromis à faire sur les formes normales en début de projet)


Là tu as mis le doigt sur un problème potentiel avec sa structure. Sa structure n'est pas extensible facilement. Après pour faire un INSERT/UPDATE/DELETE/SELECT on perd beaucoup de temps pour rien. La preuve : son sujet.

Là, je confirme toujours, je ne vois pas l'intéret du LEFT JOIN. La requête doit mettre plus de temps puisque les tables ne sont pas normalisées. Smiley cligne
Modifié par niuxe (10 Jan 2013 - 23:04)
Ouf! J'essaie de suivre là!

Seven tears a écrit :
L'inquiétude pour la suite serait plutôt du coté des caméras qui semblent être des produits mais sûrement avec des infos supplémentaires pour ne pas figurer dans produits. Julie nous en dira plus si besoin.

Justement c'est pour cette raison que je suis présentement à combiner mes liste. Je crée une liste avec tous les produits, après je ferai la séparation selon la catégorie. Et je vais mettre les infos complémentaire dans une autre table.

Je vais donc devoir remodifier mon code pour n'appeler qu'une table (produits) au lieu de 2 (produits et cameras), comme présentement.

niuxe a écrit :
Bah non, puisqu'une categorie est liée à une langue et un produit est lié à une catégorie. Là où tu pourrais dire quelque chose, alors il y aura 2 fiches pour chaque produits ? Oui, parce que nous avons deux langues cligne . En plus un nom de produit en Anglais n'aura peut être pas le même nom en Français. Pourtant ce sera le même produit. Je ne parle pas de la descrpition du produit puisque ce dernier sera dans la langue choisie.

Le nom du produit est le même en français et en anglais.
Les catégories sont les même aussi, c'est juste la langue qui change.

niuxe a écrit :
Là, je confirme toujours, je ne vois pas l'intéret du LEFT JOIN. La requête doit mettre plus de temps puisque les tables ne sont pas normalisées. cligne
Une jointure interne à la place?
J'ai essayé et ça ne fonctionne pas mieux...
Modifié par juliesunset (11 Jan 2013 - 15:22)
Bon là j'ai créée une nouvelle liste contenant tous les nom de produits, caméras comprises. J'ai modifié mon code en conséquence, mais ça ne fonctionne toujours pas comme il faut pour la partie anglais.

<select name="produit">
	<option value="">Choose product</option>
	<?php
	$recherche = 
		"SELECT 
			PROD.`produits`,
			PROD.`categorie`,
			C.`en`,
			C.`fr`
		FROM `categories` C
		LEFT JOIN `produits` PROD
			ON PROD.`categorie` = C.`fr`
		ORDER BY C.`en` NOT IN ('Cameras'), C.`en`";
	$requete = mysql_query($recherche);
	while($info = mysql_fetch_assoc($requete)) {
		$q = "SELECT produits FROM produits WHERE categorie='".$info['fr']."'";
		$q = mysql_query($q);
							
		echo '<optgroup label="'.$info['en'].'">';
		while($row = mysql_fetch_assoc($q)) {
			if(!in_array($row['produits'], $removeArr)){
				echo '<option value="'.$row['produits'].'" '.(isset($formulaire) && $formulaire->produit == $row['produits']?'selected="selected"':"").'>'.$row['produits'].'</option>';	
			}
		}
		echo '</optgroup>';
	}
	?>
</select>

Chaque catégorie se répète le nombre de fois qu'il y a de produits associé...
Modifié par juliesunset (11 Jan 2013 - 15:54)
Ta sous requête est vraiment inutile, tu as déjà l'information grâce à ta jointure. Il suffit juste de bien regrouper les résultats pour que l'algorithme d'affichage soit simple à gérer, par exemple en triant par catégorie.

select
  produits.id as PID,
  produit,
  categories.id as CID,
  fr,
  en
from produits
left join categories
  on categories.id = produits.categorie
order by
  en asc,
  produit asc

Quand tu parcours les résultats, tu n'as qu'à tester une variable $categorie que tu auras positionnée à false par exemple. Si $row['CID'] est différent de $categorie, tu ajoutes le <optgroup label="$row['en']"> et $categorie devient $row['CID'].

Bon allez, je l'écris :


echo '<select ...>';
$sql = 'la requête ci-dessus';
$r = mysql_query($sql);
$category = false;
while($row = mysql_fetch_assoc($r)) {
  if($category != $row['CID']) {
    if($category !== false) {
      echo '</optgroup>';
    }
    echo '<optgroup label="'.$row['en'].'">';
    $category = $row['CID'];
  }
  echo '<option value="'.$row['PID'].'">'.$row['en'].'</option>';
}
echo '</optgroup>';
echo '</select>';

Un truc dans le genre, je n'ai pas testé.
PARFAIT! ça fonctionne! autrement dit j'avais un while en trop, je m'en doutais, mais je ne voyais pas trop où.

Merci beaucoup pour votre aide!