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