1: <?php
2: /**
3: * This file contains the CEC registry class.
4: *
5: * @package Core
6: * @subpackage CEC
7: * @version SVN Revision $Rev:$
8: *
9: * @author Timo A. Hummel
10: * @author Murat Purc <murat@purc.de>
11: * @copyright four for business AG <www.4fb.de>
12: * @license http://www.contenido.org/license/LIZENZ.txt
13: * @link http://www.4fb.de
14: * @link http://www.contenido.org
15: */
16:
17: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
18:
19: /**
20: * CEC registry class.
21: * Used to register chains and chain functions to invoke.
22: *
23: * Following 3 types of CEC functions/callbacks are supported at the moment:
24: * - Callbacks, which should only be invoked. They don't return a value and have
25: * no
26: * break conditions, @see cApiCecHook::execute()
27: * - Callbacks, which should return a value and/or should modify a passed
28: * parameter,
29: *
30: * @see cApiCecHook::executeAndReturn() - Callbacks, which should be processed
31: * untill a defined break condition achieves,
32: * @see cApiCecHook::executeWhileBreakCondition()
33: *
34: * @package Core
35: * @subpackage CEC
36: */
37: class cApiCecRegistry {
38:
39: /**
40: * List of available chains
41: *
42: * @var array
43: */
44: private $_aChains;
45:
46: /**
47: * Self instance
48: *
49: * @var cApiCecRegistry
50: */
51: private static $_instance = NULL;
52:
53: /**
54: * Constructor
55: */
56: protected function __construct() {
57: $this->_aChains = array();
58: }
59:
60: /**
61: * Prevent cloning
62: */
63: private function __clone() {
64: // donut
65: }
66:
67: /**
68: * Returns a instance of cApiCecRegistry
69: *
70: * @return cApiCecRegistry
71: */
72: public static function getInstance() {
73: if (self::$_instance == NULL) {
74: self::$_instance = new cApiCecRegistry();
75: }
76:
77: return self::$_instance;
78: }
79:
80: /**
81: * Registers a chain (adds the chain to the internal chain holder)
82: * NOTE: The number of parameter is not restricted.
83: * You can pass
84: * as much parameter as you want.
85: *
86: * @param string $sChainName
87: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
88: */
89: public function registerChain($sChainName) {
90: cDeprecated('This method is deprecated and is not needed any longer');
91: }
92:
93: /**
94: * Unregisters a chain
95: *
96: * @param string $sChainName
97: *
98: * @throws cInvalidArgumentException if the given chain does not exist
99: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
100: */
101: public function unregisterChain($sChainName) {
102: cDeprecated('This method is deprecated and is not needed any longer');
103: }
104:
105: /**
106: * Checks if a chain is registered or not.
107: *
108: * @param string $sChainName
109: *
110: * @return bool
111: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
112: */
113: public function isChainRegistered($sChainName) {
114: cDeprecated('This method is deprecated and is not needed any longer');
115: return true;
116: }
117:
118: /**
119: * Returns list of registered chain names
120: *
121: * @return array
122: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
123: */
124: public function getRegisteredChainNames() {
125: cDeprecated('This method is deprecated and is not needed any longer');
126: return array();
127: }
128:
129: /**
130: * Adds the chain to the internal chain holder
131: *
132: * @param string $sChainName Chain name
133: * @param array $aParameters Chain parameter
134: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
135: */
136: protected function _addChain($sChainName, array $aParameters = array()) {
137: cDeprecated('This method is deprecated and is not needed any longer');
138: return null;
139: }
140:
141: /**
142: * Adds a chain function which is to invoke.
143: *
144: * @param string $sChainName Chain name
145: * @param string $sFunctionName Name of function/callback to invoke.
146: * Feasible values are:
147: * - "ClassName->methodName" to invoke a method of a ClassName
148: * instance.
149: * A instance of the clas will be created here.
150: * - "ClassName::methodName" to invoke a static method of ClassName.
151: * - "FunctionName" to invoke a function.
152: * NOTE: Necessary files must be manually included before or by
153: * defined autoloader.
154: *
155: * @throws cInvalidArgumentException if the given chain is not registered or
156: * the given callback is not callable
157: * @return bool True on success, otherwhise false
158: */
159: public function addChainFunction($sChainName, $sFunctionName) {
160: $cfg = cRegistry::getConfig();
161: // do not add the chain if the chain system is disabled
162: if ($cfg['debug']['disable_chains']) {
163: return;
164: }
165:
166: if (strpos($sFunctionName, '->') > 0) {
167: // chain function is a method of a object instance
168: list($class, $method) = explode('->', $sFunctionName);
169: if (!class_exists($class)) {
170: throw new cInvalidArgumentException('Class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
171: } elseif (!method_exists($class, $method)) {
172: throw new cInvalidArgumentException('Method ' . $method . ' in class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
173: }
174: $call = array(
175: new $class(),
176: $method
177: );
178: } elseif (strpos($sFunctionName, '::') > 0) {
179: // chain function is static method of a object
180: list($class, $method) = explode('::', $sFunctionName);
181: if (!class_exists($class)) {
182: throw new cInvalidArgumentException('Class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
183: } elseif (!method_exists($class, $method)) {
184: throw new cInvalidArgumentException('Method ' . $method . ' in class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
185: }
186: $call = array(
187: $class,
188: $method
189: );
190: } else {
191: // chain function is a function
192: if (!function_exists($sFunctionName)) {
193: throw new cInvalidArgumentException('Function ' . $sFunctionName . ' doesn\'t exist, can\'t add to chain ' . $sChainName);
194: }
195: $call = $sFunctionName;
196: }
197:
198: // Last check if the callback is callable
199: if (!is_callable($call)) {
200: throw new cInvalidArgumentException('Function ' . $sFunctionName . ' isn\'t callable, can\'t add to chain ' . $sChainName);
201: }
202:
203: $oChainItem = new cApiCecChainItem($sChainName, $sFunctionName, $this->_aChains[$sChainName]['parameters']);
204: $oChainItem->setCallback($call);
205:
206: if (!is_array($this->_aChains[$sChainName])) {
207: $this->_aChains[$sChainName] = array();
208: $this->_aChains[$sChainName]['functions'] = array();
209: }
210:
211: if (!is_array($this->_aChains[$sChainName]['functions'])) {
212: $this->_aChains[$sChainName]['functions'] = array();
213: }
214:
215: $this->_aChains[$sChainName]['functions'][] = $oChainItem;
216:
217: return true;
218: }
219:
220: /**
221: * Checks if a chain function exists.
222: *
223: * @param string $sChainName Chain name
224: * @param string $sFunctionName Name of function to check
225: *
226: * @return bool
227: */
228: public function chainFunctionExists($sChainName, $sFunctionName) {
229: $this->_resetIterator($sChainName);
230: $chainFunctions = $this->_aChains[$sChainName]['functions'];
231: foreach ($chainFunctions as $pos => $item) {
232: if ($item->getFunctionName() == $sFunctionName) {
233: return true;
234: }
235: }
236:
237: return false;
238: }
239:
240: /**
241: * Removes a chain function.
242: *
243: * @param string $sChainName Chain name
244: * @param string $sFunctionName Name of function to remove from chain.
245: */
246: public function removeChainFunction($sChainName, $sFunctionName) {
247: $this->_resetIterator($sChainName);
248: $chainFunctions = $this->_aChains[$sChainName]['functions'];
249: foreach ($this->_aChains[$sChainName]['functions'] as $pos => $item) {
250: if ($item->getFunctionName() == $sFunctionName) {
251: unset($this->_aChains[$sChainName]['functions'][$pos]);
252:
253: return;
254: }
255: }
256: }
257:
258: /**
259: * Returns the iterator for a desired chain.
260: *
261: * @todo : cIterator should be replaced by ArrayIterator (@see
262: * http://www.php.net/spl)
263: * but ArrayIterator uses rewind() instead of reset()...
264: *
265: * @param string $sChainName Chain name
266: *
267: * @return cIterator
268: */
269: public function getIterator($sChainName) {
270: return new cIterator($this->_aChains[$sChainName]['functions']);
271: }
272:
273: /**
274: * Resets the chain iterator.
275: *
276: * @param string $sChainName
277: */
278: protected function _resetIterator($sChainName) {
279: $iterator = $this->getIterator($sChainName);
280: $iterator->reset();
281: }
282:
283: /**
284: * Flushs added chains
285: *
286: */
287: public function flushAddedChains() {
288: $this->_aChains = array();
289: }
290: }
291:
292: /**
293: * CEC chain item class.
294: *
295: * @package Core
296: * @subpackage CEC
297: */
298: class cApiCecChainItem {
299:
300: /**
301: * Chain name
302: *
303: * @var string
304: */
305: protected $_sChainName;
306:
307: /**
308: * Name of function to invoke
309: *
310: * @var string
311: */
312: protected $_sFunctionName;
313:
314: /**
315: * Callback name.
316: * Contains either the function name to invoke, or a indexed array
317: * (class/object and method)
318: * and it's method to execute.
319: *
320: * @var array string
321: */
322: protected $_mCallback;
323:
324: /**
325: * Parameter to pass to the function
326: *
327: * @var array
328: */
329: protected $_aParameters;
330:
331: /**
332: * Temporary arguments holder
333: *
334: * @var array NULL
335: */
336: protected $_mTemporaryArguments;
337:
338: /**
339: * Constructor, sets the CEC chain item properties.
340: *
341: * @param string $sChainName
342: * @param string $sFunctionName
343: * @param array $aParameters
344: */
345: public function __construct($sChainName, $sFunctionName, $aParameters) {
346: $this->setChainName($sChainName);
347: $this->setFunctionName($sFunctionName);
348: $this->setCallback($this->getFunctionName());
349: }
350:
351: /**
352: * Sets the chain name
353: *
354: * @param string $sChainName
355: */
356: public function setChainName($sChainName) {
357: $this->_sChainName = $sChainName;
358: }
359:
360: /**
361: * Returns the chain name
362: *
363: * @return string
364: */
365: public function getChainName() {
366: return $this->_sChainName;
367: }
368:
369: /**
370: * Sets the function name
371: *
372: * @param string $sFunctionName
373: */
374: public function setFunctionName($sFunctionName) {
375: $this->_sFunctionName = $sFunctionName;
376: }
377:
378: /**
379: * Returns the function name
380: *
381: * @return string
382: */
383: public function getFunctionName() {
384: return $this->_sFunctionName;
385: }
386:
387: /**
388: * Sets the callback parameters
389: *
390: * @param array $aParameters
391: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
392: */
393: public function setParameters(array $aParameters) {
394: cDeprecated('This method is deprecated and is not needed any longer');
395: }
396:
397: /**
398: * Returns the function name
399: *
400: * @return array
401: * @deprecated 2014-08-07 - This method is deprecated and is not needed any longer
402: */
403: public function getParameters() {
404: cDeprecated('This method is deprecated and is not needed any longer');
405: return array();
406: }
407:
408: /**
409: * Sets the callback
410: *
411: * @param string|array $callback
412: * @throws cInvalidArgumentException if the given callback is not a string
413: * or an array
414: */
415: public function setCallback($callback) {
416: if (is_string($callback) || is_array($callback)) {
417: $this->_mCallback = $callback;
418: } else {
419: throw new cInvalidArgumentException("Callback has to be a string or an array.");
420: }
421: }
422:
423: /**
424: * Returns the callback
425: *
426: * @return string array
427: */
428: public function getCallback() {
429: return $this->_mCallback;
430: }
431:
432: /**
433: * Another way to set the arguments before invoking execute() method.
434: *
435: * @param array $args
436: */
437: public function setTemporaryArguments(array $args = array()) {
438: $this->_mTemporaryArguments = $args;
439: }
440:
441: /**
442: * Will be invoked by execute() method.
443: * If temporary arguments where set before, it returns them and resets the
444: * property.
445: *
446: * @return array
447: */
448: public function getTemporaryArguments() {
449: $args = $this->_mTemporaryArguments;
450: $this->_mTemporaryArguments = NULL;
451:
452: return $args;
453: }
454:
455: /**
456: * Invokes the CEC function/callback.
457: *
458: * @return mixed If available, the result of the CEC function/callback
459: */
460: public function execute() {
461: // get temporary arguments, if the where set before
462: if (!$args = $this->getTemporaryArguments()) {
463: // no temporary arguments available, get them by func_get_args()
464: $args = func_get_args();
465: }
466:
467: return call_user_func_array($this->getCallback(), $args);
468: }
469: }
470: