Pouze tento týden sleva až 80 % na e-learning týkající se C# .NET. Zároveň využij akce až 50 % zdarma při nákupu e-learningu. Více informací:
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í.
Slevovy týden 3/50

Lekce 13 - Objektové počítadlo návštěv v PHP - dokončení

V minulé lekci, Objektové počítadlo návštěv v PHP a PDO, jsme začali programovat počítadlo návštěv. Založili jsme si databázovou tabulku a naučili se obsluhovat databázi pomocí ovladače PDO.

V dnešním PHP tutoriálu si ukážeme, jak databázové spojení udržovat, předávat a jak usnadnit spouštění dotazů.

Databázový wrapper

Práce s databází v PDO, jak jsme si ji ukazovali, má jeden nedostatek. Určitě totiž budeme chtít používat databázi na více místech v aplikaci a takto bychom se museli pokaždé znovu připojovat nebo si instanci spojení ručně předávat. Když si vzpomeneme na statiku, tak právě ta nám umožňuje sdílet nějaká data v celé aplikaci. Vytvoříme si tzv. databázový wrapper. Bude se jednat o statickou, pomocnou třídu, kterou obalíme volání PDO. Z toho označení wrapper, jako obal.

Vytvoříme si naši známou složku pro třídy, opět ji pojmenujeme třeba tridy/. Ve složce vytvoříme soubor Databaze.php s následujícím obsahem:

<?php

class Databaze
{

    private static PDO $spojeni;

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

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

    public static function dotaz(string $sql, array $parametry = array()) : PDOStatement
    {
        $dotaz = self::$spojeni->prepare($sql);
        $dotaz->execute($parametry);
        return $dotaz;
    }

}

Třída je velmi krátká a obsahuje dva privátní statické atributy. Jedním je nastavení PDO, druhým je právě připojená instance PDO, kterou budeme v aplikaci sdílet.

Ve třídě dále nalezneme dvě veřejné statické metody. Jednu pro připojení, která vytvoří instanci PDO a tu uloží do statické proměnné $spojeni. Tam připojená instance zůstane až do skončení skriptu. Druhá statická metoda nám umožňuje zadat dotaz a jeho parametry. Dotaz je potom předán instanci PDO a metoda navrátí to, co navrátil dotaz. Wrapper je velmi jednoduchý a během tohoto i dalších seriálů ho budeme ještě vylepšovat. Zatím nám však stačí.

Třída SpravceNavstev

Logiku ke správě návštěv umístíme do nové třídy SpravceNavstev. Určitě budeme potřebovat metodu k zaznamenání návštěvy, přesněji k uložení zobrazení. Dále se nám bude hodit metoda, která vrátí celkový počet zobrazení a unikátních návštěvníků. Na konec přidejme metodu, která vrátí návštěvy a zobrazení za posledních několik dní.

Naše třída bude vypadat asi takto:

<?php

class SpravceNavstev
{

