Page 1 sur 2

PDO : obtenir les noms des colonnes d'un jeux de résultat

Posté : 09 nov. 2011, 16:47
par moogli
salut,

la question parait conne mais la je sèche :/

J'utilise des requêtes à la volée, et je ne sais pas combien de champs je vais récupérer ni même comment ils s'appellent.
en gros
<?php
$requete = array( 'requete 1','requete2');//etc etc
$pdo = new pdo();
foreach ($requete as $r ) {
$result = $pdo->query($r);
echo '<table>';
                    echo '<thead><tr>';
                    for ($i=0;$i<$result->columnCount();$i++){
                        echo '<td>&nbsp;</td>';
                    }
                    echo '</tr></thead><tfoot><tr>';
                    for ($i=0;$i<$result->columnCount();$i++){
                        echo '<td>&nbsp;</td>';
                    }
                    echo '</tr></tfoot>';
                    while ($data = $result->fetch(PDO::FETCH_ASSOC)) {
                        echo '<tr>';
                        $i =0;
                        foreach ($data as $c) {
                            $i++;
                            echo '<td class="centertext';
                            if ($i == $result->columnCount()) echo ' last';
                            echo '">'.$c.'</td>'; 
                        }
                        echo '</tr>';
                    }
                    echo '</table>';
}
?>
ça marche au poil mais c'est moche, avec le nom des colonnes ça serait beaucoup plus sympa.

j'ai donc pensé à
$d = array_keys($result->fetch(PDO::FETCH_ASSOC));
for ($i=0;$i<$result->columnCount();$i++){
echo '<td class="centertext">'.$d[$i].'</td>' ;
}
mais en fait non, car même si pdostatement implémente l'interface traversable elle fait partie des exceptions qui n'ont pas besoin d'implementer itérator.
et la c'est le drame, pas de rewind() et je ne trouve pas de moyen de remettre le jeux de résultat à "zéro".

la question est donc : est ce qu'il y a moyen remettre le jeux de résultat au début à la manière d'un mysql_data_seek ou d'un rewind de l'interface iterator ?

oui je sais question à la con mais bon :mrgreen:

mici

@+

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 09 nov. 2011, 17:04
par stealth35
fait un do...while, sinon met le dans un IteratorIterator

EDIT :
$stmt = $pdo->query('SELECT * FROM test');
$stmt->setFetchMode(PDO::FETCH_ASSOC);

echo '<table>';

$row = $stmt->fetch();

echo '<tr><th>', implode('</th><th>',  array_keys($row)), '</th></tr>';

do {
    echo '<tr><td>', implode('</td><td>',  $row), '</td></tr>';
} while($row = $stmt->fetch());

echo '</table>';
OU
$stmt = $pdo->query('SELECT * FROM test');
$stmt->setFetchMode(PDO::FETCH_ASSOC);

echo '<table>';

$iterator = new IteratorIterator($stmt);
$iterator->rewind();

echo '<tr><th>', implode('</th><th>',  array_keys($iterator->current())), '</th></tr>';

foreach ($iterator as $row) {
    echo '<tr><td>', implode('</td><td>',  $row), '</td></tr>';
}

echo '</table>';

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 09 nov. 2011, 17:26
par xTG
Il y a getColumnMeta() sinon, mais à prendre avec des pincettes car c'est un joujou expérimental. :)

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 09 nov. 2011, 21:15
par moogli
Effectivement stealth35 j'ai finis sur un do while, mais je cherchais un truc plus simple en fait.
J'avoue que je ne connais pas trop les iterateurs et que cette solution est pas mal si je veux garder mon where :)

Merci pour les infos

xTG : j'ai testé mais existe pas pour oracle :D

Globalement j'ai l'impression que php à plus de facilité avec les trucs "libre" que les grosses machine de "l'industrie" ^^


@+

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 09 nov. 2011, 22:07
par xTG
Globalement j'ai l'impression que php à plus de facilité avec les trucs "libre" que les grosses machine de "l'industrie" ^^
C'est pas plus étonnant que cela. ^^

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 09 nov. 2011, 22:29
par moogli
C'est pas faux.

