## Apache Zeta Components Manual :: File Source for signal_collection.php

## Source for file signal_collection.php

Documentation is available at signal_collection.php

1. <?php
2. /**
3. *
4. * Licensed to the Apache Software Foundation (ASF) under one
5. * or more contributor license agreements. See the NOTICE file
6. * distributed with this work for additional information
7. * regarding copyright ownership. The ASF licenses this file
8. * to you under the Apache License, Version 2.0 (the
9. * "License"); you may not use this file except in compliance
10. * with the License. You may obtain a copy of the License at
11. *
12. * http://www.apache.org/licenses/LICENSE-2.0
13. *
14. * Unless required by applicable law or agreed to in writing,
15. * software distributed under the License is distributed on an
16. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17. * KIND, either express or implied. See the License for the
18. * specific language governing permissions and limitations
19. * under the License.
20. *
21. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
22. * @version //autogentag//
23. * @filesource
24. * @package SignalSlot
25. */
27. /**
28. * ezcSignalCollection implements a mechanism for inter and intra object communication.
29. *
30. * See the tutorial for extensive examples on how to use this class.
31. *
32. * @property bool $signalsBlocked If set to true emits will not cause any slots to be called.
33. *
34. * @property-read string $identifier The identifier of this signal collection.
35. * Usually the class name of the object containing the collection.
36. *
37. * @version //autogen//
38. * @mainclass
39. * @package SignalSlot
40. */
41. class ezcSignalCollection
42. {
43. /**
44. * Holds the properties of this class.
45. *
46. * @var array(string=>mixed)
47. */
48. private $properties = array();
50. /**
51. * Holds the connections for this object with the default priority.
52. *
53. * @var array(string=>array(callback))
54. */
55. private $defaultConnections = array();
57. /**
58. * Holds the priority connections for this object.
59. *
60. * @var array(string=>array(int=>array(callback)))
61. */
62. private $priorityConnections = array();
64. /**
65. * If set this object will be used to fetch static connections instead of ezcSignalStaticConnections.
66. *
67. * @var ezcSignalStaticConnectionsBase
68. */
69. private static $staticConnectionsHolder = null;
71. /**
72. * Holds the options for this signal collection
73. *
74. * @var ezcSignalCollectionOptions
75. */
76. private $options;
78. /**
79. * Constructs a new signal collection with the identifier $identifier.
80. *
81. * The identifier can be used to connect to signals statically using
82. * ezcSignalStaticConnections.
83. *
84. * Through the associative array options you can specify the options for this class in the
85. * format array( 'optionName' => value ). See the documentation of ezcSignalCollectionOptions
86. * for information on the available options.
87. *
88. * @param string $identifier
89. * @param array $options
90. */
91. public function __construct ( $identifier = "default", array $options = array() )
92. {
93. $this->options = new ezcSignalCollectionOptions ( $options );
94. $this->properties['identifier'] = $identifier;
95. $this->signalsBlocked = false;
96. }
98. /**
99. * If set, $holder will be used to fetch static connections instead of ezcSignalStaticConnections.
100. *
101. * @param ezcSignalStaticConnectionsBase $holder
102. */
103. public static function setStaticConnectionsHolder ( ezcSignalStaticConnectionsBase $holder )
104. {
105. self::$staticConnectionsHolder = $holder;
106. }
108. /**
109. * Returns the current provider of static connections or null if there is none.
110. *
111. * @return ezcSignalStaticConnectionsBase
112. */
113. public static function getStaticConnectionsHolder ()
114. {
115. return self::$staticConnectionsHolder;
116. }
118. /**
119. * Sets the property $name to $value.
120. *
121. * @throws ezcBasePropertyNotFoundException if the property does not exist.
122. * @param string $name
123. * @param mixed $value
124. * @return void
125. */
126. public function __set ( $name, $value )
127. {
128. switch ( $name )
129. {
130. case 'signalsBlocked':
131. $this->properties[$name] = $value;
132. break;
133. case 'identifier':
134. throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException ::READ );
135. break;
136. case 'options':
137. if ( !( $value instanceof ezcSignalCollectionOptions ) )
138. {
139. throw new ezcBaseValueException ( 'options', $value, 'instanceof ezcSignalCollectionOptions' );
140. }
141. $this->options = $value;
142. break;
143. default:
144. throw new ezcBasePropertyNotFoundException ( $name );
145. break;
146. }
148. }
150. /**
151. * Returns the property $name.
152. *
153. * @throws ezcBasePropertyNotFoundException if the property does not exist.
154. * @param string $name
155. * @return mixed
156. */
157. public function __get ( $name )
158. {
159. switch ( $name )
160. {
161. case 'signalsBlocked':
162. case 'identifier':
163. return $this->properties[$name];
164. break;
165. case 'options':
166. return $this->options;
167. break;
168. default:
169. throw new ezcBasePropertyNotFoundException ( $name );
170. break;
171. }
172. }
174. /**
175. * Sets the options of this class.
176. *
177. * @param ezcSignalCollectionOptions|array(string=>value)$options The options to set
178. * either as an associative array in the form array(optionName=>value) or a
179. * ezcSignalCollectionOptions object.
180. *
181. * @throws ezcBaseSettingNotFoundException
182. * If you tried to set a non-existent option value.
183. * @throws ezcBaseSettingValueException
184. * If the value is not valid for the desired option.
185. * @throws ezcBaseValueException
186. * If you submit neither an array nor an instance of
187. * ezcSignalCollectionOptions.
188. */
189. public function setOptions ( $options )
190. {
191. if ( $options instanceof ezcSignalCollectionOptions )
192. {
193. $this->options = $options;
194. }
195. else if ( is_array ( $options ) )
196. {
197. $this->options = new ezcSignalCollectionOptions ( $options );
198. }
199. else
200. {
201. throw new ezcBaseValueException ( "options", $options, 'array or instance of ezcSignalCollectionOptions' );
202. }
203. }
205. /**
206. * Returns the options for this class.
207. *
208. * @return ezcSignalCollectionOptions
209. */
210. public function getOptions ()
211. {
212. return $this->options;
213. }
215. /**
216. * Returns true if any slots have been connected to the signal $signal.
217. * False is returned if no slots have been connected to the $signal.
218. *
219. * Note: Emitting the signal $signal may still not call any slots if
220. * the property signalsBlocked has been set.
221. *
222. * @throws ezcSignalSlotException if the signals options has been set and $signal is not in the list of signals.
223. * @param string $signal
224. * @return bool
225. */
226. public function isConnected ( $signal )
227. {
228. // if the the signals option is set we must check if the signal exists
229. if ( $this->options->signals != null && ! in_array ( $signal, $this->options->signals ) )
230. {
231. throw new ezcSignalSlotException ( "No such signal {$signal}" );
232. }
234. // static connections
235. if ( self::$staticConnectionsHolder == null ) // custom static connections class
236. {
237. if ( count ( ezcSignalStaticConnections :: getInstance ()->getConnections( $this->identifier, $signal ) ) > 0 )
238. {
239. return true;
240. }
241. }
242. else if ( count ( self::$staticConnectionsHolder->getConnections( $this->identifier, $signal ) ) > 0 )
243. {
244. return true;
245. }
246. // default connections
247. if ( isset( $this->defaultConnections[$signal] ) && count ( $this->defaultConnections[$signal] ) > 0 )
248. {
249. return true;
250. }
252. // priority connections
253. if ( isset( $this->priorityConnections[$signal] ) && count ( $this->priorityConnections[$signal] ) > 0 )
254. {
255. return true;
256. }
258. return false;
259. }
261. /**
262. * Emits the signal with the name $signal
263. *
264. * Any additional parameters are sent as parameters to the slot.
265. *
266. * @throws ezcSignalSlotException if the signals options has been set and $signal is not in the list of signals.
267. * @param string $signal
268. * @param ... $signal_parameters
269. * @return void
270. */
271. public function emit ( $signal )
272. {
273. // if the the signals option is set we must check if the signal exists
274. if ( $this->options->signals != null && ! in_array ( $signal, $this->options->signals ) )
275. {
276. throw new ezcSignalSlotException ( "No such signal {$signal}" );
277. }
279. if ( $this->signalsBlocked )
280. {
281. return;
282. }
284. // prepare the parameters
285. $parameters = array_slice ( func_get_args (), 1 );
287. // check if there are any static connections
288. $priStaticConnections = array();
289. if ( self::$staticConnectionsHolder == null )
290. {
291. $priStaticConnections = ezcSignalStaticConnections :: getInstance ()->getConnections( $this->identifier, $signal );
292. }
293. else
294. {
295. $priStaticConnections = self::$staticConnectionsHolder->getConnections( $this->identifier, $signal );
296. }
298. $hasPriStaticConnections = false;
299. if ( count ( $priStaticConnections ) > ( isset( $priStaticConnections[1000] ) ? 1 : 0) )
300. {
301. $hasPriStaticConnections = true;
302. }
304. // fast algorithm if there are no prioritized slots
305. if ( isset( $this->priorityConnections[$signal] ) === false && !$hasPriStaticConnections )
306. {
307. if ( isset( $this->defaultConnections[$signal] ) )
308. {
309. foreach ( $this->defaultConnections[$signal] as $callback )
310. {
311. call_user_func_array ( $callback, $parameters );
312. }
313. }
314. if ( isset( $priStaticConnections[1000] ) )
315. {
316. foreach ( $priStaticConnections[1000] as $callback )
317. {
318. call_user_func_array ( $callback, $parameters );
319. }
320. }
321. }
322. else // default algorithm
323. {
324. // order slots
325. $defaultKeys = array();
326. if ( isset( $this->priorityConnections[$signal] ) )
327. {
328. $defaultKeys = array_keys ( $this->priorityConnections[$signal] );
329. }
330. $staticKeys = array_keys ( $priStaticConnections );
332. $allKeys = array_unique ( array_merge ( $defaultKeys, $staticKeys, array( 1000 ) /*default*/ ) );
333. sort ( $allKeys, SORT_NUMERIC );
335. foreach ( $allKeys as $key ) // call all slots in the correct order
336. {
337. if ( $key == 1000 && isset( $this->defaultConnections[$signal] ) )
338. {
339. foreach ( $this->defaultConnections[$signal] as $callback )
340. {
341. call_user_func_array ( $callback, $parameters );
342. }
343. }
344. if ( isset( $this->priorityConnections[$signal][$key] ) )
345. {
346. foreach ( $this->priorityConnections[$signal][$key] as $callback )
347. {
348. call_user_func_array ( $callback, $parameters );
349. }
350. }
351. if ( isset( $priStaticConnections[$key] ) )
352. {
353. foreach ( $priStaticConnections[$key] as $callback )
354. {
355. call_user_func_array ( $callback, $parameters );
356. }
357. }
358. }
359. }
360. }
362. /**
363. * Connects the signal $signal to the slot $slot.
364. *
365. * To control the order in which slots are called you can set a priority
366. * from 1 - 65 536. The lower the number the higher the priority. The default
367. * priority is 1000.
368. * Slots with the same priority may be called with in any order.
369. *
370. * A slot will be called once for every time it is connected. It is possible
371. * to connect a slot more than once.
372. *
373. * See the PHP documentation for examples on the callback type.
374. * http://php.net/callback.
375. *
376. * We recommend avoiding excessive usage of the $priority parameter
377. * since it makes it much harder to track how your program works.
378. *
379. * @throws ezcSignalSlotException if the signals options has been set and $signal is not in the list of signals.
380. * @param string $signal
381. * @param callback $slot
382. * @param int $priority
383. * @return void
384. */
385. public function connect ( $signal, $slot, $priority = 1000 )
386. {
387. // if the the signals option is set we must check if the signal exists
388. if ( $this->options->signals != null && ! in_array ( $signal, $this->options->signals ) )
389. {
390. throw new ezcSignalSlotException ( "No such signal {$signal}" );
391. }
393. if ( $priority === 1000 ) // default
394. {
395. $this->defaultConnections[$signal][] = $slot;
396. }
397. else
398. {
399. $this->priorityConnections[$signal][$priority][] = $slot;
400. sort ( $this->priorityConnections[$signal][$priority], SORT_NUMERIC );
401. }
402. }
404. /**
405. * Disconnects the $slot from the $signal.
406. *
407. * If the priority is given it will try to disconnect a slot with that priority.
408. * If no such slot is found no slot will be disconnected.
409. *
410. * If no priority is given it will disconnect the matching slot with the lowest priority.
411. *
412. * @throws ezcSignalSlotException if the signals options has been set and $signal is not in the list of signals.
413. * @param string $signal
414. * @param callback $slot
415. * @param int $priority
416. * @return void
417. */
418. public function disconnect ( $signal, $slot, $priority = null )
419. {
420. // if the the signals option is set we must check if the signal exists
421. if ( $this->options->signals != null && ! in_array ( $signal, $this->options->signals ) )
422. {
423. throw new ezcSignalSlotException ( "No such signal {$signal}" );
424. }
426. if ( $priority === null ) // delete first found, searched from back
427. {
428. $priorityKeys = array();
429. if ( isset( $this->priorityConnections[$signal] ) )
430. {
431. $priorityKeys = array_keys ( $this->priorityConnections[$signal] );
432. }
434. $allPriorities = array_unique ( array_merge ( $priorityKeys, array( 1000 ) /*default*/ ) );
435. rsort ( $allPriorities, SORT_NUMERIC );
436. foreach ( $allPriorities as $priority )
437. {
438. if ( $priority === 1000 )
439. {
440. if ( isset( $this->defaultConnections[$signal] ) )
441. {
442. foreach ( $this->defaultConnections[$signal] as $key => $callback )
443. {
444. if ( ezcSignalCallbackComparer::compareCallbacks( $slot, $callback ) )
445. {
446. unset( $this->defaultConnections[$signal][$key] );
447. return;
448. }
449. }
450. }
451. }
452. else
453. {
454. if ( isset( $this->priorityConnections[$signal] ) &&
455. isset( $this->priorityConnections[$signal][$priority] ) )
456. {
457. foreach ( $this->priorityConnections[$signal][$priority] as $key => $callback)
458. {
459. if ( ezcSignalCallbackComparer::compareCallbacks( $slot, $callback ) )
460. {
461. unset( $this->priorityConnections[$signal][$priority][$key] );
462. // if the priority is empty now it should be unset
463. if ( count ( $this->priorityConnections[$signal][$priority] ) == 0 )
464. {
465. unset( $this->priorityConnections[$signal][$priority] );
466. }
467. return;
468. }
469. }
470. }
471. }
472. }
474. }
475. else if ( $priority === 1000 ) // only delete from default
476. {
477. if ( isset( $this->defaultConnections[$signal] ) )
478. {
479. foreach ( $this->defaultConnections[$signal] as $key => $callback )
480. {
481. if ( ezcSignalCallbackComparer::compareCallbacks( $slot, $callback ) )
482. {
483. unset( $this->defaultConnections[$signal][$key] );
484. return;
485. }
486. }
487. }
488. }
489. else // delete from priority connectinos
490. {
491. if ( isset( $this->priorityConnections[$signal] ) &&
492. isset( $this->priorityConnections[$signal][$priority] ) )
493. {
494. foreach ( $this->priorityConnections[$signal][$priority] as $key => $callback )
495. {
496. if ( ezcSignalCallbackComparer::compareCallbacks( $slot, $callback ) )
497. {
498. unset( $this->priorityConnections[$signal][$priority][$key] );
499. // if the priority is empty now it should be unset
500. if ( count ( $this->priorityConnections[$signal][$priority] ) == 0 )
501. {
502. unset( $this->priorityConnections[$signal][$priority] );
503. }
504. return;
505. }
506. }
507. }
508. }
509. }
510. }
511. ?>

Documentation generated by phpDocumentor 1.4.3