forked from nette/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomponents.texy
463 lines (321 loc) · 22.1 KB
/
components.texy
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
Interaktív komponensek
**********************
<div class=perex>
A komponensek különálló, újrafelhasználható objektumok, amelyeket oldalakba helyezünk. Ezek lehetnek űrlapok, adattáblák, közvélemény-kutatások, tulajdonképpen bármi, amit érdemes ismételten használni. Megmutatjuk:
- Hogyan használjuk a komponenseket?
- hogyan írjuk meg őket?
- Mik azok a jelek?
</div>
A Nette beépített komponensrendszerrel rendelkezik. Az idősebbek talán emlékeznek valami hasonlóra a Delphiből vagy az ASP.NET Web Formsből. A React vagy a Vue.js valami távolról hasonlóra épül. A PHP keretrendszerek világában azonban ez egy teljesen egyedi funkció.
Ugyanakkor a komponensek alapvetően megváltoztatják az alkalmazásfejlesztés megközelítését. Előre elkészített egységekből állíthat össze oldalakat. Adattáblára van szüksége az adminisztrációban? Megtalálhatja a [Componette-ben |https://componette.org/search/component], a Nette nyílt forráskódú kiegészítőinek (nem csak komponensek) tárházában, és egyszerűen beillesztheti a prezenterbe.
Bármennyi komponenst beépíthet a prezenterbe. Néhány komponensbe pedig más komponenseket is beilleszthet. Ezáltal egy komponensfa jön létre, amelynek gyökere a prezenter.
Gyári módszerek .[#toc-factory-methods]
=======================================
Hogyan kerülnek a komponensek elhelyezésre és későbbi használatra a prezenterben? Általában gyári metódusok segítségével.
A komponens gyár egy elegáns módja annak, hogy csak akkor hozzunk létre komponenseket, amikor valóban szükség van rájuk (lazy / on-demand). Az egész varázslat egy metódus megvalósításában rejlik, melynek neve `createComponent<Name>()`, ahol `<Name>` a komponens neve, amely létrehozza és visszaadja.
```php .{file:DefaultPresenter.php}
class DefaultPresenter extends Nette\Application\UI\Presenter
{
protected function createComponentPoll(): PollControl
{
$poll = new PollControl;
$poll->items = $this->item;
return $poll;
}
}
```
Mivel minden komponens külön metódusban jön létre, a kód tisztább és könnyebben olvasható.
.[note]
A komponensek nevei mindig kisbetűvel kezdődnek, bár a metódusnévben nagybetűvel kezdődnek.
A gyárakat sosem hívjuk közvetlenül, automatikusan meghívódnak, amikor először használjuk a komponenseket. Ennek köszönhetően egy komponens a megfelelő pillanatban jön létre, és csak akkor, ha valóban szükség van rá. Ha nem használnánk a komponenst (például valamilyen AJAX kérésnél, ahol az oldalnak csak egy részét adjuk vissza, vagy amikor a részeket gyorsítótárba helyezzük), akkor nem is jön létre, és ezzel megkíméljük a szerver teljesítményét.
```php .{file:DefaultPresenter.php}
// elérjük a komponenst, és ha ez volt az első alkalom,
// meghívja a createComponentPoll() funkciót a létrehozásához.
$poll = $this->getComponent('poll');
// alternatív szintaxis: $poll = $this['poll'];
```
A sablonban a [{control} |#Rendering] címkével renderelhetünk egy komponenst. Így nincs szükség a komponensek manuális átadására a sablonhoz.
```latte
<h2>Please Vote</h2>
{control poll}
```
Hollywood stílus .[#toc-hollywood-style]
========================================
Az alkatrészek általában egy menő technikát használnak, amit mi hollywoodi stílusnak hívunk. Bizonyára ismered a közhelyet, amit a színészek gyakran hallanak a castingokon: "Ne hívjatok minket, majd mi hívunk titeket". És erről van szó.
A Nette-ben ahelyett, hogy állandóan kérdéseket tennél fel ("elküldted az űrlapot?", "érvényes volt?" vagy "megnyomta valaki ezt a gombot?"), azt mondod a keretrendszernek, hogy "ha ez történik, hívd ezt a módszert", és hagyd rajta a további munkát. Ha JavaScriptben programozol, ismered ezt a programozási stílust. Olyan függvényeket írsz, amelyeket akkor hívsz meg, amikor egy bizonyos esemény bekövetkezik. A motor pedig átadja nekik a megfelelő paramétereket.
Ez teljesen megváltoztatja az alkalmazások írásának módját. Minél több feladatot delegálhatsz a keretrendszerre, annál kevesebb munkád marad. És annál kevesebbet tudsz elfelejteni.
Hogyan írjunk komponenst .[#toc-how-to-write-a-component]
=========================================================
A komponens alatt általában a [api:Nette\Application\UI\Control] osztály leszármazottait értjük. Maga a bemutató [api:Nette\Application\UI\Presenter] is a `Control` osztály leszármazottja.
```php .{file:PollControl.php}
use Nette\Application\UI\Control;
class PollControl extends Control
{
}
```
A megjelenítése .[#toc-rendering]
==================================
Azt már tudjuk, hogy a `{control componentName}` címkét egy komponens megrajzolására használjuk. Valójában a komponens `render()` metódusát hívja meg, amelyben a renderelésről gondoskodunk. A prezenterhez hasonlóan van egy [Latte |latte:] sablonunk a `$this->template` változóban, amelynek átadjuk a paramétereket. A prezenterben való használattal ellentétben itt meg kell adnunk egy sablonfájlt, és hagynunk kell, hogy renderelje:
```php .{file:PollControl.php}
public function render(): void
{
// néhány paramétert teszünk a sablonba
$this->template->param = $value;
// és lerajzoljuk
$this->template->render(__DIR__ . '/poll.latte');
}
```
A `{control}` címke segítségével paramétereket adhatunk át a `render()` metódusnak:
```latte
{control poll $id, $message}
```
```php .{file:PollControl.php}
public function render(int $id, string $message): void
{
// ...
}
```
Néha egy komponens több részből állhat, amelyeket külön-külön szeretnénk megjeleníteni. Mindegyikhez saját renderelési metódust hozunk létre, itt van például a `renderPaginator()`:
```php .{file:PollControl.php}
public function renderPaginator(): void
{
// ...
}
```
És a sablonban aztán meghívjuk a következővel:
```latte
{control poll:paginator}
```
A jobb megértés érdekében jó tudni, hogy a címke hogyan fordítódik PHP kóddá.
```latte
{control poll}
{control poll:paginator 123, 'hello'}
```
Ez a következőre fordítódik:
```php
$control->getComponent('poll')->render();
$control->getComponent('poll')->renderPaginator(123, 'hello');
```
`getComponent()` `poll` komponenst adja vissza, majd a `render()` vagy a `renderPaginator()` metódust hívja meg rajta.
.[caution]
Ha a paraméterrészben bárhol **`=>`** használatos, akkor az összes paramétert egy tömbbe csomagoljuk, és első argumentumként adjuk át:
```latte
{control poll, id: 123, message: 'hello'}
```
fordítja:
```php
$control->getComponent('poll')->render(['id' => 123, 'message' => 'hello']);
```
Az alkomponens renderelése:
```latte
{control cartControl-someForm}
```
fordít:
```php
$control->getComponent("cartControl-someForm")->render();
```
A komponensek, például az előadók, automatikusan átadnak számos hasznos változót a sablonoknak:
- `$basePath` egy abszolút URL elérési útvonal a gyökérkönyvtárhoz (például `/CD-collection`).
- `$baseUrl` egy abszolút URL cím a gyökérkönyvtárhoz (pl. `http://localhost/CD-collection`)
- `$user` egy objektum, [amely a felhasználót képviseli |security:authentication]
- `$presenter` az aktuális bemutató
- `$control` az aktuális komponens
- `$flashes` a módszer által küldött [üzenetek |#flash-messages] listája `flashMessage()`
Signal .[#toc-signal]
=====================
Azt már tudjuk, hogy a Nette alkalmazásban a navigáció a `Presenter:action` párokra való hivatkozásból vagy átirányításból áll. De mi van akkor, ha csak egy műveletet szeretnénk végrehajtani az **aktuális oldalon**? Például a táblázat oszlopának rendezési sorrendjét megváltoztatni; elemet törölni; világos/sötét üzemmódot váltani; űrlapot elküldeni; szavazni a szavazáson; stb.
Az ilyen típusú kérést jelnek nevezzük. És az akciókhoz hasonlóan metódusokat hívnak meg `action<Action>()` vagy `render<Action>()`a jelek hívják a módszereket `handle<Signal>()`. Míg az akció (vagy nézet) fogalma csak a prezenterekre vonatkozik, a jelek minden komponensre. És ezért a prezenterekre is, mivel a `UI\Presenter` a `UI\Control` leszármazottja.
```php
public function handleClick(int $x, int $y): void
{
// ... a jel feldolgozása ...
}
```
A jelet hívó link a szokásos módon jön létre, azaz a sablonban a `n:href` attribútummal vagy a `{link}` címkével, a kódban a `link()` metódussal. Bővebben az [URL-linkek létrehozása |creating-links#Links to Signal] című fejezetben.
```latte
<a n:href="click! $x, $y">click here</a>
```
A jel mindig az aktuális prezenteren és nézeten kerül meghívásra, így nem lehetséges a jelre más prezenteren/akcióban linkelni.
A jel tehát az oldal újratöltését pontosan ugyanúgy okozza, mint az eredeti kérésnél, csak ezen felül a megfelelő paraméterekkel hívja meg a jelkezelő metódust. Ha a metódus nem létezik, akkor a [api:Nette\Application\UI\BadSignalException] kivétel kerül dobásra, amely a felhasználó számára a 403 Forbidden hibalevélként jelenik meg.
Snippetek és AJAX .[#toc-snippets-and-ajax]
===========================================
A jelek egy kicsit emlékeztethetnek az AJAX-ra: az aktuális oldalon meghívott kezelők. És igazad van, a szignálokat valóban gyakran hívjuk meg AJAX segítségével, és akkor csak az oldal megváltozott részeit továbbítjuk a böngészőnek. Ezeket hívják snippeteknek. További információ az [AJAX-ről szóló oldalon |ajax] található.
Flash üzenetek .[#toc-flash-messages]
=====================================
Egy komponensnek saját, a prezentertől független tárolója van a flash üzeneteknek. Ezek olyan üzenetek, amelyek például a művelet eredményéről tájékoztatnak. A flash-üzenetek fontos jellemzője, hogy a sablonban az átirányítás után is rendelkezésre állnak. A megjelenítés után is még 30 másodpercig életben maradnak - például abban az esetben, ha a felhasználó véletlenül frissítené az oldalt - az üzenet nem vész el.
A küldés a [flashMessage |api:Nette\Application\UI\Control::flashMessage()] metódussal történik. Az első paraméter az üzenet szövege vagy az üzenetet reprezentáló `stdClass` objektum. A választható második paraméter az üzenet típusa (hiba, figyelmeztetés, info stb.). A `flashMessage()` metódus a flash message egy példányát adja vissza stdClass objektumként, amelyhez információkat adhatunk át.
```php
$this->flashMessage('Az elemet törölték.');
$this->redirect(/* ... */); // és átirányítás
```
A sablonban ezek az üzenetek a `$flashes` változóban állnak rendelkezésre, mint a `stdClass` objektumok, amelyek tartalmazzák a `message` (üzenet szövege), `type` (üzenet típusa) tulajdonságokat, és tartalmazhatják a már említett felhasználói információkat. Ezeket a következőképpen rajzoljuk meg:
```latte
{foreach $flashes as $flash}
<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}
```
Állandó paraméterek .[#toc-persistent-parameters]
=================================================
A tartós paraméterek a komponensek állapotának különböző kérések közötti fenntartására szolgálnak. Értékük a linkre való kattintás után is ugyanaz marad. A munkamenetadatokkal ellentétben ezek az URL-ben kerülnek átvitelre. És automatikusan továbbításra kerülnek, beleértve az ugyanazon az oldalon lévő más komponensekben létrehozott linkeket is.
Például van egy tartalom lapozó komponens. Egy oldalon több ilyen komponens is lehet. És azt szeretné, hogy minden komponens az aktuális oldalon maradjon, amikor a linkre kattint. Ezért az oldalszámot (`page`) állandó paraméterré tesszük.
A perzisztens paraméter létrehozása rendkívül egyszerű a Nette-ben. Csak hozzon létre egy nyilvános tulajdonságot, és címkézze meg az attribútummal: (korábban a `/** @persistent */` volt használatos).
```php
use Nette\Application\Attributes\Persistent; // ez a sor fontos
class PaginatingControl extends Control
{
#[Persistent]
public int $page = 1; // nyilvánosnak kell lennie
}
```
Javasoljuk, hogy a tulajdonsághoz adja meg az adattípust (pl. `int`), és alapértelmezett értéket is megadhat. A paraméterek értékei [érvényesíthetők |#Validation of Persistent Parameters].
A tartós paraméterek értékét a hivatkozás létrehozásakor módosíthatja:
```latte
<a n:href="this page: $page + 1">next</a>
```
Vagy *visszaállítható*, azaz eltávolítható az URL-ből. Ekkor az alapértelmezett értéket veszi fel:
```latte
<a n:href="this page: null">reset</a>
```
Tartós komponensek .[#toc-persistent-components]
================================================
Nem csak a paraméterek, hanem a komponensek is lehetnek állandóak. A perzisztens paramétereik a különböző műveletek vagy a különböző előadók között is átvihetők. A perzisztens komponenseket ezzel a megjegyzésekkel jelöljük a prezenter osztály számára. Itt például a `calendar` és a `poll` komponenseket jelöljük a következőképpen:
```php
/**
* @persistent(calendar, poll)
*/
class DefaultPresenter extends Nette\Application\UI\Presenter
{
}
```
Az alkomponenseket nem kell tartósnak jelölni, azok automatikusan tartósak.
A PHP 8-ban attribútumokat is használhat a tartós komponensek jelölésére:
```php
use Nette\Application\Attributes\Persistent;
#[Persistent('calendar', 'poll')]
class DefaultPresenter extends Nette\Application\UI\Presenter
{
}
```
Függőségi komponensek .[#toc-components-with-dependencies]
==========================================================
Hogyan hozhatunk létre függőségekkel rendelkező komponenseket anélkül, hogy "összezavarnánk" az őket használó prezentereket? A Nette DI konténerének okos funkcióinak köszönhetően, a hagyományos szolgáltatások használatához hasonlóan, a munka nagy részét a keretrendszerre bízhatjuk.
Vegyünk példaként egy olyan komponenst, amely függőséggel rendelkezik a `PollFacade` szolgáltatástól:
```php
class PollControl extends Control
{
public function __construct(
private int $id, // Annak a közvélemény-kutatásnak az azonosítója, amelyhez a komponens létrejön.
private PollFacade $facade,
) {
}
public function handleVote(int $voteId): void
{
$this->facade->vote($id, $voteId);
// ...
}
}
```
Ha egy klasszikus szolgáltatást írnánk, akkor nem kellene aggódnunk. A DI konténer láthatatlanul gondoskodna az összes függőség átadásáról. De mi általában úgy kezeljük a komponenseket, hogy közvetlenül a prezenterben hozunk létre egy új példányt belőlük [gyári metódusokban |#factory methods] `createComponent...()`. De az összes komponens összes függőségének átadása a prezentálónak, hogy aztán átadjuk őket a komponenseknek, nehézkes. És a megírt kód mennyisége...
A logikus kérdés az, hogy miért nem regisztráljuk a komponenst klasszikus szolgáltatásként, adjuk át a prezenternek, majd adjuk vissza a `createComponent...()` metódusban? De ez a megközelítés nem megfelelő, mert azt szeretnénk, hogy a komponenst többször is létrehozhassuk.
A helyes megoldás az, ha írunk egy gyárat a komponenshez, azaz egy olyan osztályt, amely létrehozza nekünk a komponenst:
```php
class PollControlFactory
{
public function __construct(
private PollFacade $facade,
) {
}
public function create(int $id): PollControl
{
return new PollControl($id, $this->facade);
}
}
```
Most regisztráljuk a szolgáltatásunkat a DI konténer konfigurációjához:
```neon
services:
- PollControlFactory
```
Végül ezt a gyárat fogjuk használni a prezenterünkben:
```php
class PollPresenter extends Nette\UI\Application\Presenter
{
public function __construct(
private PollControlFactory $pollControlFactory,
) {
}
protected function createComponentPollControl(): PollControl
{
$pollId = 1; // átadhatjuk a paraméterünket.
return $this->pollControlFactory->create($pollId);
}
}
```
A nagyszerű dolog az, hogy a Nette DI képes ilyen egyszerű gyárakat [generálni |dependency-injection:factory], így az egész kód megírása helyett csak az interfészét kell megírni:
```php
interface PollControlFactory
{
public function create(int $id): PollControl;
}
```
Ennyi. A Nette belsőleg megvalósítja ezt az interfészt, és befecskendezi a prezenterünkbe, ahol használhatjuk. A `$id` paraméterünket és a `PollFacade` osztály példányát is varázslatosan átadja a komponensünkbe.
A komponensek mélysége .[#toc-components-in-depth]
==================================================
A komponensek egy Nette alkalmazásban a webalkalmazás újrafelhasználható részei, amelyeket oldalakba ágyazunk be, ez a fejezet témája. Pontosan milyen képességekkel rendelkezik egy ilyen komponens?
1) egy sablonban megjeleníthető.
2) tudja, hogy egy [AJAX-kérés |ajax#invalidation] során melyik részét kell renderelni (snippet)
3) képes az állapotát egy URL-ben tárolni (állandó paraméterek).
4) képes reagálni a felhasználói műveletekre (jelek)
5) hierarchikus struktúrát hoz létre (ahol a gyökér a bemutató)
Mindegyik funkciót az öröklési vonal valamelyik osztálya kezeli. A megjelenítést (1 + 2) a [api:Nette\Application\UI\Control], az [életciklusba |presenters#life-cycle-of-presenter] való beillesztést (3, 4) a [api:Nette\Application\UI\Component] osztály, a hierarchikus struktúra létrehozását (5) pedig a [Container és a Component |component-model:] osztályok kezelik.
```
Nette\ComponentModel\Component { IComponent }
|
+- Nette\ComponentModel\Container { IContainer }
|
+- Nette\Application\UI\Component { SignalReceiver, StatePersistent }
|
+- Nette\Application\UI\Control { Renderable }
|
+- Nette\Application\UI\Presenter { IPresenter }
```
A komponens életciklusa .[#toc-life-cycle-of-component]
-------------------------------------------------------
[* lifecycle-component.svg *] *** *A komponens életciklusa* .<>
A tartós paraméterek validálása .[#toc-validation-of-persistent-parameters]
---------------------------------------------------------------------------
Az URL-ekből kapott [állandó paraméterek |#persistent parameters] értékeit a `loadState()` módszer írja a tulajdonságokba. A módszer azt is ellenőrzi, hogy a tulajdonsághoz megadott adattípus megfelel-e, ellenkező esetben 404-es hibával válaszol, és az oldal nem jelenik meg.
Soha ne bízzunk vakon a perzisztens paraméterekben, mert azokat a felhasználó könnyen felülírhatja az URL-ben. Például így ellenőrizzük, hogy a `$this->page` oldalszám nagyobb-e 0-nál. Erre jó megoldás a fent említett `loadState()` metódus felülírása:
```php
class PaginatingControl extends Control
{
#[Persistent]
public int $page = 1;
public function loadState(array $params): void
{
parent::loadState($params); // itt van beállítva a $this->page
// követi a felhasználói értékek ellenőrzését:
if ($this->page < 1) {
$this->error();
}
}
}
```
Az ellenkező folyamatot, vagyis az értékek begyűjtését a perzisztens tulajdonságokból a `saveState()` metódus kezeli.
Mélységi jelek .[#toc-signals-in-depth]
---------------------------------------
A jel az eredeti kéréshez hasonlóan az oldal újratöltését okozza (az AJAX kivételével), és meghívja a `signalReceived($signal)` metódust, amelynek alapértelmezett megvalósítása a `Nette\Application\UI\Component` osztályban a `handle{Signal}` szavakból álló metódust próbálja meghívni. A további feldolgozás az adott objektumra támaszkodik. A `Component` leszármazottai (azaz a `Control` és a `Presenter`) objektumok a `handle{Signal}` metódust próbálják meghívni a megfelelő paraméterekkel.
Más szóval: a `handle{Signal}` metódus definícióját vesszük, és a kérésben kapott összes paramétert összevetjük a metódus paramétereivel. Ez azt jelenti, hogy a `id` paramétert az URL-ből a `$id`, a `something` a `$something` és így tovább. Ha pedig a módszer nem létezik, a `signalReceived` módszer [kivételt |api:Nette\Application\UI\BadSignalException] dob.
A jelet bármely komponens, bemutató objektum, amely a `SignalReceiver` interfészt valósítja meg, fogadhatja, ha csatlakozik a komponensfához.
A jelek fő vevői a `Presenters` és a `Control` kiterjesztő vizuális komponensek. A jel egy objektum számára jelzi, hogy valamit tennie kell - a felhasználó szavazatát számolja a szavazás, a híreket tartalmazó doboznak ki kell bontakoznia, az űrlapot elküldték és fel kell dolgoznia az adatokat, és így tovább.
A jel URL-címét a [Component::link() |api:Nette\Application\UI\Component::link()] metódus segítségével hozzuk létre. A `$destination` paraméterként a `{signal}!` stringet adjuk át, a `$args` pedig egy tömbnyi argumentumot, amelyet a jelkezelőnek szeretnénk átadni. A jelparamétereket az aktuális prezenter/nézet URL-hez csatoljuk. **A `?do` paraméter az URL-ben meghatározza a hívott jelet.**
Formátuma `{signal}` vagy `{signalReceiver}-{signal}`. `{signalReceiver}` a prezenterben lévő komponens neve. Ezért nem lehet kötőjel (pontatlanul kötőjel) a komponensek nevében - ez a komponens és a jel nevének elválasztására szolgál, de több komponens is összeállítható.
Az [isSignalReceiver() |api:Nette\Application\UI\Presenter::isSignalReceiver()] metódus ellenőrzi, hogy egy komponens (első argumentum) egy jel (második argumentum) vevője-e. A második argumentum elhagyható - ekkor kiderül, hogy a komponens bármely jel vevője-e. Ha a második paraméter a `true`, akkor ellenőrzi, hogy a komponens vagy annak leszármazottai egy jel vevői-e.
Bármelyik fázisban a `handle{Signal}` megelőzően a [processSignal() |api:Nette\Application\UI\Presenter::processSignal()] metódus meghívásával manuálisan is lehet jelet végrehajtani, amely a jelek végrehajtásáért vállal felelősséget. Átveszi a vevő komponenst (ha nincs beállítva, akkor maga a prezenter) és elküldi neki a jelet.
Példa:
```php
if ($this->isSignalReceiver($this, 'paging') || $this->isSignalReceiver($this, 'sorting')) {
$this->processSignal();
}
```
A jelet idő előtt végrehajtják, és nem hívják meg újra.