Completed
Push — 6.0 ( 478934...ce2057 )
by liu
02:22
created

Event::trigger()   B

Complexity

Conditions 10
Paths 48

Size

Total Lines 30
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 10.1626

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 16
c 2
b 0
f 0
nc 48
nop 3
dl 0
loc 30
ccs 15
cts 17
cp 0.8824
crap 10.1626
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 (empty($listeners) && strpos($event, '.')) {
221
            [$prefix, $event] = explode($event, '.', 2);
222
            $listeners        = $this->listener[$prefix . '.*'] ?? [];
223
        }
224
225 24
        $listeners = array_unique($listeners, SORT_REGULAR);
226
227 24
        foreach ($listeners as $key => $listener) {
228 12
            $result[$key] = $this->dispatch($listener, $params);
229
230 12
            if (false === $result[$key] || (!is_null($result[$key]) && $once)) {
231 10
                break;
232
            }
233
        }
234
235 24
        return $once ? end($result) : $result;
236
    }
237
238
    /**
239
     * 触发事件(只获取一个有效返回值)
240
     * @param      $event
241
     * @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...
242
     * @return mixed
243
     */
244 3
    public function until($event, $params = null)
245
    {
246 3
        return $this->trigger($event, $params, true);
247
    }
248
249
    /**
250
     * 执行事件调度
251
     * @access protected
252
     * @param mixed $event  事件方法
253
     * @param mixed $params 参数
254
     * @return mixed
255
     */
256 12
    protected function dispatch($event, $params = null)
257
    {
258 12
        if (!is_string($event)) {
259 9
            $call = $event;
260 3
        } elseif (strpos($event, '::')) {
261
            $call = $event;
262
        } else {
263 3
            $obj  = $this->app->make($event);
264 3
            $call = [$obj, 'handle'];
265
        }
266
267 12
        return $this->app->invoke($call, [$params]);
268
    }
269
270
}
271