Bonjour,

J'ai suivi le tutoriel créer un site de A à Z. J'aimerais aujourd'hui améliorer ma méthode find() ou améliorer l'appel de cette méthode dans un controller pour pouvoir sélectionner chaque ligne d'une table ayant une valeur maximale dans une colonne pour chaque catégorie (l'id de la catégorie étant également renseigné dans une colonne de cette table).

Pour résumer j'ai une table regroupant 300 images dont une colonne stocke l'id des catégories d'images, et une autre le nombre de téléchargements.
J'essaie d'afficher une page regroupant les images les plus téléchargées de chaque catégorie d'images.

J'ai essayé plusieurs techniques sans succès... Je n'arrive à sélectionner ces lignes qu'avec des requêtes SQL classiques et imbriquées du type :

SELECT * FROM images WHERE telechargement = (SELECT MAX(telechargement) FROM images AS i WHERE i.categorie = images.categorie);

Merci pour votre aide.

Méthode de base d'un controller permettant d'afficher tous les entrées de la table :

function index(){
        $perPage = 10; 
        $this->loadModel('Post');
        $condition = array('online' => 1,'type'=>'post'); 
        $d'posts'] = $this->Post->find(array(
            'conditions' => $condition,
            'fields' => 'Post.id,Post.name,Post.slug,Post.created,Category.name as catname,Post.content,Category.slug as catslug',
            'order' => 'created DESC',
            'limit' => ($perPage*($this->request->page-1)).','.$perPage,
            'join' => array('categories as Category'=>'Category.id=Post.category_id')
        ));
        $d'total'] = $this->Post->findCount($condition); 
        $d'page'] = ceil($d'total'] / $perPage);
        $this->set($d);
    }

La méthode find() :

/**
    * Permet de récupérer plusieurs enregistrements
    * @param $req Tableau contenant les éléments de la requête
    **/
    public function find($req = array()){
        $sql = 'SELECT ';

        if(isset($req'fields'])){
            if(is_array($req'fields'])){
                $sql .= implode(', ',$$req'fields']);
            }else{
                $sql .= $req'fields']; 
            }
        }else{
            $sql.='*';
        }

        $sql .= ' FROM '.$this->table.' as '.get_class($this).' ';

        // Liaison
        if(isset($req'join'])){
            foreach($req'join'] as $k=>$v){
                $sql .= 'LEFT JOIN '.$k.' ON '.$v.' '; 
            }
        }

        // Construction de la condition
        if(isset($req'conditions'])){
            $sql .= 'WHERE ';
            if(!is_array($req'conditions'])){
                $sql .= $req'conditions']; 
            }else{
                $cond = array(); 
                foreach($req'conditions'] as $k=>$v){
                    if(!is_numeric($v)){
                        $v = '"'.mysql_escape_string($v).'"'; 
                    }

                    $cond] = "$k=$v";
                }
                $sql .= implode(' AND ',$cond);
            }

        }

        if(isset($req'order'])){
            $sql .= ' ORDER BY '.$req'order'];
        }

        if(isset($req'limit'])){
            $sql .= ' LIMIT '.$req'limit'];
        }

        $pre = $this->db->prepare($sql); 
        $pre->execute(); 
        return $pre->fetchAll(PDO::FETCH_OBJ);
    }

    /**
    * Alias permettant de retrouver le premier enregistrement
    **/
    public function findFirst($req){
        return current($this->find($req)); 
    }

2 réponses


Bonjour,

une idée comme ça, mes souvenirs sql datent...

Si cette requete fonctionne:

select image categorie ,max(telechargement)
from images
group by categorie

public function find($req = array()){
        $sql = 'SELECT ';

        if(isset($req'fields'])){
            if(is_array($req'fields'])){
                $sql .= implode(', ',$$req'fields']);
            }else{
                $sql .= $req'fields']; 
            }
        }else{
            $sql.='*';
        }

        $sql .= ' FROM '.$this->table.' as '.get_class($this).' ';

        // Liaison
        if(isset($req'join'])){
            foreach($req'join'] as $k=>$v){
                $sql .= 'LEFT JOIN '.$k.' ON '.$v.' '; 
            }
        }

        // Construction de la condition
        if(isset($req'conditions'])){
            $sql .= 'WHERE ';
            if(!is_array($req'conditions'])){
                $sql .= $req'conditions']; 
            }else{
                $cond = array(); 
                foreach($req'conditions'] as $k=>$v){
                    if(!is_numeric($v)){
                        $v = '"'.mysql_escape_string($v).'"'; 
                    }

                    $cond] = "$k=$v";
                }
                $sql .= implode(' AND ',$cond);
            }

        }

        if(isset($req'order'])){
            $sql .= ' ORDER BY '.$req'order'];
        }

        if(isset($req'limit'])){
            $sql .= ' LIMIT '.$req'limit'];
        }

        if(isset($req'group'])){
            $sql .= ' GROUP BY '.$req'group'];
        }
        $pre = $this->db->prepare($sql); 
        $pre->execute(); 
        return $pre->fetchAll(PDO::FETCH_OBJ);
    }

D'où

find(array(
            'fields' => array('image','categorie','MAX(Telechargement'),
             'group' => 'categorie'
        ));

Bien cordialement

ps: Absolument sur de rien du tout sur ce post XD... désolé si ça foire totalement...

Ok merci, je vais essayer ce weekend.
Moi j'avais trouvé une solution un peu sale. Le problème venait des guillemets ajoutés dans de model :

foreach($req'conditions'] as $k=>$v){
                    if(!is_numeric($v)){
                        $v = '"'.mysql_escape_string($v).'"'; 
                    }

                    $cond] = "$k=$v";
                }
                $sql .= implode(' AND ',$cond);

donc j'ai ajouté une condition qui enlève les guillemets en cas de requête imbriquée.