Body zdarma Body zdarma
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde

Lekce 3 - Směrovač (router)

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, .htaccess, autoloader a obecný kontroler, jsme si nastavili .htaccess, vytvořili index.php a obecný kontroler. Dnes se budeme věnovat směrovači, tedy komponentě, která podle URL adresy nasměruje požadavek na správný kontroler.

Směrovač

Směrovač (anglicky router) dostane URL adresu, kterou si zpracuje a na jejím základě zavolá příslušný kontroler. Opět je několik způsobů, kterými lze směrovač implementovat a opět jsem vybral ten nejjednodušší. Princip směrovače nápadně připomíná princip kontroleru, toho také využijeme, směrovač bude kontroler.

Směrovač tedy přidáme jako kontroler. Ve složce kontrolery vytvoříme soubor SmerovacKontro­ler.php a do něj stejnojmennou třídu, která bude dědit z obecného Kontroleru, který jsme si udělali minule. Nezapomeneme implementovat abstraktní metodu zpracuj().

Směrovač dle adresy zjistí, který kontroler voláme, vytvoří nám ho a zároveň i uloží do atributu $kontroler, který třídě rovněž přidáme.

<?php

class SmerovacKontroler extends Kontroler
{

    protected $kontroler;

    public function zpracuj($parametry)
    {
    }

}

Možná je trochu matoucí, že v sobě máme vlastně vložené 2 kontrolery, ale je to tak. Kontroler SmerovacKontroler bere URL od uživatele, tu zpracuje a podle ní zavolá příslušný vložený kontroler (např. ClanekKontroler). Oba kontrolery budou mít pohled, Smerovac bude mít šablonu s rozložením stránky (hlavička, menu atd.) a vložený kontroler bude mít šablonu s obsahem dané stránky (článek, kontaktní formulář, přihlašovací obrazovka atd.).

Parsování URL adresy

Jako první si naparsujeme URL adresu a to přímo v PHP. Adresa nám přijde jako textový řetězec, bude vypadat stejně, jako ta v adresním řádku. Pojďme se dohodnout nejprve na jejím formátu, který bude následující a který jsme již minule naťukli:

http://www.domena.cz/kontroler/parametr2/parametr3

V praxi by vypadala třeba takto:

http://www.domena.cz/clanek/nazev-clanku

Říkáme, že voláme kontroler ClanekKontroler a předáváme mu parametr "nazev-clanku". Kontroler si už článek vezme od modelu a předá ho pohledu, který ho vypíše uživateli.

Např. z této URL:

http://www.domena.cz/kontroler/parametr2/parametr3
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

bychom potřebovali získat takového pole:

Array
(
    [0] => kontroler
    [1] => parametr2
    [2] => parametr3
)

Přijdeme třídě tedy metodu parsujURL():

private function parsujURL($url)
{

}

K naparsování url adresy nám PHP poskytuje funkci parse_url(), která za nás sice neudělá všechnu práci, ale pomůže nám oddělit část s protokolem a doménou od části s parametry. Funkce vrátí asociativní pole, část "/kontroler/pa­rametr2/parame­tr3" dostaneme pod indexem "path". Pozor si dáme jen na "/", kterým může tato část začínat, pokud tam je, jednoduše ho odstraníme pomocí funkce ltrim(). Odstraníme také bílé znaky kolem URL (kdyby za ni třeba někdo napsal mezeru), k tomu slouží PHP funkce trim().

$naparsovanaURL = parse_url($url);
$naparsovanaURL["path"] = ltrim($naparsovanaURL["path"], "/");
$naparsovanaURL["path"] = trim($naparsovanaURL["path"]);

Nyní není nic jednoduššího, než si výsledný řetězec rozbít podle lomítek na pole jednotlivých parametrů:

$rozdelenaCesta = explode("/", $naparsovanaURL["path"]);

Výsledek vrátíme a funkce k parsování URL je hotová:

return $rozdelenaCesta;

Volání vloženého kontroleru

Přesuňme se do metody zpracuj(), která se nám na začátku požadavku zavolá. V argumentu $parametry budeme očekávat pole, kde na 1. indexu bude URL adresa. Tu si naparsujeme pomocí naší metody:

$naparsovanaURL = $this->parsujURL($parametry[0]);

Zatím nebudeme ošetřovat případy, kdy je URL zadána nekompletní nebo neexistující.

Získání názvu třídy

První úkol bude zjistit jméno třídy kontroleru. Již víme, že název kontroleru je 1. parametr v naparsované URL adrese. Pro URL adresy však platí jiné konvence, než pro názvy tříd. Proto nám název kontroleru přijde jako "nazev-kontroleru" a my z něj potřebujeme vytvořit "NazevKontrole­ruKontroler", tedy např. řetězec "clanek" převedeme na "ClanekKontroler" a "vypis-uzivatelu" na "VypisUzivate­luKontroler". Na tento převod si opět vytvoříme ve třídě metodu, bude se jmenovat pomlckyDoVelblou­diNotace();

private function pomlckyDoVelbloudiNotace($text)
{

}

Použijeme PHP funkci ucwords(), která zvětší počáteční písmeno všech slov ve větě. Funkce sice není UTF-safe, ale to nám zde nevadí. Z parametru si tedy nejprve uděláme větu a to jednoduše tak, že pomlčky nahradíme mezerami:

$veta = str_replace('-', ' ', $text);

Následně zvětšíme první písmena slov a mezery odstraníme:

$veta = ucwords($veta);
$veta = str_replace(' ', '', $veta);

To je vše. Kód by šel napsat i do jednoho řádku, ale pro potřeby tutoriálu jsem ho rozepsal. Metoda převede např. řetězec "vypis-uzivatelu" na VypisUzivatelu. Výsledek navrátíme:

return $veta;

Vraťme se do metody zpracuj() a zjistěme si název třídy kontroleru pomocí naší nové metody:

$tridaKontroleru = $this->pomlckyDoVelbloudiNotace(array_shift($naparsovanaURL)) . 'Kontroler';

Pomocí array_shift() jsme získali 1. parametr z naparsované URL a zároveň ho z tohoto pole i odstranili, již ho tam totiž nebudeme potřebovat.

Název třídy kontroleru si pro testovací účely pouze vypišme:

echo($tridaKontroleru);

Stejně tak si vypišme i zbytek pole z URL adresy:

echo('<br />');
print_r($naparsovanaURL);

Volání směrovače

Přesuňme se do index.php a vytvořme si zde směrovač. Necháme ho zpracovat URL adresu, kterou v PHP nalezneme v superglobálním poli $_SERVER pod klíčem REQUEST_URI. Hodnotu ještě musíme vložit do pole, jelikož to metoda zpracuj() očekává:

$smerovac = new SmerovacKontroler();
$smerovac->zpracuj(array($_SERVER['REQUEST_URI']));

Díky autoloaderu zminula se nám třída SmerovacKontroler sama načte. Celou magii si vyzkoušíme, zadáme následující URL:

localhost/clanek/nazev-clanku/dalsi-parametr

A měli bychom dosáhnout následujícího výsledku:

Your page
localhost/cla­nek/nazev-clanku/dalsi-parametr

Směrovač nám tedy funguje, z URL adresy nám zjistil název kontroleru a pole parametrů. Pro dnešek toho již bylo dost. Příště, v lekci Propojení kontroleru a pohledu, si systém zprovozníme.


 

Stáhnout

