Completed
Pull Request — 6.0 (#2214)
by nhzex
06:18
created

Event   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Test Coverage

Coverage 90.67%

Importance

Changes 7
Bugs 0 Features 0
Metric Value
eloc 74
dl 0
loc 239
ccs 68
cts 75
cp 0.9067
rs 9.6
c 7
b 0
f 0
wmc 35

11 Methods

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