EventProfiler   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 30
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 234
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getData() 0 5 2
A setEvent() 0 21 3
A createEventKey() 0 5 1
A createCallerTrace() 0 19 3
A createEventManagerCallbacks() 0 19 4
A createSharedEventManagerCallbacks() 0 14 2
A resolveCallbacks() 0 11 3
B resolveCallbackFromListener() 0 26 8
A resolveCallbackIdFromClosure() 0 15 2
A createMethodName() 0 4 1
1
<?php
2
/**
3
 * Webino (http://webino.sk/)
4
 *
5
 * @link        https://github.com/webino/WebinoDebug/ for the canonical source repository
6
 * @copyright   Copyright (c) 2014-2018 Webino, s. r. o. (http://webino.sk/)
7
 * @license     BSD-3-Clause
8
 */
9
10
namespace WebinoDebug\Service;
11
12
use ReflectionFunction;
13
use WebinoDebug\Debugger\DebuggerInterface;
14
use Zend\EventManager\EventInterface;
15
use Zend\EventManager\EventManager;
16
use Zend\EventManager\EventsCapableInterface;
17
use Zend\EventManager\SharedEventManagerInterface;
18
use Zend\Stdlib\CallbackHandler;
19
use Zend\Stdlib\PriorityQueue;
20
21
/**
22
 * Class EventProfiler
23
 */
24
class EventProfiler
25
{
26
    /**
27
     * Debug backtrace limit
28
     */
29
    const BACKTRACE_LIMIT = 6;
30
31
    /**
32
     * @var DebuggerInterface
33
     */
34
    protected $debugger;
35
36
    /**
37
     * @var SharedEventManagerInterface
38
     */
39
    protected $sharedEvents;
40
41
    /**
42
     * @var array
43
     */
44
    protected $data = [];
45
46
    /**
47
     * @var string
48
     */
49
    private $cwd;
50
51
    /**
52
     * @var EventInterface
53
     */
54
    private $lastEvent;
55
56
    /**
57
     * @var string
58
     */
59
    private $lastKey;
60
61
    /**
62
     * @param object|DebuggerInterface $debugger
63
     * @param object|SharedEventManagerInterface $sharedEvents
64
     */
65
    public function __construct(DebuggerInterface $debugger, SharedEventManagerInterface $sharedEvents)
66
    {
67
        $this->debugger     = $debugger;
68
        $this->sharedEvents = $sharedEvents;
69
    }
70
71
    /**
72
     * @return array
73
     */
74
    public function getData()
75
    {
76
        $this->lastEvent and $this->setEvent($this->lastEvent);
77
        return $this->data;
78
    }
79
80
    /**
81
     * @param EventInterface $event
82
     */
83
    public function setEvent(EventInterface $event)
84
    {
85
        $key  = $this->createEventKey($event);
86
        $time = $this->debugger->timer(__CLASS__)->getDelta();
87
88
        $this->lastKey and $this->data[$this->lastKey]['time']+= $time;
89
90
        if (isset($this->data[$key])) {
91
            return;
92
        }
93
94
        $this->data[$key] = [
95
            'time'        => 0,
96
            'caller'      => $this->createCallerTrace(),
97
            'event'       => $this->createEventManagerCallbacks($event),
98
            'sharedEvent' => $this->createSharedEventManagerCallbacks($event),
99
        ];
100
101
        $this->lastEvent = $event;
102
        $this->lastKey   = $key;
103
    }
104
105
    /**
106
     * @param EventInterface $event
107
     * @return string
108
     */
109
    protected function createEventKey(EventInterface $event)
110
    {
111
        $id = get_class($event->getTarget());
112
        return sprintf('%s::%s', $id, $event->getName());
113
    }
114
115
    /**
116
     * @return array
117
     */
118
    protected function createCallerTrace()
119
    {
120
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $this::BACKTRACE_LIMIT);
121
        $index = $this::BACKTRACE_LIMIT - 1;
122
123
        if (isset($backtrace[$index])
124
            && false !== strpos($backtrace[$index]['function'], 'trigger')
125
        ) {
126
            return [
127
                'file' => $backtrace[$index]['file'],
128
                'line' => $backtrace[$index]['line'],
129
            ];
130
        }
131
132
        return [
133
            'file' => null,
134
            'line' => null
135
        ];
136
    }
137
138
    /**
139
     * @param EventInterface $event
140
     * @return array
141
     */
142
    protected function createEventManagerCallbacks(EventInterface $event)
143
    {
144
        $target = $event->getTarget();
145
        $name   = $event->getName();
146
147
        $callbacks = [];
148
        if (is_object($target)
149
            && $target instanceof EventsCapableInterface
150
        ) {
151
152
            $events = $target->getEventManager();
153
            if ($events instanceof EventManager) {
154
                $listeners = $events->getListeners($name);
0 ignored issues
show
Deprecated Code introduced by
The method Zend\EventManager\EventManager::getListeners() has been deprecated with message: This method is deprecated with 2.6.0, and will be removed in 3.0.0. See {@link https://github.com/zendframework/zend-eventmanager/blob/develop/doc/book/migration/removed.md} for details.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
155
                $callbacks = $this->resolveCallbacks($listeners);
156
            }
157
        }
158
159
        return $callbacks;
160
    }
161
162
    /**
163
     * @param EventInterface $event
164
     * @return array
165
     */
166
    protected function createSharedEventManagerCallbacks(EventInterface $event)
167
    {
168
        $target = $event->getTarget();
169
        $id     = get_class($target);
170
        $name   = $event->getName();
171
172
        $callbacks = [];
173
        $sharedListeners = $this->sharedEvents->getListeners($id, $name);
174
        if ($sharedListeners !== false) {
175
            $callbacks = $this->resolveCallbacks($sharedListeners);
176
        }
177
178
        return $callbacks;
179
    }
180
181
    /**
182
     * @param PriorityQueue $listeners
183
     * @return array
184
     */
185
    protected function resolveCallbacks(PriorityQueue $listeners)
186
    {
187
        $callbacks = [];
188
        foreach ($listeners as $listener) {
189
            if ($listener instanceof CallbackHandler) {
190
                $callbacks[] = $this->resolveCallbackFromListener($listener);
191
            }
192
        }
193
194
        return $callbacks;
195
    }
196
197
    /**
198
     * @param CallbackHandler $listener
199
     * @return array
200
     */
201
    protected function resolveCallbackFromListener(CallbackHandler $listener)
202
    {
203
        $callback = $listener->getCallback();
204
        $priority = (int) $listener->getMetadatum('priority');
205
206
        if ($callback instanceof \Closure) {
207
            $id = $this->resolveCallbackIdFromClosure($callback);
208
209
        } elseif (is_array($callback) && count($callback) === 2 && is_object($callback[0])) {
210
            $id = $this->createMethodName($callback[0], $callback[1]);
211
212
        } elseif (is_string($callback)) {
213
            $id = $callback;
214
215
        } elseif (is_object($callback) && is_callable($callback)) {
216
            $id = $this->createMethodName((object) $callback, '__invoke');
217
218
        } else {
219
            $id = 'Unknown callback';
220
        }
221
222
        return [
223
            'callback' => $id,
224
            'priority' => $priority,
225
        ];
226
    }
227
228
    /**
229
     * @param \Closure $function
230
     * @return string
231
     */
232
    protected function resolveCallbackIdFromClosure(\Closure $function)
233
    {
234
        try {
235
            $ref   = new ReflectionFunction($function);
236
            $file  = $ref->getFileName();
237
            $start = $ref->getStartLine();
238
            $end   = $ref->getEndLine();
239
240
            return sprintf('Closure: %s:%d-%d', $file, $start, $end);
241
        } catch (\Throwable $exc) {
242
            error_log($exc);
243
        }
244
245
        return '';
246
    }
247
248
    /**
249
     * @param object $object
250
     * @param string $method
251
     * @return string
252
     */
253
    protected function createMethodName($object, $method)
254
    {
255
        return sprintf('%s::%s()', get_class($object), $method);
256
    }
257
}
258