IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

7. diel - Databázový wrapper

V minulej lekcii, Založenie databázy a prístupy k nej v PHP , sme si pripravili MySQL databázu a pobavili sa o možných prístupoch k databázam z PHP. V dnešnom dieli si naprogramujeme jednoduchý wrapper nad ovládačom PDO.

Wrapper a PDO

Vytvoríme si CRUD wrapper, pomocou ktorého budeme komunikovať s databázou a ktorý nám pomôže začleniť vstup aj výstup z databázy do objektového kódu. Wrapper je všeobecne akýsi "obal" nad niečím zložitejším, kde si definujeme svoje rozhranie, často jednoduchšie. Viac viď. návrhový vzor Adapter (Wrapper). Wrapper postavíme okolo ovládača PDO, ktorý nám poskytuje priamo PHP a ktorý je jeden z najlepších. Umožňuje aj prepnúť na inú databázu, mapovať entity ako objekty a podobne. Spomeniem fakt, že samotné PDO je vlastne tiež wrapper, čiže balíme wrapper, ale už to tak je. Zjednodušíme si tým ďalšie kód aplikácie.

Model

Wrapper je bezpochyby logika a preto bude patriť medzi modelmi. V priečinku modely vytvorme triedu Db. Názov je krátky a jednoduchý, pretože ju budeme často používať.

class Db
{

}

Zdieľanie inštancie spojenie

Budeme chcieť, aby sa po pripojení k databáze danej spojenie uložilo a bolo prístupné zo všetkých miest našej aplikácie. Existuje na to niekoľko návrhových vzorov, ideálne Dependency Injection, jednoduchšie Service Locator alebo Singleton (aj keď ten je skôr antipattern). Keďže sa jedná o pokročilejšie techniky, nebudeme sa s týmto v našom seriáli vôbec zaťažovať a použijeme namiesto nich statiku. Všetko v triede bude statické, dáva to tu celkom zmysel, keďže ide o pomocnú triedu.

Pridajme si teda statickú premennú $ spojení:

private static $spojeni;

Pripojenie

PDO funkcie pre pripojenie k databáze chce ako parameter nastavenia. Jedná sa o asociatívne pole, kde používame ako kľúče konštanty z triedy PDO. Pridajme triede teda ešte toto pole a rovno v ňom nastavme spôsob reakcie na databázové chyby a inicializačný príkaz. Chyby nastavíme tak, aby spôsobovali výnimky. Inicializačný príkaz bude "SET NAMES utf8", ktorý by ste mali všetci dobre poznať, nastaví kódovanie, aby fungovala diakritika. Ak nie ste na nejaké naozaj staré databázu, pridáme aj nastavenie PDO :: ATTR_EMULATE_PRE­PARES, ktoré prenechá vkladanie parametrov do dotazu na databázu, je to tak bezpečnejšie a kvalitnejšie. V triede pribudne táto premenná:

private static $nastaveni = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
    PDO::ATTR_EMULATE_PREPARES => false,
);

Máme všetko pripravené na to, aby sme pridali metódu pre pripojenie k databáze:

public static function pripoj($host, $uzivatel, $heslo, $databaze)
{
    if (!isset(self::$spojeni))
    {
        self::$spojeni = @new PDO(
            "mysql:host=$host;dbname=$databaze",
            $uzivatel,
            $heslo,
            self::$nastaveni
        );
    }
}

Kód vychádza z článku PDO objektovo a modulárne.

Metóda jednoducho vytvorí inštanciu PDO s klasickými parametrami pre pripojenie k databáze (hostiteľ, užívateľské meno, heslo a názov databázy) a tú uloží do statickej premennej $ spojení. Túto inštanciu môžeme aj vrátiť. Máme ošetrené aj to, aby sa databáza nepokúšala znova pripojiť, keď už spojenie existuje.

Volanie dotazu

Teraz potrebujeme metódu na volanie databázového dotazu. PDO perfektne zvláda tzv. Prepared statements. Jedná sa spôsob vkladania premenných (alebo presnejšie nevkládání) do dotazu. Pri starých ovládačov sa premenné vkladali do textového reťazca s dotazom. Určite ste niekedy videli otázka:

// Tento kód je nebezpečný
mysql_query('SELECT * FROM `uzivatele` WHERE `jmeno` = "' . $jmeno . '"');

Takýto dotaz je potenciálne nebezpečný, pretože ak obsah premennej pochádza od užívateľa, môže do databázy prepašovať škodlivý kód (viac viď. Pojem SQL injection, bolo o ňom na ITnetwork napísané už dosť). Postarom sa to riešilo takto:

mysql_query('SELECT * FROM `uzivatele` WHERE `jmeno` = "' . mysql_real_escape_string($jmeno) . '"');

Funkcia s krkolomným názvom mysql_real_es­cape_string () zabezpečila premennú tzv. Zescapováním nebezpečných znakov. Zabezpečenie však nebolo dokonalé, napr. Pre čísla.

Prepared statements rieši problém inak, premennú do dotazu jednoducho nevkladá a namiesto nej je vložený zástupný znak "?". Takýto dotaz sa "pripraví". Potom je spustený spolu s poľom parametrov, ktoré sa do neho dosadí namiesto otáznikov. Všetko je teda oddelené a tým pádom aj bezpečné.

Pridajme si do triedy funkciu na získanie jedného riadku z databázy:

public static function dotazJeden($dotaz, $parametry = array())
{
    $navrat = self::$spojeni->prepare($dotaz);
    $navrat->execute($parametry);
    return $navrat->fetch();
}

Na inštanciu spojenie zavoláme metódu prepare (), do ktorej sa vloží text dotazu sa zástupnými znakmi a otázka sa "pripraví". Potom zavoláme metódu execute (), ktorá k zisťovaniu pripojí poľa parametrov a otázka vykoná. Nakoniec získame 1. riadok metódou fetch () a ten vrátime.

Otázka na viac riadkov

Metóda dotazJeden () nám vráti iba jeden riadok, určite ale niekedy budeme potrebovať vyberať viac riadkov. Preto si pridajme metódu dotazVsechny (), ktorá nám vráti pole riadkov, ktoré zodpovedajú dotazu. Reálne by sa táto metóda použila napr. Pre výpis komentárov pod článok.

public static function dotazVsechny($dotaz, $parametry = array())
{
    $navrat = self::$spojeni->prepare($dotaz);
    $navrat->execute($parametry);
    return $navrat->fetchAll();
}

Dotaz na jeden stĺpec

Často sa budeme pýtať tiež len na jeden stĺpec, napr. V dotazoch SELECT COUNT (*) ... Pridáme si metódu dotazSamotny (), ktorá vráti vždy 1. hodnotu v 1. riadku:

public static function dotazSamotny($dotaz, $parametry = array())
{
    $vysledek = self::dotazJeden($dotaz, $parametry);
    return $vysledek[0];
}

Táto metóda je síce veľmi podobná metóde dotazJeden (), takto si však ušetríme niekoľko riadkov a pri opakovanom používaní vo zložitejšie aplikácii nám to príde vhod. To je napokon dôvod existencie celého nášho wrapper.

Dotaz vracajúci ovplyvnený počet riadkov

Najmä pri vkladaní, editáciu a mazanie sa nám bude ešte hodiť metóda vracajúci počet ovplyvnených riadkov. Tá bude vyzerať nasledovne:

// Spustí dotaz a vrátí počet ovlivněných řádků
public static function dotaz($dotaz, $parametry = array())
{
    $navrat = self::$spojeni->prepare($dotaz);
    $navrat->execute($parametry);
    return $navrat->rowCount();
}

Wrapper máme hotový. Nabudúce, v lekcii Výpis článkov z databázy v PHP (MVC) , si pridáme ClanekKontroler a naučíme aplikáciu zobrazovať článok z databázy a zoznam článkov v databáze. Doterajšie projekt je ako vždy k stiahnutiu nižšie.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 2052x (12.39 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP

 

Predchádzajúci článok
Založenie databázy a prístupy k nej v PHP
Všetky články v sekcii
Jednoduchý redakčný systém v PHP objektovo (MVC)
Preskočiť článok
(neodporúčame)
Výpis článkov z databázy v PHP (MVC)
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity