Bonsoir, je remanie mon forum parce que je suis partie sur une structure vielle de 20 pige qui me prend la tête, et donc il faut que je me mette a jour dans ma manière de codé, je voulais m'inspiré de grafikart.fr.

Loin de moi l'idée de pompé son design non non loin de là, juste savoir niveau code :

  1. Donc l'index liste tout les topic en vrac jusque là c'est bon
  2. Le volet a gauche liste les forum et sous forum !? qui si on clique liste les topic where leurs l'id respectif ?
  3. Les id se relis a quoi ? les réponse sont lié au topic et les topic liée au forum et sous forum, des qu'on choisis un tags ? et donc si je clique sur PHP je récupère tout se qui est liée a PHP donc les réponse et topic doivent avoir une clée liée au forum et sous forum selon les tags choisis !?
  4. Si on choisis pas de tags il se passe quoi ? si j'en choisis plusieurs ça update les sous forum etc... du coup.
  5. Si il y a une réponse elle s'affiche aussi sur l'index du forum donc !? donc on boucle sans tenir compte de quelconque id si j'ai bein capté.

Du coup c'est plus simple pour afficher ce que l'on veut, vu non vu par exemple etc... c'est surtout les clées que je capte pas.

Je vais donc repartir d'une page blanche et partir sur ça si j'ai vue juste j'aurais moins de jointure qui me rendent cinglé.

C'était juste pour être sur avant de me lancé, bonne soirée.

18 réponses


popotte
Réponse acceptée

petite précision, finalement sur tailwindUI tu as plein de templates tout prêts aussi x) ça vaut le coup si tu compte faire plein de sites, par contre c'est trop cher si tu commpte faire un seul site (ton forum)

Hello :)

Alors Grafikart n'a pas fait de Forum classique à l'ancienne (système de catégories, sous-catégories) il a fait un système de tags (tous les topics en vrac que tu peux filtrer par tags)

Quand tu accèdes au forum, tu récupère toute la liste des topics et tu boucles, ensuite quand tu places un tag, tu modifies la requête et tu ne récupère que les topics qui ont le tag séléctionné, et tu boucle le résultat

Si plusieurs tags sont selectionnés, dans ta requête tu ne récupère que les posts qui sont liés à au moins un des tags... et tu boucles le résultat dans la vue :)

Bref tu vires les catégories, tu places la liste de tous les topics en vrac et tu ajoutes un système de filtre par tags

1 - Tous les topics en vrac c'est bien ça

2 - Alors non, ce ne sont pas des forums et sous-forum, ce sont des tags, qui serviront à filtrer la liste des topics

3 - Alors les réponses ont un topic_id pour relier au sujet, et les topics ont une relation one2many, donc tu fait 3tables, une table topics, une table tags, et une table pivot topic_tag ton topic sera relié aux tags via le pivot, en gros ça donne un truc du genre:

|  topics   |  topic_tag            |  tags     |
-------------------------------------------------
|  id       |  topic_id     tag_id  |  id       |
|  1        |  1            2       |  1        |
|  2        |  2            1       |  2        |
|  3        |  2            3       |  3        |
|  4        |  3            3       |  4        |
|  5        |  3            5       |  5        |

Dans cet exemple, le topic avec l'id 1 est relié au tag 2, le topic 2 est relié au tag 1 et au tag 3, le topic 3 est relié au tag 3 et au tag 5

4 - Si on choisis pas de tags ça affiche tous les topics

5 - Alors la réponse est liée au topic, on si il ya une réponse tu peux récupérer la dernière réponse liée au topic en question

neecride
Auteur

merci @popotte

Que je comprenne bien, les tags son prédéfinie par grafikart dans la table tags ; si je regarde sa navigation PHP c'est un tags stocké dans la table tags et le laravel il est dans la même table que tags qui est relier a topic_tag qui fait le carrefour avec les topic et les tags... du coup il la fait comment différence entre laravel et PHP si laravel n'est pas une sous catégorie de php ?

si je créer un topic et que je prend PHP pour seul tags le topic ne sera pas listé dans le tags laravel.

Et si je ne met aucun tags il sera seulement a l'index ou il oblige la selection d'au moins un tags ?

Un jour on ma dit qu'il n'y avais pas de question bête, mais la je me remet en question lol.

Alors Laravel a sont propre tag, et PHP a aussi sont propre tag, ensuite si Laravel est un sous-tag de PHP tu peux très bien faire en sorte que dans le formulaire si tu sélectionnes Laravel, ça selectionne Laravel ET PHP

Comme ça les topics qui ont le tag PHP tu peux les trouver en placant le filtre PHP, et ceux qui ont le tag Laravel aura forcément le tag PHP aussi et donc tu peux retrouver le topic avec le filtre php ou laravel :)

Et du coup ce sera enregistré comme ça en base de données (tag 1 = PHP et tag 2 = Laravel, Topic 1 = topic Laravel (et PHP aussi du coup) et Topic 2 = PHP):

|  topics   |  topic_tag            |  tags     |
-------------------------------------------------
|  id       |  topic_id     tag_id  |  id       |
|  1        |  1            1       |  1        |
|  2        |  1            2       |  2        |
|           |  2            1       |           |

Alors je n'en suis pas sur mais je pense qu'il oblige au moins un tag

Exactement il n'y a pas de question bêtes, que des questions idiotes ;p' En vrai ce qui est bête c'est de ne pas poser de questions tkt x)

neecride
Auteur

merci @popotte

J'y suis presque manque plus qu'a faire les tags et créer un truc en js qui dès qu'on clique sur php ça l'insert dans le champ, comme ici quoi :)

mon final ressemblera a ça : mon espace DevianArt je me suis quand même un peut inspiré lol

si ça peut aidé les gens parce que ça fait bobo la tête, pour remonté un topic si il est nouveau ou a une réponse je fait comme ça (il faut que la table topic est un champ réponse_date et on compare) order by lastdate :

SELECT blabla.*,

CASE

WHEN f_topic_date < f_topic_reponse_date THEN f_topic_reponse_date

WHEN f_topic_date > f_topic_reponse_date THEN f_topic_date

ELSE f_topic_date

END AS Lastdate

// au moment de créer une réponse on update la date 
$lastid = $db->lastInsertId(); // id de la réponse qui viens d'être créer
$db->prepare("UPDATE f_topics SET f_topic_reponse_date = NOW() WHERE id = ?")->execute([$id]);

Là où je vais douiller c'est sur le vu non vu j'ai rien compris a sa vidéo SNIFF !!

Bonne soirée ou journée pour l'heure qu'il est lol

Ah pas mal le forum :D

Perso je changerais juste les barre avec effet relief, c'est assez ancien comme design, sinon le reste pas mal du tout :p

Alors ça c'est simple tu charges le topic aves ses réponses et tu fait un orderBy dernière réponse :)

Si tu fait le site en Laravel regardes l'eager loading, si tu le fait en PHP... bon la bon courage xD

Sinon les vidéos de cours de base Grafikart sont très anciennes, faudrait trouver des vidéos plus récentes, Laracast pour Laravel, et pour PHP cherches des vidéos sur PHP8 ;)

neecride
Auteur

Bonsoir popotte, non je n'utilise pas de framwork c'est mieux pour apprendre avec un code maison, et je suis en PHP 7.4.26 ! c'est un vieux design oui il date de 2015 et comme je suis pas top en design j'en suis plutot fiert de l'avoir fait.

Dernière question niveau insertion en base de donnée si je vois bien topic_tag n'a pas d'auto incrémente ? et j'ai pris pour habitude d'inseré une donnée a la fois je ne sais pas commenet faire pour en inséré plusieurs en même temps dans le cas des tags.

Tags c'est elle qui enregistre les nom php etc... que j'ai coisis donc j'ai fais une boucle qui les liste dans des checkbox elles on toute le même nom et je choisis, et ensuite j'envois.

je dois faire un tableau name="tags[]" après ça je vois pas ?

bonne soirée.

EDITE j'ai donc fait comme ceci ça a l'air d'être bon :

Je le met là on ne sais jamais si quelqu'un cherche a faire pareil, par contre j'ai pas mis d'auto incrémente sur topic_tags.

// formulaire
<?php foreach($tag as $tags){ ?>
       <input type="checkbox" name="tags[]" value="<?= $tags->id ?>">&nbsp;<?= $tags->name ?>
<?php } ?>

// requete
$tags = (int) $post['tags']; 
$lastid = $db->lastInsertId();

foreach($tags as $item){
     $db->prepare("INSERT INTO f_topic_tags SET topic_id = ?, tag_id = ?")->execute([$lastid,$item]);
}

