From 3fdbb2cbfe778fcf48c61bb9fe40d4ac85f8004f Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Thu, 19 Sep 2013 23:07:57 +0200 Subject: Committed TComponent patch by javalizard TComponent Update: Behaviors, Class Behaviors, fx global events, and dy one to one events. This patchset was currently available only on svn trunk/ --- framework/Util/TCallChain.php | 147 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 framework/Util/TCallChain.php (limited to 'framework/Util/TCallChain.php') diff --git a/framework/Util/TCallChain.php b/framework/Util/TCallChain.php new file mode 100644 index 00000000..9d6144b3 --- /dev/null +++ b/framework/Util/TCallChain.php @@ -0,0 +1,147 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2008-2013 Pradosoft + * @license http://www.pradosoft.com/license/ + */ + +/** + * TCallChain is a recursive event calling mechanism. This class implements + * the {@link IDynamicMethods} class so that any 'dy' event calls can be caught + * and patched through to the intended recipient + * @author Brad Anderson + * @version $Id: TCallChain.php 564 2009-01-21 22:07:10Z javalizard $ + * @package System.Util + * @since 3.2.3 + */ +class TCallChain extends TList implements IDynamicMethods +{ + /** + * @var {@link TListIterator} for moving through the chained method calls + */ + private $_iterator=null; + + /** + * @var string the method name of the call chain + */ + private $_method=null; + + /** + * This initializes the list and the name of the method to be called + * @param string the name of the function call + */ + public function __construct($method) { + $this->_method=$method; + parent::__construct(); + } + + + /** + * This initializes the list and the name of the method to be called + * @param string|array this is a callable function as a string or array with + * the object and method name as string + * @param array The array of arguments to the function call chain + */ + public function addCall($method,$args) + { + $this->add(array($method,$args)); + } + + /** + * This method calls the next Callable in the list. All of the method arguments + * coming into this method are substituted into the original method argument of + * call in the chain. + * + * If the original method call has these parameters + * + * $originalobject->dyExampleMethod('param1', 'param2', 'param3') + * + * + * $callchain->dyExampleMethod('alt1', 'alt2') + * + * then the next call in the call chain will recieve the parameters as if this were called + * + * $behavior->dyExampleMethod('alt1', 'alt2', 'param3', $callchainobject) + * + * + * When dealing with {@link IClassBehaviors}, the first parameter of the stored argument + * list in 'dy' event calls is always the object containing the behavior. This modifies + * the parameter replacement mechanism slightly to leave the object containing the behavior + * alone and only replacing the other parameters in the argument list. As per {@link __call}, + * any calls to a 'dy' event do not need the object containing the behavior as the addition of + * the object to the argument list as the first element is automatic for IClassBehaviors. + * + * The last parameter of the method parameter list for any callable in the call chain + * will be the TCallChain object itself. This is so that any behavior implementing + * these calls will have access to the call chain. Each callable should either call + * the TCallChain call method internally for direct chaining or call the method being + * chained (in which case the dynamic handler will pass through to this call method). + * + * If the dynamic intra object/behavior event is not called in the behavior implemented + * dynamic method, it will return to this method and call the following behavior + * implementation so as no behavior with an implementation of the dynamic event is left + * uncalled. This does break the call chain though and will not act as a "parameter filter". + * + * When there are no handlers or no handlers left, it returns the first parameter of the + * argument list. + * + */ + public function call() + { + $args=func_get_args(); + if($this->getCount()===0) + return isset($args[0])?$args[0]:null; + + if(!$this->_iterator) + { + $chain_array=array_reverse($this->toArray()); + $this->_iterator=new TListIterator($chain_array); + } + if($this->_iterator->valid()) + do { + $handler=$this->_iterator->current(); + $this->_iterator->next(); + if(is_array($handler[0])&&$handler[0][0] instanceof IClassBehavior) + array_splice($handler[1],1,count($args),$args); + else + array_splice($handler[1],0,count($args),$args); + $handler[1][]=$this; + $result=call_user_func_array($handler[0],$handler[1]); + } while($this->_iterator->valid()); + else + $result = $args[0]; + return $result; + } + + + /** + * This catches all the unpatched dynamic events. When the method call matches the + * call chain method, it passes the arguments to the original __call (of the dynamic + * event being unspecified in TCallChain) and funnels into the method {@link call}, + * so the next dynamic event handler can be called. + * If the original method call has these parameters + * + * $originalobject->dyExampleMethod('param1', 'param2', 'param3') + * + * and within the chained dynamic events, this can be called + * + * class DyBehavior extends TBehavior { + * public function dyExampleMethod($param1, $param2, $param3, $callchain) + * $callchain->dyExampleMethod($param1, $param2, $param3) + * } + * { + * + * to call the next event in the chain. + * @param string method name of the unspecified object method + * @param array arguments to the unspecified object method + */ + public function __dycall($method,$args) + { + if($this->_method==$method) + return call_user_func_array(array($this,'call'),$args); + return null; + } +} \ No newline at end of file -- cgit v1.2.3