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