Génération de tableaux à 2 dimensions

Enfin je crois que ca se nomme ainsi. Voilà je voudrais contruire un tableau HTML qui affiche un récapitulatif de disponibilités pour des raids sur wow.

Le principe est simple : j’ai plusieurs types de dispos (variable et paramétrable dans ma base de données), et j’ai plusieurs classes de joueurs (variable également, suivant le bon vouloir de blizzard).

Voilà ce que je voudrais afficher :

	 /	dispo 1	/	dispo 2	/	dispo n	/
classe 1 /	1	/	4	/	5	/
classe 2 /	3	/	0	/	0	/
classe 3 /	2	/	0	/	1	/
classe 4 /	0	/	0	/	2	/

J’ai une table toute bête pour stocker les types de dispos, et j’en ai une autre tout aussi simple pour stocker les classes de personnages (le nom de la classe y est dispo).

Naturellement j’ai la dispo de chacun pour le raid consulté : id joueur + id type dispo.

Naturellement la table joueur contient l’id de sa classe.

Alors je crois comprendre qu’il faut faire un array, et stocker un couple XY ou X est la classe, Y le type de dispo, et pour ce couple j’ai le compte de dispos.

Dans le principe je comprends.

C’est au niveau du PHP que j’ai des soucis et que j’aurais besoin d’aide ^^

Merci par avance pour vos lumières !
Edité le 17/01/2008 à 11:23

Si je pige bien ton souci, tu ne peux pas faire une requête simple qui grouperait tes disponibilités par classe, ie: obtenir ton tableau directement en SQL?

Dans ce cas, la solution est d’utiliser les tableaux associatifs selon une clef tel que :

$table[$classeId][$dispoId] = $valeur;

Ainsi que de remplir le tableau des colonnes : $dispo[] = $dispoId; puisque des dispo peuvent ne pas être présente pour un couple classe/dispo.

Ensuite, l’algo est con:

foreach ($table as $classe => $dispoList) {
  echo $classe;
  foreach ($dispo as $id) {
     echo "\t", isset($dispoList[$id]) ? $dispoList[$id]:0;
  } 
  echo "\n";
}

A toi de gérer au niveau SQL les bonnes requêtes :slight_smile:

donne la structure de tes tables MySQL ca sera vachement plus simple parce que surrement faisable directement en MySQL :slight_smile:

sans-nom & dalai => je serais ravis de faire une requête simple :smiley:

Avec ton système sans nom, ca affiche rien si d’aventure une classe n’a pas renseigné de dispo… faudrait que ca affiche FORCEMENT les classes et les types de dispo en intégralité. Requête séparée pour les choper ?

tables :

woe_classe :
idc // id unique
cname // nom de la classe du perso

woe_dispo :

idd // id unique
idj // id joueur
ide // id event (la sortie concernée quoi)
idtd / id type de dispo

woe_joueur :
idj // id unique
idc // id classe du joueur

woe_typedispo
idtd // id unique
tdname // nom du type de dispo

SELECT idc, ide, COUNT(*) FROM woe_dispo RIGHT JOIN woe_joueur ON woe_joueur.idj = woe_dispo.idj GROUP BY idc, ide

ca te sort quoi ?
Edité le 17/01/2008 à 13:10

Ensuite, si tu veux tu as les sous requêtes? :slight_smile:

Si tu peux faire un mini dump SQL (au moins la structure de la table, et quelques données tests), je pourrais peut-être voir ça du taff… (oui je travaille … )

idc / ide / count

Ca semble fonctionner. Par contre je crois pas avoir besoin de chercher IDE, ca sera plutôt WHERE ide = numéro du raid pour lequel je veux les dispos.

ben rajoute WHERE woe_dispo.ide = xxxxx avant le group by :slight_smile:

-- phpMyAdmin SQL Dump
-- version 2.10.1
-- [www.phpmyadmin.net...](http://www.phpmyadmin.net)
-- 
-- Serveur: localhost
-- Généré le : Jeu 17 Janvier 2008 à 13:54
-- Version du serveur: 5.0.41
-- Version de PHP: 5.2.3

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

-- 
-- Base de données: `woe2`
-- 

-- --------------------------------------------------------

-- 
-- Structure de la table `woe_classe`
-- 

CREATE TABLE `woe_classe` (
  `idc` tinyint(2) NOT NULL auto_increment,
  `cname` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`idc`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

-- 
-- Contenu de la table `woe_classe`
-- 

INSERT INTO `woe_classe` (`idc`, `cname`) VALUES 
(1, 'Chaman'),
(2, 'Chasseur'),
(3, 'Démoniste'),
(4, 'Druide'),
(5, 'Guerrier'),
(6, 'Mage'),
(7, 'Paladin'),
(8, 'Prêtre'),
(9, 'Voleur');

-- --------------------------------------------------------

-- 
-- Structure de la table `woe_dispo`
-- 

CREATE TABLE `woe_dispo` (
  `idd` int(10) NOT NULL auto_increment,
  `idj` int(10) NOT NULL default '0',
  `ide` int(10) NOT NULL default '0',
  `idtd` int(10) NOT NULL default '0',
  `datefirst` int(11) NOT NULL default '0',
  `datelast` int(11) NOT NULL default '0',
  `wasthere` tinyint(1) NOT NULL default '0',
  `active` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`idd`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9 ;

-- 
-- Contenu de la table `woe_dispo`
-- 

INSERT INTO `woe_dispo` (`idd`, `idj`, `ide`, `idtd`, `datefirst`, `datelast`, `wasthere`, `active`) VALUES 
(1, 1, 4, 6, 0, 1200495755, 0, 1),
(2, 6, 5, 2, 1200497640, 1200497662, 0, 0),
(3, 6, 3, 1, 1200497729, 0, 0, 0),
(4, 6, 2, 2, 1200497730, 0, 0, 0),
(5, 6, 1, 2, 1200497731, 0, 0, 0),
(6, 7, 5, 1, 1200498735, 0, 0, 0),
(7, 7, 3, 1, 1200498737, 0, 0, 0),
(8, 7, 1, 2, 1200501569, 1200501580, 0, 0);

-- --------------------------------------------------------

-- 
-- Structure de la table `woe_event`
-- 

CREATE TABLE `woe_event` (
  `ide` int(10) NOT NULL auto_increment,
  `idte` int(10) NOT NULL default '0',
  `idg` int(10) NOT NULL default '0',
  `date` int(11) NOT NULL default '0',
  `note` varchar(200) NOT NULL default '',
  `active` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`ide`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

-- 
-- Contenu de la table `woe_event`
-- 

INSERT INTO `woe_event` (`ide`, `idte`, `idg`, `date`, `note`, `active`) VALUES 
(1, 4, 2, 1181673900, 'Instance test', 1),
(2, 4, 2, 1181846700, '', 1),
(3, 4, 2, 1181930400, '', 1),
(4, 3, 1, 1200511800, '', 1),
(5, 4, 2, 1210960800, '', 1);

-- --------------------------------------------------------

-- 
-- Structure de la table `woe_joueur`
-- 

CREATE TABLE `woe_joueur` (
  `idj` int(10) NOT NULL auto_increment,
  `jname` varchar(50) NOT NULL default '',
  `idg` int(10) NOT NULL default '0',
  `idc` tinyint(2) NOT NULL default '0',
  `password` varchar(32) NOT NULL default '',
  `email` varchar(100) NOT NULL default '',
  `template` varchar(100) NOT NULL default '',
  `rank` varchar(50) NOT NULL default '2',
  `active` tinyint(1) NOT NULL default '0',
  `various` varchar(10) NOT NULL default '',
  PRIMARY KEY  (`idj`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;

-- 
-- Contenu de la table `woe_joueur`
-- 

INSERT INTO `woe_joueur` (`idj`, `jname`, `idg`, `idc`, `password`, `email`, `template`, `rank`, `active`, `various`) VALUES 
(1, 'Startide', 1, 5, '098f6bcd4621d373cade4e832627b4f6', 'startide@free.fr', '', '1', 1, ''),
(3, 'Malkoh', 1, 9, '098f6bcd4621d373cade4e832627b4f6', 'test@free.fr', '', '2', 3, ''),
(4, 'Darklighter', 1, 1, '098f6bcd4621d373cade4e832627b4f6', 'darklighter@free.fr', '', '2', 3, ''),
(6, 'Lapinroz', 2, 9, '098f6bcd4621d373cade4e832627b4f6', 're@free.fr', '', '1', 1, ''),
(7, 'test', 2, 1, '098f6bcd4621d373cade4e832627b4f6', 'testa@free.fr', '', '2', 1, '');

-- --------------------------------------------------------

-- 
-- Structure de la table `woe_typedispo`
-- 

CREATE TABLE `woe_typedispo` (
  `idtd` int(10) NOT NULL auto_increment,
  `idg` int(10) NOT NULL default '0',
  `tdname` varchar(50) NOT NULL default '',
  `priority` tinyint(2) NOT NULL default '0',
  `active` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`idtd`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

-- 
-- Contenu de la table `woe_typedispo`
-- 

INSERT INTO `woe_typedispo` (`idtd`, `idg`, `tdname`, `priority`, `active`) VALUES 
(1, 2, 'Présent', 1, 1),
(2, 2, 'Retard', 2, 1),
(3, 2, 'Absent', 3, 1),
(4, 2, 'Se touche', 4, 1),
(5, 1, 'Disponible', 1, 1),
(6, 1, 'Absent', 2, 1);


[quote="Dalai-Lama"] ben rajoute WHERE woe_dispo.ide = xxxxx avant le group by :) [/quote] oui oui ! Ca j'avais déjà fait, mais c'était plus pour te répondre en fait ;)
Voilà ce que je veux faire : [http://img205.imageshack.us/img205/2818/sanstitreey4.th.png](http://img205.imageshack.us/my.php?image=sanstitreey4.png)

TROUVAY !

J’ai fait plus simple pour mon faible niveau :stuck_out_tongue:

Trois requêtes : une pour choper intitulés de classe et IDclasse, la même pour les types dispos et ID typedispo

Une dernière qui ressemble à ce qu’on a fait : idclasse, idtypedispo, somme des dispos pour ce type de dispo et cette classe.

Ensuite j’ai fait du foreach :smiley:

Un premier avec mon array de type de dispo, pour faire mes cellules bleues en haut,

ensuite un pour les classes… qui en contient un chargé de dérouler les types de dispos. Là dedans je match mon array de récap des dispos et pour chaque case je demande IDC / IDTD, et si c’est vide j’affiche 0.

Je sais pas si c’est clair ^^ je posterais le code après :wink:

EDIT : maintenant la question qui tue : comment faire des totaux par classe et par type de dispo :smiley:
Edité le 17/01/2008 à 16:52

ok pour faire le total d’une ligne (total de dispos pour une classe quoi) j’y arrive :

echo array_sum($recapdispos[$key]);

Enfin je fais plus compliqué pour gérer les array vides sur certains couples, mais sinon ca marche.

En revanche, pour les colonnes j’arrive pas :

echo array_sum($recapdispos[][$keytd);

Je sais pas comment faire pour lui dire que c’est le “sous” tableau que je veux additionner… j’ai tenté de laisser le premier[] vide, des trucs comme ca, mais en fait non ca marche pas :frowning:

1- tu récupères les noms de toutes les classes que tu mets dans un tableau $classe[] = nom de la classe
2- tu récupère les noms de touts les type dispos que tu mets dans un tableau $type_dispo[id de la dispo] = nom de la dispo

ensuite tu execute la requète suivante :
SELECT woe_classe.cname, idtd, COUNT( * ) as tot
FROM woe_dispo
RIGHT JOIN woe_joueur ON woe_joueur.idj = woe_dispo.idj
RIGHT JOIN woe_classe ON woe_classe.idc = woe_joueur.idc
WHERE woe_dispo.idj IS NOT NULL
AND woe_dispo.ide = xxxxx
GROUP BY woe_joueur.idc, idtd ORDER BY woe_classe.cname ASC, woe_dispo.idtd ASC

Ca va te retourner le nombre de joueur qui ont participer a l’event par classe / type de dyspo
tu mets ca dans un tableau $joueur_event[nom de la classe][idtd] = tot

ensuite ben tu génère ton tableau

d’abord en bouclant $type_dispo pour afficher les noms des types dispo en haut du tableau

Et ensuite pour afficher chaque ligne tu boucles sur la liste des classes, et tu te réfère au tableau $joueur_event pour afficher le nbr de joueur par type_dispo.

Après pour les sous totaux, suffit de stocker ca quand tu boucles

ok donc ton truc fonctionne, c’est de toute manière du même goût que ce que j’ai fait en définitive.

SELECT `woe_classe`.`idc`, `woe_dispo`.`idtd`, COUNT(woe_dispo.idd) as `count`
FROM `woe_dispo`
INNER JOIN `woe_joueur` ON `woe_dispo`.`idj` = `woe_joueur`.`idj`
INNER JOIN `woe_classe` ON `woe_joueur`.`idc` = `woe_classe`.`idc`
GROUP BY `woe_classe`.`idc`, `woe_dispo`.`tdtd`

PS : j’ai fait inner, mais c’est probablement pas bien ? Je comprends jamais rien au LEFT, right et inner en fait :smiley:

Pour les totaux je suis bon pour faire de nouveaux array en clair ? Pour une ligne j’arrive à le faire facilement, pour les colonnes en revanche ca marche pas.

A moins qu’il existe des fonctions qui permettent de splitter le tableaux pour pourvoir l’exploiter ?

Actuellement il est ainsi :

$recapdispos = array();
$recapdispos[$data[idc]][$data[idtd]] $data[compteur];

Je peux additionner les valeurs de compteur pour une même IDC, mais pas pour une même IDTD

Bon, vu que j’ai (beaucoup?) du temps libre, …

  1. Tu pourrais utiliser InnoDB, et faire des clefs étrangères, histoire d’assurer l’intégrité du bousin :slight_smile:
  2. Tu seras je pense de toute façon obligé de faire ça en 3 requêtes

a) avoir l’intégralité des classes
b) avoir l’intégralité des types de dispos
c) avoir le nombre de joueur regroupés par classes & dispo

Ceci étant dit, ça sert à rien que je t’aide vu que tu as trouvé tout seul.

Pour le total des disponibilités par classes, ou pour le total de joueurs par disponibilité, oui tu n’as d’autres choix que de faire ça en PHP. Bien que je soupçonne SQL de pouvoir le gérer (sous requêtes, etc).

Cadeau:

(
  SELECT
    J.idc  AS class_id,
    D.idtd AS dispo_id,
    COUNT(*) AS result
  FROM woe_dispo D
  INNER JOIN woe_joueur J ON D.idj = J.idj
--  INNER JOIN woe_classe C ON J.idc = C.idc
  GROUP BY J.idc, D.idtd
) UNION (
  SELECT
    J.idc  AS class_id,
    NULL   AS dispo_id,
    COUNT(*) AS result
  FROM woe_dispo D
  INNER JOIN woe_joueur J ON D.idj = J.idj
-- INNER JOIN woe_classe C ON J.idc = C.idc
  GROUP BY J.idc
) UNION (
  SELECT
    NULL  AS class_id,
    D.idtd AS dispo_id,
    COUNT(*) AS result
  FROM woe_dispo D
--  INNER JOIN woe_joueur J ON D.idj = J.idj
--  INNER JOIN woe_classe C ON J.idc = C.idc
  GROUP BY D.idtd
) ORDER BY IF(class_id IS NULL, 1, 0), class_id, IF(dispo_id IS NULL, 1, 0), dispo_id
  1. La relation joueur/classe est en 1-1, inutile de faire un JOIN

Bien sûr, c’est mieux en PHP pour la simple raison qu’il fait deux ou trois fois la même chose, alors qu’en PHP, pendant la récupération, tu pourras:

  1. pour chaque classe, mettre un tableau avec $classes[‘ALL’] = 0, puis l’incrémenter selon que.
  2. faire pareil pour les disponibilités.

Ha vouais les Foreign keys… quel est l’intérêt “pratique” exactement ? J’ai étudié ca en cours PK foreign key, ca me dit des trucs, mais je vois pas l’impact effectif dans phpmysql ^^

Ha je fais un rajout ^^ j’ai un truc zarb. J’appelle une page ainsi : page.php?id=2

je fais un test pour vérifier que ID est pas vide, bien définie et que c’est un entier… hors ca foire sur l’entier :frowning:

!is_int($_GET[‘id’]) // false

pourquoi ce comportement ?


ok trouvay en fait (demandé à un collègue) faut "caster" avec un (int) devant ma variable :D

Supprimer automatiquement les données? Et s’assurer que le comportement est valide… (ex: tu supprimes une disponibilité, mais tu gardes les relations? idem si tu fais pareil avec un joueur? ou encore, tu supprimes une classes, et le joueur se retrouve avec une classe non valide => essaye de changer la classe d’un joueur pour 999 ou une dispo dans ta table de relation, tu verra si c’est pas intéressant l’intégrité.

Mais surtout clef étrangère = intégrité référentielle = éviter des données invalides.

Sinon, essaye intval($_GET[‘id’]).

Donc en gros ca fait quoi si je supprimes une classe ? Ca supprimes tous les membres de cette classe ?

Ca dépend de ce que tu veux. Si tu veux que le joueur n’est plus de classe, c’est possible. Si tu veux que le joueur disparaisse, c’est aussi possible. Si tu veux que supprimer la classe soit interdit, c’est possible.

Autre exemple: tu change l’identifiant de la classe, bim: tu peux choisir de dire “non c’est pas possible”, “oui c’est possible, mais faudra remettre la référence”, ou carrément dire “je mets à jour la référence”.

Bien sûr, inutile de dire que sans un brin de conception, ça ne sert à rien :slight_smile:

Toi faudrait que tu viennes à la kimodo m’expliquer tout ca :smiley: