| 199 |
lars |
1 |
<?php namespace Clockwork\DataSource;
|
|
|
2 |
|
|
|
3 |
use Clockwork\Helpers\Serializer;
|
|
|
4 |
use Clockwork\Helpers\StackTrace;
|
|
|
5 |
use Clockwork\Request\Request;
|
|
|
6 |
|
|
|
7 |
use Illuminate\Contracts\Events\Dispatcher;
|
|
|
8 |
|
|
|
9 |
// Data source for Laravel events component, provides fired events
|
|
|
10 |
class LaravelEventsDataSource extends DataSource
|
|
|
11 |
{
|
|
|
12 |
// Event dispatcher instance
|
|
|
13 |
protected $dispatcher;
|
|
|
14 |
|
|
|
15 |
// Fired events
|
|
|
16 |
protected $events = [];
|
|
|
17 |
|
|
|
18 |
// Whether framework events should be collected
|
|
|
19 |
protected $ignoredEvents = false;
|
|
|
20 |
|
|
|
21 |
// Create a new data source instance, takes an event dispatcher and additional options as arguments
|
|
|
22 |
public function __construct(Dispatcher $dispatcher, $ignoredEvents = [])
|
|
|
23 |
{
|
|
|
24 |
$this->dispatcher = $dispatcher;
|
|
|
25 |
|
|
|
26 |
$this->ignoredEvents = is_array($ignoredEvents)
|
|
|
27 |
? array_merge($ignoredEvents, $this->defaultIgnoredEvents()) : [];
|
|
|
28 |
}
|
|
|
29 |
|
|
|
30 |
// Adds fired events to the request
|
|
|
31 |
public function resolve(Request $request)
|
|
|
32 |
{
|
|
|
33 |
$request->events = array_merge($request->events, $this->events);
|
|
|
34 |
|
|
|
35 |
return $request;
|
|
|
36 |
}
|
|
|
37 |
|
|
|
38 |
// Reset the data source to an empty state, clearing any collected data
|
|
|
39 |
public function reset()
|
|
|
40 |
{
|
|
|
41 |
$this->events = [];
|
|
|
42 |
}
|
|
|
43 |
|
|
|
44 |
// Start listening to the events
|
|
|
45 |
public function listenToEvents()
|
|
|
46 |
{
|
|
|
47 |
$this->dispatcher->listen('*', function ($event = null, $data = null) {
|
|
|
48 |
if (method_exists($this->dispatcher, 'firing')) { // Laravel 5.0 - 5.3
|
|
|
49 |
$data = func_get_args();
|
|
|
50 |
$event = $this->dispatcher->firing();
|
|
|
51 |
}
|
|
|
52 |
|
|
|
53 |
$this->registerEvent($event, $data);
|
|
|
54 |
});
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
// Collect a fired event, prepares data for serialization and resolves registered listeners
|
|
|
58 |
protected function registerEvent($event, array $data)
|
|
|
59 |
{
|
|
|
60 |
if (! $this->shouldCollect($event)) return;
|
|
|
61 |
|
|
|
62 |
$trace = StackTrace::get()->resolveViewName();
|
|
|
63 |
|
|
|
64 |
$event = [
|
|
|
65 |
'event' => $event,
|
|
|
66 |
'data' => (new Serializer)->normalize(count($data) == 1 && isset($data[0]) ? $data[0] : $data),
|
|
|
67 |
'time' => microtime(true),
|
|
|
68 |
'listeners' => $this->findListenersFor($event),
|
|
|
69 |
'trace' => (new Serializer)->trace($trace)
|
|
|
70 |
];
|
|
|
71 |
|
|
|
72 |
if ($this->passesFilters([ $event ])) {
|
|
|
73 |
$this->events[] = $event;
|
|
|
74 |
}
|
|
|
75 |
}
|
|
|
76 |
|
|
|
77 |
// Returns registered listeners for the specified event
|
|
|
78 |
protected function findListenersFor($event)
|
|
|
79 |
{
|
|
|
80 |
$listener = $this->dispatcher->getListeners($event)[0];
|
|
|
81 |
|
|
|
82 |
return array_filter(array_map(function ($listener) {
|
|
|
83 |
if ($listener instanceof \Closure) {
|
|
|
84 |
// Laravel 5.4+ (and earlier versions in some cases) wrap the listener into a closure,
|
|
|
85 |
// attempt to resolve the original listener
|
|
|
86 |
$use = (new \ReflectionFunction($listener))->getStaticVariables();
|
|
|
87 |
$listener = isset($use['listener']) ? $use['listener'] : $listener;
|
|
|
88 |
}
|
|
|
89 |
|
|
|
90 |
if (is_string($listener)) {
|
|
|
91 |
return $listener;
|
|
|
92 |
} elseif (is_array($listener) && count($listener) == 2) {
|
|
|
93 |
if (is_object($listener[0])) {
|
|
|
94 |
return get_class($listener[0]) . '@' . $listener[1];
|
|
|
95 |
} else {
|
|
|
96 |
return $listener[0] . '::' . $listener[1];
|
|
|
97 |
}
|
|
|
98 |
} elseif ($listener instanceof \Closure) {
|
|
|
99 |
$listener = new \ReflectionFunction($listener);
|
|
|
100 |
|
|
|
101 |
if (strpos($listener->getNamespaceName(), 'Clockwork\\') === 0) { // skip our own listeners
|
|
|
102 |
return;
|
|
|
103 |
}
|
|
|
104 |
|
|
|
105 |
$filename = str_replace(base_path(), '', $listener->getFileName());
|
|
|
106 |
$startLine = $listener->getStartLine();
|
|
|
107 |
$endLine = $listener->getEndLine();
|
|
|
108 |
|
|
|
109 |
return "Closure ({$filename}:{$startLine}-{$endLine})";
|
|
|
110 |
}
|
|
|
111 |
}, $this->dispatcher->getListeners($event)));
|
|
|
112 |
}
|
|
|
113 |
|
|
|
114 |
// Returns whether the event should be collected (depending on ignored events)
|
|
|
115 |
protected function shouldCollect($event)
|
|
|
116 |
{
|
|
|
117 |
return ! preg_match('/^(?:' . implode('|', $this->ignoredEvents) . ')$/', $event);
|
|
|
118 |
}
|
|
|
119 |
|
|
|
120 |
// Returns default ignored events (framework-specific events)
|
|
|
121 |
protected function defaultIgnoredEvents()
|
|
|
122 |
{
|
|
|
123 |
return [
|
|
|
124 |
'Illuminate\\\\.+',
|
|
|
125 |
'Laravel\\\\.+',
|
|
|
126 |
'auth\.(?:attempt|login|logout)',
|
|
|
127 |
'artisan\.start',
|
|
|
128 |
'bootstrapped:.+',
|
|
|
129 |
'composing:.+',
|
|
|
130 |
'creating:.+',
|
|
|
131 |
'illuminate\.query',
|
|
|
132 |
'connection\..+',
|
|
|
133 |
'eloquent\..+',
|
|
|
134 |
'kernel\.handled',
|
|
|
135 |
'illuminate\.log',
|
|
|
136 |
'mailer\.sending',
|
|
|
137 |
'router\.(?:before|after|matched)',
|
|
|
138 |
'router.filter:.+',
|
|
|
139 |
'locale\.changed',
|
|
|
140 |
'clockwork\..+'
|
|
|
141 |
];
|
|
|
142 |
}
|
|
|
143 |
}
|