-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathpresenters.texy
More file actions
500 lines (326 loc) · 24.2 KB
/
presenters.texy
File metadata and controls
500 lines (326 loc) · 24.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
Presentere
**********
<div class=perex>
Vom face cunoștință cu modul în care se scriu presenterele și șabloanele în Nette. După citire, veți ști:
- cum funcționează un presenter
- ce sunt parametrii persistenți
- cum se redau șabloanele
</div>
[Știm deja |how-it-works#Nette Application] că presenterul este o clasă care reprezintă o anumită pagină specifică a aplicației web, de ex. pagina de start; un produs într-un magazin online; formularul de conectare; feed-ul sitemap etc. Aplicația poate avea de la unul la mii de presentere. În alte framework-uri li se mai spune și controllere.
De obicei, prin termenul presenter se înțelege un descendent al clasei [api:Nette\Application\UI\Presenter], care este potrivit pentru generarea interfețelor web și căruia ne vom dedica în restul acestui capitol. În sens general, un presenter este orice obiect care implementează interfața [api:Nette\Application\IPresenter].
Ciclul de viață al presenterului
================================
Sarcina presenterului este de a gestiona cererea și de a returna un răspuns (care poate fi o pagină HTML, o imagine, o redirecționare etc.).
Deci, la început i se transmite cererea. Nu este direct o cerere HTTP, ci obiectul [api:Nette\Application\Request], în care a fost transformată cererea HTTP cu ajutorul routerului. Cu acest obiect, de obicei, nu intrăm în contact, deoarece presenterul deleagă inteligent procesarea cererii către alte metode, pe care le vom prezenta acum.
[* lifecycle.svg *] *** Ciclul de viață al presenterului .<>
Imaginea reprezintă lista metodelor care sunt apelate succesiv de sus în jos, dacă există. Niciuna dintre ele nu trebuie să existe, putem avea un presenter complet gol, fără nicio metodă, și să construim pe el un site web static simplu.
`__construct()`
---------------
Constructorul nu face parte în totalitate din ciclul de viață al presenterului, deoarece este apelat în momentul creării obiectului. Dar îl menționăm datorită importanței sale. Constructorul (împreună cu [metoda inject|best-practices:inject-method-attribute]) servește la transmiterea dependențelor.
Presenterul nu ar trebui să se ocupe de logica de business a aplicației, să scrie și să citească din baza de date, să efectueze calcule etc. Pentru asta există clase din stratul pe care îl numim model. De exemplu, clasa `ArticleRepository` poate avea responsabilitatea de a încărca și salva articole. Pentru ca presenterul să poată lucra cu ea, o primește [transmisă prin dependency injection |dependency-injection:passing-dependencies]:
```php
class ArticlePresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ArticleRepository $articles,
) {
}
}
```
`startup()`
-----------
Imediat după primirea cererii, se apelează metoda `startup()`. O puteți utiliza pentru inițializarea proprietăților, verificarea permisiunilor utilizatorului etc. Este necesar ca metoda să apeleze întotdeauna părintele `parent::startup()`.
`action<Action>(args...)` .{toc: action<Action>()}
--------------------------------------------------
Similară cu metoda `render<View>()`. În timp ce `render<View>()` este destinată pregătirii datelor pentru un șablon specific care urmează să fie redat, în `action<Action>()` se procesează cererea fără legătură cu redarea șablonului. De exemplu, se procesează date, se conectează sau deconectează utilizatorul, și așa mai departe, și apoi [se redirecționează în altă parte |#Redirecționare].
Important este că `action<Action>()` se apelează înainte de `render<View>()`, deci în ea putem eventual schimba cursul ulterior al evenimentelor, adică să schimbăm șablonul care va fi redat, și, de asemenea, metoda `render<View>()` care va fi apelată. Și asta folosind `setView('jineView')`.
Metodei i se transmit parametri din cerere. Este posibil și recomandat să se specifice tipurile parametrilor, de ex. `actionShow(int $id, ?string $slug = null)` - dacă parametrul `id` lipsește sau dacă nu este un integer, presenterul va returna [eroarea 404 |#Eroare 404 etc] și va încheia activitatea.
`handle<Signal>(args...)` .{toc: handle<Signal>()}
--------------------------------------------------
Metoda procesează așa-numitele semnale, cu care ne vom familiariza în capitolul dedicat [componentelor |components#Semnal]. Este destinată în special componentelor și procesării cererilor AJAX.
Metodei i se transmit parametri din cerere, ca în cazul `action<Action>()`, inclusiv verificarea tipului.
`beforeRender()`
----------------
Metoda `beforeRender`, așa cum sugerează și numele, se apelează înainte de fiecare metodă `render<View>()`. Se utilizează pentru configurarea comună a șablonului, transmiterea variabilelor pentru layout și altele asemenea.
`render<View>(args...)` .{toc: render<View>()}
----------------------------------------------
Locul unde pregătim șablonul pentru redarea ulterioară, îi transmitem date etc.
Metodei i se transmit parametri din cerere, ca în cazul `action<Action>()`, inclusiv verificarea tipului.
```php
public function renderShow(int $id): void
{
// obținem datele din model și le transmitem șablonului
$this->template->article = $this->articles->getById($id);
}
```
`afterRender()`
---------------
Metoda `afterRender`, așa cum sugerează din nou numele, se apelează după fiecare metodă `render<View>()`. Se utilizează mai degrabă excepțional.
`shutdown()`
------------
Se apelează la sfârșitul ciclului de viață al presenterului.
**Un sfat bun, înainte de a merge mai departe**. Presenterul, după cum se vede, poate gestiona mai multe acțiuni/view-uri, adică poate avea mai multe metode `render<View>()`. Dar recomandăm proiectarea presenterelor cu una sau cât mai puține acțiuni.
Trimiterea răspunsului
======================
Răspunsul presenterului este, de regulă, [redarea unui șablon cu o pagină HTML|templates], dar poate fi și trimiterea unui fișier, JSON sau chiar o redirecționare către o altă pagină.
Oricând în timpul ciclului de viață putem trimite un răspuns folosind una dintre următoarele metode și, în același timp, să încheiem presenterul:
- `redirect()`, `redirectPermanent()`, `redirectUrl()` și `forward()` [redirecționează |#Redirecționare]
- `error()` încheie presenterul [din cauza unei erori |#Eroare 404 etc]
- `sendJson($data)` încheie presenterul și [trimite date |#Trimiterea JSON] în format JSON
- `sendTemplate()` încheie presenterul și imediat [redă șablonul |templates]
- `sendResponse($response)` încheie presenterul și trimite [un răspuns propriu |#Răspunsuri]
- `terminate()` încheie presenterul fără răspuns
Dacă nu apelați niciuna dintre aceste metode, presenterul va trece automat la redarea șablonului. 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.
Crearea linkurilor
==================
Presenterul dispune de metoda `link()`, cu ajutorul căreia se pot crea linkuri URL către alți presenteri. Primul parametru este presenterul & acțiunea țintă, urmate de argumentele transmise, care pot fi specificate ca array:
```php
$url = $this->link('Product:show', $id);
$url = $this->link('Product:show', [$id, 'lang' => 'cs']);
```
În șablon se creează linkuri către alți presenteri & acțiuni în acest mod:
```latte
<a n:href="Product:show $id">detaliu produs</a>
```
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 Latte și va genera URL-ul real. În Nette, nu trebuie să vă gândiți deloc la URL-uri, ci doar la presentere și acțiuni.
Mai multe informații găsiți în capitolul [Crearea linkurilor URL|creating-links].
Redirecționare
==============
Pentru a trece la un alt presenter se utilizează metodele `redirect()` și `forward()`, care au o sintaxă foarte similară cu metoda [link() |#Crearea linkurilor].
Metoda `forward()` trece imediat la noul presenter fără redirecționare HTTP:
```php
$this->forward('Product:show');
```
Exemplu de așa-numită redirecționare temporară cu codul HTTP 302 (sau 303, dacă metoda cererii curente este POST):
```php
$this->redirect('Product:show', $id);
```
Redirecționarea permanentă cu codul HTTP 301 se realizează astfel:
```php
$this->redirectPermanent('Product:show', $id);
```
Către un alt URL în afara aplicației se poate redirecționa cu metoda `redirectUrl()`. Ca al doilea parametru se poate specifica codul HTTP, implicit este 302 (sau 303, dacă metoda cererii curente este POST):
```php
$this->redirectUrl('https://nette.org');
```
Redirecționarea încheie imediat activitatea presenterului prin aruncarea așa-numitei excepții de terminare silențioasă `Nette\Application\AbortException`.
Înainte de redirecționare se poate trimite un [mesaj flash |#Mesaje flash], adică mesaje care vor fi afișate în șablon după redirecționare.
Mesaje flash
============
Acestea sunt mesaje care informează de obicei despre rezultatul unei operațiuni. O caracteristică importantă a mesajelor flash este că sunt disponibile în șablon chiar și după redirecționare. Chiar și după afișare, rămân active încă 30 de secunde – de exemplu, în cazul în care utilizatorul ar reîncărca pagina din cauza unei erori de transmisie - mesajul nu dispare imediat.
Este suficient să apelați metoda [flashMessage() |api:Nette\Application\UI\Control::flashMessage()] și presenterul se va ocupa de transmiterea către șablon. Primul parametru este textul mesajului și al doilea parametru opțional este tipul său (error, warning, info etc.). Metoda `flashMessage()` returnează instanța mesajului flash, căreia i se pot adăuga informații suplimentare.
```php
$this->flashMessage('Elementul a fost șters.');
$this->redirect(/* ... */); // și redirecționăm
```
În șablon, aceste mesaje sunt disponibile în variabila `$flashes` ca obiecte `stdClass`, care conțin proprietățile `message` (textul mesajului), `type` (tipul mesajului) și pot conține informațiile utilizatorului menționate anterior. Le redăm, de exemplu, astfel:
```latte
{foreach $flashes as $flash}
<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}
```
Eroare 404 etc.
===============
Dacă cererea nu poate fi îndeplinită, de exemplu, pentru că articolul pe care dorim să îl afișăm nu există în baza de date, aruncăm eroarea 404 cu metoda `error(?string $message = null, int $httpCode = 404)`.
```php
public function renderShow(int $id): void
{
$article = $this->articles->getById($id);
if (!$article) {
$this->error();
}
// ...
}
```
Codul HTTP al erorii poate fi transmis ca al doilea parametru, implicit este 404. Metoda funcționează aruncând excepția `Nette\Application\BadRequestException`, după care `Application` predă controlul error-presenterului. Acesta este un presenter a cărui sarcină este să afișeze o pagină care informează despre eroarea apărută. Setarea error-presenterului se face în [configurația application|configuration].
Trimiterea JSON
===============
Exemplu de metodă-acțiune care trimite date în format JSON și încheie presenterul:
```php
public function actionData(): void
{
$data = ['hello' => 'nette'];
$this->sendJson($data);
}
```
Parametrii cererii .{data-version:3.1.14}
=========================================
Presenterul și, de asemenea, fiecare componentă obțin parametrii săi din cererea HTTP. Valoarea lor o aflați cu metoda `getParameter($name)` sau `getParameters()`. Valorile sunt șiruri de caractere sau array-uri de șiruri de caractere, sunt în esență date brute obținute direct din URL.
Pentru mai mult confort, recomandăm accesarea parametrilor prin proprietăți. Este suficient să le marcați cu atributul `#[Parameter]`:
```php
use Nette\Application\Attributes\Parameter; // această linie este importantă
class HomePresenter extends Nette\Application\UI\Presenter
{
#[Parameter]
public string $theme; // trebuie să fie publică
}
```
Pentru proprietate, recomandăm să specificați și tipul de date (de ex. `string`), iar Nette va converti automat valoarea conform acestuia. Valorile parametrilor pot fi, de asemenea, [validate |#Validarea parametrilor].
La crearea unui link, valoarea parametrilor poate fi setată direct:
```latte
<a n:href="Home:default theme: dark">click</a>
```
Parametri persistenți
=====================
Parametrii persistenți sunt utilizați pentru a menține starea între diferite cereri. Valoarea lor rămâne aceeași chiar și după ce se face clic pe un link. Spre deosebire de datele din sesiune, acestea sunt transmise în URL. Și acest lucru se întâmplă complet automat, deci nu este necesar să le specificați explicit în `link()` sau `n:href`.
Exemplu de utilizare? Aveți o aplicație multilingvă. Limba curentă este un parametru care trebuie să fie constant parte a URL-ului. Dar ar fi incredibil de obositor să îl specificați în fiecare link. Așa că îl faceți un parametru persistent `lang` și se va transmite singur. Minunat!
Crearea unui parametru persistent în Nette este extrem de simplă. Este suficient să creați o proprietate publică și să o marcați cu un atribut: (anterior se folosea `/** @persistent */`)
```php
use Nette\Application\Attributes\Persistent; // această linie este importantă
class ProductPresenter extends Nette\Application\UI\Presenter
{
#[Persistent]
public string $lang; // trebuie să fie publică
}
```
Dacă `$this->lang` va avea valoarea, de exemplu, `'en'`, atunci și linkurile create folosind `link()` sau `n:href` vor conține parametrul `lang=en`. Și după ce se face clic pe link, va fi din nou `$this->lang = 'en'`.
Pentru proprietate, recomandăm să specificați și tipul de date (de ex. `string`) și puteți specifica și o valoare implicită. Valorile parametrilor pot fi [validate |#Validarea parametrilor].
Parametrii persistenți sunt transmiși standard între toate acțiunile presenterului respectiv. Pentru a se transmite și între mai mulți presenteri, este necesar să fie definiți fie:
- într-un strămoș comun, de la care moștenesc presenterele
- într-un trait, pe care presenterele îl utilizează:
```php
trait LanguageAware
{
#[Persistent]
public string $lang;
}
class ProductPresenter extends Nette\Application\UI\Presenter
{
use LanguageAware;
}
```
La crearea unui link, valoarea parametrului persistent poate fi modificată:
```latte
<a n:href="Product:show $id, lang: cs">detaliu în cehă</a>
```
Sau poate fi *resetat*, adică eliminat din URL. Atunci va lua valoarea sa implicită:
```latte
<a n:href="Product:show $id, lang: null">click aici</a>
```
Componente interactive
======================
Presenterele au încorporat un sistem de componente. Componentele sunt unități separate, reutilizabile, pe care le inserăm în presentere. Acestea pot fi [formulare |forms:in-presenter], datagrid-uri, meniuri, de fapt, orice are sens să fie folosit în mod repetat.
Cum se inserează componentele în presenter și cum se utilizează ulterior? Acest lucru îl veți afla în capitolul [Componente |components]. Veți descoperi chiar și ce au în comun cu Hollywood-ul.
Și de unde pot obține componente? Pe pagina [Componette |https://componette.org/search/component] găsiți componente open-source și, de asemenea, o serie de alte add-on-uri pentru Nette, pe care le-au plasat aici voluntari din comunitatea din jurul framework-ului.
Intrăm în profunzime
====================
.[tip]
Cu ceea ce am arătat până acum în acest capitol, probabil vă veți descurca complet. Următoarele rânduri sunt destinate celor care sunt interesați de presentere în profunzime și doresc să știe absolut totul.
Validarea parametrilor
----------------------
Valorile [parametrilor cererii |#Parametrii cererii] și ale [parametrilor persistenți |#Parametri persistenți] primite din URL sunt scrise în proprietăți de către metoda `loadState()`. Aceasta verifică, de asemenea, dacă tipul de date specificat la proprietate corespunde, altfel răspunde cu eroarea 404 și pagina nu se afișează.
Nu credeți niciodată orbește în parametri, deoarece pot fi ușor suprascriși de utilizator în URL. Astfel, de exemplu, verificăm dacă limba `$this->lang` se află printre cele suportate. O cale potrivită este să suprascriem metoda menționată `loadState()`:
```php
class ProductPresenter extends Nette\Application\UI\Presenter
{
#[Persistent]
public string $lang;
public function loadState(array $params): void
{
parent::loadState($params); // aici se setează $this->lang
// urmează controlul propriu al valorii:
if (!in_array($this->lang, ['en', 'cs'])) {
$this->error();
}
}
}
```
Salvarea și restaurarea cererii
-------------------------------
Cererea pe care o gestionează presenterul este obiectul [api:Nette\Application\Request] și este returnată de metoda presenterului `getRequest()`.
Cererea curentă poate fi salvată în sesiune sau, invers, restaurată din ea și lăsată presenterului să o execute din nou. Acest lucru este util, de exemplu, în situația în care utilizatorul completează un formular și îi expiră sesiunea de conectare. Pentru a nu pierde datele, înainte de redirecționarea către pagina de conectare, salvăm cererea curentă în sesiune folosind `$reqId = $this->storeRequest()`, care returnează identificatorul său sub forma unui șir scurt și îl transmitem ca parametru presenterului de conectare.
După conectare, apelăm metoda `$this->restoreRequest($reqId)`, care preia cererea din sesiune și face forward către ea. Metoda verifică, în același timp, că cererea a fost creată de același utilizator care s-a conectat acum. Dacă s-ar conecta un alt utilizator sau cheia ar fi invalidă, nu face nimic și programul continuă.
Consultați ghidul [Cum să reveniți la pagina anterioară |best-practices:restore-request].
Canonizare
----------
Presenterele au o caracteristică cu adevărat grozavă, care contribuie la un SEO mai bun (optimizarea găsirii pe internet). Previn automat existența conținutului duplicat la URL-uri diferite. Dacă către o anumită țintă duc mai multe adrese URL, de ex. `/index` și `/index?page=1`, framework-ul o determină pe una dintre ele ca fiind primară (canonică) și le redirecționează pe celelalte către ea folosind codul HTTP 301. Datorită acestui fapt, motoarele de căutare nu vă indexează paginile de două ori și nu le diluează page rank-ul.
Acest proces se numește canonizare. URL-ul canonic este cel generat de [router|routing], de regulă deci prima rută corespunzătoare din colecție.
Canonizarea este activată implicit și poate fi dezactivată prin `$this->autoCanonicalize = false`.
Redirecționarea nu are loc la o cerere AJAX sau POST, deoarece s-ar pierde date sau nu ar avea valoare adăugată din punct de vedere SEO.
Canonizarea poate fi invocată și manual folosind metoda `canonicalize()`, căreia i se transmit, similar metodei `link()`, presenterul, acțiunea și parametrii. Creează un link și îl compară cu URL-ul curent. Dacă diferă, redirecționează către linkul generat.
```php
public function actionShow(int $id, ?string $slug = null): void
{
$realSlug = $this->facade->getSlugForId($id);
// redirecționează, dacă $slug diferă de $realSlug
$this->canonicalize('Product:show', [$id, $realSlug]);
}
```
Evenimente
----------
Pe lângă metodele `startup()`, `beforeRender()` și `shutdown()`, care sunt apelate ca parte a ciclului de viață al presenterului, pot fi definite și alte funcții care să fie apelate automat. Presenterul definește așa-numitele [evenimente |nette:glossary#Evenimente], ale căror handlere le adăugați în array-urile `$onStartup`, `$onRender` și `$onShutdown`.
```php
class ArticlePresenter extends Nette\Application\UI\Presenter
{
public function __construct()
{
$this->onStartup[] = function () {
// ...
};
}
}
```
Handlerele din array-ul `$onStartup` sunt apelate chiar înainte de metoda `startup()`, apoi `$onRender` între `beforeRender()` și `render<View>()` și în final `$onShutdown` chiar înainte de `shutdown()`.
Răspunsuri
----------
Răspunsul returnat de presenter este un obiect care implementează interfața [api:Nette\Application\Response]. Există o serie de răspunsuri pregătite disponibile:
- [api:Nette\Application\Responses\CallbackResponse] - trimite un callback
- [api:Nette\Application\Responses\FileResponse] - trimite un fișier
- [api:Nette\Application\Responses\ForwardResponse] - forward()
- [api:Nette\Application\Responses\JsonResponse] - trimite JSON
- [api:Nette\Application\Responses\RedirectResponse] - redirecționare
- [api:Nette\Application\Responses\TextResponse] - trimite text
- [api:Nette\Application\Responses\VoidResponse] - răspuns gol
Răspunsurile sunt trimise prin metoda `sendResponse()`:
```php
use Nette\Application\Responses;
// Text simplu
$this->sendResponse(new Responses\TextResponse('Hello Nette!'));
// Trimite fișier
$this->sendResponse(new Responses\FileResponse(__DIR__ . '/invoice.pdf', 'Invoice13.pdf'));
// Răspunsul va fi un callback
$callback = function (Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) {
if ($httpResponse->getHeader('Content-Type') === 'text/html') {
echo '<h1>Hello</h1>';
}
};
$this->sendResponse(new Responses\CallbackResponse($callback));
```
Restricționarea accesului folosind `#[Requires]` .{data-version:3.2.2}
----------------------------------------------------------------------
Atributul `#[Requires]` oferă opțiuni avansate pentru restricționarea accesului la presentere și metodele lor. Poate fi utilizat pentru specificarea metodelor HTTP, solicitarea unei cereri AJAX, restricționarea la aceeași origine (same origin) și accesul doar prin forward. Atributul poate fi aplicat atât claselor presenterelor, cât și metodelor individuale `action<Action>()`, `render<View>()`, `handle<Signal>()` și `createComponent<Name>()`.
Puteți specifica aceste restricții:
- pentru metode HTTP: `#[Requires(methods: ['GET', 'POST'])]`
- solicitarea unei cereri AJAX: `#[Requires(ajax: true)]`
- acces doar din aceeași origine: `#[Requires(sameOrigin: true)]`
- acces doar prin forward: `#[Requires(forward: true)]`
- restricționare la acțiuni specifice: `#[Requires(actions: 'default')]`
Detalii găsiți în ghidul [Cum se utilizează atributul Requires |best-practices:attribute-requires].
Verificarea metodei HTTP
------------------------
Presenterele din Nette verifică automat metoda HTTP a fiecărei cereri primite. Motivul acestei verificări este în principal securitatea. Standard, sunt permise metodele `GET`, `POST`, `HEAD`, `PUT`, `DELETE`, `PATCH`.
Dacă doriți să permiteți în plus, de exemplu, metoda `OPTIONS`, utilizați atributul `#[Requires]` (de la Nette Application v3.2):
```php
#[Requires(methods: ['GET', 'POST', 'HEAD', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])]
class MyPresenter extends Nette\Application\UI\Presenter
{
}
```
În versiunea 3.1, verificarea se face în `checkHttpMethod()`, care verifică dacă metoda specificată în cerere este inclusă în array-ul `$presenter->allowedMethods`. Adăugarea metodei se face astfel:
```php
class MyPresenter extends Nette\Application\UI\Presenter
{
protected function checkHttpMethod(): void
{
$this->allowedMethods[] = 'OPTIONS';
parent::checkHttpMethod();
}
}
```
Este important de subliniat că, dacă permiteți metoda `OPTIONS`, trebuie ulterior să o gestionați corespunzător în cadrul presenterului dvs. Metoda este adesea utilizată ca așa-numită cerere preflight, pe care browserul o trimite automat înainte de cererea reală, când este necesar să se afle dacă cererea este permisă din punctul de vedere al politicii CORS (Cross-Origin Resource Sharing). Dacă permiteți metoda, dar nu implementați un răspuns corect, acest lucru poate duce la inconsecvențe și potențiale probleme de securitate.
Lectură suplimentară
====================
- [Metode și atribute inject |best-practices:inject-method-attribute]
- [Compunerea presenterelor din trait-uri |best-practices:presenter-traits]
- [Transmiterea setărilor către presentere |best-practices:passing-settings-to-presenters]
- [Cum să reveniți la pagina anterioară |best-practices:restore-request]