Lekce 2 - .htaccess, autoloader a obecný kontroler
V minulé lekci, Popis MVC architektury, jsme si vysvětlili MVC architekturu.
Již víme, že stránka se bude skládat z komponent 3 typů: kontrolerů,
modelů a pohledů. Dnes si připravíme prostředí, začneme souborem
.htaccess
, dále si v index.php
nastavíme PHP dle
našich potřeb a vytvoříme předka pro naše kontrolery.
Co budete potřebovat je zprovozněný lokální server (viz. XAMPP
- Instalace Apache, PHP a MySQL na Windows), ale to již určitě máte.
Přesuňme se tedy do výchozí složky (v XAMPP defaultně
c:/xampp/htdocs
) a vše v ní odstraňme.
Pozor! Je opravdu důležité, aby jste systém vložili právě do této kořenové složky, když pro něj uděláte podsložku, nebude fungovat!
Je to kvůli hezkým URL adresám, viz dále. Pokud máte na localhostu více projektů, nastavte pro projekt subdoménu.
Adresářová struktura
Vytvořme si 3 složky pro nám již známe 3 typy komponent. Budou se
jmenovat: kontrolery/
, modely/
a
pohledy/
. Rovnou si zde připravte i soubory .htaccess
a index.php
.
.htaccess
Určitě znáte soubor .htaccess
. Slouží ke konfiguraci
webserveru Apache a určuje, co se má stát, když uživatel vyťuká URL
adresu. Vše se děje ještě předtím, než se vůbec spustí jazyk PHP jako
takový.
Vytvořme tedy tento soubor (i s tou tečkou na začátku názvu) v
kořenové složce. Kolega jednou pravil, že stejně jako nechce pochopit
ženu, tak nechce pochopit .htaccess
. Nastavení Apache je opravdu
dost krkolomné a proto si s ním nelamte hlavu a berte ho jako hotovou
věc.
Jako první zakážeme výpis souborů ve složce na webu, budou tedy zvenku skryty, což my chceme. Přidáme řádek:
Options -Indexes
Hezké URL adresy
Klasická adresa PHP aplikace vypadá asi takto:
http://wwww.domena.cz/index.php?clanek=nazev-clanku¶metr=hodnota
To je poměrně ošklivé, že? V naší aplikaci budeme používat tzv. hezké URL adresy, ta samá adresa bude u nás vypadat takto:
http://wwww.domena.cz/nazev-clanku/hodnota
To je mnohem hezčí. Zpracování URL adres necháme plně na PHP a v Apache
toto "vypneme" a všechny dotazy přesměrujeme na soubor
index.php
, kde si URL sami zpracujeme. Apache by totiž jinak bral
nazev-clanku jako složku a tam hledal podsložku hodnota a v ní index. Zapneme
přesměrovávací engine a přidáme pravidlo k přesměrování, kde až na
určité typy souborů v URL přesměrujeme vždy na index.php
:
RewriteEngine On # RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule !\.(css|js|icon|zip|rar|png|jpg|gif|pdf)$ index.php [L]
Znak "#" je komentář, příkaz RewriteBase /
je
tedy zakomentovaný. To proto, že na localu ho nepotřebujeme, ale některé
webservery v produkci (až budeme web nahrávat na internet) bez tohoto
přepínače nefungují, až budete hotový web nahrávat na server, musíte to
zkusit
RewriteCond určují, že se nemá přesměrovat v případě, že soubor nebo složka existuje. Pokud tedy voláme např.:
http://wwww.domena.cz/soubor.txt
Bude tento soubor stažen (pokud existuje) a pokud ne, budeme přesměrováni na index. Kdybychom přesměrovali úplně vše (bez těch několika podmínek), nemohli bychom stahovat žádné soubory a vždy by se nám zobrazil index. Přesměrování jsme si ještě pojistili výčtem nejdůležitějších přípon, které se nebudou přesměrovávat. Všechny ostatní URL adresy směřují na index.
Jako poslední do .htaccess
přidáme zpracování přípony
.phtml
, aby nám nikdo nekoukal do zdrojáků šablon. Soubor
.phtml
se bude chovat úplně stejně, jako soubor
.php
. Přidejme tento řádek:
AddType application/x-httpd-php .php .phtml
Zde máme hotovo.
index.php
Vytvořme si index.php
, tedy soubor, ve kterém započne
veškerá komunikace a kam se budou směřovat všechny URL adresy.
Celý web budeme tvořit v kódování UTF-8, nastavte si tedy toto kódování jako výchozí ve svém editoru. Pokud používáte IDE (PHPStorm, Netbeans, Eclipse), tak tam je již velmi pravděpodobně nastavené. Pokud se vás bude editor ptát na BOM, tak s ním pracovat nebudeme (kódování UTF-8 without BOM).
Jako první samozřejmě vložíme direktivu <?php
a
nastavíme PHP interní kódování na UTF-8, díky tomu poté budou správně
fungovat PHP funkce pro práci s textovými řetězci. Docílíme toho
takto:
<?php mb_internal_encoding("UTF-8");
Autoloader
V systému budeme často tvořit instance různých tříd a je velmi nepohodlné tyto třídy ručně requirovat/includovat. Proto PHP disponuje možností vytvořit funkci, která se zavolá poté, co je volána neexistující třída. V této funkci si třídu načteme. Třídy se tedy automaticky načítají ve chvíli, kdy je potřebujeme použít.
Načítat budeme vlastně 2 typy tříd: modely (ze složky
modely/
) a kontrolery (ze složky kontrolery/
).
Pohledy u nás nebudou třídami a budou připomínat spíše HTML stránky.
Naše autoload funkce tedy bude muset poznat, zda se jedná o model nebo o
kontroler a podle toho sáhne do příslušné složky. Jak to uděláme?
Opět úplně jednoduše, názvy tříd kontrolerů budou končit na "Kontroler". Funkce autoload by mohla vypadat takto:
function autoloadFunkce(string $trida): void { // Končí název třídy řetězcem "Kontroler" ? if (preg_match('/Kontroler$/', $trida)) require("kontrolery/" . $trida . ".php"); else require("modely/" . $trida . ".php"); }
Prvotní podmínka používá tzv. regulární výraz, který ověří, zda
název třídy končí řetězcem "Kontroler". Pokud ano, načte soubor ze
složky kontrolery/
, v opačném případě třídu bude hledat ve
složce modely/
.
Naší funkci ještě zaregistrujeme, aby ji PHP vykonávalo jako autoloader:
spl_autoload_register("autoloadFunkce");
Až budeme mít nějaké kontrolery a modely, bude nám stačit napsat:
$mu = new ManazerUzivatelu(); $smerovac = new SmerovacKontroler();
Jelikož PHP nebude vědět o třídách ManazerUzivatelu.php
ve
složce modely/
a třídě SmerovacKontroler.php
ve
složce kontrolery/
, zavolá naší funkci
spl_autoload_register()
. Ta nám v prvním případě vykoná
příkaz:
require('modely/ManazerUzivatelu.php');
a v druhém případě:
require('kontrolery/SmerovacKontroler.php');
Stačí založit třídu a nemusíme se o nic starat.
Třída se samozřejmě musí jmenovat stejně, jako soubor, ve kterém je obsažena, ale tak by tomu mělo být vždy.
Ve velmi starém PHP, které bohužel ještě běží na
některých free serverech, není možné používat funkci
spl_autoload_register()
a je místo ní třeba použít starší
__autoload()
, viz PHP manuál.
Obecný kontroler
Vytvořme si ještě abstraktní třídu pro obecný kontroler, ze kterého
budou všechny naše kontrolery dědit. Ve složce kontrolery/
si
založíme Kontroler.php
. Na začátek souboru nezapomeneme vložit
direktivu <?php
.
Třída bude obsahovat 3 atributy. První bude pole s daty, tam si bude
kontroler ukládat data získaná od modelů. Toto pole se následně předá
pohledu, který data vypíše uživateli. Tímto způsobem tedy zrealizujeme
předávání dat mezi modelem a pohledem. Druhý atribut bude název pohledu,
který se má vypsat. Poslední atribut bude hlavička HTML stránky, přesněji
3 její atributy: titulek
, keywords
a
description
, kterou musí mít každá HTML stránka. Atributům
přiřadíme i výchozí hodnoty a datové typy, to je možné od verze PHP
7.
<?php abstract class Kontroler { protected array $data = array(); protected string $pohled = ""; protected array $hlavicka = array('titulek' => '', 'klicova_slova' => '', 'popis' => ''); }
Třída bude mít další 3 metody. Jedna bude ta hlavní, ve které zpracuje
kontroler své parametry. Tu si bude každý kontroler implementovat sám, proto
ji zde označíme pouze jako abstraktní. Pojmenujeme ji jednoduše
zpracuj()
a její argument pojmenujeme $parametry
.
Jako datový typ použijeme array
. Funkce nebude sama o sobě
vracet žádnou hodnotu a proto jí nastavíme návratový typ na
void
:
abstract function zpracuj(array $parametry): void;
Další funkce vypíše pohled uživateli. Pokud je nějaký pohled zadaný,
jednoduše ho requirujeme. Předtím rozbalíme proměnné z pole
$data
pomocí funkce extract()
. Všechny indexy
(klíče) pole budou v šabloně přístupné jako běžné proměnné. Funkce
také nevrací žádnou hodnotu:
public function vypisPohled(): void { if ($this->pohled) { extract($this->data); require("pohledy/" . $this->pohled . ".phtml"); } }
Pokud si tedy v kontroleru uložíme takto nějaký klíč do pole:
$this->data['promenna'] = 'hodnota';
V šabloně bude proměnná přístupná jednoduše takto:
<strong>Proměnná je: </strong><?= $promenna ?>
Pokud jste si všimli, že nejsou ošetřené HTML entity, máte bod. Časem to napravíme.
Jako poslední metodu si do kontroleru přidáme jednoduché přesměrování
na jinou stránku a zastavení zpracování současného skriptu. Bude se nám
často hodit. Jako argument bude funkce přijímat řetězec s URL adresou, na
kterou má přesměrovat. Jelikož běh skriptu končí uvnitř funkce,
použijeme pro ní návratový typ never
.
public function presmeruj(string $url): never { header("Location: /$url"); header("Connection: close"); exit; }
Zdrojové kódy dnešního výtvoru máte samozřejmě jako vždy ke stažení níže.
V příští lekci, Směrovač (router), si vytvoříme svůj první kontroler, bude jím směrovač (router)
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 4246x (2.97 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP