Lekce 5 - První objektová komponenta v PHP - Galerie obrázků
V předchozím kvízu, Kvíz - Úvod, třídy a zapouzdření v PHP OOP, jsme si ověřili nabyté zkušenosti z předchozích lekcí.
Na dnešek si vytvoříme galerii obrázků.
Motivace
Často chceme na našich stránkách zobrazit nějakou galerii obrázků, ať již se jedná o fotky z dovolené nebo o screenshoty našeho programu. Psát ručně HTML tabulku s obrázky je poněkud pracné, hlavně když jich je v dané složce hodně. Budeme tedy chtít zautomatizovat výpis obrázků z nějaké složky do přehledné tabulky a nejlépe pomocí objektové komponenty, kterou budeme moci používat vícekrát a třeba i na více webech.
Založení struktury projektu
Vytvoříme si novou složku pro projekt, já jsem ji pojmenoval
galerie/
. V ní vytvoříme soubor index.php
a složku
tridy/
, ve které vytvoříme soubor Galerie.php
.
Nakonec vytvoříme složku s obrázky, tu jsem pojmenoval jednoduše
obrazky/
. Do ní si připravíme několik obrázků, já jsem
použil ty výchozí "Ukázky obrázků" z operačního systému Windows. Ke
každému obrázku je nutné vytvořit ještě jeho miniaturu (třeba v
grafickým nástroji GIMP). Mohlo by to za nás dělat PHP při nahrávání
obrázků, ale nahrávání již není předmětem tohoto tutoriálu a můžeme
ho dodělat někdy jindy. Zvolil jsem si, že miniatura bude široká
160px
a její název bude vždy končit na _nahled
.
Vaše složka by mohla vypadat třeba nějak takto:

