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