Bonjour à tous,
Je me lance dans la création d'un forum avec cakephp 3, histoire de peaufiner mon apprentissage de celui-ci.
Mon problème :
Pour faire simple, sur la page d'accueil de mon forum, je n'arrive pas à sélectionner le dernier sujet pour chaque forum présent dans sa catégorie.
Exemple :
Cliquez sur le lien forum de ce site et vous verrez que dans le forum "Formation ", vous aurez le dernier sujet publié dans celui-ci. Idem pour chaque forum présent dans la catégorie "Détente", "Les questions - Logiciels ", etc.
Structure des tables :
Suite à la lecture du tutoriel Système de sujets lus / non lus , j'ai gardé cette structure.
Structure :
La structure du forum va être simple :
- Une table categories pour organiser nos différents forums (hasMany Forum)
- Une table forums (belongsTo Categorie, hasMany Topic)
- Une table topics (belongsTo User, belongsTo Forum, hasMany Post)
- Une table posts qui contiendra les messages de notre forum (belongsTo Topic, belongsTo User)
- L'incontournable table users pour sauvegarder les utilisateurs (hasMany Topic, hasMany Post)
Requête :
Voici la requête situé dans ForumsController, permettant d'afficher l'accueil de mon forum :
public function index()
{
$this->loadModel('ForumCategories');
$categories = $this->ForumCategories
->find()
->contain([
'ForumForums' => function ($q) {
return $q->order(['ForumForums.position' => 'asc']);
},
'ForumForums.ForumTopics' => function ($q) {
return $q
->order(['ForumTopics.created' => 'desc']);
}
])
->order([
'ForumCategories.position' => 'asc'
]);
$this->set(compact('categories'));
}
Avec un debug() dans la vue, cela me donne :
object(Cake\ORM\Entity) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 2,
'title' => 'Catégorie 2',
'position' => (int) 1,
'forum_forums' => [
(int) 0 => object(App\Model\Entity\ForumForum) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 2,
'category_id' => (int) 2,
'title' => 'Forum 2',
'slug' => 'forum-2',
'description' => 'Bla bla',
'position' => (int) 1,
'topic_count' => (int) 0,
'message_at' => null,
'forum_topics' => [
(int) 0 => object(App\Model\Entity\ForumTopic) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 6,
'forum_id' => (int) 2,
'user_id' => (int) 1,
'title' => 'Topic 6',
'content' => 'Bla bla',
'sticky' => false,
'post_count' => (int) 0,
'message_at' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-04-11T05:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => null
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumTopics'
},
(int) 1 => object(App\Model\Entity\ForumTopic) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 3,
'forum_id' => (int) 2,
'user_id' => (int) 1,
'title' => 'Topic 4',
'content' => 'Bla bla',
'sticky' => false,
'post_count' => (int) 0,
'message_at' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-04-09T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => null
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumTopics'
}
]
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumForums'
},
(int) 1 => object(App\Model\Entity\ForumForum) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 3,
'category_id' => (int) 2,
'title' => 'Forum 3',
'slug' => 'forum-3',
'description' => 'Bla bla',
'position' => (int) 2,
'topic_count' => (int) 0,
'message_at' => null,
'forum_topics' => [
(int) 0 => object(App\Model\Entity\ForumTopic) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 7,
'forum_id' => (int) 3,
'user_id' => (int) 1,
'title' => 'Topic 7',
'content' => 'Bla bla',
'sticky' => true,
'post_count' => (int) 0,
'message_at' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-04-12T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => null
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumTopics'
},
(int) 1 => object(App\Model\Entity\ForumTopic) {
'new' => false,
'accessible' => [
'*' => true
],
'properties' => [
'id' => (int) 2,
'forum_id' => (int) 3,
'user_id' => (int) 1,
'title' => 'Topic 2',
'content' => 'Bla bla',
'sticky' => false,
'post_count' => (int) 0,
'message_at' => null,
'created' => object(Cake\I18n\Time) {
'time' => '2015-04-10T00:00:00+0000',
'timezone' => 'UTC',
'fixedNowTime' => false
},
'modified' => null
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumTopics'
}
]
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumForums'
}
]
],
'dirty' => [],
'original' => [],
'virtual' => [],
'errors' => [],
'repository' => 'ForumCategories'
}
Dans la vue, après avoir listé mes forums dans une catégorie avec
<?php foreach ($category->forum_forums as $forum): ?>
Je dois utiliser actuellement $forum->forum_topics[0]['title'] pour afficher le dernier topic dans chaque forum. Vous comprendrez aisément que si j'ai 1000 topics par forum, la requête sera énorme et peu performante. J'ai donc pensé à rajouter ->first() dans mon contain ForumForums.ForumTopics pour sélectionner le dernier topic, mais j'ai une erreur fatale :
Error: Call to undefined method App\Model\Entity\ForumTopic::all()
File ../vendor/cakephp/cakephp/src/ORM/Association/ExternalAssociationTrait.php
Line: 114
Ma question :
Comment résoudre en une seule requête ce problème ? Dans divers topic, certains disent qu'une seule requête suffit sans donner de piste. J'ai également pensé à créer une autre table du genre LastTopic, mais il faudrait faire de même avec LastPost. En effet, le problème est le même lorsqu'on va dans le forum "Détente", on liste tous les sujets et pour chaque sujet, on indique le dernier message de celui-ci.
Auriez vous une idée, une solution ? Car pour le moment, le résultat est là, mais les performances/optimisations.. pas du tout. Merci d'avance.