Hello World
Každá aplikace v PClib začíná dvěma řádky: připojením knihovny a vytvořením objektu aplikace pclib\App, který obsahuje služby a údaje sdílené různými komponentami aplikace nebo se vztahující k aplikaci jako celku. To je vše, ihned poté můžete začít tvořit váš projekt!
<?php include 'vendor/autoload.php'; $app = new pclib\App('nazev_aplikace'); // Zde nasleduje vas kod...
Například formulář můžeme vypsat takto:
$form = new pclib\Form('tpl/sablona_formulare.tpl'); print $form;
Pro výpis údajů z databáze pomocí datagridu se musíme nejprve připojit k databázi:
$app->db = new pclib\Db('pdo_mysql://user:password@localhost/testovaci_databaze');
A pak vytvořit objekt grid a vypsat data z databázové tabulky:
$grid = new pclib\Grid('tpl/sablona_gridu.tpl'); $grid->setQuery('select * from tabulka'); print $grid;
Struktura aplikace
Ačkoliv lze psát kód přímo pod řádek s objektem aplikace, v reálných projektech se kód člení do jednotlivých podadresářů a souborů. Doporučenou strukturu pclib aplikace můžete najít v šabloně https://github.com/lenochware/pclib-app. Podle architektury MVC (Model / View / Controller) se pak akce volané uživatelem definují v příslušném controlleru.
Například k zobrazení formuláře bychom vytvořili akci show:
<?php ... public function showAction() { $form = new pclib\Form('tpl/home/sablona_formulare.tpl'); return $form; } ...
Po zadání adresy http://localhost/moje-aplikace/home/show se v prohlížeči vypíše příslušný formulář.
Při práci s MVC bude v souboru index.php pouze konfigurace aplikace a volání aplikační metody run() a out(), která vykoná příslušný kód a vypíše výsledek do prohlížeče. Níže je obvyklá podoba index.php, která by měla vyhovovat většině aplikací a kterou budeme předpokládat v následujících příkladech.
<?php include 'vendor/autoload.php'; $app = new pclib\App('test_app'); $app->addConfig('./config.php'); $app->db = new pclib\Db('pdo_mysql://user:password@localhost/test_app'); $app->setLayout('tpl/layout.tpl'); $app->run(); $app->out();
Vytvoříme objekt $app, načteme konfiguraci ze souboru config.php, připojíme se k databázi test_app a nastavíme šablonu layoutu do které se budou vypisovat všechny výstupy. Nakonec se podle zavolané url vykoná příslušná akce (metoda controlleru) a vypíše se výsledek.
test-app/ ├── controllers/ ├── models/ ├── tpl/ ├── css/ ├── js/ ├── vendor/ ├── index.php └── config.php
V adresáři controllers/ jsou jednotlivé controllery (potomci třídy pclib\Controller) pro každý modul aplikace. Jestliže používáte pclib ORM, mohou být v models/ databázové modely (potomci třídy pclib\Model). Adresář tpl/ obsahuje soubory šablon obvykle rozdělené do podadresářů pro každý modul. vendor/ je adresář s nainstalovanými knihovnami, spravovaný composerem a css a js obsahuje soubory stylů a javascriptu.
Adresářová struktura není závazná, místa, kde pclib hledají příslušné soubory, lze změnit v konfiguraci.
Konfigurace
Konfigurační soubor načteme při inicializaci aplikace v index.php příkazem $app->addConfig('./config.php'). Konfigurační parametry jsou pak uložené v poli $app->config. Samotný konfigurační soubor tvoří obyčejné php pole $config obsahující konfigurační parametry. Může obsahovat i další obdobná pole $develop a $production.
$config = [ 'konfiguracni-klic-1' => 'hodnota', 'konfiguracni-klic-2' => 'hodnota', ]; $develop = [ 'konfiguracni-klic-2' => 'hodnota pro develop', ]; $production = [ 'konfiguracni-klic-2' => 'hodnota pro produkcni server', ];
Hodnoty v poli $develop se uplatní na vývojovém serveru, $production slouží pro ostrý provoz. Implicitně se $develop načte při spuštění z localhostu a $production všude jinde. Pole $config se načítá vždy.
O jaké prostředí jde udává hodnota $app->environment. $app->environment = 'production' nastaví produkční prostředí. K nastavení podle IP lze použít funkci $app->environmentIp(['ip-adresa' => 'develop', 'ip-adresa' => 'production', ...])
$develop = [ 'pclib.errors' => ['display' => true, 'develop' => true], ]; $production = [ 'pclib.errors' => ['display' => true, 'develop' => false, 'log' => true, /*'template' => 'tpl/error.tpl' */], ];
Pomocí konfiguračního klíče pclib.app můžete nastavit základní konfiguraci objektu aplikace, jako je šablona layoutu, implicitní routa a automaticky spouštěné služby (další možnost je nastavení pomocí php v souboru index.php).
$config = [ 'pclib.app' => [ 'language' => 'cs', 'default-route' => 'products', 'layout' => 'tpl/layout.tpl', 'autostart' => ['db', 'auth', 'fileStorage'], ], 'service.db' => ['dsn' => 'pdo_mysql://user:password@localhost/test-app'], 'service.fileStorage' => ['rootDir' => './uploaded'], ];
Po otevření aplikace se zobrazí stránka products/index, jazyk je nastavený na češtinu a layout se načte z příslušného souboru. Automaticky se spustí služba databáze, autorizační systém a služba pro ukládání souborů.
Ke každé službě můžete přistupovat pomocí $app->jmeno_sluzby např. $app->db. Služby lze konfigurovat klíčem 'service.jmeno_sluzby'.
Seznam konfiguračních parametrůLayout
Layout aplikace je základní šablona aplikace, do které se vkládá veškerý obsah. Nastavíme ji v konfiguraci nebo příkazem $app->setLayout('tpl/layout.tpl'); Layout může vypadat například takto:
<?elements head HEAD scripts "css/website.css,js/global.js,{pclib}/www/pclib.js" messages PRECONTENT noescape string CONTENT noescape ?> <!doctype html> <html lang="cs"> <head> <meta charset="utf-8"> <title>{TITLE}</title> {HEAD} </head> <body> <main> {PRECONTENT}{CONTENT} </main> </body> </html>
Výrazy ve složených závorkách jako {CONTENT} jsou elementy šablony, které jsou nahrazeny vloženým obsahem. V sekci <?elements ?> lze doplnit typ a parametry vypisovaného elementu. Viz šablonovací systém. Layout obsahuje tři hlavní elementy: HEAD pro vkládání stylů a skriptů, PRECONTENT slouží k výpisu notifikačních a varovných hlášení aplikace a CONTENT je vlastní obsah. Hodnota vrácená controllerem bude před vypsáním vložená do layoutu jako CONTENT:
public function helloAction() { return "Hello world!"; }
K layoutu aplikace lze přistupovat pomocí $app->layout a pracovat s ním jako s každou šablonou.
$app->layout->values['TITLE'] = 'Titulek aplikace';
Pokud potřebujeme podmíněně přidat styly a skripty jen pro některou stránku, můžeme to provést pomocí metody layout->addScripts():
$app->layout->addScripts('js/editor.js', 'css/editor.css');
Pokud nějaká část webu používá odlišný layout než zbytek, lze ho snadno změnit:
public function helloAction() { $this->app->setLayout('tpl/hello-layout.tpl'); return "Hello world!"; }
Controllers
Kontrolery obsahují veškeré akce, které aplikace vykonává. Po stisknutí tlačítka nebo zadání webové adresy router rozhodne, která metoda kontroleru se zavolá a předá jí případné parametry. Kontroler je třída odvozená od pclib\Controller, její název končí na Controller a je uložená ve stejnojmeném souboru v adresáři controllers/. Obvykle každému modulu aplikace odpovídá příslušný controller.
Například eshop by mohl obsahovat HomeController, ProductsController a OrdersController pro úvodní obrazovku, přehled a detail produktů a zpracování objednávek - v odpovídajících souborech HomeController.php, ProductsController.php a OrdersController.php
class ProductsController extends pclib\Controller { public function indexAction() { $grid = new pclib\Grid('tpl/products/grid.tpl'); $grid->setQuery("select * from products"); return $grid; } public function showAction($id) { $product = $this->app->db->select('products', ['id' => $id]); if (!$product) $this->app->error("Produkt nenalezen!", "alert alert-danger"); return $this->template('tpl/products/detail.tpl', $product); } }
Metodě kontroleru končící na Action odpovídá url při jehož zadání se zavolá. Například showAction() odpovídá url test-app/index.php?r=products/show nebo při použití friendly url: test-app/products/show. indexAction je speciální a volá se implicitně. Akce mohou mít parametry - například akce show, která zobrazí detail produktu, vyžaduje jako parametr id produktu.
Route | Url | Volaná akce |
---|---|---|
products | /products | ProductsController->indexAction() |
products/show/id:1 | /products/show?id=1 | ProductsController->showAction(1) |
products/moje-oblibene | /products/moje-oblibene | ProductsController->mojeOblibeneAction() |
products/list/sleva:1/kategorie:pc | /products/list?sleva=1&kategorie=pc | ProductsController->listAction(1, 'pc') |
Uvnitř kontroleru můžete přistupovat k objektu aplikace pomocí $this->app. Například ke službě databáze lze přistupovat pomocí $this->app->db. Aplikační funkce $app->error() vypíše chybové hlášení a ukončí aplikaci /druhý parametr jsou css třídy k nastylování messageboxu/
Kontroler obsahuje několik pomocných metod. Funkce $this->template('tpl/products/detail.tpl', $product); vytvoří šablonu produktu a naplní ji hodnotami z pole $product.
Často používaná je funkce redirect(), která přesměruje na příslušnou routu. Takto po aktualizaci produktu přesměrujeme na stránku detailu produktu:
... public function updateAction($id) { $form = new pclib\Form('tpl/products/form.tpl'); if (!$form->validate()) { $this->app->error("Chybně zadané parametry.", "alert alert-danger"); }; $form->update('products', ['id' => $id]); $this->app->message('Položka byla uložena.', "alert alert-success"); $this->redirect('products/show/id:' . $id); }
Načte se formulář, zkontroluje se, jestli je správně vyplněný (podle validačních pravidel v šabloně), uloží se do databáze, nastaví se informační hlášení a nakonec se provede přesměrování.
Pokud uživatel zadá neexistující routu (např. products/xyz) , můžete ji zpracovat, pokud nadefinujete funkci defaultAction():
public function defaultAction($action) { $this->app->error("Stránka neexistuje: " . $action->path, "alert alert-danger"); }
public function deleteAction($id) { $this->authorize('products/delete'); $this->app->db->delete('products', ['id' => $id]); $this->app->message('Položka byla smazána.', "alert alert-success"); $this->redirect('products'); }
Pokud používáte ORM (databázové modely) lze využít pomocné funkce model() a selection() k jejich získání a dotazování.
Získame ORM model produktu s id=1:
$product = $this->model('products', 1); print $product->title;
Procházíme všechny produkty s cenou vyšší než 1000:
$sel = $this->selection('products')->where('price>1000'); foreach($sel as $product) { print $product->title; }
Šablony
Šablony jsou HTML soubory obsahující proměnné šablon {POLE}, jejichž hodnoty se nastavují z kódu. Se šablonami pracuje třída pclib\Tpl a také třídy pclib\Grid a pclib\Form, které přidávají elementy datagridu (stránkování a řazení) resp. elementy formuláře, jako je input, select, textarea a podobně.
Jestliže šablona obsahuje například proměnnou {title}, nastavíme její hodnotu pomocí atributu values: $tpl->values['title'] = 'Titulek šablony'; Výsledné html získáme pomocí funkce html(): print $tpl->html();
Šablona nemusí, ale může, obsahovat sekci <?elements ... ?> kde lze definovat typ, způsob zobrazení, formátování a jiné parametry pro každou proměnnou šablony.
<?elements string description format "n" bind category lookup "categories" string published_at date "d.m.Y" number price format "2,." block sleva noprint ?> <h1>{title}</h1> <p>{description}</p> <p>Kategorie: {category}</p> <p><img src="{@baseurl}{image_path}" class="product-image"></p> <p>Datum vydání: {published_at}</p> {if price}<p>Cena: {price} Kč</p>{/if} {if not price}<p>Cena dohodou.</p>{/if} {block sleva} <div class="alert alert-info">Produkt je ve slevě.</div> {/block}
V horní části je sekce elements, definující formátování některých polí, pod ní je html kód s proměnnými šablony, který se vypíše.
Formátování: V případě pole description se odřádkování zkonvertují na značku <br>, published_at se zformátuje jako datum a cena (price) bude zaokrouhlená na dvě místa s uvedenými oddělovači tisíců a desetinnou tečkou, např. 1,100.50 Kč.
Parametr {@baseurl} je proměnná dostupná v kterékoliv šabloně, obsahující hlavní (nejvyšší) url aplikace.
Jestliže máme databázovou tabulku products, která obsahuje sloupce id, title, description, price a published_at, můžeme výše uvedenou stránku detailu produktu vypsat takto:
$tpl = new pclib\Tpl("tpl/products/detail.tpl"); $product = $this->db->select('products', ['id' => $id]); $tpl->values = $product; return $tpl->html();
Nebo pomocí funkce controlleru template():
$product = $this->db->select('products', ['id' => $id]); return $this->template("tpl/products/detail.tpl", $product);
Někdy je potřeba vypsat části šablony podmíněně. K tomu slouží v šabloně bloky a "ify".
Pokud je cena nenastavená nebo nulová (falsy) vypíše se místo ceny odstavec "Cena dohodou." Blok sleva má v elements atribut noprint, takže se implicitně nezobrazí. Jeho zobrazení lze zapnout příkazem $tpl->enable('sleva'); /Obdobně existuje funkce $tpl->disable();/
Seznam možných typů a parametrů elementů pro třídu Tpl viz referenční manuál.
Šablonu je možné rozdělit na více částí a vkládat podšablony pomocí include. Například jestliže máme ve více formulářích checkboxy souhlas s obchodními podmínkami a zpracování osobních údajů, můžeme vytvořit podšablonu agreement a pak ji použít ve všech formulářích:
<?elements class form name "order-form" include agreement file "tpl/partial/agreement.tpl" ... ?> ...definice objednávkového formuláře... {agreement}
Pclib před vykreslením šablony vloží šablonu agreement a sloučí i definici elementů obou šablon.
Občas se může hodit vložit do šablony přímo i výsledek volání nějaké routy. To zajistí element action.
<?elements action title_image route "catalog/image/id:{id}" ... ?> {title_image}
Tento kód vloží do šablony obsah cesty catalog/image, tedy výsledek volání CatalogController->imageAction($id). Routa může obsahovat i parametry.
Grid
Třída Grid (potomek Tpl) slouží k výpisu záznamů, jako je seznam produktů, ve stránkovatelném seznamu. Podle jednotlivých sloupců lze řadit a seznam lze filtrovat.
public function indexAction() { $grid = new pclib\Grid('tpl/products/grid.tpl', 'products'); $grid->setQuery("select * from products"); return $grid; }
Vytvoříme šablonu (druhý parametr konstruktoru říká, že řazení, stránkování a filtr se mají pamatovat v session proměnné 'products'. To zajistí, že se nastavení bude pamatovat i když přejdete na jinou stránku. Je nutné v index.php inicializovat sessions pomocí session_start() ). Následuje dotaz, který je zdrojem záznamů. Za předpokladu, že v tabulce products jsou sloupce id, title, price atd. můžeme je použít v šabloně gridu.
<?elements class grid name "products" string title lb "Název produktu" sort string description format "n" skip bind category lookup "categories" lb "Kategorie" sort string published_at date "d.m.Y" lb "Publikováno" sort number price format "2,." lb "Cena" sort link lndetail route "products/show/id:{id}" lb "Detail" pager pager pglen "20" ?> <table> <tr>{grid.labels}</tr> {block items} <tr>{grid.fields}</tr> {block else} <tr><td colspan="10" align="center">Nenalezeny žádné výsledky.</td></tr> {/block} </table> <div class="pager">{pager}</div>
Šablona gridu obsahuje speciální blok items, který se vypíše pro každý řádek přehledu. Pokud nebudou nalezeny žádné položky, vypíše se sekce {block else}.
Každá položka obsahuje atribut lb, který se použije jako popisek sloupce a přidáním atributu sort zajistíme, že po kliknutí se grid podle sloupce seřadí. Specifickým elementem gridu je {pager}, který zobrazí komponentu navigace mezi stránkami. Délka stránky je nastavená na 20 řádků. Element link vytvoří odkaz na detail produktu (link lze použít i v obyčejných šablonách).
Seznam možných typů a parametrů elementů pro třídu Grid viz referenční manuál.
V této šabloně používáme zkrácený zápis {grid.labels} a {grid.fields}, který vypíše všechny sloupce uvedené v sekci elements (sloupec lze vynechat přidáním atributu skip). Pokud potřebujete složitější layout, můžete pole v šabloně rozepsat i jednotlivě:
<table> <tr> <th>{title.lb}</th> <th>{category.lb}</th> <th>{price.lb}</th> </tr> {block items} <tr class="link" onclick="{lndetail.js}"> <td>{title}</td> <td>{category}</td> <td>{price} Kč</td> </tr> {/block} </table>
Pokud chceme datagrid filtrovat, použijeme k tomu atribut $grid->filter. Například $grid->filter['category'] = 1; zapne filtr podle kategorie. Dotaz gridu pak musíme upravit takto:
$grid->setQuery( "select * from products where 1 ~ and category='{category}'" );
Parametr {category} se nahradí hodnotou z $grid->filter. Vlnovka (~) na začátku znamená podmíněné použití. Jestliže není proměnná category nastavená, filtr na kategorii se nevykoná (řádek s vlnovkou bude vynechán).
Grid je možné mimo jiné exportovat do formátu csv, nebo do formátu vhodného k otevření v excelu: $grid->exportCsv('soubor.csv') nebo $grid->exportExcel('soubor.csv')
Formuláře
Třída Form (potomek Tpl) slouží k zobrazení, uložení a validaci formulářů. Šablony formulářů umí vytvářet všechny běžné formulářové komponenty včetně nastavení validačních pravidel, ošetřují vstupy, umožňují flexibilitu pokud jde o podobu formuláře a zároveň zachovávají práci s formuláři v kódu jednoduchou a přehlednou.
public function editAction($id) { $product = $this->app->db->select('products', ['id' => $id]); if (!$product) $this->app->error("Produkt nenalezen!", "alert alert-danger"); $form = new pclib\Form('tpl/products/form.tpl'); $form->values = $product; $form->enable('update'); return $form; }
Tento kód vytvoří a zobrazí editační formulář produktu. Nejdřív načteme data produktu z databáze do proměnné $product, pak jimi naplníme formulář (nastavením $form->values) a zobrazíme. Stránka se zobrazí po zadání routy obsahující id produktu - například products/edit?id=1
Šablona formuláře vypadá takto:
<?elements class form route "products/id:{GET.id}" html5 input title lb "Název produktu:" required text description lb "Popis:" size "50x4" required select category lb "Kategorie:" lookup "categories" required input price lb "Cena:" size "10" input image_path file accept "image/*" size_mb "2" lb "Obrázek" check published lb "Publikováno" default "1" input published_at lb "Datum vydání:" date button insert lb "Přidat" noprint button update lb "Uložit" noprint button delete lb "Smazat" confirm "Opravdu smazat?" noprint ?> <table> {form.fields} </table>
První řádek určuje že se formulář odesílá do ProductsControlleru, konkrétní akci udává název tlačítka. Při aktualizaci je zapnuté pouze tlačítko update, routa tedy bude products/update. Id produktu převezmeme z url pomocí parametru id:{GET.id} Atribut html5 zapíná html5 klientskou validaci formuláře.
Následující položky vytvoří pole formuláře INPUT, TEXTAREA, SELECT a CHECKBOX. Atribut required znamená povinné pole, lb jeho popisek, size uvádí velikost pole, date provádí validaci datumu a default je implicitní předvyplněná hodnota pole. Tyto atributy lze použít u kteréhokoliv pole formuláře.
Pokud chcete mít ve formuláři pole, které se nebude ukládat, zajistí to parametr nosave, needitovatelné pole (disabled) vytvoříme atributem noedit. Například input order_no lb "Číslo zakázky" noedit nosave. Seznam obecných atributů.
Select musí obsahovat zdroj dat, odkud se načtou položky výběrového pole - zde se používá číselník categories. Položky lze načíst i pomocí dotazu (query), textového seznamu (list) nebo funkcí php (datasource). Stejným způsobem lze vytvořit i pole checkboxů nebo radiobuttonů. Viz též referenční manuál.
Pole input file slouží k uploadování souborů. Zde je nastavená validace pouze na obrázkové soubory s maximální velikostí souboru 2MB.
Tlačítka jsou implicitně vypnutá (noprint) a zapíná se pouze tlačítko update, které odešle formulář do akce ProductsController->updateAction($id).
V této šabloně používáme zkrácený zápis {form.fields}, který vypíše všechny pole uvedené v sekci elements (pole lze vynechat přidáním atributu skip). Pokud potřebujete složitější layout, můžete pole v šabloně rozepsat i jednotlivě:
<table> <tr> <td>{title.lb}</td> <td>{title}</td> </tr> <tr> <td>{description.lb}</td> <td>{description}</td> </tr> ... </table>
Po odeslání formuláře jsou uživatelem vyplněné hodnoty načtené v poli $form->values. Lze je upravovat, vypsat nebo uložit do databáze buď samostatně, nebo pomocí formulářových funkcí $form->insert(), $form->update() a $form->delete().
public function updateAction($id) { $form = new pclib\Form('tpl/products/form.tpl'); if (!$form->validate()) { $this->app->error("Chybně zadané parametry.", "alert alert-danger"); }; $form->update('products', ['id' => $id]); $this->app->message('Položka byla uložena.', "alert alert-success"); $this->redirect('products/show/id:' . $id); }
Tato akce se zavolá po odeslání formuláře, provede kontrolní validaci (ta uživatelská se vykoná už v prohlížeči před odesláním) a aktualizuje produkt v databázi. Následně provede přesměrování na products/show a zobrazí informační message.
Pokud je formulář odeslaný, je nastavená hodnota $form->submitted a obsahuje název odesílacího tlačítka.
Databáze
Pclib\Db je služba pro zjednodušení práce s databází, která mj. ošetřuje parametry dotazů, tak, aby nebyl možný útok pomocí sql-injection. Inicializovat ji můžete v index.php příkazem $app->db = new pclib\Db('pdo_mysql://jmeno:heslo@host/jmeno_databaze'); nebo pomocí konfiguračního souboru. V metodě controlleru k ní lze přistupovat jako $this->app->db.
Připojovací řetězec je jednotný a obsahuje uživatelské jméno a heslo, adresu hosta a jméno databáze - například 'pdo_mysql://root:abc123@127.0.0.1/test-app'.
Ukázka použití:
$product = $db->select('products', ['id' => 1]) | Vrátí záznam s id=1 z tabulky products |
$products = $db->selectAll('products', ['price' => 1000]) | Vrátí všechny produkty s cenou 1000 |
$product = $db->select('products:id,title,price', ['id' => 1]) | Vrátí vybraná pole produktu 1 |
$id = $db->insert('products', ['title' => 'Nový produkt', 'price' => 1000, 'category' => 1]) | Vloží nový produkt a vrátí jeho id |
$db->update('products', ['title' => 'Nový název', 'price' => 1000], ['id' => $id]) | Aktualizuje produkt s id=1 |
$db->delete('products', ['id' => 1]) | Smaže produkt s id=1 |
$res = $db->query("select * from products where id=1"); $row = $db->fetch($res); |
Obecný dotaz a vrácení jeho hodnoty |
Pokud potřebujeme zadat složitější podmínku s parametry můžeme využít zadání parametrů pomocí {nazev_parametru} nebo {#nazev_parametru} pro numerickou (integer) hodnotu.
$products = $db->selectAll('products', "price > {#price}", ['price' => 1000]) | Vrátí produkty s cenou větší než 1000 |
$products = $db->selectAll("select * from products where title like '%{search}%' order by title", ['search' => 'notebook']) | Vrátí produkty s názvem obsahujícím 'notebook' |
$db->update('products', ['published' => 0], "title like '%notebook%'") | Nastaví notebooky jako nepublikované |
Existují i další varianty zadávání podmínek s parametry - viz referenční manuál
Jen tak zajistíte, že vstupem z parametru nebude možné podstrčit sql-injection kód.
Služba Auth
Systém autentizace a autorizace pracuje se třemi typy objektů: uživatelé, role a oprávnění. Role má přiřazená oprávnění a uživatel může mít přiřazenou jednu nebo více rolí. Je možné přiřadit oprávnění i přímo konkrétnímu uživateli. Uživatel se přihlašuje pomocí uživatelského jména a hesla. V aplikaci pak můžeme testovat oprávnění přihlášeného uživatele.
Službu inicializujeme buď v souboru index.php: $app->auth = new pclib\Auth nebo prostřednictvím konfigurace.
'service.auth' => [ 'algo' => 'bcrypt', 'secret' => '', ], 'pclib.app' => [ 'autostart' => ['db', 'auth'], ]
Parametr 'algo' udává hashovací algoritmus pro ukládání hesel. Možnosti jsou 'md5', 'bcrypt' a 'bcrypt-md5'. Při použití md5 je nutné ještě nastavit 'secret'. Jedná se o náhodný řetězec alespoň deseti znaků, který se využívá k posílení hesla. Před použitím Auth je potřeba spustit i službu databáze, kterou Auth využívá.
Přihlášení uživatele se provede příkazem $auth->login('jmeno', 'heslo'), odhlášení pomocí $auth->logout(). Funkce login() vrací false pokud se přihlášení nepodařilo a chyby /např. chybné heslo/ lze poté vyčíst z pole $auth->errors. Po úspěšném přihlášení je přihlášený uživatel dostupný přes $auth->loggedUser.
Pro přihlášení, odhlášení, registraci, zapomenuté heslo apod. je nejlépe vytvořit samostatný controller.
class UserController extends BaseController { function signinAction() { return new pclib\Form('tpl/user/signin.tpl'); } function loginAction() { $form = new pclib\Form('tpl/user/signin.tpl'); $ok = $this->app->auth->login($form->values['username'], $form->values['password']); if ($ok) { $this->app->message('Vítáme Vás na našich stránkách.', 'alert alert-success'); $this->redirect('home'); } else { $this->app->message('Chybné přihlašovací údaje.', 'alert alert-danger'); $this->redirect('user/signin'); } } function logoutAction() { $this->app->auth->logout(); $this->app->message('Byl jste odhlášen.', 'alert alert-success'); $this->redirect('home'); } }
Akce user/signin zobrazí přihlašovací formulář, akce user/login resp. user/logout uživatele přihlásí resp. odhlásí a přesměruje na home.
Nyní můžeme testovat oprávnění přihlášeného uživatele v controlleru.
function editAction($id) { if (!$this->app->auth->hasRight('products/edit') { $this->app->error('Nemáte oprávnění editovat produkty'); } ... }
Lze použít i pomocnou metodu authorize() která ukončí aplikaci se standardní chybovou hláškou, jestliže uživatel nemá oprávnění. Pokud je nepřihlášený, přesměruje ho na přihlašovací formulář, standardně na routu user/signin.
function editAction($id) { $this->authorize('products/edit'); ... }
Často bývá výhodné vytvořit si v BaseControlleru zkratku k přihlášenému uživateli, aby byl dostupný ve všech našich controllerech.
class BaseController extends pclib\Controller { protected $user; function __construct($app) { parent::__construct($app); $this->user = $this->app->auth->loggedUser; } }
Proměnná $this->user je buď null pro nepřihlášeného uživatele, nebo objekt typu AuthUser.
function ordersAction() { if (!$this->user) { return "Nelze zobrazit objednávky pro nepřihlášeného uživatele."; } $orders = $this->app->db->selectAll('orders', ['user_id' => $this->user->id]); return $this->template('tpl/orders/list.tpl', ['orders' => $orders, 'user' => $this->user->getValues() ]); }
Lze vytvořit oprávnění, které obsahuje wildcard '*'. Pokud má uživatel přiřazené právo products/*, znamená to, že má povolená práva products/edit, products/delete, products/jakykoliv-retezec.
Id oprávnění | Popis |
---|---|
products/edit | Editace produktů |
products/delete | Smazání produktu |
products/* | Všechna práva produkty |
* | Všechna práva |
Nastavení rolí, uživatelů a oprávnění je nejjednodušší pomocí aplikace padmin. Lze to ovšem i programově pomocí třídy AuthManager.