Cum funcționează aplicațiile?
În prezent citiți documentul de bază al documentației Nette. Veți învăța toate principiile aplicațiilor web. Nisa de la A la Z, de la momentul nașterii până la ultima suflare a scriptului PHP. După ce veți citi veți ști:
- cum funcționează totul
- ce este Bootstrap, Presenter și containerul DI
- cum arată structura directoarelor
Structura directoarelor
Deschideți un exemplu de schelet al unei aplicații web numit WebProject și puteți urmări fișierele despre care se scrie.
Structura directoarelor arată cam așa:
web-project/ ├── app/ ← directory with application │ ├── Core/ ← cursuri de bază necesare │ │ └── RouterFactory.php ← configurare adrese URL │ ├── UI/ ← prezentări, șabloane & co. │ │ ├── @layout.latte ← șablon de prezentare partajată │ │ └── Home/ ← Directorul de prezentatori de acasă │ │ ├── HomePresenter.php ← Clasa de prezentator de acasă │ │ └── default.latte ← șablon pentru acțiune 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
Puteți modifica structura directoarelor în orice mod, puteți redenumi sau muta folderele și apoi puteți edita doar căile
de acces la log/
și temp/
în fișierul Bootstrap.php
și calea de acces la acest fișier
în composer.json
în secțiunea autoload
. Nimic mai mult, fără reconfigurări complicate, fără
schimbări constante. Nette are o autodetecție inteligentă.
Pentru aplicații ceva mai mari, putem împărți dosarele cu prezentatori și șabloane în subdirectoare (pe disc) și în spații de nume (în cod), pe care le numim module.
Directorul www/
este directorul public sau documentul-rădăcină al proiectului. Îl puteți redenumi fără a fi
nevoie să setați nimic altceva pe partea de aplicație. Trebuie doar să configurați găzduirea
astfel încât documentul-root să ajungă în acest director.
De asemenea, puteți descărca direct proiectul WebProject, inclusiv Nette, folosind Composer:
composer create-project nette/web-project
Pe Linux sau macOS, setați permisiunile
de scriere pentru directoarele log/
și temp/
.
Aplicația WebProject este gata să ruleze, nu mai este nevoie să configurați absolut nimic altceva și o puteți vizualiza
direct în browser accesând folderul www/
.
Cerere HTTP
Totul începe atunci când un utilizator deschide o pagină într-un browser și browserul bate la server cu o cerere HTTP.
Cererea merge la un fișier PHP aflat în directorul public www/
, care este index.php
. Să presupunem
că este vorba de o cerere către https://example.com/product/123
și va fi executat.
Sarcina sa este:
- să inițializeze mediul
- să obțină fabrica
- lansarea aplicației Nette care gestionează cererea
Ce fel de fabrică? Noi nu producem tractoare, ci site-uri web! Stați puțin, vă explicăm imediat.
Prin “inițializarea mediului” înțelegem, de exemplu, că este activat Tracy, care este un instrument uimitor pentru înregistrarea sau vizualizarea erorilor. Acesta înregistrează erorile de pe serverul de producție și le afișează direct pe serverul de dezvoltare. Prin urmare, inițializarea trebuie, de asemenea, să decidă dacă site-ul rulează în modul de producție sau de dezvoltare. Pentru a face acest lucru, Nette folosește autodetecția: dacă executați site-ul pe localhost, acesta rulează în modul dezvoltator. Nu trebuie să configurați nimic, iar aplicația este pregătită atât pentru dezvoltare, cât și pentru implementarea în producție. Acești pași sunt realizați și descriși în detaliu în capitolul despre clasa Bootstrap.
Al treilea punct (da, l-am sărit pe al doilea, dar vom reveni la el) este să pornim aplicația. Gestionarea cererilor HTTP
în Nette este realizată de clasa Nette\Application\Application
(denumită în continuare Application
),
astfel încât atunci când spunem “a rula o aplicație”, ne referim la apelarea unei metode cu numele run()
pe
un obiect din această clasă.
Nette este un mentor care vă ghidează să scrieți aplicații curate prin metodologii dovedite. Iar cea mai dovedită se
numește Injecție de dependență, prescurtat DI. Deocamdată nu vrem să vă împovărăm cu explicații despre DI,
deoarece există un capitol separat, important aici este
că obiectele cheie vor fi create de obicei de o fabrică de obiecte numită DI container (abreviat DIC). Da, aceasta este
fabrica care a fost menționată cu ceva timp în urmă. Și tot ea creează pentru noi obiectul Application
, deci
avem nevoie mai întâi de un container. Îl obținem cu ajutorul clasei Configurator
și îl lăsăm să producă
obiectul Application
, apelăm metoda run()
și astfel pornim aplicația Nette. Este exact ceea ce se
întâmplă în fișierul index.php.
Aplicația Nette
Clasa Application are o singură sarcină: să răspundă la o cerere HTTP.
Aplicațiile scrise în Nette sunt împărțite în mai multe așa-numite prezentări (în alte framework-uri este posibil să întâlniți termenul de controler, care este același), care sunt clase care reprezintă o anumită pagină de site web: de exemplu, pagina de start; produs în magazinul electronic; formular de înregistrare; feed sitemap etc. Aplicația poate avea de la unul până la mii de prezentatori.
Aplicația începe prin a cere așa-numitului router să decidă care dintre prezentatori să transmită cererea curentă
pentru procesare. Routerul decide a cui este responsabilitatea. Acesta se uită la URL-ul de intrare
https://example.com/product/123
, care dorește să show
un produs cu id: 123
ca acțiune.
Este un bun obicei să se scrie perechile prezentator + acțiune separate de două puncte ca Product:show
.
Astfel, routerul a transformat URL-ul într-o pereche Presenter:action
+ parametri, în cazul nostru
Product:show
+ id: 123
. Puteți vedea cum arată un router în fișierul
app/Core/RouterFactory.php
și îl vom descrie în detaliu în capitolul Routing.
Să mergem mai departe. Aplicația cunoaște deja numele prezentatorului și poate continua. Prin crearea unui obiect
ProductPresenter
, care este codul prezentatorului Product
. Mai exact, solicită containerului DI crearea
prezentatorului, deoarece producerea de obiecte este sarcina acestuia.
Prezentatorul ar putea arăta astfel:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// obținem datele din model și le transmitem șablonului
$this->template->product = $this->repository->getProduct($id);
}
}
Cererea este gestionată de prezentator. Iar sarcina este clară: efectuați acțiunea show
cu
id: 123
. Ceea ce în limbajul prezentatorilor înseamnă că metoda renderShow()
este apelată și în
parametrul $id
se obține 123
.
Un prezentator poate gestiona mai multe acțiuni, adică are mai multe metode render<Action>()
. Dar noi
recomandăm proiectarea de prezentatoare cu una sau cât mai puține acțiuni posibile.
Așadar, a fost apelată metoda renderShow(123)
, al cărei cod este un exemplu fictiv, dar se poate vedea pe ea
cum sunt transmise datele către șablon, adică prin scrierea la $this->template
.
Ulterior, prezentatorul returnează răspunsul. Acesta poate fi o pagină HTML, o imagine, un document XML, trimiterea unui
fișier de pe disc, JSON sau redirecționarea către o altă pagină. Este important de reținut că, dacă nu spunem în mod
explicit cum să răspundem (ceea ce este cazul ProductPresenter
), răspunsul va fi redarea șablonului cu o pagină
HTML. De ce? Ei bine, pentru că în 99% din cazuri dorim să desenăm un șablon, așa că prezentatorul ia acest comportament ca
fiind implicit și dorește să ne ușureze munca. Acesta este punctul de vedere al lui Nette.
Nici măcar nu trebuie să specificăm ce șablon să redăm; cadrul va deduce singur calea. În cazul acțiunii
show
, acesta încearcă pur și simplu să încarce șablonul show.latte
din directorul cu clasa
ProductPresenter
. De asemenea, încearcă să găsească aspectul în fișierul @layout.latte
(mai multe
informații despre căutarea șabloanelor).
Ulterior, șabloanele sunt redate. Acest lucru încheie sarcina prezentatorului și a întregii aplicații, iar activitatea este finalizată. În cazul în care șablonul nu există, ar fi returnată o pagină de eroare 404. Puteți citi mai multe despre prezentatori pe pagina Prezentatori.
Doar pentru a fi siguri, să încercăm să recapitulăm întregul proces cu un URL ușor diferit:
- URL-ul va fi
https://example.com
- vom porni aplicația, vom crea un container și vom rula
Application::run()
- routerul decodifică URL-ul ca o pereche
Home:default
- este creat un obiect
HomePresenter
- se apelează metoda
renderDefault()
(dacă există) - este redat un șablon
default.latte
cu un layout@layout.latte
Este posibil să fi întâlnit acum o mulțime de concepte noi, dar noi credem că acestea au sens. Crearea de aplicații în Nette este o joacă de copii.
Șabloane
În ceea ce privește șabloanele, Nette folosește sistemul de șabloane Latte. De
aceea, fișierele cu șabloane se termină cu .latte
. Latte este utilizat deoarece este cel mai sigur sistem de
șabloane pentru PHP și, în același timp, cel mai intuitiv sistem. Nu trebuie să învățați multe lucruri noi, trebuie doar
să cunoașteți PHP și câteva etichete Latte. Veți afla totul în
documentație.
În șablon creăm un link către alți prezentatori & acțiuni după cum urmează:
<a n:href="Product:show $productId">product detail</a>
Pur și simplu scrieți binomul cunoscut Presenter:action
în locul URL-ului real și includeți orice parametru.
Trucul este n:href
, care spune că acest atribut va fi procesat de Nette. Și acesta va genera:
<a href="/product/456">product detail</a>
Routerul menționat anterior se ocupă de generarea URL-ului. De fapt, routerele din Nette sunt unice prin faptul că pot efectua nu numai transformări de la un URL la o pereche prezentator:acțiune, ci și invers, generează un URL din numele prezentatorului + acțiune + parametri. Datorită acestui fapt, în Nette puteți schimba complet forma URL-ului în întreaga aplicație finalizată fără a schimba nici măcar un singur caracter din șablon sau prezentator, doar prin modificarea routerului. Și datorită acestui lucru, funcționează așa-numita canonizare, care este o altă caracteristică unică a Nette, care îmbunătățește SEO (optimizarea capacității de căutare pe internet) prin prevenirea automată a existenței conținutului duplicat la diferite URL-uri. Mulți programatori consideră acest lucru uimitor.
Componente interactive
Mai avem un lucru de spus despre prezentatori: aceștia au un sistem de componente încorporat. Cei mai în vârstă dintre dumneavoastră își amintesc poate ceva similar din Delphi sau ASP.NET Web Forms. React sau Vue.js este construit pe ceva foarte asemănător. În lumea cadrelor PHP, aceasta este o caracteristică complet unică.
Componentele sunt unități separate reutilizabile pe care le plasăm în pagini (adică în prezentatori). Ele pot fi formulare, datagrids, meniuri, sondaje, de fapt, orice are sens să fie folosit în mod repetat. Putem să ne creăm propriile componente sau să folosim o parte din gama imensă de componente opensource.
Componentele schimbă în mod fundamental abordarea dezvoltării aplicațiilor. Ele vor deschide noi posibilități de a compune pagini din unități predefinite. Și au ceva în comun cu Hollywood-ul.
Containerul și configurația DI
Containerul DI (fabrica de obiecte) este inima întregii aplicații.
Nu vă faceți griji, nu este o cutie neagră magică, așa cum ar putea părea din cuvintele anterioare. De fapt, este
o clasă PHP destul de plictisitoare generată de Nette și stocată într-un director de cache. Are o mulțime de metode numite
createServiceAbcd()
și fiecare dintre ele creează și returnează un obiect. Da, există, de asemenea, o metodă
createServiceApplication()
care va produce Nette\Application\Application
, de care aveam nevoie în
fișierul index.php
pentru a rula aplicația. Și există metode pentru a produce prezentatori individuali. Și așa
mai departe.
Obiectele pe care le creează containerul DI se numesc servicii dintr-un anumit motiv.
Ceea ce este cu adevărat special la această clasă este faptul că nu este programată de dumneavoastră, ci de către cadru.
Acesta generează de fapt codul PHP și îl salvează pe disc. Dumneavoastră doar dați instrucțiuni cu privire la obiectele pe
care containerul ar trebui să fie capabil să le producă și cum anume. Iar aceste instrucțiuni sunt scrise în fișiere de configurare în format NEON și, prin urmare, au extensia .neon
.
Fișierele de configurare sunt utilizate exclusiv pentru a da instrucțiuni containerului DI. Astfel, de exemplu, dacă
precizez opțiunea expiration: 14 days
în secțiunea sesiune, containerul DI, atunci când creează obiectul
Nette\Http\Session
care reprezintă sesiunea, va apela metoda sa setExpiration('14 days')
, și astfel
configurația devine realitate.
Există un întreg capitol pregătit pentru dumneavoastră, în care se descrie ce poate fi configurat și cum să vă definiți propriile servicii.
Odată ce intrați în crearea serviciilor, veți da peste cuvântul autowiring. Acesta este un gadget care vă va face viața incredibil de ușoară. Acesta poate trece automat obiectele acolo unde aveți nevoie de ele (în constructorii claselor dvs., de exemplu), fără să trebuiască să faceți nimic. Veți descoperi că containerul DI din Nette este un mic miracol.
Ce urmează?
Am trecut în revistă principiile de bază ale aplicațiilor în Nette. Până acum, foarte superficial, dar în curând veți pătrunde în profunzime și, în cele din urmă, veți crea aplicații web minunate. Unde să continuăm? Ați încercat tutorialul Creează-ți prima aplicație?
Pe lângă cele de mai sus, Nette are un întreg arsenal de clase utile, un strat de baze de date, etc. Încercați în mod intenționat doar să faceți clic prin documentație. Sau vizitați blogul. Veți descoperi o mulțime de lucruri interesante.
Lăsați cadrul să vă aducă multă bucurie 💙.