Passed
Push — 6.0 ( 5ee6bf...c5af4c )
by liu
03:41
created

Event::trigger()   B

Complexity

Conditions 9
Paths 25

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 14.184

Importance

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