Completed
Push — master ( 9eb297...aeb93c )
by Nazar
04:06
created

Event::initialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 6
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
/**
3
 * @package   CleverStyle CMS
4
 * @author    Nazar Mokrynskyi <[email protected]>
5
 * @copyright Copyright (c) 2015-2016, Nazar Mokrynskyi
6
 * @license   MIT License, see license.txt
7
 */
8
namespace cs;
9
/**
10
 * Event class
11
 *
12
 * Provides events subscribing and dispatching
13
 *
14
 * @method static $this instance($check = false)
15
 */
16
class Event {
17
	use
18
		Singleton;
19
	const INIT_STATE_METHOD = 'init';
20
	/**
21
	 * @var callable[][]
22
	 */
23
	protected $callbacks;
24
	/**
25
	 * @var callable[][]
26
	 */
27
	protected $callbacks_cache;
28
	protected function init () {
29
		$this->callbacks = [];
30
	}
31
	/**
32
	 * Add event handler
33
	 *
34
	 * @param string   $event    For example `admin/System/components/plugins/disable`
35
	 * @param callable $callback Callable, that will be called at event dispatching
36
	 *
37
	 * @return Event
38
	 */
39
	function on ($event, $callback) {
40
		if (!$event || !is_callable($callback)) {
41
			return $this;
42
		}
43
		$this->callbacks[$event][] = $callback;
44
		return $this;
45
	}
46
	/**
47
	 * Remove event handler
48
	 *
49
	 * @param string        $event
50
	 * @param callable|null $callback If not specified - all callbacks for this event will be removed
51
	 *
52
	 * @return Event
53
	 */
54
	function off ($event, $callback = null) {
55
		if (!isset($this->callbacks[$event])) {
56
			return $this;
57
		}
58
		if (!$callback) {
59
			unset($this->callbacks[$event]);
60
			return $this;
61
		}
62
		$this->callbacks[$event] = array_filter(
63
			$this->callbacks[$event],
64
			function ($c) use ($callback) {
65
				return $c !== $callback;
66
			}
67
		);
68
		return $this;
69
	}
70
	/**
71
	 * Similar to `::on()`, but but removes handler after handling of first event
72
	 *
73
	 * @param string   $event
74
	 * @param callable $callback
75
	 *
76
	 * @return Event
77
	 */
78
	function once ($event, $callback) {
79
		if (!$event || !is_callable($callback)) {
80
			return $this;
81
		}
82
		$wrapped_callback = function (...$arguments) use (&$wrapped_callback, $event, $callback) {
83
			$this->off($event, $wrapped_callback);
84
			$callback(...$arguments);
85
		};
86
		return $this->on($event, $wrapped_callback);
87
	}
88
	/**
89
	 * Fire event
90
	 *
91
	 * After event name it is possible to specify as many arguments as needed
92
	 *
93
	 * @param string  $event For example `admin/System/components/plugins/disable`
94
	 * @param mixed[] $arguments
95
	 *
96
	 * @return bool
97
	 */
98
	function fire ($event, ...$arguments) {
99
		$this->ensure_events_registered();
100
		if (
101
			!$event ||
102
			!isset($this->callbacks[$event])
103
		) {
104
			return true;
105
		}
106
		foreach ($this->callbacks[$event] as $callback) {
107
			if ($callback(...$arguments) === false) {
108
				return false;
109
			}
110
		}
111
		return true;
112
	}
113
	/**
114
	 * Before firing events we need to ensure that events callbacks were registered
115
	 */
116
	protected function ensure_events_registered () {
117
		if (!$this->callbacks_cache) {
118
			$this->register_events();
119
			$this->callbacks_cache = $this->callbacks;
120
		} elseif (!$this->callbacks) {
121
			$this->callbacks = $this->callbacks_cache;
122
		}
123
	}
124
	/**
125
	 * Initialize all events handlers
126
	 */
127
	protected function register_events () {
128
		foreach ($this->events_files_paths() as $path) {
129
			include DIR."/$path";
130
		}
131
	}
132
	/**
133
	 * @return string[]
134
	 */
135
	protected function events_files_paths () {
136
		return Cache::instance()->get(
137
			'events_files_paths',
138
			function () {
139
				$paths = [];
140
				foreach (get_files_list(MODULES, false, 'd', 'components/modules') as $path) {
141
					if (file_exists(DIR."/$path/events.php")) {
142
						$paths[] = "$path/events.php";
143
					}
144
				}
145
				foreach (get_files_list(PLUGINS, false, 'd', 'components/plugins') as $path) {
146
					if (file_exists(DIR."/$path/events.php")) {
147
						$paths[] = "$path/events.php";
148
					}
149
				}
150
				return $paths;
151
			}
152
		);
153
	}
154
}
155