    public function zapocitej() : void
    {
        Databaze::dotaz('
            INSERT INTO `zobrazeni`
            (`ip`, `datum`)
            VALUES (?, ?)
        ', array($_SERVER['REMOTE_ADDR'], time()));
    }

    public function zobrazeniCelkem() : int
    {
        $vysledek = Databaze::dotaz('
            SELECT COUNT(*) AS `pocet`
            FROM `zobrazeni`
        ');
        $data = $vysledek->fetch();
        return $data['pocet'];
    }

    public function zobrazeniZa(int $dnu) : int
    {
        $vysledek = Databaze::dotaz('
            SELECT COUNT(*) AS `pocet`
            FROM `zobrazeni`
            WHERE `datum` > ?
        ', array(time() - $dnu * 86400));
        $data = $vysledek->fetch();
        return $data['pocet'];
    }

    public function uipCelkem() : int
    {
        $vysledek = Databaze::dotaz('
            SELECT COUNT(DISTINCT `ip`) AS `pocet`
            FROM `zobrazeni`
        ');
        $data = $vysledek->fetch();
        return $data['pocet'];
    }

    public function uipZa(int $dnu) : int
    {
        $vysledek = Databaze::dotaz('
            SELECT COUNT(DISTINCT `ip`) AS `pocet`
            FROM `zobrazeni`
            WHERE `datum` > ?
        ', array(time() - $dnu * 86400));
        $data = $vysledek->fetch();
        return $data['pocet'];
    }

    public function vypisStatistiky() : void
    {
        echo('<table>');
            echo('<tr>
                <td>Zobrazení celkem</td>
                <td>' . $this->zobrazeniCelkem() . '</td>
            </tr>');
            echo('<tr>
                <td>UIP celkem</td>
                <td>' . $this->uipCelkem() . '</td>
            </tr>');
            echo('<tr>
                <td>Zobrazení měsíc</td>
                <td>' . $this->zobrazeniZa(30) . '</td>
            </tr>');
            echo('<tr>
                <td>UIP mesíc</td>
                <td>' . $this->uipZa(30) . '</td>
            </tr>');
            echo('<tr>
                <td>Zobrazení týden</td>
                <td>' . $this->zobrazeniZa(7) . '</td>
            </tr>');
            echo('<tr>
                <td>UIP týden</td>
                <td>' . $this->uipZa(7) . '</td>
            </tr>');
        echo('</table>');
    }

}

Ve třídě používáme náš statický databázový wrapper. Obsahuje celkem 6 jednoduchých metod. První je metoda pro uložení nového zobrazení. Tento dotaz jsme si již uváděli, teď jen používáme náš wrapper. Další 2 metody vracejí buď celkový počet zobrazení nebo počet zobrazení za posledních několik dní. Podobně potom máme 2 metody pro UIP. Všechny metodu jsou veřejné, kdybychom si někde v aplikaci chtěli zjistit nějakou statistiku samostatně.

Pokud z výsledku dotazu potřebujeme přečíst nějakou hodnotu, je třeba nejprve zavolat na výsledku metodu fetch() nebo fetchAll().

fetch() vrátí další řádek výsledku (při základním nastavení jako asociativní pole), fetchAll() vrátí dvojrozměrné pole všech řádků, které dotaz vrátil. fetch() budeme volat v případě, kdy nás zajímá jen jeden řádek, fetchAll() potom tehdy, kdy nás zajímají všechny řádky. Na výsledku můžeme zavolat také rowCount(), která vrátí počet řádků ve výsledku. Nepoužívejte ji však místo SQL příkazu COUNT! K zajištění počtu unikátních IP adres jsme použili klauzuli DISTINCT. Pokud jste četli zdejší MySQL seriál, tak jistě víte, že právě ta pracuje s unikátními řádky.

V dotazech dále používáme konstantu 86400, což je počet vteřin ve dni :) Konstantu vynásobíme počtem dní a výsledek odečteme od aktuálního času, který vrací funkce time(). Máme potom datum, od kterého nás statistiky zajímají. Takováto práce s datem a časem mi přijde velmi přehledná, ale to je asi věc názoru. Klidně můžete používat databázový DATETIME.

Zprovoznění aplikace

Pojďme vše zprovoznit. Vraťme se do index.php, vložme do něj HTML strukturu, PHP autoloader (abychom nemuseli třídy načítat ručně) a nakonec se připojme k databázi:

<!DOCTYPE html>

<html lang="cs-cz">
    <head>
            <meta charset="utf-8" />
            <title>OOP v PHP na ITnetwork</title>
    </head>

    <body>
    <h1>Návštěvnost webu</h1>
        <?php
        mb_internal_encoding("UTF-8");

        function nactiTridu($trida) : void
        {
            require("tridy/$trida.php");
        }

        spl_autoload_register("nactiTridu");

    Databaze::pripoj('localhost', 'root', '', 'pocitadlo_db');
    ?>
    </body>
</html>

Spojení se uložilo do statické proměnné a už se o něj nemusíme starat, zůstane tam do skončení skriptu.

Započítání návštěvy a výpis tabulky návštěv vložíme pro jednoduchost obojí do indexu. V praxi je zjištění počtu návštěv velmi náročná operace (kvůli COUNT ve velkém počtu záznamů) a proto ji budeme volat jen někde v administraci, abychom se podívali jak si stojíme. Naopak započtení návštěvy zavoláme na každé stránce webu:

$spravceNavstev = new SpravceNavstev();
$spravceNavstev->zapocitej();
$spravceNavstev->vypisStatistiky();

Výsledek jsme nijak nestylovali, takže vypadá skromně:

Your page
localhost

Výsledek dnešního snažení je ke stažení pod lekcí.

V následujícím cvičení, Řešené úlohy k 12.-13. lekci OOP v PHP, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

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 1050x (4.01 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Objektové počítadlo návštěv v PHP a PDO
Všechny články v sekci
Objektově orientované programování (OOP) v PHP
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 12.-13. lekci OOP v PHP
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
81 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity