Lista megjelenítése táblázattal php-ben

Nos, amire a cím is utal, nem egy nagyon bonyolult probléma, ám annál gyakoribb.
Elég, ha csak egy képgalériát szeretnél, ahol egy sorban maximum 10 képet szeretnél látni, vagy akár annál kevesebbet, függetlenül attól, hogy mekkorák a képek. Adott esetben az egyik sorban lehet, hogy csak 5 kép van, a másikban pedig 6, mert több fért el.

De bármilyen adattömeget szükség lehet ilyen módon megjeleníteni. Legyen az egy webes fájlkezelő, mint például a windows intéző, ahol szintén rendezett módon jelennek meg az ikonok, vagy akár bármilyen adatbázisban tárolt információ.

Erre mutatok pár példát, mert már túl sokszor írtam ezt le különböző fórumokon, és nyilván nem is csak én. De gyakran nehéz rátalálni a probléma megoldására egy fórumban, ahol temérdek kérdés és válasz váltja egymást egyetlen témában.

Első nekifutásra mindig egy tömbből indulok ki, mert ha nem tömböd van, azt is be tudod tölteni egy tömbbe. Például egy adatbázisból lekérdezett rekordokat.

Ami mindegyik megoldásnál ugyanaz lesz, az a tömb feltöltése, és az egy sorban levő elemek számának maximuma.

$egysorban = 10; //ennyi elem lesz egy sorban maximum

$tomb = range(100,200); //számok 100-tól 200-ig egy tömbben.
$c = count($tomb); //A tömb mérete. Vagyis hány elem van

Ez után az egyik lehetőség, hogy egyszerűen html sortöréssel, azaz <br /> tag-el választod el a sorokat.

for ($i=0; $i<$c; $i++)
{
        print $tomb[$i].", ";
        if (($i+1) % $egysorban == 0)
        {
                print "<br />";
        }
}

Ebben a megoldásban feltételeztem, hogy a tömb numerikus indexelésű, és az indexek növekvő sorban követik egymást. Ez leggyakrabban így is van.
A % jel a maradékos osztás, ami a maradékot adja vissza. Tehát akkor teszi ki a sortörést, ha az $i+1 -dik elem ( ami pontosan a sorszám, mert nullától indul az indexelés a tömböknél ) maradék nélkül osztható annyival, amennyi elemet egy sorban szeretnél látni.

Most ugyanez bármilyen indexelésű tömbre:

$i=1;
foreach ($tomb as $ertek)
{
        print $ertek.", ";
        if ($i++ % $egysorban == 0)
        {
                print "<br />";
        }
}

Itt csak a foreach ciklust kell ismerni. Minden más ugyanaz.

Na hát ez mind nagyon szép, és jó, de így még mindig csúnya lenne, ha képeket listáznék, és mindegyik más méretű lenne. Ezért a következő példában táblázatba rakom a tömb elemeit.

print "<table border='1'><tr>";
for ($i=0; $i<$c; $i++)
{      
        print "<td>".$tomb[$i]."</td>";
        if (($i+1) % $egysorban == 0 and $i != $c)
        {
                print "</tr><tr>";
        }
}
print "</tr></table>";

Ez annyival több a sortörésnél, hogy itt az első sor kezdését, és az utolsó sor zárását kell fixen beírni a tábla kezdés és zárás mellé, de ezen kívül a közötte levő záró és nyitó tag-eket csak akkor, ha nem az utolsó elemnél tart a ciklus. Mert abban az esetben feleslegesen nyitna egy új sort, pedig már nem kell több.

Persze lefuttatva a kódot, lehet látni, hogy az utolsó sor néhány cellája nem jelenik meg. Nem olyan szép. Ezért ki kell írni még pontosan annyi cellát, amennyi az egy sorra jutó elemek száma, mínusz az összes elem és az egy sorra jutó elemek számának maradékos osztásából adódó maradék.

print "<table border='1'><tr>";
for ($i=0; $i<$c; $i++)
{
        print "<td>".$tomb[$i]."</td>";
        if (($i+1) % $egysorban == 0 and $i != $c)
        {
                print "</tr><tr>";
        }
}
for ($i=$egysorban - $c % $egysorban; $i>0; $i--)
{
        print "<td>&nbsp;</td>";
}
print "</tr></table>";

Van egy ennél egyszerűbb, bár nem rövidebb, és nem is gyorsabb megoldás.
A tömböt fel kell darabolni. Egy olyan tömböt kell létrehozni, aminek minden eleme egy újabb tömb, aminek annyi eleme van, mint ahány elemet szeretnénk egy sorba kiírni. Erre PHP-ben van is egy függvény. Az array_chunk().
Ekkor két egymásba ágyazott foreach ciklussal simán meg lehet oldani a problémát. Természetesen itt is létre kell hozni az üres cellákat a végén. A már fent leírt számítási módszert alkalmazva az array_merge() függvénnyel össze kell fűzni a több dimenziós tömb utolsó sorát annyi &nbsp; -t tartalmazó tömbbel, amennyi cella kell még. Ezt a tömböt az array_fill() függvénnyel lehet létrehozni könnyen.

$tomb2 = array_chunk($tomb, $egysorban); //tömb darabolás

$utolso = count($tomb2)-1; // utolsó elem indexe
$tomb2[$utolso] = array_merge($tomb2[$utolso],array_fill(0,$egysorban - $c % $egysorban," ")); //összefűzés

print "<table border='1'>";
foreach ($tomb2 as $sor)
{
        print "<tr>";
        foreach ($sor as $cella)
        {
                print "<td>$cella</td>";
        }
        print "</tr>";
}
print "</table>";

Persze joggal mondhatja bárki, hogy mégis mi a fenének hoztam létre új tömböt, amikor két for ciklussal ugyanezt meg lehet oldani. Valóban így van. Bár a két foreach szebbnek tűnik, mert az indexekkel már nem kell játszani, ugyanakkor több sor kód csak az előkészület. Olyan függvények, amiket meg lehetne spórolni. Tehát a for ciklusos megoldás:

print "<table border='1'>";
for ($i=0; $i<$c;) //$i-t majd a belső ciklus növeli
{
        print "<tr>";
        for ($j=0; $j<$egysorban; $j++,$i++) //$i-t is növelni kell. Vesszővel több utasítás adható for ciklusban.
        {
                //Ha a tömb elem már nem létezik, akkor üres cella legyen
                $cella = (isset($tomb[$i])) ? $tomb[$i] : "&nbsp;";
                print "<td>".$cella."</td>";
        }
        print "</tr>";
}
print "</table>";

Itt három említésre méltó kódrészlet van.

  • A külső ciklusban az $i változót nem kell megnövelni, mert azt majd a belső ciklus növeli. A paraméterek elhagyhatók a for ciklusban. Akár az összes is. Csak a pontosvesszőket kell kitenni.

  • A belső for ciklusban növelni kell $j és $i változót is. For ciklusban akárhány utasítás megadható az első és utolsó paraméterben. Azokat vesszővel, és nem pontosvesszővel kell elválasztani!!
    A $j változó itt csak arra kellet, hogy pontosan addig fusson a ciklus, amíg megfelelő számú elemet kiírt. De most nem két dimenziós tömbről beszélünk, tehát az eredeti tömb indexét is növelni kell.

  • A ciklusban sima if helyett a rövidebb "hármas operátoros" megoldást alkalmaztam.
    Vagyis az egy változónak úgy adok értéket, hogy az egyenlőség jel után a feltételt írom. Amit nem muszáj zárójelbe tenni, de összetett feltételnél problémát okozhat a hiánya. A feltétel után kérdőjelt követően az az érték, amit a feltétel igaz voltakor kell kapnia a változónak, majd kettőspont után az, amit hamis esetén.

Mi van, ha adatbázisból jönnek az adatok?
Nos ebben az esetben két lehetőség van.

  1. A lekérdező while ciklusban a teljes rekordot átadod egy tömbnek. Így ezzel dolgozhatsz később.
    $tomb = array();
    while ($row = mysql_fetch_assoc($query))
    {
            $tomb[] = $row;
    }
  2. A $c értékét a $c = mysql_num_rows($query);-vel számolod ki. És a fent már többször is említett számítási módszerrel kiszámolod, mennyi üres cella kell még. ( persze csak ha táblázatos módszert használsz ) Majd ennyivel megnöveled a $c-t. Ez után csak a ciklus törzsében kell fetchelni az eredményeket.
    for ($i=0; $i<$c; $i++)
    {
            //..
            $row = mysql_fetch_assoc($query);
            //..
    }

Nagyjából ennyi módszert tudok hirtelen. Persze ezeket lehetne még cifrázni, optimalizálni. Az viszont látszik, hogy amennyire sokan kérdezik, hogy tudják megoldani a problémát, olyan sokféleképpen lehetséges. Csak logikusan végig kell gondolni.

Ha szükség lenne esetleg oldal lapozásra is, akkor ajánlom a Lapozás PHP-ben blogomat.

Kategóriák: 
Megosztás/Mentés

Hozzászólások

anonymuos1 képe

Üdv!

Nekem sajnos lekérdezésnél nem jelennek meg az adatok. Valamit biztos elszúrtam, csak nem tudom mit :( Meg tudnád mondani légyszíves, hogy mi a hiba?

Itt a kód: http://codepad.org/horJm4vZ

Előre is köszönöm :)

Ui.: A lekérdezés jó, mert a tömb elemeit visszaadta, csak akkor még ugye "Array"-t írt ki.

Rimelek képe

Mivel a ciklus előtt definiáltad a változót, hogy tömb legyen, akkor is Array-t ír ki, ha a lekérdezés hibás, vagy nem ad vissza eredményt. Csak ha hibás a lekérdezés, akkor még ráadásul hibaüzenetet is kéne írnia. var_dump($tomb); vagy print_r($tomb); -el írd ki a tömböt. Akkor a tartalmát is látni fogod. A $c változó értékét is írd ki. Hogy megtudd, lekérdezett-e egyáltalán valamit. Esetleg még segíthet a tömbfeltöltő ciklus után a: print mysql_error();
Nézz bele a html forrásba is a böngészőben. Hogy mennyit jelenít meg abból, amit kéne. Van egy blogom a hibakeresésről is:
http://rimelek.hu/hibakereses-php-ban/
Talán ez is segíthet megfejteni a problémát.

anonymuos1 képe

A $c értékre kiírja a megfelelő számot. A print_r($tomb) -re is kiírja a tömb összes elemét, és a print mysql_error(); nem ír hibát. Tehát nem értem mi a gond :(

Esetleg rosszul írattam ki az adatot? A tömb elemeit elvileg így tudnám kiírni: pl print $tomb[1]; igaz? Viszont erre írja eredményül az Array-t.

Rimelek képe

Jajj... Hát már látom mi a baj. Te összekevertél két külön megoldást. Nem olvastad elég figyelmesen úgy látszik a cikk végét :) Ott van, hogy két lehetőséged van. Vagy a tömbbe pakolós megoldást választod, és a fentebb írt módokon kezeled a két dimenziós tömböt, vagy lekérdezed a sorok számát, és ciklusban fetch-eled a rekordokat. Ebben az esetben szintén valamely fentebb írt ciklusos megoldást kell választanod, csak a különbség az, hogy a rekord nem a $tomb[$i] -ben lesz, hanem egy általad választott változóban. Nálad ez a $HelpDesk változó. És ez is egy tömb lesz. Mert egy fetch eljárás egy tömböt ad vissza a rekord mezőiről és értékeiről. Tehát az is érthető, hogy amikor kiírtad a $tomb[1] -et, akkor is tömböt kaptál.

anonymuos1 képe

Hoppá :D Elnézést :/ Most már működik is. Köszönöm szépen :)