expand description
[m6w6/hikke] / lib / hikke / Event / Proxy.php
1 <?php
2
3 /**
4 * Hikke
5 *
6 * @author Michael Wallner <mike@php.net>
7 */
8 namespace hikke\Event;
9
10 use hikke\Event;
11 use hikke\Event\Storage;
12
13 /**
14 * Proxy
15 *
16 * @package hikke\Event
17 */
18 class Proxy implements \SplSubject, \SplObserver, \IteratorAggregate, \Countable
19 {
20 /**
21 * @var array
22 */
23 private $events = array();
24
25 /**
26 * @var \hikke\Event\Storage
27 */
28 private $storage;
29
30 public function __construct(array $events = ["default"]) {
31 $this->storage = new Storage;
32 foreach ((array) $events as $priority => $event) {
33 $this->insert($event, $priority);
34 }
35 }
36
37 /**
38 * Notify all attached observers passing along $origin
39 * @param \SplSubject $origin
40 */
41 public function update(\SplSubject $origin) {
42 $this->notify($origin);
43 }
44
45 /**
46 * Apply a cvallback ot a specific or all events
47 * @param string $event
48 * @param callable $apply
49 */
50 public function apply($event, callable $apply) {
51 if (strlen($event)) {
52 $apply($this->events[$event]);
53 } else {
54 foreach ($this->storage as $ev) {
55 $apply($ev);
56 }
57 }
58 }
59
60 /**
61 * Notify all attached observers to a specific or all events passing alomg $origin
62 * @param object $origin
63 * @param string $event
64 */
65 public function notify($origin = null, $event = null) {
66 $this->apply($event, function($ev) use($origin) {
67 $ev->notify($origin);
68 });
69 }
70
71 /**
72 * Attach an observer to a specfiv or all events
73 * @param \SplObserver $observer
74 * @param string $event
75 * @param int|float $priority
76 * @return \hikke\Event\Proxy self
77 */
78 public function attach(\SplObserver $observer, $event = null, $priority = 0) {
79 $this->apply($event, function($ev) use($observer, $priority) {
80 $ev->attach($observer, $priority);
81 });
82 return $this;
83 }
84
85 /**
86 * Detach an observer from all or a specific event
87 * @param \SplObserver $observer
88 * @param string $event
89 * @return \hikke\Event\Proxy self
90 */
91 public function detach(\SplObserver $observer, $event = null) {
92 $this->apply($event, function($ev) use($observer) {
93 $ev->detach($observer);
94 });
95 return $this;
96 }
97
98 /**
99 * Insert a new event type
100 * @param string $name
101 * @param int|float $priority
102 */
103 private function insert($name, $priority = 0) {
104 if ($priority instanceof Event) {
105 /* assignement in the form:
106 * $proxy->foo = new Event("foo", 123);
107 */
108 $event = $priority;
109 $priority = $event->getPriority();
110
111 /* sanity check */
112 if ($name !== $event->getName()) {
113 throw new \UnexpectedValueException(
114 sprintf("The event names differ: '%s' <> '%s'",
115 $name, $event->getName()));
116 }
117 } elseif (isset($this->events[$name])) {
118 throw new \UnexpectedValueException(
119 sprintf("The event name '%s' is already in use", $name));
120 } else {
121 $event = new Event($name);
122 }
123
124 $bucket = $this->storage->insert($event, $priority);
125 $event->setPriority($bucket->getPriority());
126 $this->events[$name] = $event;
127 }
128
129 /**
130 * @ignore
131 */
132 public function __call($method, $args) {
133 $observers = new \SplObjectStorage;
134 $this->apply(null, function($ev) use($observers) {
135 foreach ($ev as $observer) {
136 if (!$observers->contains($observer)) {
137 $observers->attach($observer);
138 }
139 }
140 });
141 foreach ($observers as $observer) {
142 if (is_callable(array($observer, $method))) {
143 call_user_func_array(array($observer, $method), $args);
144 }
145 }
146 }
147
148 /**
149 * @ignore
150 */
151 public function __get($event) {
152 if (!isset($this->events[$event])) {
153 $this->insert($event);
154 }
155 return $this->events[$event];
156 }
157
158 /**
159 * @ignore
160 */
161 public function __set($event, $priority) {
162 $this->insert($event, $priority);
163 }
164
165 /**
166 * @ignore
167 */
168 public function __isset($event) {
169 return isset($this->events[$event]);
170 }
171
172 /**
173 * @ignore
174 */
175 public function __unset($event) {
176 if (isset($this->events[$event])) {
177 $this->storage->delete($this->events[$event]);
178 unset($this->events[$event]);
179 }
180 }
181
182 /**
183 * @ignore
184 */
185 public function getIterator() {
186 return $this->storage;
187 }
188
189 /**
190 * @ignore
191 */
192 public function count() {
193 return count($this->storage);
194 }
195 }