PHP: Prezentace stromové struktury z databáze

PHP Ostatní PHP: Prezentace stromové struktury z databáze

Nedávno jsem se v diskuzním fóru zmínil o tom, že jsem vyřešil prezentace stromové struktury z databáze. Nelze to dělat přímo v databázi, protože relační databáze na takový typ dat nejsou stavěny. Je však možné zkombinovat to nejlepší z databáze i PHP.

Nejprve si založím databázi a naplním ji nějakými daty

> sqlite3 tree.sqlite

BEGIN TRANSACTION;
CREATE TABLE strom(id integer primary key autoincrement, gid int, pid int, nazev text);
INSERT INTO "strom" VALUES(1,1,NULL,'prvni vlakno');
INSERT INTO "strom" VALUES(2,1,NULL,'prvni vlakno 2');
INSERT INTO "strom" VALUES(3,1,1,'prvni vlakno 3');
INSERT INTO "strom" VALUES(4,2,NULL,'druhe vlakno 1');
INSERT INTO "strom" VALUES(5,2,NULL,'druhe vlakno 2');
INSERT INTO "strom" VALUES(6,2,4,'druhe vlakno 13');
INSERT INTO "strom" VALUES(7,2,4,'druhe vlakno 14');
INSERT INTO "strom" VALUES(8,2,1,'druhe vlakno 15');
INSERT INTO "strom" VALUES(9,2,7,'druhe vlakno 141');
INSERT INTO "strom" VALUES(10,2,7,'druhe vlakno 142');
INSERT INTO "strom" VALUES(11,2,9,'Příšerně žluťoučký kůň úpěl ďábelské ódy');
INSERT INTO "strom" VALUES(12,2,5,'Přidaný text');
DELETE FROM sqlite_sequence;
INSERT INTO "sqlite_sequence" VALUES('strom',12);
COMMIT;

Význam sloupců:

  • id - jednoznačná identifikace záznamu
  • gid - identifikace stromu. V jedné tabulce může být víc stromů
  • pid - označení rodiče aktuálního záznamu
  • nazev - jakýkoli text

Jako primární klíč ponechám id, pro větší fórum je vhodné udělat další index podle gid.

Data už máme, zbývá nám jejich výpis.

<?php
$db=new PDO('sqlite:tree.sqlite');
$prep=$db->prepare('SELECT id, pid, nazev FROM strom WHERE gid=? ORDER BY id;');
$prep->execute(array(2));
$xml=new DOMdocument();
$pole=array();
$pole[0]=$xml->appendChild(new DOMElement('forum'));
while($row=$prep->fetch(PDO::FETCH_ASSOC)){
        $id=$row['id'];
        $pid=isset($row['pid'])?$row['pid']:0;
        $pid=isset($pole[$pid])?$pid:0;
        $pole[$id]=$pole[$pid]->appendChild(new DOMElement('item',$row['nazev']));
}
$xsl=new DOMdocument();
$xsl->load('strom.xsl');
$xslt = new XSLTProcessor();
$xslt->importStylesheet($xsl);
echo $xslt->transformToXML($xml);

Jak je vidět, v průběhu načítání dat z něj vytvářím stromovou strukturu v paměti. Tuto strukturu už přímo předám šablonovacímu systému.

Výstupní šablona strom.xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8" />

<xsl:template match="/">
<xsl:text disable-output-escaping="yes">&lt;!DOCTYPE html&gt;
</xsl:text>
<html>
<xsl:apply-templates />
</html>
</xsl:template>

<xsl:template match="/forum">
    <head>
    <title>Diskuzní fórum</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    </head>
    <body>
    <xsl:apply-templates />
    </body>
</xsl:template>

<xsl:template match="item">
    <div class="vetvicka">
    <xsl:apply-templates />
    </div>
</xsl:template>

</xsl:stylesheet>

A nakonec ještě odkazovaný kaskádový styl style.css. Ten pro náš účel nemusí být dlouhý.

.vetvicka {
        margin-left:4%;
}

A to je vše. Aby z toho vzniklo opravdové diskuzní fórum, musel bych přidat vstupní formulář, jeho zpracování a uložení dat do databáze. K tomu by se hodila nějaká antispamová ochrana a administrační rozhraní pro moderátora. Pro náročnější ještě registrace uživatelů, přístupová práva, ... Chybí toho ještě hodně.

Uvedený příklad vůbec neřeší běhové chyby ani formátování příspěvku. Je to jen ukázka jednoduché prezentace stromového diskuzního fóra.


 

  Aktivity (1)

Článek pro vás napsal Kit
Avatar
Jsem spokojeným uživatelem operačních systémů založených na linuxovém jádře. Zejména openSUSE a Ubuntu. Pro psaní veškerých textů a programů používám vynikající textový editor Vim. Aplikace se snažím psát vždy v tom nejvhodnějším programovacím jazyk...

Jak se ti líbí článek?
Celkem (2 hlasů) :
55555


 



 

 

Komentáře
Zobrazit starší komentáře (4)

Avatar
martinkobelka
Redaktor
Avatar
martinkobelka:

Já se snažím vše učit postupně a pořádně. Objekty ještě pořádně neumim, a snažím se to přepsat do "jednoduchého kodu" bez šablonování, bez pdo, a bez objektů, protože je ještě neumím. začnu tím, že si napíšu sql dotaz, výsledek uložím do pole, a pak začnu psát cyklus pro výpis, a tady jsem před dvěma dny skončil, a pokračování vymýšlím včera a dneska.

 
Odpovědět 26.8.2012 12:12
Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Stromovou strukturu fóra uděláš i bez Lispu, XSLT, PDO a všeho ostatního. Musíš jen umět programátorsky myslet, pracovat s kolekcemi a znát rekurzi. Byla to jedna z prvních věcí, co jsem si v PHP napsal a to jsem v něm neuměl skoro nic, skoro nic k tomu totiž nepotřebuješ.

Tím neříkám, že je Kitův způsob špatný, ale je to poněkud pokročilejší.

Odpovědět 26.8.2012 12:13
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Souhlasím, dá se to udělat i bez vychytávek. Dokonce se to dá udělat i bez rekurze, ale je to obtížnější.

Do toho kódu jsem dal to nejlepší, co z PHP znám. Snažil jsem se využít ty nejsilnější stránky každého jazyka (SQL, PHP, XSLT a CSS), zjednodušit to na minimum a spojit to do jednoho funkčního celku. To však ještě neznamená, že to nejde jinak.

Odpovědět 26.8.2012 12:27
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
martinkobelka
Redaktor
Avatar
martinkobelka:

Tak už jsem si napsal funkci, který mi bude data vypisovat, teď pro ni musím ještě data vytvořit. Snad to konečně klapne.

function vypis($seznam){
    echo "<ul>\n";
    foreach($seznam as $vypis){
        if(is_array($vypis)){
            vypis($vypis);
        }
        else{
            echo "<li>$vypis</li>\n";
        }
    }
    echo "</ul>\n";
}
 
Odpovědět 26.8.2012 12:58
Avatar
Kit
Redaktor
Avatar
Odpovídá na martinkobelka
Kit:

To vypadá dobře. Jen bych místo

vypis($vypis);

dal

echo "<li>";
vypis($vypis);
echo "</li>";

aby se to správně zanořovalo.

Odpovědět 26.8.2012 13:11
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
martinkobelka
Redaktor
Avatar
Odpovídá na Kit
martinkobelka:

Na vybírání dat se ale pořát držím na dvou úrovních. Nemůžu se dostat přes další úrovně.

 
Odpovědět 26.8.2012 14:02
Avatar
Kit
Redaktor
Avatar
Odpovídá na martinkobelka
Kit:

Prostě vyber všechny záznamy z dané skupiny (nazval jsem ji gid). Pak je musíš poskládat do stromu. Jde to jednoduchým cyklem.

Tím, že každý uzel stromu mám jako objekt, můžu mít na každý z nich 2 reference: Jednu v poli a druhou ve vytvářeném stromu.

Odpovědět 26.8.2012 14:07
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
martinkobelka
Redaktor
Avatar
martinkobelka:

Tak už se mi to povedlo. Je to sice spatlanina a ne kod, ale funguje to, a to je p ro mě hlavní.

$dotaz = mysql_query("select * from vzkazy");
$pole = array();
while($vypis = mysql_fetch_array($dotaz)){
    $pole[] = $vypis;
}
$vysledek = array();
function podmenu($id, $pole){
    foreach($pole as $vypis){
        if($vypis['rodic'] == $id){
            if(!isset($podmenu)){
                $podmenu = array();
            }
            $podmenu[] = $vypis['obsah'];
            if(is_array($dopsat = podmenu($vypis['id'], $pole))){
                $podmenu[] = $dopsat;
            }
        }
    }
    if(isset($podmenu)){
        return $podmenu;
    }
}
foreach($pole as $vypis){
    if($vypis['rodic'] == 0){
        $vysledek[] = $vypis['obsah'];
        if(is_array($dopsat = podmenu($vypis['id'], $pole))){
            $vysledek[] = $dopsat;
        }

    }
}
function vypis($seznam){
    echo "<ul>\n";
    foreach($seznam as $vypis){
        if(is_array($vypis)){
            vypis($vypis);
        }
        else{
            echo "<li>$vypis</li>\n";
        }
    }
    echo "</ul>\n";
}
vypis($vysledek);

a databáze:
vzkazy(id int, rodic int, obsah text)

 
Odpovědět 26.8.2012 14:15
Avatar
martinkobelka
Redaktor
Avatar
martinkobelka:

Nemůžeš udělat živou ukázku z tohoto článku a dát sem odkaz?

 
Odpovědět 27.8.2012 12:30
Avatar
Kit
Redaktor
Avatar
Odpovídá na martinkobelka
Kit:

Můžu, ale nevím, jestli to bude ještě dnes.

Odpovědět 27.8.2012 12:36
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 14. Zobrazit vše