11
11
12
12
namespace Symfony \Component \HttpKernel \Debug ;
13
13
14
- use Symfony \Component \Stopwatch \Stopwatch ;
15
- use Symfony \Component \HttpKernel \KernelEvents ;
14
+ use Symfony \Component \EventDispatcher \Debug \TraceableEventDispatcher as BaseTraceableEventDispatcher ;
16
15
use Symfony \Component \HttpKernel \Profiler \Profiler ;
17
- use Psr \ Log \ LoggerInterface ;
16
+ use Symfony \ Component \ HttpKernel \ KernelEvents ;
18
17
use Symfony \Component \EventDispatcher \Event ;
19
- use Symfony \Component \EventDispatcher \EventDispatcherInterface ;
20
- use Symfony \Component \EventDispatcher \EventSubscriberInterface ;
21
- use Symfony \Component \EventDispatcher \Debug \TraceableEventDispatcherInterface ;
22
18
23
19
/**
24
20
* Collects some data about event listeners.
27
23
*
28
24
* @author Fabien Potencier <[email protected] >
29
25
*/
30
- class TraceableEventDispatcher implements EventDispatcherInterface, TraceableEventDispatcherInterface
26
+ class TraceableEventDispatcher extends BaseTraceableEventDispatcher
31
27
{
32
- private $ logger ;
33
- private $ called = array ();
34
- private $ stopwatch ;
35
- private $ dispatcher ;
36
- private $ wrappedListeners = array ();
37
- private $ firstCalledEvent = array ();
38
- private $ id ;
39
- private $ lastEventId = 0 ;
40
-
41
- /**
42
- * Constructor.
43
- *
44
- * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
45
- * @param Stopwatch $stopwatch A Stopwatch instance
46
- * @param LoggerInterface $logger A LoggerInterface instance
47
- */
48
- public function __construct (EventDispatcherInterface $ dispatcher , Stopwatch $ stopwatch , LoggerInterface $ logger = null )
49
- {
50
- $ this ->dispatcher = $ dispatcher ;
51
- $ this ->stopwatch = $ stopwatch ;
52
- $ this ->logger = $ logger ;
53
- }
54
-
55
28
/**
56
29
* Sets the profiler.
57
30
*
@@ -67,268 +40,11 @@ public function setProfiler(Profiler $profiler = null)
67
40
{
68
41
}
69
42
70
- /**
71
- * {@inheritDoc}
72
- */
73
- public function addListener ($ eventName , $ listener , $ priority = 0 )
74
- {
75
- $ this ->dispatcher ->addListener ($ eventName , $ listener , $ priority );
76
- }
77
-
78
- /**
79
- * {@inheritdoc}
80
- */
81
- public function addSubscriber (EventSubscriberInterface $ subscriber )
82
- {
83
- $ this ->dispatcher ->addSubscriber ($ subscriber );
84
- }
85
-
86
- /**
87
- * {@inheritdoc}
88
- */
89
- public function removeListener ($ eventName , $ listener )
90
- {
91
- return $ this ->dispatcher ->removeListener ($ eventName , $ listener );
92
- }
93
-
94
- /**
95
- * {@inheritdoc}
96
- */
97
- public function removeSubscriber (EventSubscriberInterface $ subscriber )
98
- {
99
- return $ this ->dispatcher ->removeSubscriber ($ subscriber );
100
- }
101
-
102
43
/**
103
44
* {@inheritdoc}
104
45
*/
105
- public function getListeners ($ eventName = null )
46
+ protected function preDispatch ($ eventName, Event $ event )
106
47
{
107
- return $ this ->dispatcher ->getListeners ($ eventName );
108
- }
109
-
110
- /**
111
- * {@inheritdoc}
112
- */
113
- public function hasListeners ($ eventName = null )
114
- {
115
- return $ this ->dispatcher ->hasListeners ($ eventName );
116
- }
117
-
118
- /**
119
- * {@inheritdoc}
120
- */
121
- public function dispatch ($ eventName , Event $ event = null )
122
- {
123
- if (null === $ event ) {
124
- $ event = new Event ();
125
- }
126
-
127
- $ this ->id = $ eventId = ++$ this ->lastEventId ;
128
-
129
- $ this ->preDispatch ($ eventName , $ event );
130
-
131
- $ e = $ this ->stopwatch ->start ($ eventName , 'section ' );
132
-
133
- $ this ->firstCalledEvent [$ eventName ] = $ this ->stopwatch ->start ($ eventName .'.loading ' , 'event_listener_loading ' );
134
-
135
- if (!$ this ->dispatcher ->hasListeners ($ eventName )) {
136
- $ this ->firstCalledEvent [$ eventName ]->stop ();
137
- }
138
-
139
- $ this ->dispatcher ->dispatch ($ eventName , $ event );
140
-
141
- // reset the id as another event might have been dispatched during the dispatching of this event
142
- $ this ->id = $ eventId ;
143
-
144
- unset($ this ->firstCalledEvent [$ eventName ]);
145
-
146
- if ($ e ->isStarted ()) {
147
- $ e ->stop ();
148
- }
149
-
150
- $ this ->postDispatch ($ eventName , $ event );
151
-
152
- return $ event ;
153
- }
154
-
155
- /**
156
- * {@inheritDoc}
157
- */
158
- public function getCalledListeners ()
159
- {
160
- return $ this ->called ;
161
- }
162
-
163
- /**
164
- * {@inheritDoc}
165
- */
166
- public function getNotCalledListeners ()
167
- {
168
- $ notCalled = array ();
169
-
170
- foreach ($ this ->getListeners () as $ name => $ listeners ) {
171
- foreach ($ listeners as $ listener ) {
172
- $ info = $ this ->getListenerInfo ($ listener , $ name );
173
- if (!isset ($ this ->called [$ name .'. ' .$ info ['pretty ' ]])) {
174
- $ notCalled [$ name .'. ' .$ info ['pretty ' ]] = $ info ;
175
- }
176
- }
177
- }
178
-
179
- return $ notCalled ;
180
- }
181
-
182
- /**
183
- * Proxies all method calls to the original event dispatcher.
184
- *
185
- * @param string $method The method name
186
- * @param array $arguments The method arguments
187
- *
188
- * @return mixed
189
- */
190
- public function __call ($ method , $ arguments )
191
- {
192
- return call_user_func_array (array ($ this ->dispatcher , $ method ), $ arguments );
193
- }
194
-
195
- /**
196
- * This is a private method and must not be used.
197
- *
198
- * This method is public because it is used in a closure.
199
- * Whenever Symfony will require PHP 5.4, this could be changed
200
- * to a proper private method.
201
- */
202
- public function logSkippedListeners ($ eventName , Event $ event , $ listener )
203
- {
204
- if (null === $ this ->logger ) {
205
- return ;
206
- }
207
-
208
- $ info = $ this ->getListenerInfo ($ listener , $ eventName );
209
-
210
- $ this ->logger ->debug (sprintf ('Listener "%s" stopped propagation of the event "%s". ' , $ info ['pretty ' ], $ eventName ));
211
-
212
- $ skippedListeners = $ this ->getListeners ($ eventName );
213
- $ skipped = false ;
214
-
215
- foreach ($ skippedListeners as $ skippedListener ) {
216
- $ skippedListener = $ this ->unwrapListener ($ skippedListener );
217
-
218
- if ($ skipped ) {
219
- $ info = $ this ->getListenerInfo ($ skippedListener , $ eventName );
220
- $ this ->logger ->debug (sprintf ('Listener "%s" was not called for event "%s". ' , $ info ['pretty ' ], $ eventName ));
221
- }
222
-
223
- if ($ skippedListener === $ listener ) {
224
- $ skipped = true ;
225
- }
226
- }
227
- }
228
-
229
- /**
230
- * This is a private method.
231
- *
232
- * This method is public because it is used in a closure.
233
- * Whenever Symfony will require PHP 5.4, this could be changed
234
- * to a proper private method.
235
- */
236
- public function preListenerCall ($ eventName , $ listener )
237
- {
238
- // is it the first called listener?
239
- if (isset ($ this ->firstCalledEvent [$ eventName ])) {
240
- $ this ->firstCalledEvent [$ eventName ]->stop ();
241
-
242
- unset($ this ->firstCalledEvent [$ eventName ]);
243
- }
244
-
245
- $ info = $ this ->getListenerInfo ($ listener , $ eventName );
246
-
247
- if (null !== $ this ->logger ) {
248
- $ this ->logger ->debug (sprintf ('Notified event "%s" to listener "%s". ' , $ eventName , $ info ['pretty ' ]));
249
- }
250
-
251
- $ this ->called [$ eventName .'. ' .$ info ['pretty ' ]] = $ info ;
252
-
253
- return $ this ->stopwatch ->start (isset ($ info ['class ' ]) ? $ info ['class ' ] : $ info ['type ' ], 'event_listener ' );
254
- }
255
-
256
- /**
257
- * Returns information about the listener
258
- *
259
- * @param object $listener The listener
260
- * @param string $eventName The event name
261
- *
262
- * @return array Informations about the listener
263
- */
264
- private function getListenerInfo ($ listener , $ eventName )
265
- {
266
- $ listener = $ this ->unwrapListener ($ listener );
267
-
268
- $ info = array (
269
- 'event ' => $ eventName ,
270
- );
271
- if ($ listener instanceof \Closure) {
272
- $ info += array (
273
- 'type ' => 'Closure ' ,
274
- 'pretty ' => 'closure '
275
- );
276
- } elseif (is_string ($ listener )) {
277
- try {
278
- $ r = new \ReflectionFunction ($ listener );
279
- $ file = $ r ->getFileName ();
280
- $ line = $ r ->getStartLine ();
281
- } catch (\ReflectionException $ e ) {
282
- $ file = null ;
283
- $ line = null ;
284
- }
285
- $ info += array (
286
- 'type ' => 'Function ' ,
287
- 'function ' => $ listener ,
288
- 'file ' => $ file ,
289
- 'line ' => $ line ,
290
- 'pretty ' => $ listener ,
291
- );
292
- } elseif (is_array ($ listener ) || (is_object ($ listener ) && is_callable ($ listener ))) {
293
- if (!is_array ($ listener )) {
294
- $ listener = array ($ listener , '__invoke ' );
295
- }
296
- $ class = is_object ($ listener [0 ]) ? get_class ($ listener [0 ]) : $ listener [0 ];
297
- try {
298
- $ r = new \ReflectionMethod ($ class , $ listener [1 ]);
299
- $ file = $ r ->getFileName ();
300
- $ line = $ r ->getStartLine ();
301
- } catch (\ReflectionException $ e ) {
302
- $ file = null ;
303
- $ line = null ;
304
- }
305
- $ info += array (
306
- 'type ' => 'Method ' ,
307
- 'class ' => $ class ,
308
- 'method ' => $ listener [1 ],
309
- 'file ' => $ file ,
310
- 'line ' => $ line ,
311
- 'pretty ' => $ class .':: ' .$ listener [1 ],
312
- );
313
- }
314
-
315
- return $ info ;
316
- }
317
-
318
- private function preDispatch ($ eventName , Event $ event )
319
- {
320
- // wrap all listeners before they are called
321
- $ this ->wrappedListeners [$ this ->id ] = new \SplObjectStorage ();
322
-
323
- $ listeners = $ this ->dispatcher ->getListeners ($ eventName );
324
-
325
- foreach ($ listeners as $ listener ) {
326
- $ this ->dispatcher ->removeListener ($ eventName , $ listener );
327
- $ wrapped = $ this ->wrapListener ($ eventName , $ listener );
328
- $ this ->wrappedListeners [$ this ->id ][$ wrapped ] = $ listener ;
329
- $ this ->dispatcher ->addListener ($ eventName , $ wrapped );
330
- }
331
-
332
48
switch ($ eventName ) {
333
49
case KernelEvents::REQUEST :
334
50
$ this ->stopwatch ->openSection ();
@@ -342,7 +58,7 @@ private function preDispatch($eventName, Event $event)
342
58
break ;
343
59
case KernelEvents::TERMINATE :
344
60
$ token = $ event ->getResponse ()->headers ->get ('X-Debug-Token ' );
345
- // There is a very special case when using builtin AppCache class as kernel wrapper, in the case
61
+ // There is a very special case when using built-in AppCache class as kernel wrapper, in the case
346
62
// of an ESI request leading to a `stale` response [B] inside a `fresh` cached response [A].
347
63
// In this case, `$token` contains the [B] debug token, but the open `stopwatch` section ID
348
64
// is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception
@@ -354,7 +70,10 @@ private function preDispatch($eventName, Event $event)
354
70
}
355
71
}
356
72
357
- private function postDispatch ($ eventName , Event $ event )
73
+ /**
74
+ * {@inheritdoc}
75
+ */
76
+ protected function postDispatch ($ eventName , Event $ event )
358
77
{
359
78
switch ($ eventName ) {
360
79
case KernelEvents::CONTROLLER :
@@ -373,41 +92,5 @@ private function postDispatch($eventName, Event $event)
373
92
} catch (\LogicException $ e ) {}
374
93
break ;
375
94
}
376
-
377
- foreach ($ this ->wrappedListeners [$ this ->id ] as $ wrapped ) {
378
- $ this ->dispatcher ->removeListener ($ eventName , $ wrapped );
379
- $ this ->dispatcher ->addListener ($ eventName , $ this ->wrappedListeners [$ this ->id ][$ wrapped ]);
380
- }
381
-
382
- unset($ this ->wrappedListeners [$ this ->id ]);
383
- }
384
-
385
- private function wrapListener ($ eventName , $ listener )
386
- {
387
- $ self = $ this ;
388
-
389
- return function (Event $ event ) use ($ self , $ eventName , $ listener ) {
390
- $ e = $ self ->preListenerCall ($ eventName , $ listener );
391
-
392
- call_user_func ($ listener , $ event , $ eventName , $ self );
393
-
394
- if ($ e ->isStarted ()) {
395
- $ e ->stop ();
396
- }
397
-
398
- if ($ event ->isPropagationStopped ()) {
399
- $ self ->logSkippedListeners ($ eventName , $ event , $ listener );
400
- }
401
- };
402
- }
403
-
404
- private function unwrapListener ($ listener )
405
- {
406
- // get the original listener
407
- if (is_object ($ listener ) && isset ($ this ->wrappedListeners [$ this ->id ][$ listener ])) {
408
- return $ this ->wrappedListeners [$ this ->id ][$ listener ];
409
- }
410
-
411
- return $ listener ;
412
95
}
413
96
}
0 commit comments