144 lines
4.0 KiB
PHP
144 lines
4.0 KiB
PHP
<?php namespace Clockwork\DataSource;
|
|
|
|
use Clockwork\Helpers\Serializer;
|
|
use Clockwork\Helpers\StackTrace;
|
|
use Clockwork\Request\Request;
|
|
|
|
use Illuminate\Contracts\Events\Dispatcher;
|
|
|
|
// Data source for Laravel events component, provides fired events
|
|
class LaravelEventsDataSource extends DataSource
|
|
{
|
|
// Event dispatcher instance
|
|
protected $dispatcher;
|
|
|
|
// Fired events
|
|
protected $events = [];
|
|
|
|
// Whether framework events should be collected
|
|
protected $ignoredEvents = false;
|
|
|
|
// Create a new data source instance, takes an event dispatcher and additional options as arguments
|
|
public function __construct(Dispatcher $dispatcher, $ignoredEvents = [])
|
|
{
|
|
$this->dispatcher = $dispatcher;
|
|
|
|
$this->ignoredEvents = is_array($ignoredEvents)
|
|
? array_merge($ignoredEvents, $this->defaultIgnoredEvents()) : [];
|
|
}
|
|
|
|
// Adds fired events to the request
|
|
public function resolve(Request $request)
|
|
{
|
|
$request->events = array_merge($request->events, $this->events);
|
|
|
|
return $request;
|
|
}
|
|
|
|
// Reset the data source to an empty state, clearing any collected data
|
|
public function reset()
|
|
{
|
|
$this->events = [];
|
|
}
|
|
|
|
// Start listening to the events
|
|
public function listenToEvents()
|
|
{
|
|
$this->dispatcher->listen('*', function ($event = null, $data = null) {
|
|
if (method_exists($this->dispatcher, 'firing')) { // Laravel 5.0 - 5.3
|
|
$data = func_get_args();
|
|
$event = $this->dispatcher->firing();
|
|
}
|
|
|
|
$this->registerEvent($event, $data);
|
|
});
|
|
}
|
|
|
|
// Collect a fired event, prepares data for serialization and resolves registered listeners
|
|
protected function registerEvent($event, array $data)
|
|
{
|
|
if (! $this->shouldCollect($event)) return;
|
|
|
|
$trace = StackTrace::get()->resolveViewName();
|
|
|
|
$event = [
|
|
'event' => $event,
|
|
'data' => (new Serializer)->normalize(count($data) == 1 && isset($data[0]) ? $data[0] : $data),
|
|
'time' => microtime(true),
|
|
'listeners' => $this->findListenersFor($event),
|
|
'trace' => (new Serializer)->trace($trace)
|
|
];
|
|
|
|
if ($this->passesFilters([ $event ])) {
|
|
$this->events[] = $event;
|
|
}
|
|
}
|
|
|
|
// Returns registered listeners for the specified event
|
|
protected function findListenersFor($event)
|
|
{
|
|
$listener = $this->dispatcher->getListeners($event)[0];
|
|
|
|
return array_filter(array_map(function ($listener) {
|
|
if ($listener instanceof \Closure) {
|
|
// Laravel 5.4+ (and earlier versions in some cases) wrap the listener into a closure,
|
|
// attempt to resolve the original listener
|
|
$use = (new \ReflectionFunction($listener))->getStaticVariables();
|
|
$listener = isset($use['listener']) ? $use['listener'] : $listener;
|
|
}
|
|
|
|
if (is_string($listener)) {
|
|
return $listener;
|
|
} elseif (is_array($listener) && count($listener) == 2) {
|
|
if (is_object($listener[0])) {
|
|
return get_class($listener[0]) . '@' . $listener[1];
|
|
} else {
|
|
return $listener[0] . '::' . $listener[1];
|
|
}
|
|
} elseif ($listener instanceof \Closure) {
|
|
$listener = new \ReflectionFunction($listener);
|
|
|
|
if (strpos($listener->getNamespaceName(), 'Clockwork\\') === 0) { // skip our own listeners
|
|
return;
|
|
}
|
|
|
|
$filename = str_replace(base_path(), '', $listener->getFileName());
|
|
$startLine = $listener->getStartLine();
|
|
$endLine = $listener->getEndLine();
|
|
|
|
return "Closure ({$filename}:{$startLine}-{$endLine})";
|
|
}
|
|
}, $this->dispatcher->getListeners($event)));
|
|
}
|
|
|
|
// Returns whether the event should be collected (depending on ignored events)
|
|
protected function shouldCollect($event)
|
|
{
|
|
return ! preg_match('/^(?:' . implode('|', $this->ignoredEvents) . ')$/', $event);
|
|
}
|
|
|
|
// Returns default ignored events (framework-specific events)
|
|
protected function defaultIgnoredEvents()
|
|
{
|
|
return [
|
|
'Illuminate\\\\.+',
|
|
'Laravel\\\\.+',
|
|
'auth\.(?:attempt|login|logout)',
|
|
'artisan\.start',
|
|
'bootstrapped:.+',
|
|
'composing:.+',
|
|
'creating:.+',
|
|
'illuminate\.query',
|
|
'connection\..+',
|
|
'eloquent\..+',
|
|
'kernel\.handled',
|
|
'illuminate\.log',
|
|
'mailer\.sending',
|
|
'router\.(?:before|after|matched)',
|
|
'router.filter:.+',
|
|
'locale\.changed',
|
|
'clockwork\..+'
|
|
];
|
|
}
|
|
}
|