Kako delujejo aplikacije?

Trenutno berete osnovni dokument dokumentacije Nette. Spoznali boste vsa načela delovanja spletnih aplikacij. Lepo od A do Ž, od trenutka rojstva do zadnjega diha skripte PHP. Po branju boste vedeli:

  • kako vse to deluje
  • kaj so Bootstrap, Presenter in DI kontejner
  • kako je videti struktura imenikov

Struktura imenika

Odprite skeletni primer spletne aplikacije z imenom WebProject in si oglejte datoteke, o katerih se piše.

Struktura imenikov je videti nekako takole:

web-project/
├── app/                      ← directory with application
│   ├── Core/                 ← osnovni potrebni razredi
│   │   └── RouterFactory.php ← konfiguracija naslovov URL
│   ├── UI/                   ← predstavitev, predloge in podobno.
│   │   ├── @layout.latte     ← predloga skupne postavitve
│   │   └── Home/             ← Domači imenik predstavnikov
│   │       ├── HomePresenter.php ← Razred HomePresenter
│   │       └── default.latte ← predloga za akcijo 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

Lahko kakor koli spremenite imeniško strukturo, preimenujete ali premaknete mape, nato pa samo uredite poti do log/ in temp/ v datoteki Bootstrap.php ter pot do te datoteke v composer.json v razdelku autoload. Nič več, nobene zapletene ponovne konfiguracije, nobenih stalnih sprememb. Nette ima pametno samodejno zaznavanje.

Za nekoliko večje aplikacije lahko mape s predvajalniki in predlogami razdelimo v podimenike (na disku) in v imenske prostore (v kodi), ki jih imenujemo moduli.

Imenik www/ je javni imenik ali dokumentni koren projekta. Lahko ga preimenujete, ne da bi vam bilo treba na strani aplikacije nastaviti kar koli drugega. Gostovanje morate le konfigurirati tako, da bo korenina dokumentov prešla v ta imenik.

WebProject lahko prenesete tudi neposredno, vključno z Nette, z uporabo Composerja:

composer create-project nette/web-project

V operacijskem sistemu Linux ali macOS nastavite dovoljenja za pisanje za imenike log/ in temp/.

Aplikacija WebProject je pripravljena za zagon, ničesar več ni treba nastavljati, ogledate pa si jo lahko neposredno v brskalniku z dostopom do mape www/.

Zahteva HTTP

Vse se začne, ko uporabnik odpre stran v brskalniku in brskalnik z zahtevo HTTP zaklepa strežnik. Zahteva gre v datoteko PHP, ki se nahaja v javnem imeniku www/, ki je index.php. Predpostavimo, da je to zahteva na naslov https://example.com/product/123 in se bo izvršil.

Njegova naloga je:

  1. inicializacija okolja
  2. pridobiti tovarno
  3. zagnati aplikacijo Nette, ki obravnava zahtevo

Katere vrste je tovarna? Ne proizvajamo traktorjev, temveč spletne strani! Počakajte, takoj vam bo razloženo.

Z “inicializacijo okolja” mislimo na primer na to, da se aktivira Tracy, ki je izjemno orodje za beleženje ali vizualizacijo napak. Beleži napake v produkcijskem strežniku in jih prikazuje neposredno v razvojnem strežniku. Zato je treba pri inicializaciji odločiti tudi, ali spletno mesto deluje v produkcijskem ali razvojnem načinu. Za to Nette uporablja samodejno zaznavanje: če zaženete spletno mesto na lokalnem gostitelju, se zažene v razvijalskem načinu. Ničesar vam ni treba konfigurirati in aplikacija je pripravljena tako za razvojno kot produkcijsko namestitev. Ti koraki so izvedeni in podrobno opisani v poglavju o razredu Bootstrap.

Tretja točka (da, drugo smo preskočili, vendar se bomo k njej vrnili) je zagon aplikacije. Obravnavo zahtevkov HTTP v Nette izvaja razred Nette\Application\Application (v nadaljevanju Application), zato ko rečemo “zagnati aplikacijo”, imamo v mislih klic metode z imenom run() na objektu tega razreda.

Nette je mentor, ki vas vodi pri pisanju čistih aplikacij po preverjenih metodologijah. Najbolj preizkušena se imenuje vbrizgavanje odvisnosti, skrajšano DI. Trenutno vas ne želimo obremenjevati z razlago DI, saj je za to namenjeno posebno poglavje, pomembno pa je, da bodo ključni objekti običajno ustvarjeni s tovarno za objekte, imenovano kontejner DI (skrajšano DIC). Da, to je tista tovarna, ki smo jo omenili pred kratkim. Ta nam ustvari tudi objekt Application, zato najprej potrebujemo vsebnik. Dobimo ga z uporabo razreda Configurator in mu pustimo, da izdela objekt Application, pokličemo metodo run() in s tem zaženemo aplikacijo Nette. Natanko to se zgodi v datoteki index.php.

Aplikacija Nette

Razred Application ima eno samo nalogo: odgovoriti na zahtevo HTTP.

Aplikacije, napisane v okolju Nette, so razdeljene na številne tako imenovane predstavnike (v drugih ogrodjih lahko naletite na izraz controller, ki je enak), ki so razredi, ki predstavljajo določeno spletno stran: npr. domača stran; izdelek v e-trgovini; prijavni obrazec; vir zemljevida spletnega mesta itd. Aplikacija ima lahko od enega do več tisoč predstavnikov.

Aplikacija se začne tako, da zahteva od tako imenovanega usmerjevalnika, da se odloči, kateremu od predstavnikov bo posredoval trenutno zahtevo v obdelavo. Usmerjevalnik se odloči, čigava je to odgovornost. Pregleda vhodni naslov URL https://example.com/product/123, ki želi show izdelek z id: 123 kot dejanjem. Dobra navada je, da se pari predstavnik + akcija, ločeni z dvopičjem, zapišejo kot Product:show.

Usmerjevalnik je torej pretvoril naslov URL v par Presenter:action + parametri, v našem primeru Product:show + id: 123. Kako je videti usmerjevalnik, si lahko ogledate v datoteki app/Core/RouterFactory.php, podrobno pa ga bomo opisali v poglavju Usmerjanje.

Pojdimo naprej. Aplikacija že pozna ime predavatelja in lahko nadaljuje. Z ustvarjanjem predmeta ProductPresenter, ki je koda predstavnika Product. Natančneje, za ustvarjanje predstavnika zaprosi vsebnik DI, saj je izdelovanje objektov njegova naloga.

Predstavnik je lahko videti takole:

class ProductPresenter extends Nette\Application\UI\Presenter
{
	public function __construct(
		private ProductRepository $repository,
	) {
	}

	public function renderShow(int $id): void
	{
		// pridobimo podatke iz modela in jih posredujemo predlogi
		$this->template->product = $this->repository->getProduct($id);
	}
}

Zahtevo obravnava predstavnik. In naloga je jasna: izvedite dejanje show s id: 123. Kar v jeziku predstavnikov pomeni, da se pokliče metoda renderShow() in v parametru $id dobi 123.

Predstavnik lahko obravnava več dejanj, tj. ima več metod render<Action>(). Vendar priporočamo, da predstavnike oblikujete z eno ali čim manj akcijami.

Tako je bila klicana metoda renderShow(123), katere koda je izmišljen primer, vendar lahko na njej vidite, kako se podatki posredujejo predlogi, tj. z zapisom v $this->template.

Nato predstavnik vrne odgovor. To je lahko stran HTML, slika, dokument XML, pošiljanje datoteke z diska, JSON ali preusmeritev na drugo stran. Pomembno je, da če izrecno ne navedemo, kako odgovoriti (kar je primer ProductPresenter), bo odgovor prikaz predloge s stranjo HTML. Zakaj? No, ker v 99 % primerov želimo izrisati predlogo, zato predstavnik to vedenje sprejme kot privzeto in nam želi olajšati delo. To je Nettejeva poanta.

Sploh nam ni treba navesti, katero predlogo je treba prikazati; ogrodje bo pot določilo samo. V primeru akcije show preprosto poskuša naložiti predlogo show.latte v imeniku z razredom ProductPresenter. Prav tako poskuša najti postavitev v datoteki @layout.latte (več o iskanju predlog).

Nato se predloge izrišejo. S tem je naloga predstavnika in celotne aplikacije končana in delo je opravljeno. Če predloga ne bi obstajala, bi se vrnila stran z napako 404. Več o predstavnikih si lahko preberete na strani Predstavniki.

Da bi se prepričali, poskusite celoten postopek ponoviti z nekoliko drugačnim naslovom URL:

  1. naslov URL bo https://example.com
  2. zaženemo aplikacijo, ustvarimo vsebnik in zaženemo Application::run()
  3. usmerjevalnik dekodira naslov URL kot par Home:default
  4. ustvari se objekt HomePresenter
  5. kličemo metodo renderDefault() (če obstaja)
  6. prikaže se predloga default.latte z razporeditvijo @layout.latte

Morda ste zdaj naleteli na veliko novih konceptov, vendar verjamemo, da so smiselni. Ustvarjanje aplikacij v programu Nette je zelo enostavno.

Predloge

Pri predlogah Nette uporablja sistem predlog Latte. Zato se datoteke s predlogami končajo s .latte. Latte se uporablja, ker je najbolj varen sistem predlog za PHP in hkrati najbolj intuitiven sistem. Ni se vam treba naučiti veliko novega, poznati morate le PHP in nekaj oznak Latte. Vse boste našli v dokumentaciji.

V predlogi ustvarimo povezave do drugih predstavnikov in akcij, kot sledi:

<a n:href="Product:show $productId">product detail</a>

Preprosto zapišite znani par Presenter:action namesto pravega URL in vključite vse parametre. Trik je n:href, ki pove, da bo ta atribut obdelal program Nette. In ustvaril bo:

<a href="/product/456">product detail</a>

Za generiranje naslova URL je odgovoren prej omenjeni usmerjevalnik. Pravzaprav so usmerjevalniki v Nette edinstveni, saj lahko izvajajo ne le pretvorbe iz naslova URL v par predstavnik:dejanje, temveč tudi obratno, generirajo naslov URL iz imena predstavnika + dejanja + parametrov. Zahvaljujoč temu lahko v Nette v celoti spremenite obliko URL v celotni dokončani aplikaciji, ne da bi spremenili en sam znak v predlogi ali predstavniku, samo s spremembo usmerjevalnika. Zahvaljujoč temu pa deluje tudi tako imenovana kanonizacija, ki je še ena edinstvena lastnost sistema Nette, ki izboljša SEO (optimizacijo iskanja v internetu), saj samodejno preprečuje obstoj podvojene vsebine na različnih URL-jih. Številnim programerjem se to zdi neverjetno.

Interaktivne komponente

O predstavitvah vam moramo povedati še nekaj: imajo vgrajen sistem komponent. Starejši med vami se morda spomnite nečesa podobnega iz Delphija ali ASP.NET Web Forms. React ali Vue.js sta zgrajena na nečem zelo podobnem. V svetu ogrodij PHP je to povsem edinstvena lastnost.

Komponente so ločene enote za večkratno uporabo, ki jih namestimo v strani (tj. predstavnike). To so lahko obrazci, podatkovne mreže, meniji, ankete, pravzaprav vse, kar je smiselno uporabiti večkrat. Ustvarimo lahko lastne komponente ali uporabimo katero od številnih odprtokodnih komponent.

Komponente bistveno spremenijo pristop k razvoju aplikacij. Odprle bodo nove možnosti za sestavljanje strani iz vnaprej določenih enot. In imajo nekaj skupnega s Hollywoodom.

Kontejner DI in konfiguracija

Kontejner DI (tovarna predmetov) je srce celotne aplikacije.

Ne skrbite, to ni magična črna škatla, kot se morda zdi iz prejšnjih besed. Pravzaprav gre za en precej dolgočasen razred PHP, ki ga ustvari Nette in je shranjen v imeniku predpomnilnika. Ima veliko metod, poimenovanih kot createServiceAbcd(), in vsaka od njih ustvari in vrne objekt. Da, obstaja tudi metoda createServiceApplication(), ki ustvari Nette\Application\Application, ki smo jo potrebovali v datoteki index.php za zagon aplikacije. Obstajajo pa tudi metode za izdelavo posameznih predstavnikov. In tako naprej.

Predmeti, ki jih ustvarja vsebnik DI, se iz nekega razloga imenujejo storitve.

Posebnost tega razreda je, da ga ne programirate vi, temveč ogrodje. Pravzaprav ustvari kodo PHP in jo shrani na disk. Vi samo podate navodila o tem, katere predmete naj bi vsebnik znal ustvariti in kako natančno. Ta navodila so zapisana v konfiguracijskih datotekahformatu NEON in imajo zato končnico .neon.

Konfiguracijske datoteke se uporabljajo izključno za dajanje navodil vsebniku DI. Tako bo na primer, če v razdelku seje navedem možnost expiration: 14 days, vsebnik DI pri ustvarjanju objekta Nette\Http\Session, ki predstavlja sejo, poklical njegovo metodo setExpiration('14 days'), s čimer bo konfiguracija postala resničnost.

Za vas je pripravljeno celotno poglavje, v katerem je opisano, kaj je mogoče konfigurirati in kako opredeliti lastne storitve.

Ko se boste lotili ustvarjanja storitev, boste naleteli na besedo samodejno povezovanje. To je pripomoček, ki vam bo neverjetno olajšal življenje. Z njim lahko samodejno posredujete predmete, kjer jih potrebujete (na primer v konstruktorjih vaših razredov), ne da bi vam bilo treba kar koli storiti. Ugotovili boste, da je zabojnik DI v Netteu majhen čudež.

Kaj naprej?

Pregledali smo osnovna načela aplikacij v programu Nette. Zaenkrat zelo površno, vendar se boste kmalu poglobili v globino in sčasoma ustvarili čudovite spletne aplikacije. Kje nadaljevati? Ste že poskusili z učbenikom Ustvarite svojo prvo aplikacijo?

Poleg zgoraj navedenega ima Nette še cel arzenal uporabnih razredov, sloj podatkovnih zbirk itd. Poskusite namenoma samo klikniti po dokumentaciji. Ali pa obiščite blog. Odkrili boste veliko zanimivih stvari.

Naj vam ogrodje prinese veliko veselja 💙

različica: 4.0