8. díl - Výpis článků z databáze v PHP (MVC)

PHP MVC Výpis článků z databáze v PHP (MVC) American English version English version

V minulém dílu našeho seriálu tutoriálů pro jednoduchý objektový redakční systém v PHP jsme si vytvořili databázový wrapper nad PHP ovladačem PDO. Databázi máme již také připravenou, nic nám nebrání s ní komunikovat.

Připojení

Jako první se musíme k databázi připojit. To provedeme v index.php, těsně před vytvořením směrovače:

// Připojení k databázi
Db::pripoj("127.0.0.1", "root", "", "mvc_db");

Údaje si samozřejmě změňte podle svého webhostingu, takto jsou vyplněné pro localhost. Databázi máme v aplikaci přístupnou, pojďme se ji na něco zeptat.

Model - Správce článků

Vytvoříme třídu s logikou ohledně práce s články, která bude obsahovat jednotlivé SQL dotazy. Třída bude samozřejmě v modelech a jmenovat se bude SpravceClanku. Pro každou databázovou entitu si v našem systému vytvoříme nějakou podobnou třídu. SpravceClanku bude mít následující podobu:

<?php

// Třída poskytuje metody pro správu článků v redakčním systému
class SpravceClanku
{

        // Vrátí článek z databáze podle jeho URL
        public function vratClanek($url)
        {
                return Db::dotazJeden('
                        SELECT `clanky_id`, `titulek`, `obsah`, `url`, `popisek`, `klicova_slova`
                        FROM `clanky`
                        WHERE `url` = ?
                ', array($url));
        }

        // Vrátí seznam článků v databázi
        public function vratClanky()
        {
                return Db::dotazVsechny('
                        SELECT `clanky_id`, `titulek`, `url`, `popisek`
                        FROM `clanky`
                        ORDER BY `clanky_id` DESC
                ');
        }

}

Třída má celkem 2 metody:

  • vratClanek() vrací jeden článek z databáze podle jeho URL. Získávání dat od uživatele není záležitost modelu, všimněte si, že URL mu jednoduše přijde v argumentu metody a neřeší odkud se vzalo. Do podmínky SQL dotazu proměnnou nevložíme přímo, ale místo její hodnoty vložíme zástupný znak (otazník). Všechny parametry SQL dotazu následně předáme databázi jako hodnoty v poli, ona si je do dotazu sama a bezpečně dosadí.
  • vratClanky() vrací seznam všech článků (bez jejich obsahu). Články jsou seřazené sestupně podle ID, tedy od nejnovějších po nejstarší. Všimněte si, že nevybíráme jejich obsah, metodu budeme používat pouze pro výpis seznamu.

Pohledy

Budeme potřebovat 2 pohledy. Jeden pro článek a druhý pro seznam článků.

clanek.phtml

U článku vypíšeme nadpis a potom jeho obsah. Pohled bude následující:

<header>
        <h1><?= $titulek ?></h1>
</header>
<section>
        <?= $obsah ?>
</section>

Druhý pohled necháme na konec lekce.

Kontroler

Máme model, máme pohled, zbývá náš známý prostředník - kontroler, který vše spojí dohromady. ClanekKontroler bude mít následující podobu:

class ClanekKontroler extends Kontroler
{
        public function zpracuj($parametry)
        {
                // Vytvoření instance modelu, který nám umožní pracovat s články
                $spravceClanku = new SpravceClanku();

                // Získání článku podle URL
                $clanek = $spravceClanku->vratClanek($parametry[0]);
                // Pokud nebyl článek s danou URL nalezen, přesměrujeme na ChybaKontroler
                if (!$clanek)
                        $this->presmeruj('chyba');

                // Hlavička stránky
                $this->hlavicka = array(
                        'titulek' => $clanek['titulek'],
                        'klicova_slova' => $clanek['klicova_slova'],
                        'popis' => $clanek['popis'],
                );

                // Naplnění proměnných pro šablonu
                $this->data['titulek'] = $clanek['titulek'];
                $this->data['obsah'] = $clanek['obsah'];

                // Nastavení šablony
                $this->pohled = 'clanek';
        }
}

Kontroler si vytvoří model a získá od něj článek podle URL adresy. Pokud článek nebyl nalezený, vyhodnotí se proměnná s ním jako false a přesměrujeme na ChybaKontroler. Hlavičku stránky nastavíme podle článku, dále pohledu předáme titulek a obsah, aby článek mohl vypsat. Nakonec nastavíme pohled na clanek.phtml.

Pojďme si vše vyzkoušet. Když aplikaci zapneme, uvidíme vypsaný úvodní článek:

Výpis článku z databáze v MVC architektuře v PHP

Můžete si zkusit zadat URL neexistujícího článku, budete přesměrování na chybovou stránku.

clanky.phtml

Seznam článků bude o něco složitější, protože potřebujeme vypsat jejich seznam z pole článků, které dostaneme od databáze. Jak že to ale uděláme, když zatím umíme vypisovat jen jednotlivé proměnné a zde potřebujeme vypsat obsah kolekce? Pojďme si rozšířit naše znalosti o PHP syntaxi, přesněji o šablonové verzi cyklů.

Šablonová syntaxe PHP

Kromě direktivy <?= nám PHP nabízí šablonové ekvivalenty nejběžnějších konstrukcí jazyka. Můžeme tak do pohledu (šablony) vložit minimální část logiky, která nebude znepřehledňovat HTML kód. Tyto šablonové ekvivalenty nám totiž umožňují vkládat PHP do HTML.

Bez znalosti šablonové syntaxe PHP by výpis seznamu článků do tabulky vypadal asi takto:

<h1>Seznam článků</h1>
<table>
        <?php
                foreach ($clanky as $clanek)
                {
                        echo('<tr><td><h2>
                                        <a href="clanek/' . $clanek['url'] . '">
                                                        ' . $clanek['titulek'] . '</a>
                                        </h2>' . $clanek['popisek']);
                        echo('</td></tr>');
                }
        ?>
</table>

HTML je nezvýrazněné, šablona nepřehledná., ztrácíme se v uvozovkách jak řetězce spojujeme. Pojďme kód převést do šablonové verze:

<h1>Seznam článků</h1>
<table>
<?php foreach ($clanky as $clanek) : ?>
        <tr>
                <td>
                        <h2><a href="clanek/<?= $clanek['url'] ?>"><?= $clanek['titulek'] ?></a></h2>
                        <?= $clanek['popisek'] ?>
                </td>
        </tr>
<?php endforeach ?>
</table>

Všimněte si, že cyklus foreach má za sebou napsanou dvojtečku a potom se ukončí PHP direktiva. Toto je šablonová verze foreach, která pro každý prvek vyechuje HTML kód, který je napsaný pod ním a to až do značky endforeach. Podobně lze přepsat i cykly for a while nebo podmínky if. HTML je zapsané jako HTML, ne jako string. Proměnné vložíme do HTML pomocí <?=, jak jsme zvyklí. Soubor clanky.phtml si s tímto obsahem ve složce pohledy vytvořte.

Pozn.: V šablonách stále neošetřujeme HTML entity a vystavujeme se tak útoku XSS. Napravíme to hned v příštím dílu.

Úprava ClanekKontroler

Seznam článků bude vypisovat ClanekKontroler a to v případě, když mu nezadáme žádný parametr. Kontroler jednoduše podmínkou rozpůlíme na dvě části. Jedna vypisuje konkrétní článek a druhá seznam. Pro tyto akce by se daly použít 2 kontrolery, ale obvykle se zapisují do jednoho, když spolu úzce souvisí. Metodu zpracuj() upravíme do následující podoby:

public function zpracuj($parametry)
{
        // Vytvoření instance modelu, který nám umožní pracovat s články
        $spravceClanku = new SpravceClanku();

        // Je zadáno URL článku
        if (!empty($parametry[0]))
        {
                // Získání článku podle URL
                $clanek = $spravceClanku->vratClanek($parametry[0]);
                // Pokud nebyl článek s danou URL nalezen, přesměrujeme na ChybaKontroler
                if (!$clanek)
                        $this->presmeruj('chyba');

                // Hlavička stránky
                $this->hlavicka = array(
                        'titulek' => $clanek['titulek'],
                        'klicova_slova' => $clanek['klicova_slova'],
                        'popis' => $clanek['popisek'],
                );

                // Naplnění proměnných pro šablonu
                $this->data['titulek'] = $clanek['titulek'];
                $this->data['obsah'] = $clanek['obsah'];

                // Nastavení šablony
                $this->pohled = 'clanek';
        }
        else
        // Není zadáno URL článku, vypíšeme všechny
        {
                $clanky = $spravceClanku->vratClanky();
                $this->data['clanky'] = $clanky;
                $this->pohled = 'clanky';
        }
}

Nyní přejděme na kontroler clanek a nezadáme URL článku, který se má zobrazit. Zobrazí se seznam všech článků na webu:

Seznam článků na MVC webu v PHP

Příště se budeme věnovat zabezpečení šablon proti XSS.


 

Stáhnout

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

 

  Aktivity (2)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

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


 


Miniatura
Předchozí článek
Databázový wrapper
Miniatura
Následující článek
Zabezpečení šablon

 

 

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

Avatar
Bebbana
Člen
Avatar
Bebbana:

Ahoj, vše mám udělané přesně podle návodu, ale když spustím web přímo z netbeans, nespustí se mi úvodní článek, ale chybová stránka. Problém je v metode zpracuj() ve třídě SmerovacKontroler:

public function zpracuj($parametry)
    {
        // vytvori pole kde na 0.indexu je cast nazvu kontroleru, napr. "clanek"
        $naparsovanaURL = $this->parsujURL($parametry[0]);

        if (empty($naparsovanaURL[0]))
        {
            //presmeruje na uvodni stranku
            $this->presmeruj('clanek/uvod');
        }

...

0. místo v poli $naparsovanaURL nemůže být nikdy prázdné, vždycky tam je přece minimálně "index.php", ne? Proto jsem kod nahradila takhle:

public function zpracuj($parametry)
    {
        // vytvori pole kde na 0.indexu je cast nazvu kontroleru, napr. "clanek"
        $naparsovanaURL = $this->parsujURL($parametry[0]);

        if ($naparsovanaURL[0] == "index.php")
        {
            //presmeruje na uvodni stranku
            $this->presmeruj('clanek/uvod');
        }

...

Může to tak být? Těď už se úvodník zobrazuje. Případně pro jistotu takhle:

 public function zpracuj($parametry)
    {
        // vytvori pole kde na 0.indexu je cast nazvu kontroleru, napr. "clanek"
        $naparsovanaURL = $this->parsujURL($parametry[0]);

        if ($naparsovanaURL[0] == "index.php" || (empty($naparsovanaURL[0])))
        {
            //presmeruje na uvodni stranku
            $this->presmeruj('clanek/uvod');
        }

...
 
Odpovědět 30.11.2015 15:32
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Bebbana
David Čápka:

Projekt je napsaný tak, aby používal pretty-URL, takže pokud to máš správně, nikdy tam index.php mít nebudeš. Nevím teď co to v tomhle okamžiku udělá, když otevřeš index.php, ale určitě bych to z NetBeans na tuto adresu nepouštěl. Dá se to tam někde myslím nastavit, i když mi přijde jednodušší prostě v prohlížeči vyťukat localhost.

Odpovědět 30.11.2015 17:20
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
Bebbana
Člen
Avatar
Bebbana:

Ano, mám nastavene použití pretty-URL, ale netbeans to spustí tak, ze nejdřív zavolá index.php, tj. v adresním řádku se nejdřív objeví localhost/index­.php. Pak se přepne na to, co mám nastavené ve smerovači, momentálně tedy http://localhost/clanek/uvod. "index.php" se tím uloží jako 0. řádek pole $naparsovanaURL. Takže podmínka tak, jak je použitá v tutoriálu nefunguje.

 
Odpovědět 30.11.2015 17:41
Avatar
Bebbana
Člen
Avatar
Bebbana:

Samozřejmě to stačí někde přenastavit (a už i vím kde) ale připsat to do podmínky jen pro jistotu - tím se nic neskazí.

 
Odpovědět 30.11.2015 17:44
Avatar
Michal Bažant:

Ahoj, pro mě velmi přínosný soubor článků, děkuji moc!
Mám dotaz ohledně seznamu článků - jak by se dalo nejlépe vyřešit, aby se zobrazovalo např. 10 článků na stránku a pak pod takovým seznamem by byly řekněme čísla stránek?

 
Odpovědět 20. dubna 16:17
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Michal Bažant
Matúš Petrofčík:

Ahoj, ak si dobre pamätám, tak paginácia sa rieši až v ďalšom seriáli Kompletní e-shop v PHP (Mistrovství MVC) .

Inak počet dodazov vrátených obmedzíš v SQL klauzulou /snad spravne/ LIMIT. Napr.:

SELECT FROM tabulka LIMIT 10
Editováno 20. dubna 17:55
Odpovědět 20. dubna 17:52
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Jan Zamecnik
Člen
Avatar
Jan Zamecnik:

a

Editováno 14. října 10:05
 
Odpovědět 14. října 10:02
Avatar
Jan Zamecnik
Člen
Avatar
Jan Zamecnik:

Docela mě štvalo, že můsí být projekt (vlastněani není založen) v rootu a nemůže být v nějaké podsložce. Tak jsem trochu upravil kód a jede to.
Úpravy jsou tyto:

  1. vše se přehraje do adresare podslozka:
  2. do Kontroler.php se přidá proměnná:
protected $pod_slozka = 'podslozka/';

a ve funkci presmeruj($url) se změní první řádek na

$url = $this->pod_slozka . $url;

to je proto ať přesměrovává na podsložku.

  1. do SmerovacKontroler se do funkce parsujURL přidá za řádek za řádek, kde je ltrim
$naparsovanaURL["path"] = ltrim($naparsovanaURL["path"], $this->pod_slozka);

To je kvůli tomu, ať se zahodí podsložka z parsování.

  1. pak se všude (zatím do rozlozeni.phtml a clanek.phtm) předřadí před složku tento kód
<?= $pod_slozka ?>

Např.:

<li><a href="<?= $pod_slozka ?>clanek/uvod">Úvod</a></li>

To je proto, ať linky odkazují na podsložky.
Vše jsem dělal NetBeans. Je to založeno jako normální projekt s názvem podslozka (u mně je to MVCMag).
Jen spouštění je nastaveno na localhost/MVCMag bez index.php.
Pro produkci se pak změní v kontroleru proměná $pod_slozka na prázdnou hodnotu a je to.

 
Odpovědět 14. října 10:13
Avatar
Jan Zamecnik
Člen
Avatar
Jan Zamecnik:

Ještě doplnění, bez čehož by to nefungovalo:
Tam kde se předávají data do zobrazení je třeba doplnit řádek

$this->data['pod_slozka'] = $this->pod_slozka;

Tj. do SmerovacKontro­ler.php a ClanekKontroler.php funkce

public function zpracuj($parametry)
 
Odpovědět 14. října 10:31
Avatar
sam hud
Člen
Avatar
sam hud:

Ahojte všetci. Testujem kompletný zdroják k tomuto tutoriálu a s jednou vecou si neviem rady. Pridal som dva podobné články klasicky z web rozhrania a potom som chcel ten prvý oodstrániť, a :

  1. Vo výpise článkov ten článok stále existuje
  2. Keď na to kliknem a chcem ho otvoriť, zobrazí sa Chyba 404
  3. Pri kontrole phpMyAdmina tam ten článok stále je

... Z toho vyplýva, že systém nepozná url, ale v databáze nechýba článku nič, aj svoju url má. Zaujímavé sú ďalšie dve veci :

  1. Obidva články majú rovnakú url
  2. Druhý, ktorý nebol odstránený sa po kliknutí zobrazí korektne

Zdroják som okrem pripojenia na databázu a style.css nijak neupravoval.
Poraďte mi prosím vás, ako mám upraviť kód, aby sa po kliknutí článok naozaj odstránil a aby sa odstránil aj údaj z výpisu článkov.
Vďaka za pomoc.

Odpovědět 5. listopadu 16:36
Kde je vule, tam je i cesta
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 35. Zobrazit vše