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
│   ├── Presenters/           ← presenter classes
│   │   ├── HomePresenter.php ← Home presenter class
│   │   └── templates/        ← templates directory
│   │       ├── @layout.latte ← template of shared layout
│   │       └── Home/         ← templates for Home presenter
│   │           └── default.latte  ← template for action `default`
│   ├── Router/               ← configuration of URL addresses
│   └── 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:

  1. să inițializeze mediul
  2. să obțină fabrica
  3. 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/Router/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ă precizăm ce șablon să desenăm, el derivă calea către acesta conform unei logici simple. În cazul prezentatorului Product și al acțiunii show, el încearcă să vadă dacă unul dintre aceste fișiere șablon există în raport cu directorul în care se află clasa ProductPresenter:

  • templates/Product/show.latte
  • templates/Product.show.latte

De asemenea, va încerca să găsească aspectul în fișierul @layout.latte și apoi va reda șablonul. Acum sarcina prezentatorului și a întregii aplicații este finalizată. În cazul în care șablonul nu există, va fi returnată o pagină cu eroarea 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:

  1. URL-ul va fi https://example.com
  2. vom porni aplicația, vom crea un container și vom rula Application::run()
  3. routerul decodifică URL-ul ca o pereche Home:default
  4. este creat un obiect HomePresenter
  5. se apelează metoda renderDefault() (dacă există)
  6. este redat un șablon templates/Home/default.latte cu un layout templates/@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 💙.

versiune: 4.0