Hogyan működnek az alkalmazások?
Ön jelenleg a Nette dokumentáció alapdokumentumát olvassa. Megismerheti a webes alkalmazások összes alapelvét. Szépen A-tól Z-ig, a születés pillanatától a PHP-szkript utolsó leheletéig. Az olvasás után tudni fogja:
- hogyan működik az egész
- mi az a Bootstrap, Presenter és DI konténer
- hogyan néz ki a könyvtárszerkezet
Könyvtárszerkezet
Nyissa meg a WebProject nevű webalkalmazás vázlatpéldáját, és megnézheti, hogy milyen fájlokat írnak le.
A könyvtárszerkezet valahogy így néz ki:
web-project/ ├── app/ ← directory with application │ ├── Core/ ← alapvető szükséges osztályok │ │ └── RouterFactory.php ← URL címek konfigurálása │ ├── UI/ ← prezenterek, sablonok és társai. │ │ ├── @layout.latte ← a megosztott elrendezés sablonja │ │ └── Home/ ← Főoldal bemutatókönyvtár │ │ ├── HomePresenter.php ← Home prezenter osztály │ │ └── default.latte ← cselekvési sablon default │ └── Bootstrap.php ← booting class Bootstrap ├── bin/ ← scripts for the command line ├── config/ ← configuration files │ ├── common.neon │ └── services.neon ├── log/ ← error logs ├── temp/ ← temporary files, cache, … ├── vendor/ ← libraries installed by Composer │ ├── ... │ └── autoload.php ← autoloading of libs installed by Composer ├── www/ ← public directory, document root of project │ ├── .htaccess ← mod_rewrite rules etc │ └── index.php ← initial file that launches the application └── .htaccess ← prohibits access to all directories except www
A könyvtárszerkezetet bármilyen módon megváltoztathatja, átnevezhet vagy áthelyezhet mappákat, majd csak szerkesztheti
a log/
és a temp/
elérési útvonalakat a Bootstrap.php
fájlban, és az ehhez a fájlhoz
vezető útvonalat a composer.json
fájlban a autoload
szakaszban. Semmi több, semmi bonyolult
átkonfigurálás, semmi állandó változtatás. A Nette intelligens
automatikus felismeréssel rendelkezik.
Kicsit nagyobb alkalmazásoknál a bemutatókat és sablonokat tartalmazó mappákat alkönyvtárakra (a lemezen) és névterekre (a kódban) oszthatjuk, amelyeket moduloknak nevezünk.
A www/
könyvtár a projekt nyilvános könyvtára vagy dokumentum-gyökere. Ezt átnevezhetjük anélkül, hogy
az alkalmazás oldalán bármi mást be kellene állítanunk. Csak a tárhelyet kell úgy beállítania, hogy a
document-root ebbe a könyvtárba kerüljön.
A WebProjectet közvetlenül is letöltheti, beleértve a Nette-et is, a Composer segítségével:
composer create-project nette/web-project
Linuxon vagy macOS-en állítsa be a log/
és a temp/
könyvtárak írási engedélyeit.
A WebProject alkalmazás készen áll a futtatásra, nincs szükség további konfigurálásra, és közvetlenül a
böngészőben is megtekinthető a www/
mappát elérve.
HTTP-kérés
Minden akkor kezdődik, amikor a felhasználó megnyitja az oldalt a böngészőben, és a böngésző HTTP-kérelemmel
kopogtat a szerveren. A kérés a www/
nyilvános könyvtárban található PHP fájlhoz megy, amely a
index.php
. Tegyük fel, hogy ez a kérés a https://example.com/product/123
fájlhoz kapcsolódik, és
végrehajtásra kerül.
Feladata a következő:
- a környezet inicializálása
- megszerezni a gyárat
- elindítani a Nette alkalmazást, amely a kérést kezeli.
Milyen gyárat? Mi nem traktorokat gyártunk, hanem weboldalakat! Várjon, mindjárt elmagyarázzuk.
A „környezet inicializálása“ alatt például azt értjük, hogy a Tracy aktiválódik, ami egy csodálatos eszköz a hibák naplózására vagy vizualizálására. Naplózza a hibákat a termelő szerveren, és közvetlenül a fejlesztői szerveren jeleníti meg azokat. Ezért az inicializálásnak azt is el kell döntenie, hogy az oldal termelő vagy fejlesztői üzemmódban fut-e. Ehhez a Nette automatikus felismerést használ: ha a webhelyet localhoston futtatja, akkor fejlesztői módban fut. Nem kell semmit sem konfigurálnia, és az alkalmazás készen áll mind a fejlesztői, mind a gyártói telepítésre. Ezeket a lépéseket a Bootstrap osztályról szóló fejezetben végezzük el és ismertetjük részletesen.
A harmadik pont (igen, a másodikat kihagytuk, de visszatérünk rá) az alkalmazás elindítása. A HTTP-kérések
kezelését a Nette-ben a Nette\Application\Application
osztály végzi (a továbbiakban Application
),
így amikor azt mondjuk, hogy „futtassunk egy alkalmazást“, akkor azt értjük, hogy hívjunk meg egy run()
nevű metódust ennek az osztálynak egy objektumán.
A Nette egy olyan mentor, aki a bevált módszertanok segítségével vezet el a tiszta alkalmazások írásához.
A legjobban bevált pedig az úgynevezett dependency injection, röviden DI. A DI magyarázatával most nem akarunk
terhelni, hiszen van egy külön fejezet, a lényeg itt az, hogy a
kulcsobjektumokat általában egy DI container (röviden DIC) nevű objektumgyár fogja létrehozni. Igen, ez az a gyár,
amelyet nemrég említettünk. És létrehozza nekünk a Application
objektumot is, tehát először is szükségünk
van egy konténerre. Ezt megkapjuk a Configurator
osztály segítségével, és hagyjuk, hogy létrehozza a
Application
objektumot, meghívjuk a run()
metódust, és ez elindítja a Nette alkalmazást. Pontosan
ez történik az index.php fájlban is.
Nette alkalmazás
Az Application osztálynak egyetlen feladata van: válaszolni egy HTTP-kérésre.
A Nette-ben írt alkalmazások sok úgynevezett prezenterre oszlanak (más keretrendszerekben találkozhatunk a controller kifejezéssel, ami ugyanez), amelyek egy adott weboldal oldalt reprezentáló osztályok: pl. honlap; termék a webáruházban; bejelentkezési űrlap; sitemap feed, stb. Az alkalmazásnak egytől akár több ezer prezenter is lehet.
Az alkalmazás azzal indul, hogy az ún. routertől kéri, hogy döntse el, hogy az aktuális kérést melyik prezenternek adja
át feldolgozásra. A router dönti el, hogy kinek a felelőssége. Megnézi a bemeneti URL-t
https://example.com/product/123
, aki a show
egy terméket id: 123
művelettel akarja
ellátni. Jó szokás a prezenter + akció párokat kettősponttal elválasztva Product:show
-ként írni.
Tehát a router az URL-t átalakította Presenter:action
+ paraméterek párrá, esetünkben
Product:show
+ id: 123
. A app/Core/RouterFactory.php
fájlban láthatjuk, hogyan néz ki
egy útválasztó, és ezt részletesen az Útválasztás fejezetben fogjuk leírni.
Lépjünk tovább. Az alkalmazás már ismeri a bemutató nevét, és folytathatja. Egy ProductPresenter
objektum
létrehozásával, amely a Product
bemutató kódja. Pontosabban megkéri a DI konténert a prezenter
létrehozására, mert az objektumok előállítása az ő feladata.
A prezenter így nézhet ki:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// adatokat kapunk a modellből és átadjuk a sablonhoz.
$this->template->product = $this->repository->getProduct($id);
}
}
A kérést a prezenter kezeli. A feladat pedig egyértelmű: a show
művelet elvégzése a id: 123
címen. Ami a prezenterek nyelvén azt jelenti, hogy meghívja a renderShow()
metódust, és a $id
paraméterében a 123
kapja meg.
Egy prezenter több akciót is kezelhet, azaz több metódusa is lehet. render<Action>()
. De javasoljuk,
hogy a prezentereket egy vagy a lehető legkevesebb művelettel tervezzük.
Tehát a renderShow(123)
metódust hívtuk meg, amelynek kódja fiktív példa, de láthatjuk rajta, hogy az
adatokat hogyan adjuk át a sablonba, azaz a $this->template
címre írva .
Ezt követően a prezenter visszaadja a választ. Ez lehet egy HTML oldal, egy kép, egy XML dokumentum, egy fájl elküldése
a lemezről, JSON vagy egy másik oldalra való átirányítás. Fontos, hogy ha nem mondjuk meg kifejezetten, hogyan kell
válaszolni (ami a ProductPresenter
esetében a helyzet), akkor a válasz az lesz, hogy a sablon egy HTML-oldallal
jeleníti meg a sablont. Hogy miért? Nos, mert az esetek 99%-ában egy sablont szeretnénk kirajzolni, így a prezentáló ezt a
viselkedést veszi alapértelmezettnek, és a mi munkánkat akarja megkönnyíteni. Ez a Nette lényege.
Még azt sem kell megadnunk, hogy melyik sablont kell megjelenítenünk; a keretrendszer magától levonja az útvonalat. A
show
akció esetében egyszerűen megpróbálja betölteni a show.latte
sablont a
ProductPresenter
osztályt tartalmazó könyvtárban. Megpróbálja megtalálni az elrendezést is a
@layout.latte
fájlban (a sablonkeresésről bővebben).
Ezt követően a sablonok megjelenítésre kerülnek. Ezzel a bemutató és az egész alkalmazás feladata befejeződik, és a munka elvégeztetett. Ha a sablon nem létezne, akkor egy 404-es hibaoldalt kapna vissza. A prezenterekről bővebben a Prezenterek oldalon olvashat.
A biztonság kedvéért próbáljuk meg az egész folyamatot egy kicsit más URL-címmel felidézni:
- az URL a következő lesz
https://example.com
- elindítjuk az alkalmazást, létrehozunk egy konténert és futtatjuk
Application::run()
- a router dekódolja az URL-t, mint egy párat
Home:default
- létrejön egy
HomePresenter
objektum - a
renderDefault()
metódust meghívjuk (ha létezik) - egy
default.latte
sablon@layout.latte
elrendezéssel megjelenik.
Lehet, hogy most sok új fogalommal találkoztál, de úgy gondoljuk, hogy van értelme. Az alkalmazások létrehozása a Nette-ben gyerekjáték.
Sablonok
A sablonokat illetően a Nette a Latte sablonrendszert használja. Ezért a
sablonokat tartalmazó fájlok a .latte
végződéssel végződnek. A Latte-t azért használjuk, mert ez a
legbiztonságosabb sablonrendszer a PHP számára, ugyanakkor a legintuitívabb rendszer. Nem kell sok újat tanulnod, csak
ismerned kell a PHP-t és néhány Latte taget. Mindent megtudhatsz a dokumentációból.
A sablonban létrehozunk egy linket más előadókhoz és akciókhoz az alábbiak szerint:
<a n:href="Product:show $productId">product detail</a>
Egyszerűen csak írja a megszokott Presenter:action
párost a valódi URL helyett, és adjon meg minden
paramétert. A trükk a n:href
, amely azt mondja, hogy ezt az attribútumot a Nette fogja feldolgozni. És ez
generálni fogja:
<a href="/product/456">product detail</a>
Az URL generálásáért a korábban említett router felel. Valójában a Nette routerek egyedülállóak abban, hogy nem csak URL-ből prezenter:action párossá történő átalakításokat tudnak elvégezni, hanem fordítva is képesek URL-t generálni a prezenter + action + paraméterek nevéből. Ennek köszönhetően a Nette-ben teljesen megváltoztathatja az URL formáját az egész kész alkalmazásban anélkül, hogy egyetlen karaktert is megváltoztatna a sablonban vagy a prezenterben, csupán a router módosításával. És ennek köszönhetően működik az úgynevezett kanonizáció, ami a Nette másik egyedülálló funkciója, amely javítja a SEO-t (az internetes kereshetőség optimalizálása) azáltal, hogy automatikusan megakadályozza a duplikált tartalmak létezését a különböző URL-eken. Sok programozó ezt elképesztőnek találja.
Interaktív komponensek
Még egy dolgot el kell mondanunk a prezenterekről: rendelkeznek egy beépített komponensrendszerrel. Az idősebbek talán emlékeznek valami hasonlóra a Delphiből vagy az ASP.NET Web Formsből. A React vagy a Vue.js valami távolról hasonlóra épül. A PHP keretrendszerek világában ez egy teljesen egyedülálló funkció.
A komponensek különálló, újrafelhasználható egységek, amelyeket oldalakba (azaz prezenterekbe) helyezünk. Ezek lehetnek űrlapok, adagramok, menük, közvélemény-kutatások, tulajdonképpen bármi, amit érdemes ismételten használni. Készíthetünk saját komponenseket, vagy használhatjuk az opensource komponensek hatalmas választékának valamelyikét.
A komponensek alapvetően megváltoztatják az alkalmazásfejlesztés megközelítését. Új lehetőségeket nyitnak meg az oldalak előre definiált egységekből történő összeállítására. És van valami közös bennük Hollywooddal.
DI konténer és konfiguráció
A DI konténer (az objektumok gyára) az egész alkalmazás szíve.
Ne aggódj, ez nem egy varázslatos fekete doboz, mint ahogy az az előző szavakból látszik. Valójában ez egy elég
unalmas PHP osztály, amelyet a Nette generál és egy cache könyvtárban tárol. Rengeteg metódusa van, amelyeket
createServiceAbcd()
néven neveznek, és mindegyik létrehoz és visszaad egy objektumot. Igen, van egy
createServiceApplication()
metódus is, amely a Nette\Application\Application
létrehozza, amelyre a
index.php
fájlban volt szükségünk az alkalmazás futtatásához. És vannak metódusok az egyes előadók
előállítására. És így tovább.
Az objektumokat, amelyeket a DI konténer hoz létre, valamiért szolgáltatásoknak hívják.
Ami igazán különleges ebben az osztályban, hogy nem te programozod, hanem a keretrendszer. Valójában ez generálja a PHP
kódot, és elmenti a lemezre. Te csak utasításokat adsz arra vonatkozóan, hogy a konténer milyen objektumokat és pontosan
hogyan tudjon előállítani. Ezek az utasítások pedig NEON formátumú konfigurációs fájlokban íródnak, ezért a .neon
kiterjesztéssel rendelkeznek.
A konfigurációs fájlok pusztán a DI konténer utasítására szolgálnak. Így például, ha a munkamenet szakaszban megadom a expiration: 14 days
opciót, akkor a DI
konténer a munkamenetet reprezentáló Nette\Http\Session
objektum létrehozásakor meghívja annak
setExpiration('14 days')
metódusát, és így a konfiguráció valósággá válik.
Egy egész fejezet áll rendelkezésünkre, amely leírja, hogy mit lehet konfigurálni, és hogyan definiálhatjuk a saját szolgáltatásainkat.
Amint belekezdünk a szolgáltatások létrehozásába, találkozunk az autowiring szóval. Ez egy olyan szerkentyű, amely hihetetlenül megkönnyíti az életét. Automatikusan át tud adni objektumokat ott, ahol szükséged van rájuk (például az osztályaid konstruktoraiban), anélkül, hogy bármit is tenned kellene. Úgy fogod találni, hogy a DI konténer a Nette-ben egy kis csoda.
Mi a következő lépés?
Végigvettük a Nette alkalmazások alapelveit. Eddig nagyon felületesen, de hamarosan elmerülhetsz a mélységekben, és végül csodálatos webes alkalmazásokat hozhatsz létre. Hol folytassuk? Kipróbálta már az Első alkalmazás létrehozása című bemutatót?
A fentieken kívül a Nette egy egész arzenálnyi hasznos osztállyal, adatbázis réteggel stb. rendelkezik. Próbálja ki szándékosan csak a dokumentációt átkattintani. Vagy látogasson el a blogra. Sok érdekes dolgot fogsz felfedezni.
Hagyd, hogy a keretrendszer sok örömet szerezzen neked 💙