Skip to content

Commit 610ae44

Browse files
committed
init
0 parents  commit 610ae44

14 files changed

+642
-0
lines changed

.editorconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
root = true
3+
4+
[*]
5+
end_of_line = lf
6+
indent_style = space
7+
indent_size = 4
8+
trim_trailing_whitespace = true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
!.gitkeep
2+
vendor/*
3+
composer.lock

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
Soli Event Manager
2+
------------------
3+
4+
当前项目参考 [Phalcon 框架的事件管理器]实现。
5+
6+
事件管理器的目的是为了通过创建"钩子"拦截框架或应用中的部分组件操作。
7+
8+
这些钩子允许开发者获得状态信息,操纵数据或者改变某个组件进程中的执行流向。
9+
10+
以上介绍摘自[Phalcon 框架的事件管理器]官方文档。
11+
12+
## 安装
13+
14+
使用 `composer` 安装到你的项目:
15+
16+
composer require soliphp/events
17+
18+
## 命名约定
19+
20+
当前事件管理器的命名规则采用分组的方式,目的是为了避免不同组件间的事件名称重名,产生碰撞,
21+
同时也便于对项目中同一维度的事件进行聚合整理;事件命名格式为 "component:event",
22+
类比类的命名空间,我们暂且将这种对事件的命名方式称之为「事件命名空间」。
23+
24+
如,我们有一个 `\Soli\Application` 类,它的事件命名空间可以定义为 "application",
25+
对于此类 "boot" 事件的全名为 "application:boot"。
26+
27+
## 使用
28+
29+
### 针对具体的某个事件设置监听器
30+
31+
use Soli\Events\EventManager;
32+
use Soli\Events\Event;
33+
34+
$eventManager = new EventManager();
35+
36+
$eventManager->on('application:boot', function (Event $event, $application) {
37+
echo "应用已启动\n";
38+
});
39+
40+
`监听器的格式`,只要是 [call_user_func_array] 允许的格式即可,
41+
也可以是包含与事件名称同名的实例化类。
42+
43+
如,我们这里定义一个 `AppEvents` 类用于处理针对 `Application` 类的事件:
44+
45+
class AppEvents
46+
{
47+
public function boot(Event $event, $application)
48+
{
49+
echo "应用已启动\n";
50+
}
51+
52+
public function beforeSendResponse(Event $event, $application, $extraData)
53+
{
54+
echo "Here, beforeSendResponse\n";
55+
}
56+
}
57+
58+
// 注册事件监听
59+
$eventManager->on('application:boot', array(new AppEvents, 'boot'));
60+
也可以这样:
61+
$eventManager->on('application:boot', new AppEvents);
62+
63+
或 call_user_func_array 支持的其他格式。
64+
65+
### 聚合事件监听器到专门的事件类中进行处理
66+
67+
上面我们定义了 `AppEvents` 类,其中有两个方法 `boot``beforeSendResponse`
68+
这两个方法可以直接用来监听 `application:boot` 事件和 `application:beforeSendResponse` 事件,
69+
注册方法很简单,如下:
70+
71+
$eventManager->on('application', new AppEvents);
72+
73+
这样我们便可以很方便的注册和整理不同纬度的不同事件。
74+
75+
### 触发事件
76+
77+
触发事件调用 `fire` 方法,其参数为具体的某个事件名称,事件源(当前类),
78+
也可以传入更多整合后的数据,供监听器使用。
79+
80+
$eventManager->fire('application:boot', $this, $extraData);
81+
82+
### 事件传播
83+
84+
$eventManager->on('application:boot', function (Event $event, $application) {
85+
// 终止事件传播,这样其他的侦听器就不会再收到此事件通知
86+
$event->stopPropagation();
87+
});
88+
89+
## 测试
90+
91+
$ composer install
92+
$ phpunit
93+
94+
## License
95+
96+
MIT Public License
97+
98+
99+
[Phalcon 框架的事件管理器]: https://docs.phalconphp.com/zh/latest/reference/events.html
100+
[call_user_func_array]: http://cn2.php.net/call_user_func_array

composer.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "soliphp/events",
3+
"description": "Soli Event Manager",
4+
"type": "library",
5+
"keywords": ["event", "EventManager", "soliphp"],
6+
"homepage": "https://github.com/soliphp/event-manager",
7+
"support": {
8+
"issues": "https://github.com/soliphp/event-manager/issues",
9+
"source": "https://github.com/soliphp/event-manager"
10+
},
11+
"license": "MIT",
12+
"authors": [
13+
{
14+
"name": "ueaner",
15+
"email": "[email protected]"
16+
}
17+
],
18+
"require": {
19+
"php": ">=5.5.0"
20+
},
21+
"autoload": {
22+
"psr-4": {
23+
"Soli\\": "src/"
24+
}
25+
},
26+
"minimum-stability": "dev"
27+
}

phpcs.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="Soli Coding Standard">
3+
<description>Soli Coding Standard</description>
4+
5+
<!-- display progress -->
6+
<arg value="p"/>
7+
<!-- display sniff codes -->
8+
<arg value="s"/>
9+
<!-- use colors in output -->
10+
<arg name="colors"/>
11+
<!-- file extensions -->
12+
<arg name="extensions" value="php"/>
13+
14+
<!-- inherit rules from: -->
15+
<rule ref="PSR2"/>
16+
<rule ref="Generic.Arrays.DisallowLongArraySyntax"/>
17+
<rule ref="PSR1">
18+
<exclude name="PSR1.Classes.ClassDeclaration"/>
19+
</rule>
20+
21+
<!-- ignore vendor -->
22+
<exclude-pattern>*/vendor/*</exclude-pattern>
23+
</ruleset>

phpunit.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
colors="true"
5+
convertErrorsToExceptions="true"
6+
convertNoticesToExceptions="true"
7+
convertWarningsToExceptions="true"
8+
processIsolation="false"
9+
stopOnFailure="false"
10+
syntaxCheck="false"
11+
bootstrap="tests/bootstrap.php"
12+
>
13+
<testsuites>
14+
<testsuite name="Soli Test Suite">
15+
<directory>./tests/</directory>
16+
</testsuite>
17+
</testsuites>
18+
<filter>
19+
<whitelist>
20+
<directory suffix=".php">./src/</directory>
21+
</whitelist>
22+
</filter>
23+
<php>
24+
</php>
25+
</phpunit>

src/Events/Event.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
/**
3+
* @author ueaner <[email protected]>
4+
*/
5+
namespace Soli\Events;
6+
7+
use Closure;
8+
9+
/**
10+
* 事件原型
11+
*/
12+
class Event
13+
{
14+
/**
15+
* 事件名称,当事件监听器为对象时,事件名称对应事件监听器中的方法名
16+
*
17+
* @var string
18+
*/
19+
protected $name;
20+
21+
/**
22+
* 事件来源
23+
*
24+
* @var object
25+
*/
26+
protected $source;
27+
28+
/**
29+
* 事件相关数据
30+
*
31+
* @var mixed
32+
*/
33+
protected $data;
34+
35+
/**
36+
* Whether no further event listeners should be triggered
37+
*
38+
* @var bool
39+
*/
40+
protected $propagationStopped = false;
41+
42+
/**
43+
* Event constructor.
44+
*
45+
* @param string $name
46+
* @param object $source
47+
* @param mixed $data
48+
* @throws \Exception
49+
*/
50+
public function __construct($name, $source, $data = null)
51+
{
52+
if (!is_string($name) || !is_object($source)) {
53+
throw new \Exception('Invalid parameter type.');
54+
}
55+
56+
$this->name = $name;
57+
$this->source = $source;
58+
59+
if ($data !== null) {
60+
$this->data = $data;
61+
}
62+
}
63+
64+
/**
65+
* 激活事件监听队列
66+
*
67+
* @param array $queue
68+
* @return mixed
69+
* @throws \Exception
70+
*/
71+
public function fire($queue)
72+
{
73+
if (!is_array($queue)) {
74+
throw new \Exception('The queue is not valid');
75+
}
76+
77+
// 事件监听队列中最后一个监听器的执行状态
78+
$status = null;
79+
80+
foreach ($queue as $listener) {
81+
if ($this->isPropagationStopped()) {
82+
break;
83+
}
84+
85+
if (is_callable($listener)) {
86+
$status = call_user_func_array($listener, [$this, $this->source, $this->data]);
87+
} elseif (is_object($listener)) {
88+
if (method_exists($listener, $this->name)) {
89+
// 调用对象监听器
90+
$status = $listener->{$this->name}($this, $this->source, $this->data);
91+
}
92+
} elseif (is_string($listener) && class_exists($listener)) {
93+
// 注意这里的 $this->name 需要是 $listener 的静态方法
94+
if (method_exists($listener, $this->name)) {
95+
$status = call_user_func_array([$listener, $this->name], [$this, $this->source, $this->data]);
96+
}
97+
}
98+
}
99+
100+
return $status;
101+
}
102+
103+
/**
104+
* Stops the propagation of the event to further event listeners.
105+
*/
106+
public function stopPropagation()
107+
{
108+
$this->propagationStopped = true;
109+
}
110+
111+
/**
112+
* Has this event indicated event propagation should stop?
113+
*
114+
* @return bool
115+
*/
116+
public function isPropagationStopped()
117+
{
118+
return $this->propagationStopped;
119+
}
120+
}

0 commit comments

Comments
 (0)