Completed
Push — 6.0 ( f9d0f5...4775e2 )
by liu
05:41
created

Event::bind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 $observer = [];
35
36
    /**
37
     * 事件别名
38
     * @var array
39
     */
40
    protected $bind = [
41
        'AppInit'     => event\AppInit::class,
42
        'HttpRun'     => event\HttpRun::class,
43
        'HttpEnd'     => event\HttpEnd::class,
44
        'RouteLoaded' => event\RouteLoaded::class,
45
        'LogWrite'    => event\LogWrite::class,
46
    ];
47
48
    /**
49
     * 是否需要事件响应
50
     * @var bool
51
     */
52
    protected $withEvent = true;
53
54
    /**
55
     * 应用对象
56
     * @var App
57
     */
58
    protected $app;
59
60 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
61
    {
62 9
        $this->app = $app;
63 9
    }
64
65
    /**
66
     * 设置是否开启事件响应
67
     * @access protected
68
     * @param  bool $event 是否需要事件响应
69
     * @return $this
70
     */
71 6
    public function withEvent(bool $event)
72
    {
73 6
        $this->withEvent = $event;
74 6
        return $this;
75
    }
76
77
    /**
78
     * 批量注册事件监听
79
     * @access public
80
     * @param  array $events 事件定义
81
     * @return $this
82
     */
83 1
    public function listenEvents(array $events)
84
    {
85 1
        if (!$this->withEvent) {
86
            return $this;
87
        }
88
89 1
        foreach ($events as $event => $listeners) {
90
            if (isset($this->bind[$event])) {
91
                $event = $this->bind[$event];
92
            }
93
94
            $this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners);
95
        }
96
97 1
        return $this;
98
    }
99
100
    /**
101
     * 注册事件监听
102
     * @access public
103
     * @param  string $event    事件名称
104
     * @param  mixed  $listener 监听操作(或者类名)
105
     * @param  bool   $first    是否优先执行
106
     * @return $this
107
     */
108
    public function listen(string $event, $listener, bool $first = false)
109
    {
110
        if (!$this->withEvent) {
111
            return $this;
112
        }
113
114
        if (isset($this->bind[$event])) {
115
            $event = $this->bind[$event];
116
        }
117
118
        if ($first && isset($this->listener[$event])) {
119
            array_unshift($this->listener[$event], $listener);
120
        } else {
121
            $this->listener[$event][] = $listener;
122
        }
123
124
        return $this;
125
    }
126
127
    /**
128
     * 是否存在事件监听
129
     * @access public
130
     * @param  string $event 事件名称
131
     * @return bool
132
     */
133
    public function hasListen(string $event): bool
134
    {
135
        if (isset($this->bind[$event])) {
136
            $event = $this->bind[$event];
137
        }
138
139
        return isset($this->listener[$event]);
140
    }
141
142
    /**
143
     * 移除事件监听
144
     * @access public
145
     * @param  string $event 事件名称
146
     * @return $this
147
     */
148
    public function remove(string $event): void
149
    {
150
        if (isset($this->bind[$event])) {
151
            $event = $this->bind[$event];
152
        }
153
154
        unset($this->listener[$event]);
155
    }
156
157
    /**
158
     * 指定事件别名标识 便于调用
159
     * @access public
160
     * @param  array $events 事件别名
161
     * @return $this
162
     */
163 1
    public function bind(array $events)
164
    {
165 1
        $this->bind = array_merge($this->bind, $events);
166
167 1
        return $this;
168
    }
169
170
    /**
171
     * 注册事件订阅者
172
     * @access public
173
     * @param  mixed $subscriber 订阅者
174
     * @param  array $events     事件列表
175
     * @return $this
176
     */
177 1
    public function subscribe($subscriber, array $events = [])
178
    {
179 1
        if (!$this->withEvent) {
180
            return $this;
181
        }
182
183 1
        $subscribers = (array) $subscriber;
184
185 1
        foreach ($subscribers as $subscriber) {
0 ignored issues
show
introduced by
$subscriber is overwriting one of the parameters of this function.
Loading history...
186
            if (is_string($subscriber)) {
187
                $subscriber = $this->app->make($subscriber);
188
            }
189
190
            if (method_exists($subscriber, 'subscribe')) {
191
                // 手动订阅
192
                $subscriber->subscribe($this);
193
            } else {
194
                // 智能订阅
195
                $this->observe($subscriber, $events);
196
            }
197
        }
198
199 1
        return $this;
200
    }
201
202
    /**
203
     * 自动注册事件观察者
204
     * @access public
205
     * @param  string|object $observer 观察者
206
     * @param  array         $events   事件列表
207
     * @return $this
208
     */
209
    public function observe($observer, array $events = [])
210
    {
211
        if (!$this->withEvent) {
212
            return $this;
213
        }
214
215
        if (is_string($observer)) {
216
            $observer = $this->app->make($observer);
217
        }
218
219
        if (!empty($events)) {
220
            foreach ($events as $event) {
221
                $name   = false !== strpos($event, '\\') ? substr(strrchr($event, '\\'), 1) : $event;
222
                $method = 'on' . $name;
223
224
                if (method_exists($observer, $method)) {
225
                    $this->listen($event, [$observer, $method]);
226
                }
227
            }
228
        } else {
229
            $reflect = new ReflectionClass($observer);
230
            $methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC);
231
232
            foreach ($methods as $method) {
233
                $name = $method->getName();
234
                if (0 === strpos($name, 'on')) {
235
                    $this->listen(substr($name, 2), [$observer, $name]);
236
                }
237
            }
238
        }
239
240
        return $this;
241
    }
242
243
    /**
244
     * 触发事件
245
     * @access public
246
     * @param  string|object $event  事件名称
247
     * @param  mixed         $params 传入参数
248
     * @param  bool          $once   只获取一个有效返回值
249
     * @return mixed
250
     */
251 8
    public function trigger($event, $params = null, bool $once = false)
252
    {
253 8
        if (!$this->withEvent) {
254
            return;
255
        }
256
257 8
        if (is_object($event)) {
258 2
            $params = $event;
259 2
            $event  = get_class($event);
260
        }
261
262 8
        if (isset($this->bind[$event])) {
263 6
            $event = $this->bind[$event];
264
        }
265
266 8
        $result    = [];
267 8
        $listeners = $this->listener[$event] ?? [];
268
269 8
        foreach ($listeners as $key => $listener) {
270
            $result[$key] = $this->dispatch($listener, $params);
271
272
            if (false === $result[$key] || (!is_null($result[$key]) && $once)) {
273
                break;
274
            }
275
        }
276
277 8
        return $once ? end($result) : $result;
278
    }
279
280
    /**
281
     * 执行事件调度
282
     * @access protected
283
     * @param  mixed $event  事件方法
284
     * @param  mixed $params 参数
285
     * @return mixed
286
     */
287
    protected function dispatch($event, $params = null)
288
    {
289
        if (!is_string($event)) {
290
            $call = $event;
291
        } elseif (strpos($event, '::')) {
292
            $call = $event;
293
        } else {
294
            $obj  = $this->app->make($event);
295
            $call = [$obj, 'handle'];
296
        }
297
298
        return $this->app->invoke($call, [$params]);
299
    }
300
301
}
302