C'est juste que la pour le coup j'ai pas le choix du sgbd :)

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 11 nov. 2011, 13:30
par Cyrano
En gros, tu voudrais faire un tableau HTML dynamique à la manière de PHPMyAdmin, avec en en-tête les noms des colonnes, quelque soit le nombre de ces colonnes et même si la requête est du type « SELECT * FROM ... » ?

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 11 nov. 2011, 17:31
par moogli
Vi c'est peux ça. Sauf que la j'ai exo sur les DML avec 20 questions et vu que j'avais du temps à perdre j'ai fait une belle page qui affiche les résultats.

Vu que je suis assez feignant j'ai mis questions / réponses dans des tableaux et j'affiche la chose à la volée. (pas besoin d'afficher 25 fois le même tableau de prévoir entêté / pieds de page etc).
Et Vu qu'avec l'extension mysql j'utilisais la remise à zéro je voulais faire pareil avec pdo :)

C'est stupid de la par de ne pas avoir pensé au do while et j'ai vu un cas d'utilisation des itérateurs ce qui est pas mal (même si je suis pas sur de me le rappeler ;) )

@+

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 11 nov. 2011, 19:05
par Cyrano
Ok, je voulais être sûr.

En fait, je m'étais fait un truc à des fins de débogage précisément pour ça. Je n'utilise pas de do/while du tout, je me suis construit la petite classe suivante :
<?php
/**
 * Construction d'un tableau HTML dynamique pour un jeu de
 * résultats issus d'une requête SQL, quel que soit le nombre de colonnes et/ou de
 * lignes retournées.
 *
 * Le tableau comportera en en-tête le nom des colonnes, même si la requête est
 * du type « SELECT * FROM ... » et en pied de tableau le nombre total de lignes
 * affichées.
 *
 * Utilisation :
 * Il faut dans un premier temps récupérer le jeu de résultats dans un tableau (voir les
 * commentaires du constructeur.)
 * L'exemple suivant est simplifié et part de l'utilisation d'une classe qui va exécuter la
 * requête SQL et retourner un tableau indexé :
 * <code>
 * $oDb = new mydb();
 * $sql = "SELECT * FROM matable WHERE condition = 1";
 * $oDb->execute($sql);
 * $aDatas = $oDb->fetchAssoc();
 *
 * </code>
 * On crée ensuite une instance en lui passant ce tableau en paramètre.
 * <code>
 * $oTable = new db_html_table($aDateFct);
 * </code>
 * Si l'instance existait déjà, on met à jour les informations avec le nouveau je de résultats à
 * afficher avec la méthode setNewTable().
 * <code>
 * $oTable->setNewTable($aDatas);
 * </code>
 * Enfin, on récupère le tableau HTML avec la méthode getTableau.
 * <code>
 * echo($oTable->getTableau());
 * </code>
 */
class db_html_table
{
    /**
     * Tableau de données à 3 dimensions de résultat de requête SQL.
     *
     * @var Array
     */
    private $_aInfos = array();
    /**
     * Table HTML d'affichage du contenu du tableau.
     *
     * @var String
     */
    private $_sTableau = '';

    /**
     * Définition de l'instance.
     *
     * Le tableau de données attendues sera de la forme suivante :
     * tableau => array(
     *   0 => array(
     *     'nom_colonne_1'   => 'valeur_1',
     *     'nom_colonne_2'   => 'valeur_2',
     *     'nom_colonne_...' => 'valeur_...',
     *     'nom_colonne_n'   => 'valeur_n',
     *   ),
     *   1 => array(
     *     'nom_colonne_1'   => 'valeur_1',
     *     'nom_colonne_2'   => 'valeur_2',
     *     'nom_colonne_...' => 'valeur_...',
     *     'nom_colonne_n'   => 'valeur_n',
     *   ),
     *   etc...
     * )
     *
     * @param Array $aInfos
     */
    public function __construct($aInfos = null)
    {
        $this->_aInfos = (!is_null($aInfos)) ? $aInfos : array();
    }

    /**
     * Remplacement des données par un nouveau tableau à 3 dimensions.
     *
     * Permet l'utilisation de l'instance en cours pour un autre jeu de résultat à afficher
     *
     * @param Array $aInfos
     */
    public function setNewTable($aInfos)
    {
        $this->_aInfos = $aInfos;
        $this->_sTableau = '';
    }

    /**
     * Construction dynamique d'une table HTML pour afficher
     * le contenu du tableau.
     *
     * @param  Array    $aInfos Optionnel, si absent, le jeu de résultat passé au constructeur sera utilisé.
     * @param  String   $sTable Optionnel, nom de la table ou de la vue qui servira de titre du tableau.
     * @return String
     */
    public function getTableau($aInfos = null, $sTable = null)
    {
        if(is_null($aInfos))
        {
            $aInfos = $this->_aInfos;
        }
        $nl = count($aInfos);
        $label = (isset($sTable)) ? 'Contenu de la table '. $sTable .' : ' : null;
        if($nl == 0):
            /* Tableau de données vide, donc on affiche simplement un message */
            $this->_sTableau = <<<CODE
    <p class="erreur">{$label}Pas de données disponibles pour ces critères.</p>
    <hr />

CODE;
        else:
            /* Il y a des données, on va identifier les noms des colonnes et leur nombre */
            $l1 = $aInfos[0];
            $aIndexes = array();
            /* On construit le header avec les noms des colonnes et le footer avec le nombre total de lignes */
            $this->_sTableau  = <<<CODE
    <table summary="{$label}">
      <caption>{$label}</caption>
      <thead>
        <tr>

CODE;
            foreach ($l1 as $index => $val):
                $aIndexes[] = $index;
                $this->_sTableau .= <<<CODE
          <th>{$index}</th>

CODE;
            endforeach;
            $nc = count($aIndexes);
            $s = ($nl > 1) ? 's' : null;
            $this->_sTableau .= <<<CODE
        </tr>
      </thead>
      <tfoot>
        <tr>
          <td colspan="{$nc}">{$nl} ligne{$s}</td>
        </tr>
      </tfoot>
      <tbody>

CODE;
            /* On construit maintenant les lignes de données */
            foreach($aInfos as $i => $ligne):
                $this->_sTableau .= <<<CODE
        <tr>

CODE;
                foreach ($aIndexes as $idcol):
                    $align = (is_numeric($ligne[$idcol])) ? ' style="text-align: right;"' : null;
                    $this->_sTableau .= <<<CODE
          <td{$align}>{$ligne[$idcol]}</td>

CODE;
                endforeach;
                $this->_sTableau .= <<<CODE
        </tr>

CODE;
            endforeach;
            $this->_sTableau .= <<<CODE
      </tbody>

CODE;
                $this->_sTableau .= <<<CODE
    </table>
    <hr />

CODE;
        endif;
        return($this->_sTableau);
    }
}
Ensuite, ben c'est pas très dur à utiliser, dans ton cas, si je reprends un tout petit bout de ton premier code, ça devrait ressembler à quelque chose dans ce style là :
<?php
$stmt = $pdo->query('SELECT * FROM test');
$stmt->setFetchMode(PDO::FETCH_ASSOC);
/* Ici est le bout important : on alimente le tableau des données à afficher */
$aDatas = array();
while(false != ($row = $stmt->fetch()))
{
    $aDatas[] = $row;
}
/* Inclusion de la classe et création de l'instance : */
include_once($classetableau);
$oTable = new db_html_table();
/* Affichage : */
echo($oTable->getTableau($aDatas, 'Test'));
C'est tout, je te laisse observer ce que ça donne, que ton tableau ait 1 ou 25 colonnes, et de 1 à 5 000 000 de lignes, ça fera l'affaire et s'il n'y a pas de résultat du tout, ben ce sera traité aussi.

J'ai largement commenté le code de la classe, je te laisse l'adapter si nécessaire ;)

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 11 nov. 2011, 20:25
par stealth35
$aDatas = array();
while(false != ($row = $stmt->fetch()))
{
    $aDatas[] = $row;
}
fecthAll ?

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 11 nov. 2011, 20:30
par Cyrano
$aDatas = array();
while(false != ($row = $stmt->fetch()))
{
    $aDatas[] = $row;
}
fecthAll ?
J'ai pas vérifié dans le détail mais c'est possible, l'idée générale, c'est qu'on va passer le tableau de données à la classe et la classe va construire le tableau HTML.

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 12 nov. 2011, 14:02
par Cyrano
@moogli, ce truc ne t'inspire pas ? :-k

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 13 nov. 2011, 01:23
par moogli
pour être j'ai pas testé, je passe beaucoup (trop) de temps dans les transports la semaine alors le week end c'est limité :)


