Bonjour à tous,

En ce moment, je travail sur un projet qui sera de faire une communauté sur les jeux en ligne. Je développe pour le moment un script sur un des jeux, puis le site/forum.

Au niveau du forum, je bloque par rapport à la requête SQL, je serai capable de faire plusieurs requêtes, mais très mal optimisé à mon gout. Alors je cherche à tout faire en une, je connais la manière des conditions dans le where avec 'AND', mais si une information manque (comme aucun message de posté), alors je n'aurai pas le forum à afficher.

Donc j'aimerai savoir si de la manière dont j'ai construit ma requête, elle serai valide. Après je n'ai aucune idée pour formuler ma partie LIMIT.

J'aurais aimé limiter par rapport à chaque table le nombre de résultats pour éviter de générer des résultat inutiles (imaginons qu'il faut charger 60 messages par sujet inutilement alors qu'il nous faut seulement quelques informations).

J'attends donc vos commentaires et votre aide. Merci.

<?php
class ForumsController extends AppController {
    public function index() {
        $this->loadModel('Category');
        $requete = array();
        $requete = $this->Category->query('SELECT forums.*, 
            categories.*,
            forums.*,
            topics.*,
            responses.user,
            responses.created,
            users.username,
            users.slug FROM forums, 
            categories, 
            responses,
            topics, 
            users WHERE forums.category = categories.id,
            responses.topic = topics.id,
            users.id = responses.user,
            users.id = forums.user ORDER BY categories.order ASC, 
            forums.order ASC, 
            responses.id DESC');
    }
    public function beforeFilter() {
        parent::beforeFilter();
        $this->Auth->Allow('index');
    }
}

Merci d'avance

4 réponses


Pakito
Réponse acceptée

Salut Carpetos,

Perso, j'ai trouvé ta requête imbuvable à la lecture, et sans avoir le modèle de données sous les yeux, j'ai choisi de ne pas aller plus loin.

Une seule requête, c'est souvent très compliqué, notamment dans le cas de tables liés, et de différents niveau de liaisons (un forum a une ou plusieurs catégories qui ont un ou plusieurs sujets qui ont une ou plusieurs réponses postées par un utilisateur...).

Cake fait ça très bien, et avec un code propre, toutes les requêtes sont très rapidement exécutées.
On pourrait essayer de faire tout tenir en une, avec des INNER JOIN etc, mais la tête du retour ne risque pas de coller à tes models.

Cependant, j'espère pouvoir t'aider un peu avec un cas concret.

Tout d'abord, voici la requête que j'ai sur mon forums/index :

$this->Forum->find('all', array(
            'contain' => array(
                'Forumscategory',
                'Forumscategory.Topic' => array(
                    'limit' => 1,
                    'conditions' => array('reply_count > 0'),
                    'order' => 'Topic.created DESC'
                ),
                'Forumscategory.Reply' => array(
                    'limit' => 1,
                    'order' => array('Reply.created DESC'),
                    'fields' => array('Reply.id', 'Reply.forumscategory_id', 'Reply.created', 'Reply.user_id', 'Reply.user_username')
                )
            )
        ));

Ce qui affiche quelque chose dans ce goût là :

Et ensuite, quand je vais à l'intérieur d'une catégorie, là ça se aurait pu se compliquer, puisque je veux récupérer :

  • la description

  • la liste des sujets du plus récent au plus ancien

  • pour chaque sujet, le nombre de réponse (pour ça, je me sers du counterCache)

  • pour chaque sujet, date du dernier message

  • pour chaque dernier message, l'utilisateur qui l'a posté

Du coup, ma requête sur "forumscategories/show/:slug" est de type :

$this->Forumscategory->find('all', array(
            'conditions' => array('Forumscategory.slug' => $slug),
            'contain' => array('Topic' => array(
                'order' => array('Topic.last_reply DESC')
            ), 'Topic.Reply' => array(
                'limit' => 1,
                'order' => array('Reply.created DESC'),
                'fields' => array('Reply.id', 'Reply.forumscategory_id', 'Reply.created', 'Reply.user_id', 'Reply.user_username')
            )),
        ));

Mais le gros des liaisons étant définies dans les models, on a pas trop de souci et ça fonctionne assez bien.

Le résultat est là :

En espérant que ça t'aura aidé.

Je t'avoue que je n'aime pas du tout surcharger les requêtes quand un outil comme Cake permet d'avoir accès à des tas de paramètres (conditions, contains, etc) qui permettent d ele faire proprement.

PS : penser à tester ton code en local ou sur un serveur de dev avec des fausses données injectées en base, mais des données quand même. Comme ça tu pourras couvrir tous les cas de figure.

Salut,

Ne serait-il pas plus simple d'effectuer une requête qui trouve toutes tes Category.id à afficher. De la mettre en cache et d'utiliser ce résultat dans une seconde qui ira chercher les informations utiles à l'affichage de ta page .

Après tu peux remettre ce cache à jour lors de l'ajout/suppression/maj d'une catégorie .

carpetos
Auteur

Merci pour cette suggestion, mais je travaillerai sur les systèmes de caches certainement plus tard.

Toujours en attente de solutions ^^'

Peux tu me donner un mlc ou mcd de tes tables stp ?