Egoblog.cz - Petr Kobelka

Jak na Nette s funkčními moduly

Již nějakou dobu pracuji s Nette a vyvíjím pro zákazníky aplikace, které jim ulehčují život a vydělávají peníze. V takových případech často chtějí mít přístup pro správce oddělený od přihlašování zákazníků.


PHP | Komentáře (3) | Shlédnuto 10757 × | Vloženo: 10. srpna 2014

Co k tomu potřebujeme? Nette!

Ano, Nette je k tomu skutečně potřeba protože na něm stavíme celou aplikaci :-) V celém článku Vám představím řešení, které jsme poskládal jak z vědomostí a zkušeností z praxe, tak i z mnoha diskuzí na webu a které mám vyzkoušené a funguje.

Základem je Nette. Aktuální verzi, kterou stále ještě používám je 2.1.4. Obecně bych řekl, že kterákoliv z verzí z rodiny 2.1.* bude OK. A to je tak asi vše, co je třeba.

Jen pro zajímavost pro vizuální stránku a zároveň mobile friendly aplikaci používám Bootstrap ve verzi 3 a pro administraci nějakou pěknou free šablonu. Hodně jich najdete například zde: http://bootswatch.com/.

Adresářová struktura modulů

Kostra, kterou používám má následující adresářovou strukturu, která více méně kopíruje sandbox dodávaný s Nette.

app
--AdminModule
----control
----presenters
----templates
--PublicModule
----control
----presenters
----templates
--CuastomerModule
----control
----presenters
----templates
--config
--model
--router
--template
log
temp
tests
vendor
www

Nebudu zde vysvětlovat význam jednotlivých složek, to by bylo jen plýtvání Vaším časem. Kdo význam nezná, najde jej v dokumentaci Nette.

Co ale popíšu jsou jednotlivé složky, které mají trochu jiná data, než je v sandboxu uvedeno.

Ve adresáři app jsou tři nové podaresáře. AdminModule zastřešuje administrační část webu, kde se editují články, www menu apod. Adresář PublicModule pak reprezentuje pohled pro běžného návštěvníka webu. Adresář CustomerModule má na starosti informace pro přihlášeného uživatele.

V aktuálním pohledu máme tři moduly a potřebujeme dva nezávislé postupy pro přihlášení. Jeden pro administrátora a druhý pro zákazníka. Více o takovém přihlašování popisuji níže v sekci Multi přihlašování.

Adresář Model je pouze jeden, nemá každý z modulů vlastní. Je to z toho důvodu, že hodně metod je společných pro všechy moduly a přijde mi zbytečné psát neustále dokola to samé (viz princip. DRY, nebo DRY).

V adresáři template pak mám definice layoutů a šablony obecné, platné pro celou aplikaci, např. základní šablonu pro e-mailové zprávy.

Každý z modulů má pak vlastní adresáře pro vlastní šablony, presentery a pro control prvky. Můžete dojít k situaci, že budete chtít jeden control prvek mít všude v aplikaci, pak je vhodné mít ještě jeden adresář control jako podadresář app.

Router

Pravidla pro routopvání využívám pro každý modul zvlášť jako kolekci rout. Následující příkald vysvětlí vše.

use Nette,
    Nette\Application\Routers\RouteList,
    Nette\Application\Routers\Route;
/**
 * Router factory.
 */
class RouterFactory
{
    /**
     * @return \Nette\Application\IRouter
     */
    public function createRouter()
    {
        $router = new RouteList();

    $admin = new RouteList('Admin');
    $admin[] = new Route('admin/<presenter>/<action>[/<id>]', 'Homepage:default');
    $router[] = $admin;

    $member = new RouteList('Customer');
    $member[] = new Route('customer/<presenter>/<action>[/<id>]', 'Homepage:default');
    $router[] = $member;

    $public = new RouteList('Public');
    $public[] = new Route('<presenter>/<action>[/<id>]', 'Public:Homepage:default');
    $router[] = $public;

        $router[] = new Route('<presenter>/<action>[/<id>]', 'Public:Homepage:default');

        return $router;
    }
}

Je to zjednodušeno, protože tam mám ještě i vlastní routy pro speciální aktivity, ale pro potřeby ilustrace není nic takového nutné tu vypisovat. Pohled na router ukazuje jedinou metodu, která sestavuje aktivity pro jednotlivé moduly. Myslím si, že je to rychle pochopitelné. Vytvoříte si pro každý z modulů RouteList a do něj nacpete routy pro daný modul. Takto vytvořený seznam pak nacpete do hlavního seznamu rout. To je vše.

Layout Nette - šablonová kostra pro moduly

V adresáři /app/template mám layoutové šablony pro každý z modulů. Tedy, pokud je potřebuji nějak oddělit. Nemusí to být třeba, ale bývá to výhodné. Je lepší mít tři jednodušší šablony, než jednu s miliónem pravidel pro ne/zobrazování obsahů různých modulů. Tyto pak připojíte v BasePresenteru v metodě startUp() pomocí metody $this->setLayout().

