Event::trigger()   B
last analyzed

Complexity

Conditions 10
Paths 72

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 10.4632

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 17
c 2
b 0
f 0
nc 72
nop 3
dl 0
loc 32
ccs 15
cts 18
cp 0.8333
crap 10.4632
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use ReflectionClass;
16
use ReflectionMethod;
17
18
/**
19
 * 事件管理类
20
 * @package think
21
 */
22
class Event
23
{
24
    /**
25
     * 监听者
26
     * @var array
27
     */
28
    protected $listener = [];
29
30
    /**
31
     * 事件别名
32
     * @var array
33
     */
34
    protected $bind = [
35
        'AppInit'     => event\AppInit::class,
36
        'HttpRun'     => event\HttpRun::class,
37
        'HttpEnd'     => event\HttpEnd::class,
38
        'RouteLoaded' => event\RouteLoaded::class,
39
        'LogWrite'    => event\LogWrite::class,
40
        'LogRecord'   => event\LogRecord::class,
41
    ];
42
43
    /**
44
     * 应用对象
45
     * @var App
46
     */
47
    protected $app;
48
49 27
    public function __construct(App $app)
50
    {
51 27
        $this->app = $app;
52 27
    }
53
54
    /**
55
     * 批量注册事件监听
56
     * @access public
57
     * @param array $events 事件定义
58
     * @return $this
59
     */
60 3
    public function listenEvents(array $events)
61
    {
62 3
        foreach ($events as $event => $listeners) {
63 3
            if (isset($this->bind[$event])) {
64
                $event = $this->bind[$event];
65
            }
66
67 3
            $this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners);
68
        }
69
70 3
        return $this;
71
    }
72
73
    /**
74
     * 注册事件监听
75
     * @access public
76
     * @param string $event    事件名称
77
     * @param mixed  $listener 监听操作(或者类名)
78
     * @param bool   $first    是否优先执行
79
     * @return $this
80
     */
81 12
    public function listen(string $event, $listener, bool $first = false)
82
    {
83 12
        if (isset($this->bind[$event])) {
84 6
            $event = $this->bind[$event];
85
        }
86
87 12
        if ($first && isset($this->listener[$event])) {
88
            array_unshift($this->listener[$event], $listener);
89
        } else {
90 12
            $this->listener[$event][] = $listener;
91
        }
92
93 12
        return $this;
94
    }
95
96
    /**
97
     * 是否存在事件监听
98
     * @access public
99
     * @param string $event 事件名称
100
     * @return bool
101
     */
102 6
    public function hasListener(string $event): bool
103
    {
104 6
        if (isset($this->bind[$event])) {
105 3
            $event = $this->bind[$event];
106
        }
107
108 6
        return isset($this->listener[$event]);
109
    }
110
111
    /**
112
     * 移除事件监听
113
     * @access public
114
     * @param string $event 事件名称
115
     * @return void
116
     */
117 3
    public function remove(string $event): void
118
    {
119 3
        if (isset($this->bind[$event])) {
120 3
            $event = $this->bind[$event];
121
        }
122
123 3
        unset($this->listener[$event]);
124 3
    }
125
126
    /**
127
     * 指定事件别名标识 便于调用
128
     * @access public
129
     * @param array $events 事件别名
130
     * @return $this
131
     */
132 3
    public function bind(array $events)
133
    {
134 3
        $this->bind = array_merge($this->bind, $events);
135
136 3
        return $this;
137
    }
138
139
    /**
140
     * 注册事件订阅者
141
     * @access public
142
     * @param mixed $subscriber 订阅者
143
     * @return $this
144
     */
145 3
    public function subscribe($subscriber)
146
    {
147 3
        $subscribers = (array) $subscriber;
148
149 3
        foreach ($subscribers as $subscriber) {
0 ignored issues
show
introduced by
$subscriber is overwriting one of the parameters of this function.
Loading history...
150 3
            if (is_string($subscriber)) {
151 3
                $subscriber = $this->app->make($subscriber);
152
            }
153
154 3
            if (method_exists($subscriber, 'subscribe')) {
155
                // 手动订阅
156 3
                $subscriber->subscribe($this);
157
            } else {
158
                // 智能订阅
159 1
                $this->observe($subscriber);
160
            }
161
        }
162
163 3
        return $this;
164
    }
165
166
    /**
167
     * 自动注册事件观察者
168
     * @access public
169
     * @param string|object $observer 观察者
170
     * @param null|string   $prefix   事件名前缀
171
     * @return $this
172
     */
173 3
    public function observe($observer, string $prefix = '')
174
    {
175 3
        if (is_string($observer)) {
176 3
            $observer = $this->app->make($observer);
177
        }
178
179 3
        $reflect = new ReflectionClass($observer);
180 3
        $methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC);
181
182 3
        if (empty($prefix) && $reflect->hasProperty('eventPrefix')) {
183
            $reflectProperty = $reflect->getProperty('eventPrefix');
184
            $reflectProperty->setAccessible(true);
185
            $prefix = $reflectProperty->getValue($observer);
186
        }
187
188 3
        foreach ($methods as $method) {
189 3
            $name = $method->getName();
190 3
            if (0 === strpos($name, 'on')) {
191 3
                $this->listen($prefix . substr($name, 2), [$observer, $name]);
192
            }
193
        }
194
195 3
        return $this;
196
    }
197
198
    /**
199
     * 触发事件
200
     * @access public
201
     * @param string|object $event  事件名称
202
     * @param mixed         $params 传入参数
203
     * @param bool          $once   只获取一个有效返回值
204
     * @return mixed
205
     */
206 24
    public function trigger($event, $params = null, bool $once = false)
207
    {
208 24
        if (is_object($event)) {
209 6
            $params = $event;
210 6
            $event  = get_class($event);
211
        }
212
213 24
        if (isset($this->bind[$event])) {
214 3
            $event = $this->bind[$event];
215
        }
216
217 24
        $result    = [];
218 24
        $listeners = $this->listener[$event] ?? [];
219
220 24
        if (strpos($event, '.')) {
221
            [$prefix, $event] = explode('.', $event, 2);
222
            if (isset($this->listener[$prefix . '.*'])) {
223
                $listeners = array_merge($listeners, $this->listener[$prefix . '.*']);
224
            }
225
        }
226
227 24
        $listeners = array_unique($listeners, SORT_REGULAR);
228
229 24
        foreach ($listeners as $key => $listener) {
230 12
            $result[$key] = $this->dispatch($listener, $params);
231
232 12
            if (false === $result[$key] || (!is_null($result[$key]) && $once)) {
233 10
                break;
234
            }
235
        }
236
237 24
        return $once ? end($result) : $result;
238
    }
239
240
    /**
241
     * 触发事件(只获取一个有效返回值)
242
     * @param      $event
243
     * @param null $params
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $params is correct as it would always require null to be passed?
Loading history...
244
     * @return mixed
245
     */
246 3
    public function until($event, $params = null)
247
    {
248 3
        return $this->trigger($event, $params, true);
249
    }
250
251
    /**
252
     * 执行事件调度
253
     * @access protected
254
     * @param mixed $event  事件方法
255
     * @param mixed $params 参数
256
     * @return mixed
257
     */
258 12
    protected function dispatch($event, $params = null)
259
    {
260 12
        if (!is_string($event)) {
261 9
            $call = $event;
262 3
        } elseif (strpos($event, '::')) {
263
            $call = $event;
264
        } else {
265 3
            $obj  = $this->app->make($event);
266 3
            $call = [$obj, 'handle'];
267
        }
268
269 12
        return $this->app->invoke($call, [$params]);
270
    }
271
272
}
273