Completed
Push — master ( 67d50f...8a7d08 )
by Nazar
04:56
created

Event::events_files_paths()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 3
rs 9.6666
1
<?php
2
/**
3
 * @package   CleverStyle Framework
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 50
	protected function init () {
29
		/** @noinspection PhpUndefinedFieldInspection */
30 50
		if ($this->__request_id > 1) {
31 2
			$this->callbacks = [];
32
		}
33 50
	}
34
	/**
35
	 * Add event handler
36
	 *
37
	 * @param string   $event    For example `admin/System/components/modules/disable`
38
	 * @param callable $callback Callable, that will be called at event dispatching
39
	 *
40
	 * @return Event
41
	 */
42 50
	function on ($event, $callback) {
43 50
		if (!$event || !is_callable($callback)) {
44 2
			return $this;
45
		}
46 50
		$this->callbacks[$event][] = $callback;
47 50
		return $this;
48
	}
49
	/**
50
	 * Remove event handler
51
	 *
52
	 * @param string        $event
53
	 * @param callable|null $callback If not specified - all callbacks for this event will be removed
54
	 *
55
	 * @return Event
56
	 */
57 6
	function off ($event, $callback = null) {
58 6
		if (!isset($this->callbacks[$event])) {
59 2
			return $this;
60
		}
61 6
		if (!$callback) {
62 2
			unset($this->callbacks[$event]);
63 2
			return $this;
64
		}
65 6
		$this->callbacks[$event] = array_filter(
66 6
			$this->callbacks[$event],
67
			function ($c) use ($callback) {
68 6
				return $c !== $callback;
69 6
			}
70
		);
71 6
		return $this;
72
	}
73
	/**
74
	 * Similar to `::on()`, but but removes handler after handling of first event
75
	 *
76
	 * @param string   $event
77
	 * @param callable $callback
78
	 *
79
	 * @return Event
80
	 */
81 8
	function once ($event, $callback) {
82 8
		if (!$event || !is_callable($callback)) {
83 2
			return $this;
84
		}
85 8
		$wrapped_callback = function (...$arguments) use (&$wrapped_callback, $event, $callback) {
86 6
			$this->off($event, $wrapped_callback);
87 6
			return $callback(...$arguments);
88 8
		};
89 8
		return $this->on($event, $wrapped_callback);
90
	}
91
	/**
92
	 * Fire event
93
	 *
94
	 * After event name it is possible to specify as many arguments as needed
95
	 *
96
	 * @param string  $event For example `admin/System/components/modules/disable`
97
	 * @param mixed[] $arguments
98
	 *
99
	 * @return bool
100
	 */
101 40
	function fire ($event, ...$arguments) {
102 40
		$this->ensure_events_registered();
103
		if (
104 40
			!$event ||
105 40
			!isset($this->callbacks[$event])
106
		) {
107 40
			return true;
108
		}
109 30
		foreach ($this->callbacks[$event] as $callback) {
110 30
			if ($callback(...$arguments) === false) {
111 30
				return false;
112
			}
113
		}
114 30
		return true;
115
	}
116
	/**
117
	 * Before firing events we need to ensure that events callbacks were registered
118
	 */
119 40
	protected function ensure_events_registered () {
120 40
		if (!$this->callbacks_cache) {
121 40
			$this->register_events();
122 40
			$this->callbacks_cache = $this->callbacks;
123 40
		} elseif (!$this->callbacks) {
124 2
			$this->callbacks = $this->callbacks_cache;
125
		}
126 40
	}
127
	/**
128
	 * Initialize all events handlers
129
	 */
130 40
	protected function register_events () {
131 40
		foreach ($this->events_files_paths() as $path) {
132 40
			include $path;
133
		}
134 40
	}
135
	/**
136
	 * @return string[]
137
	 */
138 40
	protected function events_files_paths () {
139 40
		$paths = [];
140 40
		foreach (get_files_list(MODULES, false, 'd', true) as $path) {
141 40
			if (file_exists("$path/events.php")) {
142 40
				$paths[] = "$path/events.php";
143
			}
144
		}
145 40
		return $paths;
146
	}
147
}
148