V mém případě tedy mám tyto:


@layout.latte // Public module - veřejná část
@admin.latte // admin module - správa obsahu webu
@customer.latte // Customer module - přihlášený zákazník

Multi přihlašování

Poslední důležitou částí, kterou jsem musel vyřešit je to, aby se mi nekřížily přihlášené identity. Ve výchozím nastavení toto nebude fungovat a uživatel, který se přihlásí v adminu se může (nemusí) dostat do sekce pro přihlášeného zákazníka což je nežádoucí efekt, protože to může fungovat i obráceně. Na to, aby jste oddělili dva přihlášené uživatele je třeba využít dvou fíglů.

1. Mít dva autentikátory

To je z toho důvodu, že autentikujete uživatele vůči různým datovým základnám (rozumněj různé tabulky). Autentikace se spouští v presenteru, ve kterém realizujete přihlášení uživatele. V mém případě zachovávám notaci ze sandboxu a presenter se jmenuje SignPresenter.

V něm v metodě, která autentikaci spouští mám následující kód:


$u = $this->getUser();
$u->getStorage()->setNamespace('Admin');
$u->login($values->username, $values->password);

V prvním řádku přečtu aktuální (prázdnou) identitu. V druhém řádku nastavím namespace, kam se budou ukládat informace o přihlášeném uživateli. Ve třetím řádku již mohu provést pokus o autentikaci, namespace je již správně nastaven.

Namespace nastavíte na takový název, aby jste mu rozumněli. Pro zákazníka použiji např. název "Customer".

Ještě je třeba zrušit u autenticator tříd autowiring, aby vzájemně nekolidovaly. Toho docílíte úpravou services v configu. Zápis vypadá např. takto:


services:
  - PBT\RouterFactory
  authenticator:
    class: Authenticator
    autowired: no
  customerAuthenticator:
    class: CustomerAuthenticator
    autowired: no

autenticator je služba pro autentikaci správce systému v modulu AdminModule.
customerAuthenticator je služba pro autentikaci zákazníka v modulu CustomerModule.

2. Různé úložiště pro infomrace o přihlášením uživateli

Navíc je třeba změnit úložiště, kam se ukládají informace o přihlášeném uživateli v presenterech, aby jste vždy pracovali pouze s těmi informaci, se kterýmí máte. Je třeba provést změnu na dvou místech. Poprvé v autentikátoru, kde ukládáte úspěšně přihlášeného uživatele.

V druhém kroku je třeba přetížit metodu getUser() aby četla informace o přihlášeném uživateli pouze a právě z našeho požadovaného úložiště.

Tuto metodu přetížíte v BasePresenteru v modulu. Další příkald, který je platný pro můj AdminModule:

public function getUser()
{
  $user = parent::getUser();
  $user->getStorage()->setNamespace('Admin');
  return $user;
}

V aplikaci v modulu je pak potřeba vždy volat $this->getUser() aby jste se dotázali vždy na správný namespace - ! z toho plyne nepoužívat zjednodušené volání $this->user.

Na konec japonec

Tohle by mělo být tak vše. Myslím si, že jsem na nic nezapomněl. Přijde mi, že celý princip je opravdu jednoduchý. Jestli máte nějaké dotazy, nebojte se o něpodělit v komentářích.

Podobné články jako "Jak na Nette s funkčními moduly"

Petr Kobelka | Egoblog.cz | Tvorba www stránek - www.petrkobelka.cz

Petr Kobelka
Autor je zkušeným web developerem a programátorem s více než 10 letými zkušenostmi. Pracuje jako programátor pro známou Olomouckou společnost zabývající se tvorbou internetových a intranetových řešení. Spolu se zaměstnáním pracuje na volné noze a zabývá se tvorbou internetových stránek. Ve volném čase rád fotí, jezdí na kole, plave a cestuje.

Komentáře

E-mail je potřeba pouze pro vygenerování Gravataru!

1
Exquis | vloženo 24. července 2015
Výborně, díky moc ;)
Petr Kobelka
Díky za pozitivní komentář. Ten potěší vždy!! :-)
2
vojta001 | vloženo 28. září 2015
Jen doplním, s čím jsem dlouho bojoval v modulech já. Chceme-li přesměrovat v presenteru metodou redirect na jiný modul, musíme před jeho název uvést ":" (Přesměrování na přihlášení admin modulu ":Admin:Login:default" nebo jen ":Admin:Login")
Petr Kobelka
Je to tak. Díky za doplnění!
3
JakubCh | vloženo 1. října 2015
Super článek :) konečně někde srozumitelně sepsaný. Díky :)
Petr Kobelka
Děkuji, takový komentář vždy potěší ;-)

Blog píše Petr Kobelka

Petr Kobelka - egoblog.cz

Žádám všechny, kteří mají zájem vkládat komentáře, aby se řídili pravidly NETikety. Komentáře, porušující tato pravidla můžou být bez varování smazány.