Galerie
Máme připravená data a strukturu, pusťme se do programování. Začneme
samozřejmě třídou Galerie
, jejíž instance bude reprezentovat
galerii obrázků. Pojďme si promyslet, jaké atributy bude třída mít.
Atributy
Budeme chtít určit kolik náhledů se má zobrazit v jednom řádku, tedy kolik sloupců bude mít tabulka s obrázky. Dále budeme chtít samozřejmě uchovávat cestu ke složce s obrázky. Ani jeden atribut není důvod zpřístupňovat zvenčí, stačí, když si je necháme zadat v konstruktoru.
Kód třídy s těmito atributy a konstruktorem bude vypadat následovně:
class Galerie { public function __construct(private string $slozka, private int $sloupcu) {} }
Metody
Přejděme k metodám. Jednu ve třídě již samozřejmě máme (konstruktor), přidáme tam 2 další.
nacti()
Metoda nacti()
prohledá složku a uloží si do paměti
náhledy obrázků. K prohledání složky nám PHP nabízí třídu
Directory
. Vzpomínáte si, jak jsme si říkali, že se v PHP
začínají objevovat objekty? Directory
je jedním z nich.
Bohužel lze instanci vytvořit jen pomocí funkce dir()
, no, nic
není dokonalé. Na instanci nás zajímají 2 metody:
read()
- Načte obsah dalšího souboru nebo složky ve složce a vrátí ho jako textový řetězecclose()
- Ukončí čtení složky
Naše metoda nacti()
by mohla vypadat prozatím takto:
public function nacti(): void { $slozka = dir($this->slozka); while ($polozka = $slozka->read()) { // TODO } $slozka->close(); }
Vytvoříme si instanci Directory
a pomocí metody
read()
čteme postupně složky a soubory v této složce. Metoda
vrátí hodnotu false
v případě, že jsme se prokousali až na
"konec" složky (za poslední soubor nebo složku). Díky tomu můžeme dát
načítání názvu souboru do while
cyklu, který skončí ve
chvíli, kdy načteme poslední. Název budeme mít uvnitř cyklu dostupný v
proměnné $polozka
. Možná je trochu nezvyklé, že v podmínce
while cyklu provádíme rovnou i přiřazení do proměnné, ale dělá se to
tak velmi často.
Každý soubor nyní načítáme 2× (miniatura + originál) a k tomu nám
funkce ještě vrátí vždy 2 složky navíc. Jsou to složky s názvem
.
a ..
, které označují současnou a nadřazenou
složku. My budeme chtít zobrazovat jen miniatury, proto do cyklu umístíme
podmínku, že nás zajímají pouze soubory, obsahující v názvu
_nahled.
. Tyto soubory si uložíme do pole. Jelikož chceme, aby
bylo toto pole přístupné pro metodu vypis()
, musíme ho přidat
třídě jako privátní atribut:
private array $soubory = array();
Nyní se přesuňme do těla cyklu while
a přidejme název
souboru do našeho pole pokaždé, když se jedná o náhled. Použijeme k tomu
funkci strpos()
, která vrací pozici podřetězce v řetězci.
Pokud se v názvu položky vyskytuje od druhého znaku někde text
_nahled.
, bude položka přidána do našeho pole. Pokud ne, funkce
vrátí hodnotu false
. Pro jistotu ještě přidáme podmínku
kontrolující, zda je daná položka skutečně souborem a ne adresářem. K
tomu nám poslouží funkce is_file()
, která přijímá jako
argument cestu k položce a vrací hodnotu true
, jedná-li se o
soubor:
if (strpos($polozka, '_nahled.') && is_file($this->slozka . '/' . $polozka)) { $this->soubory[] = $polozka; }
Funkce strpos()
vrátí hodnotu 0
v případě, že
řetězec podřetězcem začíná (protože 0
označuje první
pozici). V našem případě by se hodnota 0
vyhodnotila jako
nepravda a podmínka by neplatila. To je správně, soubor
_nahled.jpg
by se vázal k obrázku bez názvu a není tedy
platný. Pokud bychom však chtěli opodmínkovat kompletně výskyt
podřetězce, třeba v jiné aplikaci, používá se k odlišení 0
a hodnoty false
operátor !==
takto:
if (strpos($polozka, '_nahled.') !== false) { $this->soubory[] = $polozka; }
Nyní podmínka neprojde pouze s hodnotou false
a projde s
hodnotou 0
. V našem případě se nám však spíše hodí první
varianta.
vypis()
Tu složitější část máme za sebou, přesuňme se nyní k výpisu HTML
tabulky, tedy k metodě vypis()
. I když by načtení i výpis
mohly být v jedné metodě, jedná se o 2 logické úlohy a proto je lepší je
rozdělit do 2 metod. Metoda by měla dělat vždy jednu věc a měli bychom ji
být schopni popsat bez spojky a. Tedy "Metoda zobraz()
zobrazí
HTML tabulku s náhledy", nikoli "Metoda zobraz()
načte a zobrazí
galerii".
Metoda vypis()
vyechuje začátek tabulky. Dále proiterujeme
cyklem foreach
miniatury a ty vyechujeme do buňky tabulky jako tag
<img>
. Kolem tagu <img>
samozřejmě
uděláme odkaz na originální obrázek. Ten získáme velmi jednoduše,
stačí v názvu miniatury nahradit _nahled.
za .
.
Nahrazení provedeme funkcí str_replace()
. Aby nebyla celá
tabulka v jednom řádku, budeme si počítat kolikátý sloupec vypisujeme.
Jakmile dosáhneme hodnoty nastavené v atributu $sloupcu
,
uzavřeme řádek, začneme nový a vynulujeme počítadlo sloupců.
Kód metody vypis()
by mohl vypadat nějak takto:
public function vypis(): void { echo('<table id="galerie"><tr>'); $sloupec = 0; foreach ($this->soubory as $soubor) { $nahled = $this->slozka . '/' . $soubor; $obrazek = $this->slozka . '/' . str_replace('_nahled.', '.', $soubor); echo('<td><a href="' . htmlspecialchars($obrazek) . '"><img src="' . htmlspecialchars($nahled) . '" alt=""></a></td>'); $sloupec++; if ($sloupec >= $this->sloupcu) { echo('</tr><tr>'); $sloupec = 0; } } echo('</tr></table>'); }
Použití
Přesuneme se do index.php
, vložíme sem základní HTML
strukturu a vytvoříme instanci galerie. Do konstruktoru předáme složku a
počet sloupců. Následně zavoláme nacti()
a
vypis()
.
<!DOCTYPE html> <html lang="cs-cz"> <head> <meta charset="utf-8" /> <title>Galerie obrázků</title> </head> <body> <h1>Galerie obrázků</h1> <?php require_once('tridy/Galerie.php'); $galerie = new Galerie('obrazky', 5); $galerie->nacti(); $galerie->vypis(); ?> </body> </html>
Máme hotovo.
Když přidáme minimum CSS, může vaše aplikace vypadat třeba takto (zdrojový kód jako vždy níže ke stažení, k zobrazování originální obrázků jsem ještě přidal javascriptový plugin LightBox):

Po kliknutí na obrázek se aktivuje lightbox:

Možná vylepšení
Metoda vypis()
není úplně ideální, jelikož se HTML kód
echuje a proto je práce s ním poněkud nepřehledná. Dalším, již
zmíněným vylepšením, by mohl být nahrávač obrázků, který nám na FTP
nahraje obrázky do galerie a sám vytvoří miniatury. Pro naše účely je
však aplikace dostačující a myslím, že má i tak praktické využití.
Naprogramovali jsme objektovou komponentu, kterou můžeme používat na různých webech, pro různé složky a na různě široké tabulky.
V příští lekci, Referenční a primitivní datové typy v PHP, si vysvětlíme referenční datové typy v PHP.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 3457x (5.78 MB)
Aplikace je včetně zdrojových kódů v jazyce PHP