Staženo 2789x (4.21 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
28 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
.htaccess, autoloader a obecný kontroler
Všechny články v sekci
Jednoduchý redakční systém v PHP objektově (MVC)
Miniatura
Následující článek
Propojení kontroleru a pohledu
Aktivity (8)

 

 

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

Avatar
Alma Mater
Člen
Avatar
Alma Mater:27. ledna 20:36

$naparsovanaURL = $this->parsujURL($pa­rametry[0]);

$parametry[0]; index 0 by mal byť s hodnotou $parametry[0]= clanok

Odpovědět 27. ledna 20:36
Kopírovanie je forma zdieľania informácii, bez autorských práv sa informácie nezadržiavajú - šíria sa tam kde treba..
Avatar
Alma Mater
Člen
Avatar
Alma Mater:27. ledna 20:49
$naparsovanaURL = $this->parsujURL($parametry[0]);

$parametry[0]; pole s indexom 0 by mal byť s hodnotou $parametry[0]= clanek;

Prečo vypisuje pri print_r ($this->parsujURL($pa­rametry[0])); cele pole a nie iba hodnotu poľa??

ako vypíšem hodnotu napr.poľa indexu 1?? keď toto mi vykazuje chybu
echo ($this->parsujURL($pa­rametry[1]));

Odpovědět 27. ledna 20:49
Kopírovanie je forma zdieľania informácii, bez autorských práv sa informácie nezadržiavajú - šíria sa tam kde treba..
Avatar
Odpovídá na Alma Mater
Michal Šmahel:28. ledna 17:03

Ahoj, nech si vypsat proměnnou $parametry funkcí var_dump(). Je to testovací funkce, která ti detailně zobrazí strukturu pole v ní uloženého.

Pokud tě výsledek nějak překvapí, projdi si celou cestu změn této proměnné. Když bys narazil na něco, čemu nerozumíš, ještě napiš.

Odpovědět 28. ledna 17:03
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
Alma Mater
Člen
Avatar
Odpovídá na Michal Šmahel
Alma Mater:30. ledna 1:18
       <?php

      $url = "http://www.mydomain.com/clanek/nazev-clanku/dalsi-parametr";

$naparsovanaURL = parse_url($url);
$naparsovanaURL["path"] = ltrim($naparsovanaURL["path"], "/");
$naparsovanaURL["path"] = trim($naparsovanaURL["path"]);
$rozdelenaCesta = explode("/", $naparsovanaURL["path"]);

echo('<br />');
print_r ($rozdelenaCesta); // vypíše pole: Array ( [0] => clanek [1] => nazev-clanku [2] => dalsi-parametr )


$tridaKontroleru = (array_shift($rozdelenaCesta)) . 'Kontroler';

echo('<br />');
echo($tridaKontroleru); //vypíše: clanekKontroler

echo('<br />');
echo('<br />');
print_r ($rozdelenaCesta);//vypíše:Array ( [0] => nazev-clanku [1] => dalsi-parametr )

echo('<br />');
echo ($rozdelenaCesta[1]); //vypíše: dalsi-parametr

?>

všetko čo chcem z lekce 3 aby mi vypísalo hodnotu poľa: dalsi-parametr,vieš mi to napísať?

Odpovědět 30. ledna 1:18
Kopírovanie je forma zdieľania informácii, bez autorských práv sa informácie nezadržiavajú - šíria sa tam kde treba..
Avatar
Alma Mater
Člen
Avatar
Odpovídá na Alma Mater
Alma Mater:30. ledna 3:21
// pôvodná časť súboru:index.php
$smerovac = new SmerovacKontroler();
$smerovac->zpracuj(array($_SERVER['REQUEST_URI'])); // hodnota v poli s indexom 0

//upravená časť súboru:index.php
$smerovac = new SmerovacKontroler();
$smerovac->zpracuj($_SERVER['REQUEST_URI']); // hodnota v reťazci


// pôvodná časť súboru:SmerovacKontroler.php

public function zpracuj($parametry)
    {

                $naparsovanaURL = $this->parsujURL($parametry[0]);


             echo('<br />');
                print_r($parametry);    //vypíše: Array ( [0] => /clanek/nazev-clanku/dalsi-parametr )

// kontroler je 1. parametr URLArray ( [0] => /clanek/nazev-clanku/dalsi-parametr

$tridaKontroleru = $this->pomlckyDoVelbloudiNotace(array_shift($naparsovanaURL)) . 'Kontroler';
                 echo('<br />');
                echo($tridaKontroleru); //vypíše: ClanekKontroler

                echo('<br />');
                print_r($naparsovanaURL);//vypíše: Array ( [0] => nazev-clanku [1] => dalsi-parametr )
    }

// upravená časť súboru:SmerovacKontroler.php

 public function zpracuj($parametry)
    {
                $naparsovanaURL = $this->parsujURL($parametry); //odkazuje na reťazec nie na pole.

                echo('<br />');
                print_r($parametry); //vypisuje: /clanek/nazev-clanku/dalsi-parametr

                $tridaKontroleru = $this->pomlckyDoVelbloudiNotace(array_shift($naparsovanaURL)) . 'Kontroler';
                 echo('<br />');
                echo($tridaKontroleru); // vypisuje: ClanekKontroler

                echo('<br />');
                print_r($naparsovanaURL); // vypisuje: Array ( [0] => nazev-clanku [1] => dalsi-parametr )

}

Až teraz som si všimol že, pôvodné súbory predávaju url do poľa Array ( [0] => /clanek/nazev-clanku/dalsi-parametr

ďalší index už neexistuje. Prečo autor neodkazoval url do reťazca ako mam uvedené upravenom kóde ale dával to do poľa:-). Prečo to treba dať do poľa?

Odpovědět 30. ledna 3:21
Kopírovanie je forma zdieľania informácii, bez autorských práv sa informácie nezadržiavajú - šíria sa tam kde treba..
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Odpovídá na Alma Mater
Michal Šmahel:30. ledna 17:21

Aha, takhle. Být tebou bych to nechal podle Davida. Svou úpravou porušuješ dědičnost.

Články zatím nejsou převedeny pod verzi PHP 7+, tedy nevyužívají striktní typování. Metoda zpracuj() je zděděna ze třídy Kontroler, kde je deklarována. Aktualizovaná deklarace by vypadala nějak takto:

// Kontroler

public abstract function zpracuj(array $parametry): void;

// ...

Jak je vidět, parametry se ve všech implementacích této abstraktní metody budou předávat jako pole. Je to zejména kvůli tomu, že později (i v tomto seriálu) bude potřeba předávat několik parametrů dalším kontrolerům (těm, které budou volané pro další zpracování a nastavení dat pro obsah). Tebou zmiňovaná implementace tedy nesmí být výjimkou.

Odpovědět 30. ledna 17:21
Nejdůležitější je motivace, ovšem musí být doprovázena činy.
Avatar
Petr
Člen
Avatar
Petr:4. června 7:38

Na localhost se mi vypíše:
Kontroler
Array ( )
Má být:ClanekKontroler
Array ( [0] => nazev-clanku [1] => dalsi-parametr )

nebo:
http://localhost/…lsi-parametr se vypíše:
The requested URL /clanek/nazev-clanku/dalsi-parametr was not found on this server.

Je to ze vzorového ITnetworkMVC02
Netuším, kde je chyba. /clanek/ neexistuje. Jinak apache2 a localhost funguje korektně. (phpinfo())

 
Odpovědět 4. června 7:38
Avatar
Jan Lupčík
Šéfredaktor
Avatar
Odpovídá na Petr
Jan Lupčík:9. června 16:14

Ahoj, máš vytvořený soubor .htaccess s obsahem z minulé lekce?

Odpovědět 9. června 16:14
TruckersMP vývojář
Avatar
Petr
Člen
Avatar
Petr:11. června 10:42

Nefunguje mi "RewriteEngine", ani na primitivní akci. Samozřejmě na vzorové také ne.

_htaccess
Options -Indexes
RewriteEngine On
RewriteRule index\.html indexy.html

Mám Linux Mint 19 Cinnamon, apache2 php 7.2. Používám Localhost.

Virtual host mi v home funguje normálně, včetně databáze. Modul rewrite.so je v /usr/lib/apache2/. Asi mod Rewrite na Localhostu nesmí fungovat. Nevím.

 
Odpovědět 11. června 10:42
Avatar
Petr
Člen
Avatar
Petr:12. června 19:33

sudo a2enmod rewrite, to byl ten správný příkaz roota, aby apache povolilo mod RewriteEngine. Potom v htaccess příkaz "RewriteEngine On" dostal smysl.
Dále v sites-enable ve virtual.conf bylo třeba změnit příkazy na:
Options Indexes FollowSymLinks MultiViews
AllowOverride All ... nikoliv none

Restart apache2 a bylo vše funkční.
Takže problém byl jenom v konfiguraci apache, který jsem netušil, jak ho vyřešit.
Google pomohl.

 
Odpovědět 12. června 19:33
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 100. Zobrazit vše