reste plus qu'a faire les jointure et d'afficher tout ça... on verra plus tard pour le jquery !

Ah je vois c'est bien du design de 2015, ouai pour ce qui est des design faut s'y connaitre un peu, après si un jour tu veux mettre le design a jour la mode en ce moment c'est le fluent design :p

Alors oui topic_tags n'a pas de ID, c'est une table pivot, il ne sert qu'a mettre en place les relation many2many, c'est tout :)

Aloors ça m'a l'air pas mal pour le formulaire, ensuite dans la partie PHP tu castes le $post['tags'] en int, ça ne va pas fonctionner, ton post est un array :p

Ensuite le lastID faudrait faire autrement, en gros tu va créer un topic, tu va l'enregistrer puis récupérer dans une variable $topic, au lieux de $lastid il faudrait utiliser $newTopic->id, ce sera plus carré, et pareil pour la modification tu récupères le topic puis son id ^^

Ensuite ce serait mieux pour ton projet de séparer ton formulaire et tes requêtes, regardes les vidéos sur le MVC (Modèle/View/Controller) c'est un standard de base de PHP ;)

Dèrnière chose pour ta requête, il faut que tu checkes si la paire de topic_id/tag_id n'existe pas déjà avant de l'enregistrer ^^ (Par exemple quand tu modifies un topic et que tu laisses le tag coché, faut pas que PHP essaies de rajouter encore une paire topic tag) :)

A part ça ça m'a l'air pas mal ^^

neecride
Auteur

Merci popotte, je vois pas pour le $newTopic->id

J'ai une dernière question quand je créer mon topic je fais mon insertion j'incrément aussi topic_tags selon les tags que j'ai choisis et même en créant un tags je dois incrémenté tag_id.

sauf que a l'affichage tout les post qui ont le tags php je dois les listé donc que faire je prend le lien avec quel id j'ai mis un slug sur les tags ça me parait logique donc dans le get j'ai php-1 ; donc au moment de faire ma requète je boucle sur l'id en get avec la table topic je join topic_tag puissque l'id du tag je l'ai en get mais ça foire a chaque fois avant j'avais un forum_id sur chaque topic, là je ne comprend pas cette requète.

Bonne journée.

Alors en gros avant de créer le pivot topic_tags, tu va créer le topic, quand tu créées le topic tu peux l'enregistrer dans une variable qui est par exemple $newTopic mais tu peux l'appeler comme tu veux, et dans cette variable tu aura l'id qu'il faut :p

Ensuite pour le tag_id, il ne faut pas l'incrémenter mais lui attribuer la valeur du tag entré dans le formulaire, il n'y a pas de clé primaire dans les pivot, il n'y a que des clés étrangères ^^'

Quand tu créées un tag tu n'a pas besoin d'incrémenter tag_id, c'est seulement au moment de créer un topic que tu créées un tag_id qui va lier le topic avec le tag qui a comme id le tag_id du pivot

Fait voir le rendu total de ton controller?

neecride
Auteur

Bonjour popotte,

Je ne suis pas encore sur le réfactoring je peut juste te filer ma requète et mon insert c'est le bordel mais c'est temporaire le but étant de listé tout les topic avec le get php c'est la première fois que je vois ce genre de méthode, donc je suis paumé, en gros l'insertion ça va je pense !?

je crée mon topic comme ça : les id se mettent bein là où il faut en base de donée

if(isset($_POST['topics'])){
    checkCsrf();//on verifie les faille csrf
    $topic_name = htmlspecialchars(trim($_POST['f_topic_name']));
    $topic_slug = $generator->generate($topic_name);
    $content = htmlspecialchars(trim($_POST['f_topic_content']));
    $userid = intval($_SESSION['auth']->id);
    $username = htmlspecialchars($_SESSION['auth']->username);
    $tags = $_POST['tags'];
    $error = '';
    if((grapheme_strlen($topic_name) < 6) || (grapheme_strlen($topic_name) > 100)){

        $error .= errors(['Le titre du topic doit avoir en 6 et 100 caractères']);

    }if(grapheme_strlen($content) < 100){

        $error .= errors(['Votre topic dois contenir au moins 100 caractères soyez créatif']);

    }/* add tags verify */
    else if(empty($error)){

            $i = [$topic_name, $topic_slug, $userid, $username ,$content];

            $db->prepare("INSERT INTO
              f_topics
              SET
              f_topic_name = ?,
              f_topic_slug = ?,//au final je vais enlevé ça 
              f_user_id = ?,
              f_autor_topic = ?,
              f_topic_content = ?,
              f_topic_date = NOW()")->execute($i);

            //redirection ver le topic creer a l'instant voir la pagination
            $lastid = $db->lastInsertId();

            //insertion des tags 
            foreach($tags as $item){

              $db->prepare("INSERT INTO f_topic_tags SET topic_id = ?, tag_id = ?")->execute([$lastid,$item]);

            }
            setFlash('<strong>Super !</strong> Votre topic a bien étais poster <strong>Bien jouer </strong>');

            $pageflag = $lastid.'#topic-'.$lastid;

            redirect($router->generate('viewtopic', ['slug' => $topic_slug, 'id' => $pageflag]));

    }
}

Mais c'est la requète d'affichage qui pose problème j'ai encore ma page viewforum qui devrais listé les topics qui on choisis le même tags comme, ici quoi.

$render = $db->prepare("SELECT

    f_topics.id AS topicid,
    f_topics.f_topic_name,
    f_topics.f_topic_slug AS topicslug,
    f_topics.f_topic_content,
    f_topics.f_user_id,
    f_topics.f_autor_topic,
    f_topics.f_topic_date,
    f_topics.f_topic_update_date,
    f_topics.f_topic_message_date,
    f_topics.f_forum_id,
    f_topics.f_topic_vu,
    f_topics.sticky,
        users.id AS usersid,
        users.username,
        users.description,
        users.authorization,
        users.avatar,
        users.email,
        users.slug AS userslug,
        users.userurl,
            f_topic_track.read_topic,

            /*
            CASE - si on a un nouveau topic on le met au dessu
            et si on a une réponse a un topic on passe au repasse dessu aussi
            */
            CASE

              WHEN f_topic_date < f_topic_message_date THEN f_topic_message_date

              WHEN f_topic_date > f_topic_message_date THEN f_topic_date

              ELSE f_topic_date

            END AS Lastdate,
            /*
            fin de condition - voir pour sticky plus tard !!
            */

            /* si le topic ou la réponse n'est pas déjà lu */
            /*(
              (read_topic IS NULL OR read_topic < f_topic_message_date)
            ) AS is_not_read*/

    FROM f_topics

    /*LEFT JOIN f_topic_track ON f_topic_track.topic_id = f_topics.id AND f_topic_track.user_id = ?*/

    LEFT JOIN users ON users.id = f_topics.f_user_id

    //a partir d'ici je pige plus ??
    LEFT JOIN f_topic_tags ON f_topic_tags.tag_id = f_topic_tags.topic_id

    WHERE f_topic_tags.topic_id = ?

    GROUP BY f_topic_tags.tag_id

    ORDER BY Lastdate DESC
    ");

    $userid = isset($_SESSION['auth']->id) ? intval($_SESSION['auth']->id) : '' ;

    /*$f_forum_read = isset($_SESSION['auth']->f_forum_read) ? $_SESSION['auth']->f_forum_read : '' ;*/

    $render->execute([$userid,$match['params']['id']]);

Voilà j'en suis arrivée ici c'est un bordel sans nom mais ça va être réfactoré plus tard avant ça je dois viré mon moteur de template pour twigg je dois lire la doc.

Je sais c'est loin des belles lignes de l'objet mais je viens d'un monde ou composer ni l'autoloading éxistai lol là j'ai déjà pas mal refactoré mais c'était un cms complet de 2010 il y a beaucoup de taf encore et je suis seul imagine j'ai du implémenté pdo partout dans chaque module et là c'est le forum.

Le monde va trop vite mdr

Bonne journée.

EDITE - j'ai remanier ma formule au lieux de faire ma requete sur from topic j'ai fait sur tags du coup ça fonctionne je sais pas si c'est la bonne méthodologie mais ça fait ce que je lui demande, un truc nouveau que j'ai compris grace a toi !!

l'édition ne devrai pas être si compliquer.

  FROM f_tags

    INNER JOIN f_topic_tags ON f_topic_tags.tag_id = f_tags.id

    INNER JOIN f_topics ON f_topics.id = f_topic_tags.topic_id

    INNER JOIN users ON users.id = f_topics.f_user_id

    WHERE f_tags.id = ?

Alors dans ton premier bloc je vois le problème x)

    //a partir d'ici je pige plus ??
    LEFT JOIN f_topic_tags ON f_topic_tags.tag_id = f_topic_tags.topic_id

En gros tu cherches a joindre uniquement les topic_tags où le tag_id et égal au topic_id, bref il faut que ton topics 1 ait le tag 1 pour pouvoir être récupéré, alors que ce n'est pas ça :p

En gros il faut que tu fasses une sous requete, tu dois joindre le f_tags puis faire un ON f_tags.id = f_topic_tags.tag_id, tu aura toutes les lignes de tag avec comme tag celui qui est selectionné, et dans ces lignes de tags il y a les topic_id, tu récupères tous les topic_id et tu récupères tous les topics qui ont comme id les topic_id que tu as récupéré

Eeeet en faisant la méthode a l'envers c'est bon tu as fait je que je vien de dire plus haut :p

INNER JOIN f_topic_tags ON f_topic_tags.tag_id = f_tags.id

C'est top comme ça ^^

Ca peut se faire dans les deux sens, il faut prendre le sens le plus simple ;)

Avec plaisir :p

Il y a un truc sur stackoverflow qui essaye de faire un peu comme ce que tu veux faire:

https://stackoverflow.com/questions/50844381/display-a-many-to-many-relation-in-sql-as-list-in-select

neecride
Auteur

Bonjour popotte,

En tout cas j'ai fait/on a fait le plus dur ça l'était pour moi lol, la création des tags je continue a faire comme avant mais ça ne sera plus des forum lié au topic... l'édition du topic je devrais prendre en compte ses tags et faire en sorte que si on change ça éfface ceux que l'utilisateur avait choisis contre les nouveau tags, mais bon en même temps qui changerais de tags a part des gens qui ne savent pas ce qu'ils veulent, est-ce judicieux de les modifié !? je vais de toutes façon mettre une limite a 4 tags par topic je ferais un count avant l'insertion et je vérifierai si ils existent bien avec un champ de selection comme on peut le voir ici, bien que je ne sache pas grand chose au Js.

du coup le vu non vu que je dois encore faire j'ai plus besoin de forum track ce qui allège encore la base de donnée j'ai plus besoin de table catégorie non plus.

PS : si tu connais un site de vente de design ? je voudrai bien en faire un moi même mais je ne suis pas top.

Bonne journée.

Hello,

Pas de htmlspecialchars pour de l'insertion en BDD ne-pas-confondre-faille-par-injection-sql-et-faille-xss

Pourquoi retenir le userid et le username ?

Mmmh ça peut arriver de vouloir changer de tags, quelqu'un qui vient d'arriver sur le forum va faire un topic Laravel avec le tag PHP, ensuite il va se rendre compte qu'il y a un tag Laravel et il voudra surement le rajouter, après tu peux le faire en recherchant SQL sync ou SQL merge :p

Pour les design, alors si tu veux toucher au design un peu quand même tu peux passer par Tailwind UI, 200$ environs, sinon si tu veut un design tout prêt il y a des templates bootstrap qui countent entre 20$ et 70$ (et certains gratuits mais c'est vraiment basique)

Ah sympas l'article j'irais le lire quand j'aurais un peu de temps :)

neecride
Auteur

quenti77 - merci pour l'article, et oui le htmlspecial j'avais toujours des doutes du coup c'est devenue une habitude comme un réflex, a la base dans mon crew je faisait surtout les intégrations je méttait juste le html/ccs j'ai commencer dans la team nukedklan mon design date de cette époque, et puis nukedklan étant mort et entéré donc j'ai commencer a créer mon propre code et là je fait les mise a jour... l'userid c'est pour topic track mais je me rend compte de plus en plus que j'ai pris de mauvaise habitude.

Je fait pas mal de test avec html purifier et parsedown safe mode... le faite est que je ne connais pas toutes les failles

Merci popotte je regarderai ça :)

neecride
Auteur

bonjour popotte, j'ai aussi trouver un pack de 100 design et des template admin par ici -> pas moche du tout et > <, c'est toujours une bonne base pour ceux qui cherche un truc pour commencer.

j'ai fait un système de changement de template a la volé jusque là j'en avais qu'un et ma structure s'adapte, a la base je l'avais bosser pour worpress tant que c'est du bootstrap un peut de css et c'est bon.