IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Zend_Db PHP Discussion :

Zend_Db_Select et préparation de requête [ZF 1.7]


Sujet :

Zend_Db PHP

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut Zend_Db_Select et préparation de requête
    Bonjour,

    Je procède actuellement la création de la v2 de mon site, et vous avez deviné, je fais cette v2 avec Zend. J'ai cependant un problème pour traduire l'ancien traitement :

    Voici le schéma :

    Le but est de créer un tableau.
    Ce tableau contient une liste de titre d'articles (au sens texte, pas un produit à vendre).
    Les informations propre à l'article sont contenu dans une table ; les commentaires sont dans une autre table ; les votes sont dans une autre table.

    Code ; Récupération de la note : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT SUM(vo_not) AS note FROM table_de_votes WHERE id_referant = $le_dit_id

    Code ; Comptabilisation des commentaires : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT COUNT(*) AS page FROM table_des_commentaires WHERE id_referant = $le_dit_id

    Voici comment je procédais avant.
    Voici avec Zend, où j'en suis :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        $item = new Item();
        $select_item = $item->select();
        $select_item->from($item,array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'));
        $select_item->order('i_date DESC');
        $select_item->limit($config->liste->nbreElement);
     
        $vote = new Vote();
    /* Et la je ne sais plus... */
    Je voudrais utiliser les requêtes préparées pour pouvoir récupérer le nombre de commentaires et la note de chaque élément de la liste, tout en gardant la syntaxe type "->select", et donc pas de sql à proprement dit.

    Merci de m'éclairer.

  2. #2
    Membre expérimenté Avatar de Alshten
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 157
    Par défaut
    Je n'ai pas vraiment compris le problème en fait. Quand tu fais ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        $item = new Item();
        $select_item = $item->select();
        $select_item->from($item,array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'));
        $select_item->order('i_date DESC');
        $select_item->limit($config->liste->nbreElement);
    Tu récupère les informations de tous les articles mais ensuite tu veux récupérer les votes et commentaires de tous les articles ou d'un seul ?

    En tout cas ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT SUM(vo_not) AS note FROM table_de_votes WHERE id_referant = $le_dit_id
    Cela se traduirait en Zend par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $table_vote = new Vote();
    $query_vote = $table_vote->select()->from('table_de_votes',array('note' => 'SUM(vo_not)'))
                             ->where('id_referant  = ?', $le_dit_id);

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Bonjour,

    Merci de ta réponse sur la somme via SQL.

    Le but est bien sur de récupérer la note et le nombre de commentaire de CHAQUE article.

  4. #4
    Membre expérimenté Avatar de Alshten
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 157
    Par défaut
    D'accord mais quel est ton problème ? Est-ce que tu n'arrive pas à faire ta requête ou est-ce que tu ne sais pas comment la faire sous Zend ?

    Est-ce que tu as consulté cette documentation :
    http://framework.zend.com/manual/fr/zend.db.select.html

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Voici ce à quoi je suis arrivé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    <?php
    class ItemController extends Zend_Controller_Action 
    {
        public function indexAction() {
             /* Récuparation des informations principales */
            $item = new Item();
     
            echo $config->liste->nbreElement;
     
            $select = $item->select();
            $select->from($item,array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'))
            ->order('i_date DESC')
            ->limit($config->liste->nbreElement);
     
            $type = $this->_request->getQuery('type');
            if(!empty($type)){ 
            echo $type;
            $select->where('i_type= ?',$type);
            }
     
            $liste_item = $item->fetchAll($select)->toArray();
     
            /* Récupération des notes de chaque ligne de la liste */
            $vote = new Vote();
            $select_vote = $vote->select()
            ->from($vote,array('note' => 'SUM(v_note)'))
            ->where('v_ref  = :reference');
     
            $preparation = $db->prepare($select_vote);
     
     
            foreach($liste_item AS $value){
     
                $preparation->bindValue('reference',$value['i_id']);
            }
     
            $preparation->execute();
            $liste_note = $preparation->fetchAll($preparation)->toArray();
     
            /* Récupération des commentaires de chaque ligne de la liste */
            $commentaire = new Commentaire();
            $select_commentaire = $commentaire->select()
            ->from($commentaire,array('nbre_commentaire' => 'COUNT(*)'))
            ->where('com_ref  = :reference');
     
            $preparation = $db->prepare($select_commentaire);
     
            reset($liste_item);
            foreach($liste_item AS $value){
     
                $preparation->bindValue('reference',$value['i_id']);
            }
     
            $preparation->execute();
            $liste_commentaire = $preparation->fetchAll($preparation)->toArray();
     
            $i = 0;
            reset($liste_item);
            foreach($liste_item AS $value){
     
                $liste_finale[$i]['id'] = $value['i_id'];
                $liste_finale[$i]['type'] = $value['i_type'];
                $liste_finale[$i]['titre'] = $value['i_titre'];
                $liste_finale[$i]['date'] = $value['i_date'];
                $liste_finale[$i]['explication'] = $value['i_explication'];
                $liste_finale[$i]['coeur'] = $value['i_coeur'];
                $liste_finale[$i]['note'] = $liste_note['note'];
                $liste_finale[$i]['nbre_commentaire'] = $liste_commentaire['nbre_commentaire'];
     
                next($liste_note);
                next($liste_commentaire);
                $i++;
     
            }
     
            $this->view->type = $type;
            $this->view->item = $item->$liste_finale;
     
            }
     
    }
    Merci de ton aide et de tes recommandations.


    EDIT :

    J'ai enfin réaliser des tests, j'ai modifié le code ci-dessus car certains point ne fonctionnaient pas et je savais les résoudre, cependant, avec le code actuel (ci-dessus puisque je l'ai actualisé), je reçoit l'erreur suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Fatal error: Call to undefined method Vote::prepare() in /var/www/lepiredunet_v2/application/controllers/ItemController.php on line 29
    Je comprends bien le problème, en regardant les exemples sur les requêtes préparées, il faut faire la préparation sur l'objet "primaire" de base de donnée, le problème est que j'utilise ceci dans mon index.php ( dans /public donc ) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        $db = Zend_Db::factory($config->db);
        $db->getConnection()->exec("SET NAMES 'utf8'");
        Zend_Db_Table::setDefaultAdapter($db);
    J'évite ainsi l'ouverture manuelle d'un connexion à la base de donnée à chaque fonction de mes contrôleurs...

    Donc je vois pas trop comment procéder...

  6. #6
    Membre expérimenté Avatar de Alshten
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 157
    Par défaut
    A première vue ton code me parait très compliqué pour ce que tu veux faire. Si j'ai bien compris tu as une table qui contient les articles et deux autres contenant les votes et les commentaires avec pour chacun une clé étrangère vers la table qui contient les articles.
    La méthode la plus rapide pour obtenir le tout est de faire une jointure entre ces trois tables avec un Group By sur les articles.

    En Zend ça devrait ressembler à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $item = new Item();
    $select = $item->select()->setIntegrityCheck(false)
    	->from($item, array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'))
    	->join('vote', 'v_ref = i_id',array('note' => 'SUM(v_note)'))
    	->join('commentaire', 'com_ref = i_id',array('nbre_commentaire' => 'COUNT(*)'))
    	->group(array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'))
    	->order('i_date DESC');
    Là ça devrait déjà te retourner un tableau avec tous les articles et les infos que tu veux par article (par contre c'est à revoir pour le nom des tables vu que je ne les connais pas). Si tu as besoin d'infos sur ce bout de code hésite pas à demander.

    Puis pour tout récupérer de cette requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    $result = $item->fetchAll($select);
    foreach($result AS $row){          
    	$liste_finale[$i]['id'] = $row->i_id;
    	$liste_finale[$i]['type'] = $row->i_type;
    	$liste_finale[$i]['titre'] = $row->i_titre;
    	$liste_finale[$i]['date'] = $row->i_date;
    	$liste_finale[$i]['explication'] = $row->i_explication;
    	$liste_finale[$i]['coeur'] = $row->i_coeur;
    	$liste_finale[$i]['note'] = $row->note;
    	$liste_finale[$i]['nbre_commentaire'] = $row->nbre_commentaire;
    	$i++;
    }
    Ensuite pour récupérer l'adaptateur, tu peux faire simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $db = $item->getAdapter();
    Et là tu pourras utiliser prepare sur cet objet $db mais normalement avec mon bout de code tu n'auras plus besoin de prepare.

    Quand tu fais ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $type = $this->_request->getQuery('type');
    if(!empty($type)){ 
    	echo $type;
    	$select->where('i_type= ?',$type);
    }
    Je ne connaissais pas la méthode getQuery personnellement mais je te conseille de faire comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $type = $this->_request->getQuery('type');
    if($this->_request->hasParam('type')){ 
    	echo $type;
    	$select->where('i_type= ?',$this->_request->getParam('type'));
    }
    Bon voilà, si tu as des questions sur le code que j'ai mis n'hésite pas à demander.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Ah ouais une jointure pas bête du tout... Cependant je ne connais pas les group by, si tu pouvais m'en dire deux mots (je sais : google toussa, mais bon au moins tu pourras me donner ton avis sur la chose directement).

    Pour ton code de requête, on utilise directement le nom des tables, c'est un peu anti-(je sais pas quoi) non ? par exemple dans mon "->from()" je passe un objet, je peux faire pareil dans les jointures non ? Oui je sais ça fait deux instances de plus mais c'est plus flexible non ?

    A quoi sert setIntegrityCheck(false) ?

    Pour ce qui est de l'adapter, merci de l'info ; mais comme tu le souligne, je n'en ai plus besoin si j'utilise les jointures.

    Pour ->getQuery('plop'), ça revient à un $_GET['plop']. Le problème de getParam est qu'il choisi dans n'importe quelle superglobale, un peu comme si register_globals = on, donc je ne peux que décourager ceux qui utilisent getParam !

    Merci de ton aide, je test après ta réponse

  8. #8
    Membre expérimenté Avatar de Alshten
    Homme Profil pro
    Développeur Web
    Inscrit en
    Novembre 2005
    Messages
    157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 157
    Par défaut
    Citation Envoyé par Feng-Huang Voir le message
    Ah ouais une jointure pas bête du tout... Cependant je ne connais pas les group by, si tu pouvais m'en dire deux mots (je sais : google toussa, mais bon au moins tu pourras me donner ton avis sur la chose directement).
    J'ai pas grand chose à dire l'instruction group by est super utile dans des cas comme le tien justement. Cela permet de faire des opérations sur certains enregistrements uniquement et ressortir les données voulues très proprement sans avoir besoin d'utiliser pleins de boucles PHP. Au niveau utilisation c'est pas automatique au départ et pas forcément évident mais avec un peu d'expérience, on s'en sort.

    Citation Envoyé par Feng-Huang Voir le message
    Pour ton code de requête, on utilise directement le nom des tables, c'est un peu anti-(je sais pas quoi) non ? par exemple dans mon "->from()" je passe un objet, je peux faire pareil dans les jointures non ? Oui je sais ça fait deux instances de plus mais c'est plus flexible non ?
    Tout à fait, tu peux faire comme tu veux mais le problème c'est que si tu crée une instance pour chaque table, à la fin on se retrouve vite avec pleins de ligne du type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $table1 = new Table1();
    $table2 = new Table2();
    ...
    $table5 = new Table5();
    ...
    Où les instances ne sont utilisées que pour des jointures. Alors après moi je trouve ça moche et inutile de crée une instance à chaque fois mais comme tu dis c'est plus flexible, si tu change le nom de ta table par exemple mais ça arrive rarement non ?

    Citation Envoyé par Feng-Huang Voir le message
    A quoi sert setIntegrityCheck(false) ?
    Disons que normalement on peut faire des jointures mais sans sélectionner des colonnes des tables jointes (pour filtrer uniquement). Dès qu'on veut prendre des colonnes venant d'une autre table, on doit mettre ce paramètre à false mais personnellement j'ai jamais vraiment compris pourquoi Zend nous empêchait de faire cela.

    Citation Envoyé par Feng-Huang Voir le message
    Pour ->getQuery('plop'), ça revient à un $_GET['plop']. Le problème de getParam est qu'il choisi dans n'importe quelle superglobale, un peu comme si register_globals = on, donc je ne peux que décourager ceux qui utilisent getParam !
    Ah d'accord, mais si je ne me trompe pas Zend ne prend pas dans n'importe quelle superglobale mais uniquement dans $_GET et $_POST. Et en fait je ne vois pas en quoi c'est néfaste ?

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    215
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 215
    Par défaut
    Citation Envoyé par Doc, parlant de getParam
    En accédant à des données superglobales par Zend_Controller_Request_Http [moi : et donc via getParam]en tant que propriétés publiques de membre, il est nécessaire de maintenir dans l'esprit que le nom de propriété (clé du tableau des superglobales) est assorti à une superglobale dans un ordre spécifique de priorité : 1. GET, 2. POST, 3. COOKIE, 4. SERVER, 5. ENV.
    Certes en re-regardant, ce n'est pas tout à fait comme register_globals, mais je préfère rester rigoureux pour savoir quoi transite via quoi.

    Pour les instances de tables, j'me suis fais la même réflexion "en même temps, t'es pas prêt de changer le nom des tables ^^ ", donc effectivement c'est une instance pour rien ici.

    D'autre part, le code ne fonctionne pas. En faisant un echo de $select (qui permet d'afficher la requête SQL générée), j'ai vu clairement que le problème ne vient pas de $select en lui-même mais de la logique. En effet, avec une jointure de sélection + filtrage, si il n'y a pas de vote ou pas de commentaire, il ne sélectionne pas les lignes...

    EDIT :
    En relisant ce tuto, j'ai trouvé la solution qui consiste à faire une jointure externe : left join.
    Ceci fonctionne quand j'utilise la requête directement dans SQL, mais pas via le controller.

    EDIT2 : j'ai dis une connerie, ça marche avec le controller, j'avais oublié de dé-commenter mon code XD

    EDIT3 : Merci Alshten


    Question subsidiaire si quelqu'un de calé passe par là => pourquoi Zend ne veut pas récupérer les champs avec un join ?!

    EDIT4 (oui j'aime les edit) :

    Voici le code final, pour ceux qui ont du mal à suivre (ce que je peux comprendre :p) :
    A noter le COUNT(com_msg), sinon il renvoi toujours 1 puisqu'il se rapporte à la ligne de la table principale...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <?php
    class ItemController extends Zend_Controller_Action 
    {
        public function indexAction() {
     
           var_dump($config);
     
            $item = new Item();
            $select = $item->select()->setIntegrityCheck(false)
                    ->from($item, array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'))
                    ->joinLeft('lpdn_vote', 'v_ref = i_id',array('note' => 'SUM(v_note)'))
                    ->joinLeft('lpdn_commentaire', 'com_ref = i_id',array('nbre_commentaire' => 'COUNT(com_msg)'))
                    ->group(array('i_id','i_type','i_titre','i_date','i_explication','i_coeur'))
                    ->order('i_date DESC')
                    ->limit($config->liste->nbreElement);
     
     
            $raw_liste = $item->fetchAll($select);
     
            foreach($raw_liste AS $value){
     
            $liste_finale[$i]['id'] = $value->i_id;
            $liste_finale[$i]['type'] = $value->i_type;
            $liste_finale[$i]['titre'] = $value->i_titre;
            $liste_finale[$i]['date'] = $value->i_date;
            $liste_finale[$i]['explication'] = $value->i_explication;
            $liste_finale[$i]['coeur'] = $value->i_coeur;
            $liste_finale[$i]['note'] = $value->note;
            $liste_finale[$i]['nbre_commentaire'] = $value->nbre_commentaire;
            $i++;
     
            }
     
            $this->view->type = $type;
            $this->view->item = $liste_finale; 
     
            }
     
    }

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Requête pour préparation de commande fournisseur
    Par fraginfo dans le forum Requêtes
    Réponses: 1
    Dernier message: 30/04/2008, 22h32
  2. Pb préparation requête MySQL
    Par Sylvain James dans le forum XMLRAD
    Réponses: 7
    Dernier message: 17/11/2006, 12h03
  3. Utilisation de MAX dans une requête SQL
    Par Evil onE dans le forum Langage SQL
    Réponses: 7
    Dernier message: 15/06/2004, 18h38
  4. Requete requête sous sybase
    Par eddie dans le forum Sybase
    Réponses: 3
    Dernier message: 02/04/2003, 14h51
  5. [BDD] Enregistrer le résultat d'une requête
    Par Mowgly dans le forum C++Builder
    Réponses: 5
    Dernier message: 19/06/2002, 15h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo