Zend FR

Consultez la FAQ sur le ZF avant de poster une question

Vous n'êtes pas identifié.

#1 07-01-2008 10:16:41

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

[Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

je suis en train de travailler à la réalisation d'un contrôleur CRUD générique.
j'en attends beaucoup, notamment le fait qu'il soit utilisable en cascade pour traiter les cas où j'aurai à renseigner des tables reliées de façon "1-à-plusieurs" dans la base de données.

Cela suppose donc la gestion d'un mécanisme de type "fil d'Ariane" qui permettrait de tracer quels sont les enregistrements visités et à renseigner dans la base. Par exemple :

Dossier n°1234 - Fiche n°56 - Intervenant n°78

pourrait être un exemple de trace d'un tel fil  (les relations 1 vers N pointent bien sur de gauche à droite). Ce mécanisme s'implémente avec une pile bien entendu, et les traces de visite en cours sont stockées au moyen de la session.

Tout irait bien dans le meilleur des mondes si j'avais les droits sur toute la base ! pour être plus précis le niveau "Dossier" de mon schéma, n'est pas une table, mais une vue d'une base externe.

Et là patatras ! fini le contrôleur générique ! Car  au lieu de pouvoir s'appuyer sur de bien gentilles Zend_Db_Table qui vous procurent des Zend_Db_Table_Rowset remplies de Zend_Db_Table_Row avec qui on peut se promener, consulter, modifier et enregistrer à souhait, voilà qu'on se retrouve avec des résultats de requête (sur la vue) qui sont des Zend_Db_Pdo_Statement et tous les fetch() qu'on pourra n sortir.

Comment faire pour tendre vers quelque chose de générique ? tout passer par des stdClass ?

meilleurs voeux à tous et merci à qui aura une idée

Héfeust

Dernière modification par hefeust (21-01-2008 12:13:34)

Hors ligne

 

#2 07-01-2008 13:15:50

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

tu peux très bien faire cela sur une Zend_Db_table

la première chose à faire est de créer une classe dérivé de zend_Db_Table et d'ajouter les champs adéquat dans le constructeur

Code:

Class Model_Facture_Table extends Zend_Db_Table_Abstract {
   protected $_name = 'facture';
   protected $_rowClass = ' Model_Facture_Row';
   public function __construct($config = array())
   {
      parent::__construct($config);
    $this->_cols[] = 'fac_total';
   }
}

une fois cela fait il faut surcharger la methode _fetch

Code:

    /**
     * Support method for fetching rows.
     *
     * @param  string|array $where  OPTIONAL An SQL WHERE clause.
     * @param  string|array $order  OPTIONAL An SQL ORDER clause.
     * @param  int          $count  OPTIONAL An SQL LIMIT count.
     * @param  int          $offset OPTIONAL An SQL LIMIT offset.
     * @return array The row results, in FETCH_ASSOC mode.
     */
    protected function _fetch($where = null, $order = null, $count = null, $offset = null)
    {
        // selection tool
        $select = $this->_db->select();

        // the FROM clause
        $select->from($this->_name, $this->_cols, $this->_schema);

        // the WHERE clause
        $where = (array) $where;
        foreach ($where as $key => $val) {
            // is $key an int?
            if (is_int($key)) {
                // $val is the full condition
                $select->where($val);
            } else {
                // $key is the condition with placeholder,
                // and $val is quoted into the condition
                $select->where($key, $val);
            }
        }

        // the ORDER clause
        if (!is_array($order)) {
            $order = array($order);
        }
        foreach ($order as $val) {
            $select->order($val);
        }

        // the LIMIT clause
        $select->limit($count, $offset);
        // return the results
        $stmt = $this->_db->query($select);
        $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
        return $data;
    }

et mettre le necessaire pour la ou les jointure

Code:

$select->from($this->_name, $this->_cols, $this->_schema)
->join('lignes',’ligne.fac_id = facture.fac_id’, array('fac_total' =>Zend_Db_Exp('SUM(lig_prix * lig_qte)')))
->group('fac_id');

une fois cela fait tu remonte avec les méthode standard de Zend_Db_Table des Row de ta jointure.
reste l'enregistrement.

il te faut aussi surcharger les méthode delete update et insert pour tenir compte des champs que tu as ajouté à ta classe table et qui ne sont pas dans la table. (et eventuellement gérer une transaction pour enregistrer les éléments liées)

A+JYT

Hors ligne

 

#3 07-01-2008 14:14:44

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

et ca va traiter un Pdo_Statement comme un Rowset ?

pour mémoire je cherche à me rapprocher de ce qui se fait avec MS-Access programmé avec VB (j'ai commencé avec ça smile

--> si on requête avec un  SELECT on obtient un jeu d'enregistrements (Recorset) en lecture seule (normal) et si on requête sur une table, on obtient AUSSI un jeu d'enregistrements (Recorset) cette fois en lecture et écriture. D'ailleurs le mauvais positionnement des indicateurs de lecture/écriture pouvait provoquer des résultats inattendus de l'application, notamment en utilisant directement l'interface graphique.

Bon c'est du commentaire, merci de ta réponse rapide, je vais étudier ça cet aprem'  ;-)

Hors ligne

 

#4 07-01-2008 14:24:06

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

je ne dirais même plus :

le hic vient du fait que le fetchAll() d'un Zend_Db_Table est un Zend_Db_Table_Rowset tandis que le fetchAll() d'un Zend_Db_Pdo_Statement est un tableau de...  [ ce qu'on a défini comme type de retour pour cet objet (tableau de colonnes, objets stdClass, etc) ] donc ce n'est pas la même chose :-( !!!!!

Hors ligne

 

#5 07-01-2008 15:59:13

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

Mais c'est bien sûr !

en relisant le fond du code (tout au fond)  de la classe Zend_Db_Table_Abstract j'ai bien retrouvé cette méthode _fetch(), je vais voir ce que je peux en faire...

Hors ligne

 

#6 07-01-2008 17:08:45

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

non ca va pas traiter un Pdo_Statement comme un Rowset.

ça va utiliser des rowset et non plus des Pdo_Statement

si tu passe par une Zend_Db_Table tu as toute les fonctionnalités d'une Zend_Db_Table
il faut juste veillier à faire correctement les jointure sur le _fetch et redispatcher les données sur les insert update et delete

tu as donc un objet table comme si tu avait une table derrière et ça lit et enregistre dans plusieurs tables.

A+JYT

Hors ligne

 

#7 08-01-2008 14:15:18

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

super j'espère que ca marchera avec les vues cette idée de "Table qui peut en cacher une autre". je vais tester ca en vrai d'ici la fin de la semaine.
un grand merci à toi.

au fait  lecture en passant : (pour ceux qui ne connaissent pas, moi non plus avant de le lire!!!)

http://en.wikipedia.org/wiki/Object-rel … e_mismatch

ca parle de l'incompréhension fondamentale (ou divvergence de vues) qui peut exister entre la programmation objet (UML, etc) et le monde des bases de données relationnelles (Merise, etc)
très complet mais en anglais

bonne lecture !

Hors ligne

 

#8 18-01-2008 18:41:14

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

voilà les résultats de mes essais :

- on peut planquer une vue derrière une Zend_Db_Table, par contre il vaut mieux cacher les warnings du constructeur car il en envoie plein, notamment quand il essaie de trouver la clé primaire avec describeTable() notamment en utilisant Zend_Db_Adapter_Pdo_Mssql.php
donc :

@parent::__construct($config);

avec un arobase devant règle l'affaire.

par contre : je suis ok pour placer de la logique supplémentaire dans une méthode _fetch() surchargée. Par contre, comment éviter d'envoyer les champs ajoutés à $this->_cols[] dans la requête faite par le _fetch en standard ? je ne vais quand même pas y aller à coups de unset($this->_cols[''fac_total]) avant la requête pour ensuite remplir le tableau $data avec une boucle derrière ?

c'est à dire : insérer ma logique quelque part entre les lignes terminant le _fetch

Code:

        // return the results
        $stmt = $this->_db->query($select);
        $data = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
/////
  // on fait une requete qui fabrique du contenu pour $data
 foreach($data as $index => $ligne) {
  $data[$index] = array_merge($ligne, $champ_calcules[$index])
 }
/////

        return $data;

ou alors il y a une astuce que je n'ai pas vu ! la je seche !
bon week end

Hors ligne

 

#9 19-01-2008 11:22:31

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

Oui il faut effectivement nettoyer le tableau des cols et le restituer après

le mieux est de garder dans la tables un tableau des cols d'origine et celui qu'on a enrichie
ainsi dans le insert et le update
on peut subsitiuer les tableau de cols en fonction du besoin.
pour le constructeur si on mappe une Zend_Db8table sur une vue il suffit de surcharger le constructeur pour qu'il n'appelle plus le describeTable en le remplaçant par sont équivalent sur la vue


Je suis en train de réfléchir pour faire une classe abstraite qui permette de mapper un classe table sur une table qui joint automatiquement ses tables de référence.

je pense qu'on doit pouvoir faire le même genre de chose avec une table mappé sur une vue.
A+JYT

Hors ligne

 

#10 21-01-2008 12:09:22

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

ca marche mieux comme ca, merci ;-)

j'ajouterai que je vais sûrement être obligé de redéfinir fetchAll() afin qu'elle évite de me générer TOUS les champs calculés (= extraits par jointures) quand je demande TOUS les enregistrements, car sinon il y aura trop de consommation CPU.

OU alors je vais devoir jouer correctement avec les COUNT et OFFSET qu'on peut intercaler dans cette méthode

Hors ligne

 

#11 31-01-2008 17:48:38

hefeust
Membre
Date d'inscription: 14-12-2007
Messages: 26

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

ca s'arrange en effet...
et ca marche !

donc :  une classe de modele qui hérite de Zend_Db_Table_Abstract avec dedans
- des méthodes (mon_fetchRow, mon_fetchAll, mon_find et protected:_mon_fetch) avec un paramètre booleen en plus pour dire si on doit calculer les champs 'rapportés'
- une méthode protégée _ajouterChampEtendu($nom, $type, $ressource, $params) qui permet, au niveau du init post construction d'ajouter dans les Row ou Rowset générés soit : 1/ une valeur constante, 2/ le résultat de l'appel d'une fonction interne à la classe (qui peut éventuellement faire une requête), 3/ un Rowset retourné à partir d'un appel magique find ou findParent...
- enfin deux méthodes lister(array $criteres) qui renvoie une liste d'enregistrements SANS champs calculés (sinon c'est gourmand :-) et une autre, détailler($primary_key_value) qui renvoie un enregistrement sur la base de mon_find($primary_key_value) avec les champs calculés dedans

Les fonctions mon_fetch...() ne font que reprendre le code des fonctions de Zend, laissées inchangées et qui sont donc toujours utilisables.

Ca permet, si on a une liste d'Albums de musique, d'avoir juste la liste, et si on affiche le détail d'un Album, d'avoir la liste de ses titres : ce n'est donc plus du Lazy Loading, ce n'est pas du Full Loading, c'est du "[suffisant] Loading"
;-)

Hors ligne

 

#12 01-02-2008 13:26:15

sekaijin
Membre
Date d'inscription: 17-08-2007
Messages: 1137

Re: [Ca s'arrange!] Db_Pdo_Statement != Rowset en lecture seule...

salut je viens de publier un article sur ce sujet illustrant ce que j'ai posté le 07-01-2008
http://sekaijin.ovh.org/?p=18

A+JYT

Hors ligne

 

Pied de page des forums

Propulsé par PunBB
© Copyright 2002–2005 Rickard Andersson
Traduction par punbb.fr

Graphisme réalisé par l'agence Rodolphe Eveilleau
Développement par Kitpages