mais sur le principe c'est exactement ce que je voulais, j'ai fait ça en moins bien et moins réutilisable :)

je regarderais lundi je pense que je vais avoir un peu de temps.

en tout cas merci pour l'info (et le taf qui va avec)

@+

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 13 nov. 2011, 02:41
par Cyrano
Note bien que ça me rassure quand même un peu, au moins tu as vu la réponse ;)

Re: PDO : obtenir les noms des colonnes d'un jeux de résulta

Posté : 15 nov. 2011, 15:09
par moogli
Note bien que ça me rassure quand même un peu, au moins tu as vu la réponse ;)
Au final c'est sur que c'est plus clair que ma sauce :)

J'ai juste modifié un peu l'affichage car ça me gène d'avoir un <caption></caption> quand je ne passe pas de second paramètre à "getTableau" (idem pour le "summary")
public function getTableau($aInfos = null, $sTable = null) {
        if (is_null($aInfos)) {
            $aInfos = $this->_aInfos;
        }
        $nl = count($aInfos);
        $label = (isset($sTable)) ? 'Contenu de la table ' . $sTable . ' :' : null;
        if ($nl == 0):
            /* Tableau de données vide, donc on affiche simplement un message */
            $this->_sTableau = <<<CODE
 <p class="erreur">{$label}Pas de données disponibles pour ces critères.</p>
 <hr />

CODE;
        else:
            // la ^^
           if ( !is_null($label)){
                $label = '<caption>'.$label.'</caption>';
                $summary = 'summary="'.$label.'"';
            }
            /* Il y a des données, on va identifier les noms des colonnes et leur nombre */
            $l1 = $aInfos[0];
            $aIndexes = array();
            /* On construit le header avec les noms des colonnes et le footer avec le nombre total de lignes */
            $this->_sTableau = <<<CODE
 <table {$summary}>
   {$label}
   <thead>
     <tr>

CODE;
            foreach ($l1 as $index => $val):
                $aIndexes[] = $index;
                $this->_sTableau .= <<<CODE
       <th>{$index}</th>

CODE;
            endforeach;
            $nc = count($aIndexes);
            $s = ($nl > 1) ? 's' : null;
            $this->_sTableau .= <<<CODE
     </tr>
   </thead>
   <tfoot>
     <tr>
       <td colspan="{$nc}">{$nl} ligne{$s}</td>
     </tr>
   </tfoot>
   <tbody>

CODE;
            /* On construit maintenant les lignes de données */
            foreach ($aInfos as $i => $ligne):
                $this->_sTableau .= <<<CODE
     <tr>

CODE;
                foreach ($aIndexes as $idcol):
                    $align = (is_numeric($ligne[$idcol])) ? ' style="text-align: right;"' : null;
                    $this->_sTableau .= <<<CODE
       <td{$align}>{$ligne[$idcol]}</td>

CODE;
                endforeach;
                $this->_sTableau .= <<<CODE
     </tr>

CODE;
            endforeach;
            $this->_sTableau .= <<<CODE
   </tbody>

CODE;
            $this->_sTableau .= <<<CODE
 </table>
 <hr />

CODE;
        endif;
        return($this->_sTableau);
    }
Par contre je ne comprend pas l'utilité de setNewTable vu que l'on peux renouveler les données avec getTableau, le plus simple pourrait être de supprimer le passage de paramètre a getTableau pour "séparer" les deux, sinon supprimer setNewTable ^^

après c'est du cosmétique, une amélioration serais de proposer d'indiquer les classes css des éléments si besoin (par exemple j'affiche les chiffres centré mais pas le texte etc etc) mais bon après c'est poussé le vice un peux loin mais pour une classe de rendu c'est sympa :)

@+