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: * @deprecated [2014-08-07]
87: * This method is deprecated and is not needed any longer
88: * @param string $sChainName
89: */
90: public function registerChain($sChainName) {
91: cDeprecated('This method is deprecated and is not needed any longer');
92: }
93:
94: /**
95: * Unregisters a chain
96: *
97: * @deprecated [2014-08-07]
98: * This method is deprecated and is not needed any longer
99: * @param string $sChainName
100: * @throws cInvalidArgumentException if the given chain does not exist
101: */
102: public function unregisterChain($sChainName) {
103: cDeprecated('This method is deprecated and is not needed any longer');
104: }
105:
106: /**
107: * Checks if a chain is registered or not.
108: *
109: * @deprecated [2014-08-07]
110: * This method is deprecated and is not needed any longer
111: * @param string $sChainName
112: * @return bool
113: */
114: public function isChainRegistered($sChainName) {
115: cDeprecated('This method is deprecated and is not needed any longer');
116: return true;
117: }
118:
119: /**
120: * Returns list of registered chain names
121: *
122: * @deprecated [2014-08-07]
123: * This method is deprecated and is not needed any longer
124: * @return array
125: */
126: public function getRegisteredChainNames() {
127: cDeprecated('This method is deprecated and is not needed any longer');
128: return array();
129: }
130:
131: /**
132: * Adds the chain to the internal chain holder
133: *
134: * @deprecated [2014-08-07]
135: * This method is deprecated and is not needed any longer
136: * @param string $sChainName
137: * Chain name
138: * @param array $aParameters [optional]
139: * Chain parameter
140: * @return NULL
141: */
142: protected function _addChain($sChainName, array $aParameters = array()) {
143: cDeprecated('This method is deprecated and is not needed any longer');
144: return NULL;
145: }
146:
147: /**
148: * Adds a chain function which is to invoke.
149: *
150: * @param string $sChainName
151: * Chain name
152: * @param string $sFunctionName
153: * Name of function/callback to invoke.
154: * Feasible values are:
155: * - "ClassName->methodName" to invoke a method of a ClassName
156: * instance.
157: * A instance of the clas will be created here.
158: * - "ClassName::methodName" to invoke a static method of ClassName.
159: * - "FunctionName" to invoke a function.
160: * NOTE: Necessary files must be manually included before or by
161: * defined autoloader.
162: * @throws cInvalidArgumentException
163: * if the given chain is not registered or the given callback is not callable
164: * @return bool
165: * True on success, otherwise false
166: */
167: public function addChainFunction($sChainName, $sFunctionName) {
168: $cfg = cRegistry::getConfig();
169: // do not add the chain if the chain system is disabled
170: if ($cfg['debug']['disable_chains']) {
171: return;
172: }
173:
174: if (strpos($sFunctionName, '->') > 0) {
175: // chain function is a method of a object instance
176: list($class, $method) = explode('->', $sFunctionName);
177: if (!class_exists($class)) {
178: throw new cInvalidArgumentException('Class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
179: } elseif (!method_exists($class, $method)) {
180: throw new cInvalidArgumentException('Method ' . $method . ' in class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
181: }
182: $call = array(
183: new $class(),
184: $method
185: );
186: } elseif (strpos($sFunctionName, '::') > 0) {
187: // chain function is static method of a object
188: list($class, $method) = explode('::', $sFunctionName);
189: if (!class_exists($class)) {
190: throw new cInvalidArgumentException('Class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
191: } elseif (!method_exists($class, $method)) {
192: throw new cInvalidArgumentException('Method ' . $method . ' in class ' . $class . ' doesn\'t exist, can\'t add ' . $sFunctionName . ' to chain ' . $sChainName);
193: }
194: $call = array(
195: $class,
196: $method
197: );
198: } else {
199: // chain function is a function
200: if (!function_exists($sFunctionName)) {
201: throw new cInvalidArgumentException('Function ' . $sFunctionName . ' doesn\'t exist, can\'t add to chain ' . $sChainName);
202: }
203: $call = $sFunctionName;
204: }
205:
206: // Last check if the callback is callable
207: if (!is_callable($call)) {
208: throw new cInvalidArgumentException('Function ' . $sFunctionName . ' isn\'t callable, can\'t add to chain ' . $sChainName);
209: }
210:
211: $oChainItem = new cApiCecChainItem($sChainName, $sFunctionName, $this->_aChains[$sChainName]['parameters']);
212: $oChainItem->setCallback($call);
213:
214: if (!is_array($this->_aChains[$sChainName])) {
215: $this->_aChains[$sChainName] = array();
216: $this->_aChains[$sChainName]['functions'] = array();
217: }
218:
219: if (!is_array($this->_aChains[$sChainName]['functions'])) {
220: $this->_aChains[$sChainName]['functions'] = array();
221: }
222:
223: $this->_aChains[$sChainName]['functions'][] = $oChainItem;
224:
225: return true;
226: }
227:
228: /**
229: * Checks if a chain function exists.
230: *
231: * @param string $sChainName
232: * Chain name
233: * @param string $sFunctionName
234: * Name of function to check
235: * @return bool
236: */
237: public function chainFunctionExists($sChainName, $sFunctionName) {
238: $this->_resetIterator($sChainName);
239: $chainFunctions = $this->_aChains[$sChainName]['functions'];
240: foreach ($chainFunctions as $pos => $item) {
241: if ($item->getFunctionName() == $sFunctionName) {
242: return true;
243: }
244: }
245:
246: return false;
247: }
248:
249: /**
250: * Removes a chain function.
251: *
252: * @param string $sChainName
253: * Chain name
254: * @param string $sFunctionName
255: * Name of function to remove from chain.
256: */
257: public function removeChainFunction($sChainName, $sFunctionName) {
258: $this->_resetIterator($sChainName);
259: $chainFunctions = $this->_aChains[$sChainName]['functions'];
260: foreach ($this->_aChains[$sChainName]['functions'] as $pos => $item) {
261: if ($item->getFunctionName() == $sFunctionName) {
262: unset($this->_aChains[$sChainName]['functions'][$pos]);
263:
264: return;
265: }
266: }
267: }
268:
269: /**
270: * Returns the iterator for a desired chain.
271: *
272: * @todo : cIterator should be replaced by ArrayIterator (@see
273: * http://www.php.net/spl)
274: * but ArrayIterator uses rewind() instead of reset()...
275: *
276: * @param string $sChainName
277: * Chain name
278: * @return cIterator
279: */
280: public function getIterator($sChainName) {
281: return new cIterator($this->_aChains[$sChainName]['functions']);
282: }
283:
284: /**
285: * Resets the chain iterator.
286: *
287: * @param string $sChainName
288: */
289: protected function _resetIterator($sChainName) {
290: $iterator = $this->getIterator($sChainName);
291: $iterator->reset();
292: }
293:
294: /**
295: * Flushs added chains
296: *
297: */
298: public function flushAddedChains() {
299: $this->_aChains = array();
300: }
301: }
302:
303: /**
304: * CEC chain item class.
305: *
306: * @package Core
307: * @subpackage CEC
308: */
309: class cApiCecChainItem {
310:
311: /**
312: * Chain name
313: *
314: * @var string
315: */
316: protected $_sChainName;
317:
318: /**
319: * Name of function to invoke
320: *
321: * @var string
322: */
323: protected $_sFunctionName;
324:
325: /**
326: * Callback name.
327: * Contains either the function name to invoke, or a indexed array
328: * (class/object and method)
329: * and it's method to execute.
330: *
331: * @var array string
332: */
333: protected $_mCallback;
334:
335: /**
336: * Parameter to pass to the function
337: *
338: * @var array
339: */
340: protected $_aParameters;
341:
342: /**
343: * Temporary arguments holder
344: *
345: * @var array NULL
346: */
347: protected $_mTemporaryArguments;
348:
349: /**
350: * Constructor, sets the CEC chain item properties.
351: *
352: * @param string $sChainName
353: * @param string $sFunctionName
354: * @param array $aParameters
355: */
356: public function __construct($sChainName, $sFunctionName, $aParameters) {
357: $this->setChainName($sChainName);
358: $this->setFunctionName($sFunctionName);
359: $this->setCallback($this->getFunctionName());
360: }
361:
362: /**
363: * Sets the chain name
364: *
365: * @param string $sChainName
366: */
367: public function setChainName($sChainName) {
368: $this->_sChainName = $sChainName;
369: }
370:
371: /**
372: * Returns the chain name
373: *
374: * @return string
375: */
376: public function getChainName() {
377: return $this->_sChainName;
378: }
379:
380: /**
381: * Sets the function name
382: *
383: * @param string $sFunctionName
384: */
385: public function setFunctionName($sFunctionName) {
386: $this->_sFunctionName = $sFunctionName;
387: }
388:
389: /**
390: * Returns the function name
391: *
392: * @return string
393: */
394: public function getFunctionName() {
395: return $this->_sFunctionName;
396: }
397:
398: /**
399: * Sets the callback parameters
400: *
401: * @deprecated [2014-08-07]
402: * This method is deprecated and is not needed any longer
403: * @param array $aParameters
404: */
405: public function setParameters(array $aParameters) {
406: cDeprecated('This method is deprecated and is not needed any longer');
407: }
408:
409: /**
410: * Returns the function name
411: *
412: * @deprecated [2014-08-07]
413: * This method is deprecated and is not needed any longer
414: * @return array
415: */
416: public function getParameters() {
417: cDeprecated('This method is deprecated and is not needed any longer');
418: return array();
419: }
420:
421: /**
422: * Sets the callback
423: *
424: * @param string|array $callback
425: * @throws cInvalidArgumentException if the given callback is not a string
426: * or an array
427: */
428: public function setCallback($callback) {
429: if (is_string($callback) || is_array($callback)) {
430: $this->_mCallback = $callback;
431: } else {
432: throw new cInvalidArgumentException("Callback has to be a string or an array.");
433: }
434: }
435:
436: /**
437: * Returns the callback
438: *
439: * @return string|array
440: */
441: public function getCallback() {
442: return $this->_mCallback;
443: }
444:
445: /**
446: * Another way to set the arguments before invoking execute() method.
447: *
448: * @param array $args [optional]
449: */
450: public function setTemporaryArguments(array $args = array()) {
451: $this->_mTemporaryArguments = $args;
452: }
453:
454: /**
455: * Will be invoked by execute() method.
456: * If temporary arguments where set before, it returns them and resets the
457: * property.
458: *
459: * @return array
460: */
461: public function getTemporaryArguments() {
462: $args = $this->_mTemporaryArguments;
463: $this->_mTemporaryArguments = NULL;
464:
465: return $args;
466: }
467:
468: /**
469: * Invokes the CEC function/callback.
470: *
471: * @return mixed
472: * If available, the result of the CEC function/callback
473: */
474: public function execute() {
475: // get temporary arguments, if the where set before
476: if (!$args = $this->getTemporaryArguments()) {
477: // no temporary arguments available, get them by func_get_args()
478: $args = func_get_args();
479: }
480:
481: return call_user_func_array($this->getCallback(), $args);
482: }
483: }
484: