Diskuze: Komentáře a odpovědi výpis ke článku

jAkErCZ
Člen | 321
+
-1
-

Čau,
mám tokový problém a hledám řešení všude možně ale mám sql

comment_id	int(11) Auto Increment
user_id	int(11)
article_id	int(11)
parent_id	int(11) NULL
content	text
created_at	timestamp [CURRENT_TIMESTAMP]

Z nich se pokouším udělat funkci na výpis komentářů a jejich odpovědí.

Můj pokus byl něco takového

public function getComments($article_id, $parent_id = null){
	    $comments = null;

	    if ($parent_id === null) {
            $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID, $article_id)->order('created_at')->fetchAll();
        } else {
            $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID ,$article_id)->where(self::COLUMN_COM_PARENT_ID, $parent_id)->fetchAll();
        }

        $_comments = [];

	    foreach ($comments as $comm) {
            // zpracování komentáře
            $_comment = [
                'comment_id' => $comm->comment_id,
                'user_id' => $comm->user_id,
                'created_at' => $comm->created_at,
                'content' => $comm->content,
            ];
        }

        if ($parent_id === null) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_comment['comments'] = $this->getComments($article_id, $parent_id);
        }

        $_comments[] = $_comment;


        return $_comments; // vrátit komentáře

    }

ale to mi hází: Maximum function nesting level of ‚256‘ reached, aborting! ( Jelikož se mi to tam ciklí)

Šablona jak bych si to představoval:

{snippet comments}
                      <div n:foreach="$comments as $comment" class="media">
                          <a class="media-left" href="#">
                              <img src="{$basePath}/images/user/avatar3.jpg" alt="" />
                          </a>
                          <div class="media-body">
                              <div class="media-content">
                                  <a href="#" class="media-heading"></a>
                                  <a n:if="$user->isLoggedIn()" n:href="reply! $comment['comment_id']" id="reply" class="btn btn-sm btn-primary pull-right ajax">reply</a>
                                  <span class="date">{$comment['created_at']|date:'j. n. Y H.i'}</span>
                                  <p>{$comment['content']}</p>
                              </div>

                              <div n:foreach="$comment['comments'] as $comm" class="media">
                                  <a class="media-left" href="#">
                                      <img src="{$basePath}/images/user/avatar.jpg" alt="" />
                                  </a>
                                  <div class="media-body">
                                      <div class="media-content">
                                          <a href="#" class="media-heading">YAKUZI</a>
                                          <a href="#" class="btn btn-sm btn-primary pull-right">reply</a>
                                          <span class="date">{$comm['created_at']|date:'j. n. Y H.i'}</span>
                                          <p>{$comm['content']}</p></div>
                                  </div>
                              </div>
                          </div>
                      </div>
                  {/snippet}

Chtěl bych si to udělat tak že bych měl jeden hlavní foreach $comments a v něm vnořený další foreach na výpis odpovědí ke komontáři pokud jsou.

Tady jsem vycházel ze starého kódu z mého už fakt old systému :D

$pocetKomentaru = 0;

function processComments($clanek_id, $parent_id = NULL) {
    global $pocetKomentaru;
    $komentare = NULL;

    if ($parent_id === NULL) {
        $komentare = dibi::query("
                SELECT k.*, a.nick, a.avatar FROM komentare k
                LEFT JOIN accounts a ON k.author_id = a.id
                WHERE k.clanek_id = %i AND k.parent_id IS NULL", $clanek_id);
    } else {
        $komentare = dibi::query("
                SELECT k.*, a.nick, a.avatar FROM komentare k
                LEFT JOIN accounts a ON k.author_id = a.id
                WHERE k.clanek_id = %i AND k.parent_id
                ", $clanek_id, " = %i", $parent_id);
    }

    $_komentare = [];

    foreach ($komentare as $komentar) {
        // zpracování komentáře
        $_komentar = [
            'id' => $komentar->id,
            'avatar' => $komentar->avatar,
            'komentar' => $komentar->komentar,
            'pridano' => $komentar->pridano,
            'nick' => $komentar->nick,
        ];

        if ($parent_id === NULL) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_komentar['komentare'] = processComments($clanek_id, $komentar->id);
        }

        $pocetKomentaru++;
        $_komentare[] = $_komentar; // přidat zpracovaný komentář do pole komentářů
    }

    return $_komentare; // vrátit komentáře
}

Díky všem za rady :)

IJVo
Člen | 38
+
0
-

Ahoj, myslím, že ve volání funkce getComments by jsi neměl předávat $parent_id ale hodnotu $comm->comment_id, protože nyní tam předáváš $parent_id, které v tu chvíli je null.

IJVo
Člen | 38
+
0
-

Ještě jedna věc, myslím, že cyklus foreach by měl končit až za podmínkou, kde testuješ, jestli je ($parent_id === null). Nyní tam máš jednu složenou konečnou závorku navíc.

jazby
Člen | 44
+
0
-

namísto

if ($parent_id === null) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_comment['comments'] = $this->getComments($article_id, $parent_id);
        }

dej

if ($parent_id === null) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_comment['comments'] = $this->getComments($article_id, $comm->parent_id);
        }

a je to hotovo. Nikde neměníš hodnotu parent, takže voláš pořád dokolečka získání komentářu pro hlavní vlákno až se zacyklíš na max level.

a mimochodem..tohle je šílenej prasokod. cejtím z něj historii :-D

Editoval jazby (16. 10. 2018 12:21)

jAkErCZ
Člen | 321
+
-1
-

jazby napsal(a):

namísto

if ($parent_id === null) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_comment['comments'] = $this->getComments($article_id, $parent_id);
        }

dej

if ($parent_id === null) { // pokud je to hlacní komentář zjistit pod-komentáře
            $_comment['comments'] = $this->getComments($article_id, $comm->parent_id);
        }

a je to hotovo. Nikde neměníš hodnotu parent, takže voláš pořád dokolečka získání komentářu pro hlavní vlákno až se zacyklíš na max level.

a mimochodem..tohle je šílenej prasokod. cejtím z něj historii :-D

Tak jsem s pomocí pokročil

public function getComments($article_id, $parent_id = null, &$_comments = [])
{
    if ($parent_id === null) {
        $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID, $article_id)->order('created_at')->fetchAll();
    } else {
        $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID ,$article_id)->where(self::COLUMN_COM_PARENT_ID, $parent_id)->fetchAll();
    }

    foreach ($comments as $comm) {
        // zpracování komentáře
        $_comment = [
            'comment_id' => $comm->comment_id,
            'user_id' => $comm->user_id,
            'created_at' => $comm->created_at,
            'content' => $comm->content,
        ];

        if ($comm->parent_id !== null) {
            $_comment['comments'] = $this->getComments($article_id, $comm->parent_id, $_comments);
        }

        $_comments[] = $_comment;
    }

    return $_comments; // vrátit komentáře
}

ale opět chyba

Řádek: $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID ,$article_id)->where(self::COLUMN_COM_PARENT_ID, $parent_id)->fetchAll();

Chyba: Maximum function nesting level of ‚256‘ reached, aborting!

Nějaké další rady?

Kcko
Člen | 465
+
-1
-

Porad rekurze

jAkErCZ
Člen | 321
+
-1
-

Tak jsem zkusil něco takového…

public function getComments($article_id){

        $comments = $this->database->table(self::TABLE_COMMENTS)->where(self::COLUMN_COM_ARTICLE_ID, $article_id)->order('created_at')->fetchAll();

        foreach ($comments as $comment) {
            // zpracování komentáře
            $_comments = [
                'comment_id' => $comment->comment_id,
                'user_id' => $comment->user_id,
                'created_at' => $comment->created_at,
                'content' => $comment->content,
            ];
            foreach ($comment->related('comments.parent_id') as $com) {
                $_comment['comments'] = [
                    'comment_id' => $com->comment_id,
                    'user_id' => $com->user_id,
                    'created_at' => $com->created_at,
                    'content' => $com->content,
                ];
            }
        }

        $_comments[] = $_comment;

        return $_comments; // vrátit komentáře

    }

Ale stále to není co bych potřeboval…

Jak jsem říkal:
Že 1 foreach je jen na hlavní komentáře tudíž ty co mají parrent_id=null a v tom vnořený 2 foreach na odpovědi pokud je komentář má.

Někdo nějaké další řešení?

David Matějka
Moderator | 6445
+
+3
-
  1. nikde nevidim, ze bys pri vyberu filtroval pouze ty komentare, ktere maji parent_id = null
  2. opravdu nemuzes $_comments[] = $_comment; provadet az za cyklem