Cum funcționează aplicațiile?
Tocmai citiți documentul de bază al documentației Nette. Veți afla întregul principiu de funcționare al aplicațiilor web. De la A la Z, de la momentul nașterii până la ultima suflare a scriptului PHP. După citire, veți ști:
- cum funcționează totul
- ce sunt Bootstrap, Presenter și containerul DI
- cum arată structura directoarelor
Structura directoarelor
Deschideți exemplul de schelet al unei aplicații web numit WebProject și, în timp ce citiți, puteți privi fișierele despre care este vorba.
Structura directoarelor arată cam așa:
web-project/ ├── app/ ← director cu aplicația │ ├── Core/ ← clase de bază necesare pentru funcționare │ │ └── RouterFactory.php ← configurarea adreselor URL │ ├── Presentation/ ← presentere, șabloane & co. │ │ ├── @layout.latte ← șablon de layout │ │ └── Home/ ← directorul presenterului Home │ │ ├── HomePresenter.php ← clasa presenterului Home │ │ └── default.latte ← șablonul acțiunii default │ └── Bootstrap.php ← clasa de inițializare Bootstrap ├── bin/ ← scripturi rulate din linia de comandă ├── config/ ← fișiere de configurare │ ├── common.neon │ └── services.neon ├── log/ ← erori înregistrate ├── temp/ ← fișiere temporare, cache, … ├── vendor/ ← biblioteci instalate de Composer │ ├── ... │ └── autoload.php ← autoloading pentru toate pachetele instalate ├── www/ ← director public sau document-root al proiectului │ ├── .htaccess ← reguli mod_rewrite │ └── index.php ← fișierul inițial prin care se lansează aplicația └── .htaccess ← interzice accesul la toate directoarele, cu excepția www
Structura directoarelor poate fi modificată oricum, folderele pot fi redenumite sau mutate, este complet flexibilă. Nette dispune, în plus, de autodetecție inteligentă și recunoaște automat locația aplicației, inclusiv baza sa URL.
Pentru aplicații puțin mai mari, putem împărți folderele cu presentere și șabloane în subdirectoare și clasele în spații de nume, pe care le numim module.
Directorul www/
reprezintă așa-numitul director public sau document-root al proiectului. Îl puteți redenumi
fără a fi nevoie să setați altceva în partea de aplicație. Este necesar doar să configurați hostingul astfel
încât document-root să indice către acest director.
WebProject poate fi, de asemenea, descărcat direct, inclusiv Nette, folosind Composer:
Pe Linux sau macOS, setați permisiunile de
scriere pentru directoarele log/
și temp/
.
Aplicația WebProject este gata de rulare, nu este nevoie să configurați absolut nimic și o puteți afișa direct în
browser accesând folderul www/
.
Cerere HTTP
Totul începe în momentul în care utilizatorul deschide pagina în browser. Adică atunci când browserul bate la ușa
serverului cu o cerere HTTP. Cererea vizează un singur fișier PHP, care se află în directorul public www/
, și
acesta este index.php
. Să presupunem că este vorba despre o cerere pentru adresa
https://example.com/product/123
. Datorită setărilor adecvate ale serverului,
chiar și acest URL este mapat pe fișierul index.php
și acesta se execută.
Sarcina sa este:
- inițializarea mediului
- obținerea fabricii
- pornirea aplicației Nette, care va gestiona cererea
Ce fel de fabrică? Nu producem tractoare, ci pagini web! Aveți răbdare, se va explica imediat.
Prin „inițializarea mediului” ne referim, de exemplu, la faptul că se activează Tracy, care este un instrument uimitor pentru înregistrarea sau vizualizarea erorilor. Pe serverul de producție, înregistrează erorile, pe cel de dezvoltare le afișează direct. Prin urmare, inițializarea include și decizia dacă site-ul rulează în modul de producție sau de dezvoltare. Pentru aceasta, Nette utilizează autodetecția inteligentă: dacă rulați site-ul pe localhost, rulează în modul de dezvoltare. Nu trebuie să configurați nimic și aplicația este direct pregătită atât pentru dezvoltare, cât și pentru implementarea live. Acești pași se efectuează și sunt descriși detaliat în capitolul despre clasa Bootstrap.
Al treilea punct (da, am sărit peste al doilea, dar vom reveni la el) este pornirea aplicației. Gestionarea cererilor HTTP
este responsabilitatea clasei Nette\Application\Application
(în continuare Application
), așa că
atunci când spunem pornirea aplicației, ne referim în mod specific la apelarea metodei cu numele sugestiv run()
pe
obiectul acestei clase.
Nette este un mentor care vă ghidează să scrieți aplicații curate conform metodologiilor dovedite. Și una dintre cele
absolut cele mai dovedite se numește dependency injection, prescurtat DI. În acest moment, nu vrem să vă încărcăm cu
explicații despre DI, pentru asta există un capitol separat, esențial este
rezultatul că obiectele cheie ne vor fi de obicei create de o fabrică de obiecte, care se numește container DI
(prescurtat DIC). Da, aceasta este fabrica despre care am vorbit mai devreme. Și ne va produce și obiectul
Application
, de aceea avem nevoie mai întâi de container. Îl obținem folosind clasa Configurator
și
îl lăsăm să producă obiectul Application
, apelăm pe el metoda run()
și astfel pornește
aplicația Nette. Exact acest lucru se întâmplă în fișierul index.php.
Nette Application
Clasa Application are o singură sarcină: să răspundă la cererea HTTP.
Aplicațiile scrise în Nette sunt împărțite în multe așa-numite presentere (în alte framework-uri puteți întâlni termenul controller, este același lucru), care sunt clase, fiecare reprezentând o anumită pagină specifică a site-ului: de ex. homepage; produs într-un magazin online; formular de conectare; feed sitemap etc. Aplicația poate avea de la unul la mii de presentere.
Application începe prin a solicita așa-numitului router să decidă căruia dintre presentere să îi transmită cererea
curentă pentru gestionare. Routerul decide a cui este responsabilitatea. Se uită la URL-ul de intrare
https://example.com/product/123
și, pe baza modului în care este setat, decide că aceasta este treaba, de ex., a
presenterului Product
, de la care va dori ca acțiune afișarea (show
) produsului cu
id: 123
. Perechea presenter + acțiune este o bună practică să fie scrisă separată prin două puncte ca
Product:show
.
Deci, routerul a transformat URL-ul în perechea Presenter:action
+ parametri, în cazul nostru
Product:show
+ id: 123
. Cum arată un astfel de router puteți vedea în fișierul
app/Core/RouterFactory.php
și îl descriem detaliat în capitolul Rutare.
Să mergem mai departe. Application cunoaște deja numele presenterului și poate continua. Prin crearea obiectului clasei
ProductPresenter
, care este codul presenterului Product
. Mai precis, solicită containerului DI să
creeze presenterul, deoarece crearea este treaba lui.
Presenterul poate arăta, de exemplu, așa:
Gestionarea cererii este preluată de presenter. Și sarcina este clară: execută acțiunea show
cu
id: 123
. Ceea ce, în limbajul presenterelor, înseamnă că se apelează metoda renderShow()
și în
parametrul $id
primește 123
.
Presenterul poate gestiona mai multe acțiuni, adică poate avea mai multe metode render<Action>()
. Dar
recomandăm proiectarea presenterelor cu una sau cât mai puține acțiuni.
Deci, s-a apelat metoda renderShow(123)
, al cărei cod este un exemplu fictiv, dar puteți vedea pe el cum se
transmit datele către șablon, adică prin scrierea în $this->template
.
Ulterior, presenterul returnează un răspuns. Acesta poate fi o pagină HTML, o imagine, un document XML, trimiterea unui
fișier de pe disc, JSON sau chiar o redirecționare către o altă pagină. Important este că, dacă nu spunem explicit cum
să răspundă (ceea ce este cazul ProductPresenter
), răspunsul va fi redarea șablonului cu pagina HTML. De ce?
Deoarece în 99% din cazuri dorim să redăm un șablon, prin urmare presenterul consideră acest comportament ca fiind implicit
și vrea să ne ușureze munca. Acesta este scopul Nette.
Nu trebuie nici măcar să specificăm ce șablon să redăm, calea către acesta o deduce singur. În cazul acțiunii
show
, încearcă pur și simplu să încarce șablonul show.latte
din directorul cu clasa
ProductPresenter
. De asemenea, încearcă să găsească layout-ul în fișierul @layout.latte
(mai
detaliat despre găsirea șabloanelor).
Și ulterior redă șabloanele. Astfel, sarcina presenterului și a întregii aplicații este finalizată și lucrarea este încheiată. Dacă șablonul nu ar exista, s-ar returna o pagină cu eroarea 404. Mai multe despre presentere puteți citi pe pagina Presentere.
Pentru siguranță, să încercăm să recapitulăm întregul proces cu un URL puțin diferit:
- URL-ul va fi
https://example.com
- inițializăm aplicația, se creează containerul și se rulează
Application::run()
- routerul decodează URL-ul ca perechea
Home:default
- se creează obiectul clasei
HomePresenter
- se apelează metoda
renderDefault()
(dacă există) - se redă șablonul, de ex.
default.latte
cu layout-ul, de ex.@layout.latte
Poate că v-ați întâlnit acum cu o mulțime de termeni noi, dar credem că au sens. Crearea aplicațiilor în Nette este o adevărată plăcere.
Șabloane
Deoarece am ajuns la subiectul șabloanelor, în Nette se utilizează sistemul de șabloane Latte. De aceea și extensiile .latte
la șabloane. Latte se utilizează, pe
de o parte, pentru că este cel mai sigur sistem de șabloane pentru PHP și, pe de altă parte, și cel mai intuitiv sistem. Nu
trebuie să învățați multe lucruri noi, vă descurcați cu cunoștințele de PHP și câteva tag-uri. Totul veți afla în documentație.
În șablon se creează linkuri către alți presenteri & acțiuni astfel:
Pur și simplu, în loc de URL-ul real, scrieți perechea cunoscută Presenter:action
și specificați eventualii
parametri. Trucul este în n:href
, care spune că acest atribut va fi procesat de Nette. Și va genera:
Generarea URL-ului este responsabilitatea routerului menționat anterior. De fapt, routerele din Nette sunt excepționale prin faptul că pot efectua nu numai transformări din URL în perechea presenter:action, ci și invers, adică din numele presenterului + acțiunii + parametrilor să genereze un URL. Datorită acestui fapt, în Nette puteți schimba complet formele URL-urilor în întreaga aplicație finalizată, fără a schimba un singur caracter în șablon sau presenter. Doar prin modificarea routerului. De asemenea, datorită acestui fapt funcționează așa-numita canonizare, care este o altă caracteristică unică a Nette, care contribuie la un SEO mai bun (optimizarea găsirii pe internet) prin prevenirea automată a existenței conținutului duplicat la URL-uri diferite. Mulți programatori consideră acest lucru uimitor.
Componente interactive
Despre presentere trebuie să vă mai spunem un lucru: au încorporat un sistem de componente. Ceva similar ar putea fi cunoscut de veterani din Delphi sau ASP.NET Web Forms, ceva asemănător stă la baza React sau Vue.js. În lumea framework-urilor PHP, este o caracteristică complet unică.
Componentele sunt unități separate, reutilizabile, pe care le inserăm în pagini (adică presentere). Acestea pot fi formulare, datagrid-uri, meniuri, sondaje de votare, de fapt, orice are sens să fie folosit în mod repetat. Putem crea propriile componente sau putem folosi unele din oferta imensă de componente open source.
Componentele influențează fundamental abordarea creării aplicațiilor. Vă vor deschide noi posibilități de compunere a paginilor din unități pre-pregătite. Și, în plus, au ceva în comun cu Hollywood-ul.
Container DI și configurare
Containerul DI sau fabrica de obiecte este inima întregii aplicații.
Nu vă faceți griji, nu este nicio cutie neagră magică, așa cum ar putea părea din rândurile anterioare. De fapt, este
o clasă PHP destul de plictisitoare, pe care Nette o generează și o salvează în directorul de cache. Are o mulțime de
metode numite precum createServiceAbcd()
și fiecare dintre ele știe să creeze și să returneze un anumit obiect.
Da, există și metoda createServiceApplication()
, care creează Nette\Application\Application
, de care
aveam nevoie în fișierul index.php
pentru a porni aplicația. Și există metode care creează presentere
individuale. Și așa mai departe.
Obiectelor pe care le creează containerul DI li se spune, din anumite motive, servicii.
Ceea ce este cu adevărat special la această clasă este că nu o programați voi, ci framework-ul. El generează efectiv
codul PHP și îl salvează pe disc. Voi doar dați instrucțiuni despre ce obiecte ar trebui să știe să creeze containerul și
cum anume. Iar aceste instrucțiuni sunt scrise în fișierele de
configurare, pentru care se utilizează formatul NEON și, prin urmare, au și
extensia .neon
.
Fișierele de configurare servesc exclusiv pentru a instrui containerul DI. Deci, dacă, de exemplu, specific în secțiunea session opțiunea expiration: 14 days
, atunci containerul DI, la crearea
obiectului Nette\Http\Session
reprezentând sesiunea, va apela metoda sa setExpiration('14 days')
și
astfel configurația devine realitate.
Există un capitol întreg pregătit pentru voi, care descrie ce totul poate fi configurat și cum să definiți propriile servicii.
Odată ce pătrundeți puțin în crearea serviciilor, veți întâlni cuvântul autowiring. Acesta este un truc care vă va simplifica viața într-un mod incredibil. Poate transmite automat obiectele acolo unde aveți nevoie de ele (de exemplu, în constructorii claselor voastre), fără a fi nevoie să faceți nimic. Veți descoperi că containerul DI din Nette este un mic miracol.
Unde să mergem mai departe?
Am parcurs principiile de bază ale aplicațiilor în Nette. Deocamdată foarte superficial, dar în curând veți pătrunde în profunzime și, în timp, veți crea aplicații web minunate. Unde să continuăm? Ați încercat deja tutorialul Scriem prima aplicație?
Pe lângă cele descrise mai sus, Nette dispune de un întreg arsenal de clase utile, un strat de baze de date, etc. Încercați să răsfoiți documentația. Sau blogul. Veți descoperi o mulțime de lucruri interesante.
Sperăm ca framework-ul să vă aducă multă bucurie 💙