diff options
Diffstat (limited to 'framework/TComponent.php')
-rw-r--r-- | framework/TComponent.php | 1576 |
1 files changed, 97 insertions, 1479 deletions
diff --git a/framework/TComponent.php b/framework/TComponent.php index 8298f694..9dcd3c5b 100644 --- a/framework/TComponent.php +++ b/framework/TComponent.php @@ -1,15 +1,12 @@ <?php /** * TComponent, TPropertyValue classes + * * @author Qiang Xue <qiang.xue@gmail.com> - * - * Global Events, intra-object events, Class behaviors, expanded behaviors - * @author Brad Anderson <javalizard@mac.com> - * * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2013 PradoSoft * @license http://www.pradosoft.com/license/ - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System */ @@ -17,8 +14,7 @@ * TComponent class * * TComponent is the base class for all PRADO components. - * TComponent implements the protocol of defining, using properties, behaviors, - * and events. + * TComponent implements the protocol of defining, using properties and events. * * A property is defined by a getter method, and/or a setter method. * Properties can be accessed in the way like accessing normal object members. @@ -39,8 +35,6 @@ * in the format of concatenated words, with the first letter of each word * capitalized (e.g. DisplayMode, ItemStyle). * - * Javascript Get and Set - * * Since Prado 3.2 a new class of javascript-friendly properties have been introduced * to better deal with potential security problems like cross-site scripting issues. * All the data that gets sent clientside inside a javascript block is now encoded by default. @@ -66,8 +60,6 @@ * statement and will not be encoded when rendered inside a javascript block. * This special handling makes use of the {@link TJavaScriptLiteral} class. * - * Events - * * An event is defined by the presence of a method whose name starts with 'on'. * The event name is the method name and is thus case-insensitive. * An event can be attached with one or several methods (called event handlers). @@ -82,7 +74,6 @@ * To raise an event (assuming named as 'Click') of a component, use * <code> * $component->raiseEvent('OnClick'); - * $component->raiseEvent('OnClick', $this, $param); * </code> * To attach an event handler to an event, use one of the following ways, * <code> @@ -90,7 +81,7 @@ * $component->attachEventHandler('OnClick',$callback); * </code> * The first two ways make use of the fact that $component->OnClick refers to - * the event handler list {@link TPriorityList} for the 'OnClick' event. + * the event handler list {@link TList} for the 'OnClick' event. * The variable $callback contains the definition of the event handler that can * be either a string referring to a global function name, or an array whose * first element refers to an object and second element a method name/path that @@ -99,185 +90,9 @@ * - array($object,'buttonClicked') : $object->buttonClicked($sender,$param); * - array($object,'MainContent.SubmitButton.buttonClicked') : * $object->MainContent->SubmitButton->buttonClicked($sender,$param); - * - * @author Qiang Xue <qiang.xue@gmail.com> - * - * With the addition of behaviors, a more expansive event model is needed. There - * are two new event types (global and dynamic events) as well as a more comprehensive - * behavior model that includes class wide behaviors. - * - * A global event is defined by all events whose name starts with 'fx'. - * The event name is potentially a method name and is thus case-insensitive. All 'fx' events - * are valid as the whole 'fx' event/method space is global in nature. Any object may patch into - * any global event by defining that event as a method. Global events have priorities - * just like 'on' events; so as to be able to order the event execution. Due to the - * nature of all events which start with 'fx' being valid, in effect, every object - * has every 'fx' global event. It is simply an issue of tapping into the desired - * global event. - * - * A global event that starts with 'fx' can be called even if the object does not - * implement the method of the global event. A call to a non-existing 'fx' method - * will, at minimal, function and return null. If a method argument list has a first - * parameter, it will be returned instead of null. This allows filtering and chaining. - * 'fx' methods do not automatically install and uninstall. To install and uninstall an - * object's global event listeners, call the object's {@link listen} and - * {@link unlisten} methods, respectively. An object may auto-install its global event - * during {@link __construct} by overriding {@link getAutoGlobalListen} and returning true. - * - * As of PHP version 5.3, nulled objects without code references will still continue to persist - * in the global event queue because {@link __destruct} is not automatically called. In the common - * __destruct method, if an object is listening to global events, then {@link unlisten} is called. - * {@link unlisten} is required to be manually called before an object is - * left without references if it is currently listening to any global events. This includes - * class wide behaviors. - * - * An object that contains a method that starts with 'fx' will have those functions - * automatically receive those events of the same name after {@link listen} is called on the object. - * - * An object may listen to a global event without defining an 'fx' method of the same name by - * adding an object method to the global event list. For example - * <code> - * $component->fxGlobalCheck=$callback; // or $component->OnClick->add($callback); - * $component->attachEventHandler('fxGlobalCheck',array($object, 'someMethod')); - * </code> - * - * Events between Objects and their behaviors, Dynamic Events - * - * An intra-object/behavior event is defined by methods that start with 'dy'. Just as with - * 'fx' global events, every object has every dynamic event. Any call to a method that - * starts with 'dy' will be handled, regardless of whether it is implemented. These - * events are for communicating with attached behaviors. - * - * Dynamic events can be used in a variety of ways. They can be used to tell behaviors - * when a non-behavior method is called. Dynamic events could be used as data filters. - * They could also be used to specify when a piece of code is to be run, eg. should the - * loop process be performed on a particular piece of data. In this way, some control - * is handed to the behaviors over the process and/or data. - * - * If there are no handlers for an 'fx' or 'dy' event, it will return the first - * parameter of the argument list. If there are no arguments, these events - * will return null. If there are handlers an 'fx' method will be called directly - * within the object. Global 'fx' events are triggered by calling {@link raiseEvent}. - * For dynamic events where there are behaviors that respond to the dynamic events, a - * {@link TCallChain} is developed. A call chain allows the behavior dynamic event - * implementations to call further implementing behaviors within a chain. - * - * If an object implements {@link IDynamicMethods}, all global and object dynamic - * events will be sent to {@link __dycall}. In the case of global events, all - * global events will trigger this method. In the case of behaviors, all undefined - * dynamic events which are called will be passed through to this method. - * - * - * Behaviors - * - * There are two types of behaviors. There are individual object behaviors and - * there are class wide behaviors. Class behaviors depend upon object behaviors. - * - * When a new class implements {@link IBehavior} or {@link IClassBehavior} or - * extends {@link TBehavior} or {@link TClassBehavior}, it may be added to an - * object by calling the object's {@link attachBehavior}. The behaviors associated - * name can then be used to {@link enableBehavior} or {@link disableBehavior} - * the specific behavior. - * - * All behaviors may be turned on and off via {@link enableBehaviors} and - * {@link disableBehaviors}, respectively. To check if behaviors are on or off - * a call to {@link getBehaviorsEnabled} will provide the variable. - * - * Attaching and detaching whole sets of behaviors is done using - * {@link attachBehaviors} and {@link detachBehaviors}. {@link clearBehaviors} - * removes all of an object's behaviors. - * - * {@link asa} returns a behavior of a specific name. {@link isa} is the - * behavior inclusive function that acts as the PHP operator {@link instanceof}. - * A behavior could provide the functionality of a specific class thus causing - * the host object to act similarly to a completely different class. A behavior - * would then implement {@link IInstanceCheck} to provide the identity of the - * different class. - * - * Class behaviors are similar to object behaviors except that the class behavior - * is the implementation for all instances of the class. A class behavior - * will have the object upon which is being called be prepended to the parameter - * list. This way the object is known across the class behavior implementation. - * - * Class behaviors are attached using {@link attachClassBehavior} and detached - * using {@link detachClassBehavior}. Class behaviors are important in that - * they will be applied to all new instances of a particular class. In this way - * class behaviors become default behaviors to a new instances of a class in - * {@link __construct}. Detaching a class behavior will remove the behavior - * from the default set of behaviors created for an object when the object - * is instanced. - * - * Class behaviors are also added to all existing instances via the global 'fx' - * event mechanism. When a new class behavior is added, the event - * {@link fxAttachClassBehavior} is raised and all existing instances that are - * listening to this global event (primarily after {@link listen} is called) - * will have this new behavior attached. A similar process is used when - * detaching class behaviors. Any objects listening to the global 'fx' event - * {@link fxDetachClassBehavior} will have a class behavior removed. - * - * Dynamic Intra-Object Events - * - * Dynamic events start with 'dy'. This mechanism is used to allow objects - * to communicate with their behaviors directly. The entire 'dy' event space - * is valid. All attached, enabled behaviors that implement a dynamic event - * are called when the host object calls the dynamic event. If there is no - * implementation or behaviors, this returns null when no parameters are - * supplied and will return the first parameter when there is at least one - * parameter in the dynamic event. - * <code> - * null == $this->dyBehaviorEvent(); - * 5 == $this->dyBehaviorEvent(5); //when no behaviors implement this dynamic event - * </code> - * - * Dynamic events can be chained together within behaviors to allow for data - * filtering. Dynamic events are implemented within behaviors by defining the - * event as a method. - * <code> - * class TObjectBehavior extends TBehavior { - * public function dyBehaviorEvent($param1, $callchain) { - * //Do something, eg: $param1 += 13; - * return $callchain->dyBehaviorEvent($param1); - * } - * } - * </code> - * This implementation of a behavior and dynamic event will flow through to the - * next behavior implementing the dynamic event. The first parameter is always - * return when it is supplied. Otherwise a dynamic event returns null. - * - * In the case of a class behavior, the object is also prepended to the dynamic - * event. - * <code> - * class TObjectClassBehavior extends TClassBehavior { - * public function dyBehaviorEvent($hostobject, $param1, $callchain) { - * //Do something, eg: $param1 += $hostobject->getNumber(); - * return $callchain->dyBehaviorEvent($param1); - * } - * } - * </code> - * When calling a dynamic event, only the parameters are passed. The host object - * and the call chain are built into the framework. - * - * Global Event and Dynamic event catching * - * Given that all global 'fx' events and dynamic 'dy' events are valid and - * operational, there is a mechanism for catching events called that are not - * implemented (similar to the built-in PHP method {@link __call}). When - * a dynamic or global event is called but a behavior does not implement it, - * yet desires to know when an undefined dynamic event is run, the behavior - * implements the interface {@link IDynamicMethods} and method {@link __dycall}. - * - * In the case of dynamic events, {@link __dycall} is supplied with the method - * name and its parameters. When a global event is raised, via {@link raiseEvent}, - * the method is the event name and the parameters are supplied. - * - * When implemented, this catch-all mechanism is called for event global event event - * when implemented outside of a behavior. Within a behavior, it will also be called - * when the object to which the behavior is attached calls any unimplemented dynamic - * event. This is the fall-back mechanism for informing a class and/or behavior - * of when an global and/or undefined dynamic event is executed. - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System * @since 3.0 */ @@ -287,279 +102,6 @@ class TComponent * @var array event handler lists */ private $_e=array(); - - /** - * @var boolean if listening is enabled. Automatically turned on or off in - * constructor according to {@link getAutoGlobalListen}. Default false, off - */ - private $_listeningenabled=false; - - /** - * @var array static registered global event handler lists - */ - private static $_ue=array(); - - /** - * @var boolean if object behaviors are on or off. default true, on - */ - private $_behaviorsenabled=true; - - /** - * @var TPriorityMap list of object behaviors - */ - private $_m=null; - - /** - * @var array static global class behaviors, these behaviors are added upon instantiation of a class - */ - private static $_um=array(); - - - /** - * @const string the name of the global {@link raiseEvent} listener - */ - const GLOBAL_RAISE_EVENT_LISTENER='fxGlobalListener'; - - - /** - * The common __construct - * If desired by the new object, this will auto install and listen to global event functions - * as defined by the object via 'fx' methods. This also attaches any predefined behaviors. - * This function installs all class behaviors in a class hierarchy from the deepest subclass - * through each parent to the top most class, TComponent. - */ - public function __construct() { - if($this->getAutoGlobalListen()) - $this->listen(); - - $classes=array_reverse($this->getClassHierarchy(true)); - foreach($classes as $class) { - if(isset(self::$_um[$class])) - $this->attachBehaviors(self::$_um[$class]); - } - } - - - /** - * Tells TComponent whether or not to automatically listen to global events. - * Defaults to false because PHP variable cleanup is affected if this is true. - * When unsetting a variable that is listening to global events, {@link unlisten} - * must explicitly be called when cleaning variables allocation or else the global - * event registry will contain references to the old object. This is true for PHP 5.4 - * - * Override this method by a subclass to change the setting. When set to true, this - * will enable {@link __construct} to call {@link listen}. - * - * @return boolean whether or not to auto listen to global events during {@link __construct}, default false - */ - public function getAutoGlobalListen() { - return false; - } - - - /** - * The common __destruct - * This unlistens from the global event routines if listening - * - * PHP 5.3 does not __destruct objects when they are nulled and thus unlisten must be - * called must be explicitly called. - */ - public function __destruct() { - if($this->_listeningenabled) - $this->unlisten(); - } - - - /** - * This utility function is a private array filter method. The array values - * that start with 'fx' are filtered in. - */ - private function filter_prado_fx($name) { - return strncasecmp($name,'fx',2)===0; - } - - - /** - * This returns an array of the class name and the names of all its parents. The base object first, - * {@link TComponent}, and the deepest subclass is last. - * @param boolean optional should the names be all lowercase true/false - * @return array array of strings being the class hierarchy of $this. - */ - public function getClassHierarchy($lowercase = false) - { - $class=get_class($this); - $classes=array($class); - while($class=get_parent_class($class)){array_unshift($classes,$class);} - if($lowercase) - return array_map('strtolower',$classes); - return $classes; - } - - - /** - * This adds an object's fx event handlers into the global broadcaster to listen into any - * broadcast global events called through {@link raiseEvent} - * - * Behaviors may implement the function: - * <code> - * public function dyListen($globalEvents[, $chain]) { - * $this->listen(); //eg - * } - * </code> - * to be executed when listen is called. All attached behaviors are notified through dyListen. - * - * @return numeric the number of global events that were registered to the global event registry - */ - public function listen() { - if($this->_listeningenabled) - return; - - $fx=array_filter(get_class_methods($this),array($this,'filter_prado_fx')); - - foreach($fx as $func) - $this->attachEventHandler($func,array($this,$func)); - - if(is_a($this,'IDynamicMethods')) { - $this->attachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER,array($this,'__dycall')); - array_push($fx,TComponent::GLOBAL_RAISE_EVENT_LISTENER); - } - - $this->_listeningenabled=true; - - $this->dyListen($fx); - - return count($fx); - } - - /** - * this removes an object's fx events from the global broadcaster - * - * Behaviors may implement the function: - * <code> - * public function dyUnlisten($globalEvents[, $chain]) { - * $this->behaviorUnlisten(); //eg - * } - * </code> - * to be executed when listen is called. All attached behaviors are notified through dyUnlisten. - * - * @return numeric the number of global events that were unregistered from the global event registry - */ - public function unlisten() { - if(!$this->_listeningenabled) - return; - - $fx=array_filter(get_class_methods($this),array($this,'filter_prado_fx')); - - foreach($fx as $func) - $this->detachEventHandler($func,array($this,$func)); - - if(is_a($this,'IDynamicMethods')) { - $this->detachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER,array($this,'__dycall')); - array_push($fx,TComponent::GLOBAL_RAISE_EVENT_LISTENER); - } - - $this->_listeningenabled=false; - - $this->dyUnlisten($fx); - - return count($fx); - } - - /** - * Gets the state of listening to global events - * @return boolean is Listening to global broadcast enabled - */ - public function getListeningToGlobalEvents() - { - return $this->_listeningenabled; - } - - - /** - * Calls a method. - * Do not call this method directly. This is a PHP magic method that we override - * to allow behaviors, dynamic events (intra-object/behavior events), - * undefined dynamic and global events, and - * to allow using the following syntax to call a property setter or getter. - * <code> - * $this->getPropertyName($value); // if there's a $this->getjsPropertyName() method - * $this->setPropertyName($value); // if there's a $this->setjsPropertyName() method - * </code> - * - * Additional object behaviors override class behaviors. - * dynamic and global events do not fail even if they aren't implemented. - * Any intra-object/behavior dynamic events that are not implemented by the behavior - * return the first function paramater or null when no parameters are specified. - * - * @param string method name that doesn't exist and is being called on the object - * @param mixed method parameters - * @throws TInvalidOperationException If the property is not defined or read-only or - * method is undefined - * @return mixed result of the method call, or false if 'fx' or 'dy' function but - * is not found in the class, otherwise it runs - */ - public function __call($method, $args) - { - $getset=substr($method,0,3); - if(($getset=='get')||($getset=='set')) - { - $propname=substr($method,3); - $jsmethod=$getset.'js'.$propname; - if(method_exists($this,$jsmethod)) - { - if(count($args)>0) - if($args[0]&&!($args[0] instanceof TJavaScriptString)) - $args[0]=new TJavaScriptString($args[0]); - return call_user_func_array(array($this,$jsmethod),$args); - } - - if (($getset=='set')&&method_exists($this,'getjs'.$propname)) - throw new TInvalidOperationException('component_property_readonly',get_class($this),$method); - } - - if($this->_m!==null&&$this->_behaviorsenabled) - { - if(strncasecmp($method,'dy',2)===0) - { - $callchain=new TCallChain($method); - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&(method_exists($behavior,$method)||($behavior instanceof IDynamicMethods))) - { - $behavior_args=$args; - if($behavior instanceof IClassBehavior) - array_unshift($behavior_args,$this); - $callchain->addCall(array($behavior,$method),$behavior_args); - } - - } - if($callchain->getCount()>0) - return call_user_func_array(array($callchain,'call'),$args); - } - else - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&method_exists($behavior,$method)) - { - if($behavior instanceof IClassBehavior) - array_unshift($args,$this); - return call_user_func_array(array($behavior,$method),$args); - } - } - } - } - - if(strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0) - { - if($this instanceof IDynamicMethods) - return $this->__dycall($method,$args); - return isset($args[0])?$args[0]:null; - } - - throw new TApplicationException('component_method_undefined',get_class($this),$method); - } - /** * Returns a property value or an event handler list by property or event name. @@ -573,27 +115,21 @@ class TComponent * <code> * $eventHandlerList=$component->EventName; * </code> - * This will also return the global event handler list when specifing an 'fx' - * event, - * <code> - * $globalEventHandlerList=$component->fxEventName; - * </code> - * When behaviors are enabled, this will return the behavior of a specific - * name, a property of a behavior, or an object 'on' event defined by the behavior. * @param string the property name or the event name - * @return mixed the property value or the event handler list as {@link TPriorityList} + * @return mixed the property value or the event handler list * @throws TInvalidOperationException if the property/event is not defined. */ public function __get($name) { - if(method_exists($this,$getter='get'.$name)) + $getter='get'.$name; $jsgetter = 'getjs'.$name; + if(method_exists($this,$getter)) { // getting a property return $this->$getter(); } - else if(method_exists($this,$jsgetter='getjs'.$name)) + else if(method_exists($this,$jsgetter)) { - // getting a javascript property + // getting a property return (string)$this->$jsgetter(); } else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) @@ -601,33 +137,13 @@ class TComponent // getting an event (handler list) $name=strtolower($name); if(!isset($this->_e[$name])) - $this->_e[$name]=new TPriorityList; + $this->_e[$name]=new TList; return $this->_e[$name]; } - else if(strncasecmp($name,'fx',2)===0) - { - // getting a global event (handler list) - $name=strtolower($name); - if(!isset(self::$_ue[$name])) - self::$_ue[$name]=new TPriorityList; - return self::$_ue[$name]; - } - else if($this->_behaviorsenabled) + else { - // getting a behavior property/event (handler list) - if(isset($this->_m[$name])) - return $this->_m[$name]; - else if($this->_m!==null) - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&& - (property_exists($behavior,$name)||$behavior->canGetProperty($name)||$behavior->hasEvent($name))) - return $behavior->$name; - } - } + throw new TInvalidOperationException('component_property_undefined',get_class($this),$name); } - throw new TInvalidOperationException('component_property_undefined',get_class($this),$name); } /** @@ -638,47 +154,30 @@ class TComponent * $this->PropertyName=$value; * $this->jsPropertyName=$value; // $value will be treated as a JavaScript literal * $this->EventName=$handler; - * $this->fxEventName=$handler; //global event listener * </code> - * When behaviors are enabled, this will also set a behaviors properties and events. * @param string the property name or event name * @param mixed the property value or event handler * @throws TInvalidOperationException If the property is not defined or read-only. */ public function __set($name,$value) { - if(method_exists($this,$setter='set'.$name)) + if(method_exists($this, $setter='set'.$name)) { - if(strncasecmp($name,'js',2)===0&&$value&&!($value instanceof TJavaScriptLiteral)) + if (strncasecmp($name,'js',2)===0 && $value && !($value instanceof TJavaScriptLiteral)) $value = new TJavaScriptLiteral($value); - return $this->$setter($value); - } - else if(method_exists($this,$jssetter='setjs'.$name)) - { - if($value&&!($value instanceof TJavaScriptString)) - $value=new TJavaScriptString($value); - return $this->$jssetter($value); + $this->$setter($value); } - else if((strncasecmp($name,'on',2)===0&&method_exists($this,$name))||strncasecmp($name,'fx',2)===0) + else if(method_exists($this, $jssetter = 'setjs'.$name)) { - return $this->attachEventHandler($name,$value); + if ($value and !($value instanceof TJavaScriptString)) + $value = new TJavaScriptString($value); + $this->$jssetter($value); } - else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled) + else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) { - $sets=0; - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&& - (property_exists($behavior,$name)||$behavior->canSetProperty($name)||$behavior->hasEvent($name))) { - $behavior->$name=$value; - $sets++; - } - } - if($sets)return $value; - + $this->attachEventHandler($name,$value); } - - if(method_exists($this,'get'.$name)||method_exists($this,'getjs'.$name)) + else if(method_exists($this,'get'.$name) || method_exists($this,'getjs'.$name)) { throw new TInvalidOperationException('component_property_readonly',get_class($this),$name); } @@ -689,86 +188,37 @@ class TComponent } /** - * Checks if a property value is null, there are no events in the object - * event list or global event list registered under the name, and, if - * behaviors are enabled, + * Calls a method. * Do not call this method. This is a PHP magic method that we override - * to allow using isset() to detect if a component property is set or not. - * This also works for global events. When behaviors are enabled, it - * will check for a behavior of the specified name, and also check - * the behavior for events and properties. - * @param string the property name or the event name - * @since 3.2.1 + * to allow using the following syntax to call a property setter or getter. + * <code> + * $this->getPropertyName($value); // if there's a $this->getjsPropertyName() method + * $this->setPropertyName($value); // if there's a $this->setjsPropertyName() method + * </code> + * @param string the getter or setter method name + * @param mixed method call parameters + * @throws TInvalidOperationException If the property is not defined or read-only. */ - public function __isset($name) + public function __call($name,$params) { - if(method_exists($this,$getter='get'.$name)) - return $this->$getter()!==null; - else if(method_exists($this,$jsgetter='getjs'.$name)) - return $this->$jsgetter()!==null; - else if(strncasecmp($name,'on',2)===0&&method_exists($this,$name)) - { - $name=strtolower($name); - return isset($this->_e[$name])&&$this->_e[$name]->getCount(); - } - else if(strncasecmp($name,'fx',2)===0) + $getset = substr($name,0,3); + if (($getset=='get') || ($getset=='set')) { - $name=strtolower($name); - return isset(self::$_ue[$name])&&self::$_ue[$name]->getCount(); - } - else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled) - { - if(isset($this->_m[$name])) - return true; - foreach($this->_m->toArray() as $behavior) + $propname = substr($name,3); + $jsmethod = $getset.'js'.$propname; + if (method_exists($this, $jsmethod)) { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())) - return isset($behavior->$name); + if (count($params)>0) + if ($params[0] && !($params[0] instanceof TJavaScriptString)) + $params[0] = new TJavaScriptString($params[0]); + return call_user_func_array(array($this, $jsmethod), $params); } - + + if (($getset=='set') and method_exists($this, 'getjs'.$propname)) + throw new TInvalidOperationException('component_property_readonly',get_class($this),$name); } - else - return false; - } - /** - * Sets a component property to be null. Clears the object or global - * events. When enabled, loops through all behaviors and unsets the - * property or event. - * Do not call this method. This is a PHP magic method that we override - * to allow using unset() to set a component property to be null. - * @param string the property name or the event name - * @throws TInvalidOperationException if the property is read only. - * @since 3.2.1 - */ - public function __unset($name) - { - if(method_exists($this,$setter='set'.$name)) - $this->$setter(null); - else if(method_exists($this,$jssetter='setjs'.$name)) - $this->$jssetter(null); - else if(strncasecmp($name,'on',2)===0&&method_exists($this,$name)) - $this->_e[strtolower($name)]->clear(); - else if(strncasecmp($name,'fx',2)===0) - $this->getEventHandlers($name)->remove(array($this, $name)); - else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled) - { - if(isset($this->_m[$name])) - $this->detachBehavior($name); - else { - $unset=0; - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())) { - unset($behavior->$name); - $unset++; - } - } - if(!$unset&&method_exists($this,'get'.$name)) - throw new TInvalidOperationException('component_property_readonly',get_class($this),$name); - } - } else if(method_exists($this,'get'.$name)) - throw new TInvalidOperationException('component_property_readonly',get_class($this),$name); + throw new TInvalidOperationException('component_property_undefined',get_class($this),$name); } /** @@ -780,55 +230,34 @@ class TComponent */ public function hasProperty($name) { - return $this->canGetProperty($name)||$this->canSetProperty($name); + return + method_exists($this,'get'.$name) || method_exists($this,'set'.$name) || + method_exists($this,'getjs'.$name) || method_exists($this,'setjs'.$name) + ; } /** * Determines whether a property can be read. * A property can be read if the class has a getter method * for the property name. Note, property name is case-insensitive. - * This also checks for getjs. When enabled, it loops through all - * active behaviors for the get property when undefined by the object. * @param string the property name * @return boolean whether the property can be read */ public function canGetProperty($name) { - if(method_exists($this,'get'.$name)||method_exists($this,'getjs'.$name)) - return true; - else if($this->_m!==null&&$this->_behaviorsenabled) - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->canGetProperty($name)) - return true; - } - } - return false; + return method_exists($this,'get'.$name) || method_exists($this,'getjs'.$name); } /** * Determines whether a property can be set. * A property can be written if the class has a setter method * for the property name. Note, property name is case-insensitive. - * This also checks for setjs. When enabled, it loops through all - * active behaviors for the set property when undefined by the object. * @param string the property name * @return boolean whether the property can be written */ public function canSetProperty($name) { - if(method_exists($this,'set'.$name)||method_exists($this,'setjs'.$name)) - return true; - else if($this->_m!==null&&$this->_behaviorsenabled) - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->canSetProperty($name)) - return true; - } - } - return false; + return method_exists($this,'set'.$name) || method_exists($this,'setjs'.$name); } /** @@ -836,8 +265,6 @@ class TComponent * A property path is a sequence of property names concatenated by '.' character. * For example, 'Parent.Page' refers to the 'Page' property of the component's * 'Parent' property value (which should be a component also). - * When a property is not defined by an object, this also loops through all - * active behaviors of the object. * @param string property path * @return mixed the property path value */ @@ -854,8 +281,6 @@ class TComponent * A property path is a sequence of property names concatenated by '.' character. * For example, 'Parent.Page' refers to the 'Page' property of the component's * 'Parent' property value (which should be a component also). - * When a property is not defined by an object, this also loops through all - * active behaviors of the object. * @param string property path * @param mixed the property path value */ @@ -874,90 +299,41 @@ class TComponent /** * Determines whether an event is defined. - * An event is defined if the class has a method whose name is the event name - * prefixed with 'on', 'fx', or 'dy'. - * Every object responds to every 'fx' and 'dy' event as they are in a universally - * accepted event space. 'on' event must be declared by the object. - * When enabled, this will loop through all active behaviors for 'on' events - * defined by the behavior. + * An event is defined if the class has a method whose name is the event name prefixed with 'on'. * Note, event name is case-insensitive. * @param string the event name * @return boolean */ public function hasEvent($name) { - if((strncasecmp($name,'on',2)===0&&method_exists($this,$name))||strncasecmp($name,'fx',2)===0||strncasecmp($name,'dy',2)===0) - return true; - - else if($this->_m!==null&&$this->_behaviorsenabled) - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEvent($name)) - return true; - } - } - return false; + return strncasecmp($name,'on',2)===0 && method_exists($this,$name); } /** - * Checks if an event has any handlers. This function also checks through all - * the behaviors for 'on' events when behaviors are enabled. - * 'dy' dynamic events are not handled by this function. - * @param string the event name * @return boolean whether an event has been attached one or several handlers */ public function hasEventHandler($name) { $name=strtolower($name); - if(strncasecmp($name,'fx',2)===0) - return isset(self::$_ue[$name])&&self::$_ue[$name]->getCount()>0; - else - { - if(isset($this->_e[$name])&&$this->_e[$name]->getCount()>0) - return true; - else if($this->_m!==null&&$this->_behaviorsenabled) { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEventHandler($name)) - return true; - } - } - } - return false; + return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0; } /** - * Returns the list of attached event handlers for an 'on' or 'fx' event. This function also - * checks through all the behaviors for 'on' event lists when behaviors are enabled. - * @return TPriorityList list of attached event handlers for an event + * Returns the list of attached event handlers for an event. + * @return TList list of attached event handlers for an event * @throws TInvalidOperationException if the event is not defined */ public function getEventHandlers($name) { - if(strncasecmp($name,'on',2)===0&&method_exists($this,$name)) + if(strncasecmp($name,'on',2)===0 && method_exists($this,$name)) { $name=strtolower($name); if(!isset($this->_e[$name])) - $this->_e[$name]=new TPriorityList; + $this->_e[$name]=new TList; return $this->_e[$name]; } - else if(strncasecmp($name,'fx',2)===0) - { - $name=strtolower($name); - if(!isset(self::$_ue[$name])) - self::$_ue[$name]=new TPriorityList; - return self::$_ue[$name]; - } - else if($this->_m!==null&&$this->_behaviorsenabled) - { - foreach($this->_m->toArray() as $behavior) - { - if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEvent($name)) - return $behavior->getEventHandlers($name); - } - } - throw new TInvalidOperationException('component_event_undefined',get_class($this),$name); + else + throw new TInvalidOperationException('component_event_undefined',get_class($this),$name); } /** @@ -972,18 +348,16 @@ class TComponent * * The event handler must be of the following signature, * <code> - * function handlerName($sender, $param) {} - * function handlerName($sender, $param, $name) {} + * function handlerName($sender,$param) {} * </code> * where $sender represents the object that raises the event, - * and $param is the event parameter. $name refers to the event name - * being handled. + * and $param is the event parameter. * * This is a convenient method to add an event handler. * It is equivalent to {@link getEventHandlers}($name)->add($handler). * For complete management of event handlers, use {@link getEventHandlers} * to get the event handler list first, and then do various - * {@link TPriorityList} operations to append, insert or remove + * {@link TList} operations to append, insert or remove * event handlers. You may also do these operations like * getting and setting properties, e.g., * <code> @@ -996,37 +370,29 @@ class TComponent * $component->getEventHandlers('OnClick')->insertAt(0,array($object,'buttonClicked')); * </code> * - * Due to the nature of {@link getEventHandlers}, any active behaviors defining - * new 'on' events, this method will pass through to the behavior transparently. - * * @param string the event name * @param callback the event handler - * @param numeric|null the priority of the handler, defaults to null which translates into the - * default priority of 10.0 within {@link TPriorityList} * @throws TInvalidOperationException if the event does not exist */ - public function attachEventHandler($name,$handler,$priority=null) + public function attachEventHandler($name,$handler) { - $this->getEventHandlers($name)->add($handler,$priority); + $this->getEventHandlers($name)->add($handler); } /** * Detaches an existing event handler. - * This method is the opposite of {@link attachEventHandler}. It will detach - * any 'on' events definedb by an objects active behaviors as well. + * This method is the opposite of {@link attachEventHandler}. * @param string event name * @param callback the event handler to be removed - * @param numeric|false|null the priority of the handler, defaults to false which translates - * to an item of any priority within {@link TPriorityList}; null means the default priority * @return boolean if the removal is successful */ - public function detachEventHandler($name,$handler,$priority=false) + public function detachEventHandler($name,$handler) { if($this->hasEventHandler($name)) { try { - $this->getEventHandlers($name)->remove($handler,$priority); + $this->getEventHandlers($name)->remove($handler); return true; } catch(Exception $e) @@ -1037,133 +403,42 @@ class TComponent } /** - * Raises an event. This raises both inter-object 'on' events and global 'fx' events. + * Raises an event. * This method represents the happening of an event and will - * invoke all attached event handlers for the event in {@link TPriorityList} order. - * This method does not handle intra-object/behavior dynamic 'dy' events. - * - * There are ways to handle event responses. By defailt {@link EVENT_RESULT_FILTER}, - * all event responses are stored in an array, filtered for null responses, and returned. - * If {@link EVENT_RESULT_ALL} is specified, all returned results will be stored along - * with the sender and param in an array - * <code> - * $result[] = array('sender'=>$sender,'param'=>$param,'response'=>$response); - * </code> - * - * If {@link EVENT_RESULT_FEED_FORWARD} is specified, then each handler result is then - * fed forward as the parameters for the next event. This allows for events to filter data - * directly by affecting the event parameters - * - * If a callable function is set in the response type or the post function filter is specified then the - * result of each called event handler is post processed by the callable function. Used in - * combination with {@link EVENT_RESULT_FEED_FORWARD}, any event (and its result) can be chained. - * - * When raising a global 'fx' event, registered handlers in the global event list for - * {@link GLOBAL_RAISE_EVENT_LISTENER} are always added into the set of event handlers. In this way, - * these global events are always raised for every global 'fx' event. The registered handlers for global - * raiseEvent events have priorities. Any registered global raiseEvent event handlers with a priority less than zero - * are added before the main event handlers being raised and any registered global raiseEvent event handlers - * with a priority equal or greater than zero are added after the main event handlers being raised. In this way - * all {@link GLOBAL_RAISE_EVENT_LISTENER} handlers are always called for every raised 'fx' event. - * - * Behaviors may implement the following functions: - * <code> - * public function dyPreRaiseEvent($name,$sender,$param,$responsetype,$postfunction[, $chain]) { - * return $name; //eg, the event name may be filtered/changed - * } - * public function dyIntraRaiseEventTestHandler($handler,$sender,$param,$name[, $chain]) { - * return true; //should this particular handler be executed? true/false - * } - * public function dyIntraRaiseEventPostHandler($name,$sender,$param,$handler,$response[, $chain]) { - * //contains the per handler response - * } - * public function dyPostRaiseEvent($responses,$name,$sender,$param,$responsetype,$postfunction[, $chain]) { - * return $responses; - * } - * </code> - * to be executed when raiseEvent is called. The 'intra' dynamic events are called per handler in - * the handler loop. - * - * dyPreRaiseEvent has the effect of being able to change the event being raised. This intra - * object/behavior event returns the name of the desired event to be raised. It will pass through - * if no dynamic event is specified, or if the original event name is returned. - * dyIntraRaiseEventTestHandler returns true or false as to whether a specific handler should be - * called for a specific raised event (and associated event arguments) - * dyIntraRaiseEventPostHandler does not return anything. This allows behaviors to access the results - * of an event handler in the per handler loop. - * dyPostRaiseEvent returns the responses. This allows for any post processing of the event - * results from the sum of all event handlers - * - * When handling a catch-all {@link __dycall}, the method name is the name of the event - * and the parameters are the sender, the param, and then the name of the event. - * + * invoke all attached event handlers for the event. * @param string the event name * @param mixed the event sender object * @param TEventParameter the event parameter - * @param numeric how the results of the event are tabulated. default: {@link EVENT_RESULT_FILTER} The default filters out - * null responses. optional - * @param function any per handler filtering of the response result needed is passed through - * this if not null. default: null. optional - * @return mixed the results of the event * @throws TInvalidOperationException if the event is undefined * @throws TInvalidDataValueException If an event handler is invalid */ - public function raiseEvent($name,$sender,$param,$responsetype=null,$postfunction=null) + public function raiseEvent($name,$sender,$param) { - $p=$param; - if(is_callable($responsetype)) - { - $postfunction=$responsetype; - $responsetype=null; - } - - if($responsetype===null) - $responsetype=TEventResults::EVENT_RESULT_FILTER; - $name=strtolower($name); - $responses=array(); - - $name=$this->dyPreRaiseEvent($name,$sender,$param,$responsetype,$postfunction); - - if($this->hasEventHandler($name)||$this->hasEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER)) + if(isset($this->_e[$name])) { - $handlers=$this->getEventHandlers($name); - $handlerArray=$handlers->toArray(); - if(strncasecmp($name,'fx',2)===0&&$this->hasEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER)) - { - $globalhandlers=$this->getEventHandlers(TComponent::GLOBAL_RAISE_EVENT_LISTENER); - $handlerArray=array_merge($globalhandlers->toArrayBelowPriority(0),$handlerArray,$globalhandlers->toArrayAbovePriority(0)); - } - $response=null; - foreach($handlerArray as $handler) + foreach($this->_e[$name] as $handler) { - if($this->dyIntraRaiseEventTestHandler($handler,$sender,$param,$name)===false) - continue; - if(is_string($handler)) { if(($pos=strrpos($handler,'.'))!==false) { $object=$this->getSubProperty(substr($handler,0,$pos)); $method=substr($handler,$pos+1); - if(method_exists($object,$method)||strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0) - { - if($method=='__dycall') - $response=$object->__dycall($name,array($sender,$param,$name)); - else - $response=$object->$method($sender,$param,$name); - } + if(method_exists($object,$method)) + $object->$method($sender,$param); else throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,$handler); } else - $response=call_user_func($handler,$sender,$param,$name); + call_user_func($handler,$sender,$param); } else if(is_callable($handler,true)) { + // an array: 0 - object, 1 - method name/path list($object,$method)=$handler; - if(is_string($object)) - $response=call_user_func($handler,$sender,$param,$name); + if(is_string($object)) // static method call + call_user_func($handler,$sender,$param); else { if(($pos=strrpos($method,'.'))!==false) @@ -1171,66 +446,27 @@ class TComponent $object=$this->getSubProperty(substr($method,0,$pos)); $method=substr($method,$pos+1); } - if(method_exists($object,$method)||strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0) - { - if($method=='__dycall') - $response=$object->__dycall($name,array($sender,$param,$name)); - else - $response=$object->$method($sender,$param,$name); - } + if(method_exists($object,$method)) + $object->$method($sender,$param); else throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,$handler[1]); } } else throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,gettype($handler)); - - $this->dyIntraRaiseEventPostHandler($name,$sender,$param,$handler,$response); - - if($postfunction) - $response=call_user_func_array($postfunction,array($sender,$param,$this,$response)); - - if($responsetype&TEventResults::EVENT_RESULT_ALL) - $responses[]=array('sender'=>$sender,'param'=>$param,'response'=>$response); - else - $responses[]=$response; - - if($response!==null&&($responsetype&TEventResults::EVENT_RESULT_FEED_FORWARD)) - $param=$response; - } } - else if(strncasecmp($name,'on',2)===0&&!$this->hasEvent($name)) + else if(!$this->hasEvent($name)) throw new TInvalidOperationException('component_event_undefined',get_class($this),$name); - - if($responsetype&TEventResults::EVENT_RESULT_FILTER) - $responses=array_filter($responses); - - $responses=$this->dyPostRaiseEvent($responses,$name,$sender,$param,$responsetype,$postfunction); - - return $responses; } /** * Evaluates a PHP expression in the context of this control. - * - * Behaviors may implement the function: - * <code> - * public function dyEvaluateExpressionFilter($expression, $chain) { - * return $chain->dyEvaluateExpressionFilter(str_replace('foo', 'bar', $expression)); //example - * } - * </code> - * to be executed when evaluateExpression is called. All attached behaviors are notified through - * dyEvaluateExpressionFilter. The chaining is important in this function due to the filtering - * pass-through effect. - * - * @param string PHP expression * @return mixed the expression result * @throws TInvalidOperationException if the expression is invalid */ public function evaluateExpression($expression) { - $expression=$this->dyEvaluateExpressionFilter($expression); try { if(eval("\$result=$expression;")===false) @@ -1245,24 +481,12 @@ class TComponent /** * Evaluates a list of PHP statements. - * - * Behaviors may implement the function: - * <code> - * public function dyEvaluateStatementsFilter($statements, $chain) { - * return $chain->dyEvaluateStatementsFilter(str_replace('foo', 'bar', $statements)); //example - * } - * </code> - * to be executed when evaluateStatements is called. All attached behaviors are notified through - * dyEvaluateStatementsFilter. The chaining is important in this function due to the filtering - * pass-through effect. - * * @param string PHP statements * @return string content echoed or printed by the PHP statements * @throws TInvalidOperationException if the statements are invalid */ public function evaluateStatements($statements) { - $statements=$this->dyEvaluateStatementsFilter($statements); try { ob_start(); @@ -1284,22 +508,11 @@ class TComponent * The default implementation of this method will invoke * the potential parent component's {@link addParsedObject}. * This method can be overridden. - * - * Behaviors may implement the function: - * <code> - * public function dyCreatedOnTemplate($parent, $chain) { - * return $chain->dyCreatedOnTemplate($parent); //example - * } - * </code> - * to be executed when createdOnTemplate is called. All attached behaviors are notified through - * dyCreatedOnTemplate. - * * @param TComponent potential parent of this control * @see addParsedObject */ public function createdOnTemplate($parent) { - $parent=$this->dyCreatedOnTemplate($parent); $parent->addParsedObject($this); } @@ -1308,397 +521,11 @@ class TComponent * The object can be either a component or a static text string. * This method can be overridden to customize the handling of newly created objects in template. * Only framework developers and control developers should use this method. - * - * Behaviors may implement the function: - * <code> - * public function dyAddParsedObject($object[, $chain]) { - * } - * </code> - * to be executed when addParsedObject is called. All attached behaviors are notified through - * dyAddParsedObject. - * * @param string|TComponent text string or component parsed and instantiated in template * @see createdOnTemplate */ public function addParsedObject($object) { - $this->dyAddParsedObject($object); - } - - - /** - * This is the method registered for all instanced objects should a class behavior be added after - * the class is instanced. Only when the class to which the behavior is being added is in this - * object's class hierarchy, via {@link getClassHierarchy}, is the behavior added to this instance. - * @param $sender the application - * @param $param TClassBehaviorEventParameter - * @since 3.2.1 - */ - public function fxAttachClassBehavior($sender,$param) { - if(in_array($param->getClass(),$this->getClassHierarchy(true))) - return $this->attachBehavior($param->getName(),$param->getBehavior(),$param->getPriority()); - } - - - /** - * This is the method registered for all instanced objects should a class behavior be removed after - * the class is instanced. Only when the class to which the behavior is being added is in this - * object's class hierarchy, via {@link getClassHierarchy}, is the behavior removed from this instance. - * @param $sender the application - * @param $param TClassBehaviorEventParameter - * @since 3.2.1 - */ - public function fxDetachClassBehavior($sender,$param) { - if(in_array($param->getClass(),$this->getClassHierarchy(true))) - return $this->detachBehavior($param->getName(),$param->getPriority()); - } - - - /** - * This will add a class behavior to all classes instanced (that are listening) and future newly instanced objects. - * This registers the behavior for future instances and pushes the changes to all the instances that are listening as well. - * The universal class behaviors are stored in an inverted stack with the latest class behavior being at the first position in the array. - * This is done so class behaviors are added last first. - * @param string name the key of the class behavior - * @param object|string class behavior or name of the object behavior per instance - * @param string|class string of class or class on which to attach this behavior. Defaults to null which will error - * but more important, if this is on PHP 5.3 it will use Late Static Binding to derive the class - * it should extend. - * <code> - * TPanel::attachClassBehavior('javascripts', (new TJsPanelBehavior())->init($this)); - * </code> - * @param numeric|null priority of behavior, default: null the default priority of the {@link TPriorityList} Optional. - * @throws TInvalidOperationException if the class behavior is being added to a {@link TComponent}; due to recursion. - * @throws TInvalidOperationException if the class behavior is already defined - * @since 3.2.1 - */ - public static function attachClassBehavior($name,$behavior,$class=null,$priority=null) { - if(!$class&&function_exists('get_called_class')) - $class=get_called_class(); - if(!$class) - throw new TInvalidOperationException('component_no_class_provided_nor_late_binding'); - - if(!is_string($name)) - $name=get_class($name); - $class=strtolower($class); - if($class==='tcomponent') - throw new TInvalidOperationException('component_no_tcomponent_class_behaviors'); - if(empty(self::$_um[$class])) - self::$_um[$class]=array(); - if(isset(self::$_um[$class][$name])) - throw new TInvalidOperationException('component_class_behavior_defined',$class,$name); - $param=new TClassBehaviorEventParameter($class,$name,$behavior,$priority); - self::$_um[$class]=array($name=>$param)+self::$_um[$class]; - $behaviorObject=is_string($behavior)?new $behavior:$behavior; - return $behaviorObject->raiseEvent('fxAttachClassBehavior',null,$param); - } - - - /** - * This will remove a behavior from a class. It unregisters it from future instances and - * pulls the changes from all the instances that are listening as well. - * PHP 5.3 uses Late Static Binding to derive the static class upon which this method is called. - * @param $name the key of the class behavior - * @param $class string class on which to attach this behavior. Defaults to null. - * @param $priority numeric|null|false priority. false is any priority, null is default - * {@link TPriorityList} priority, and numeric is a specific priority. - * @throws Exception if the the class cannot be derived from Late Static Binding and is not - * not supplied as a parameter. - * @since 3.2.1 - */ - public static function detachClassBehavior($name,$class=null,$priority=false) { - if(!$class&&function_exists('get_called_class')) - $class=get_called_class(); - if(!$class) - throw new TInvalidOperationException('component_no_class_provided_nor_late_binding'); - - $class=strtolower($class); - if(!is_string($name)) - $name=get_class($name); - if(empty(self::$_um[$class])||!isset(self::$_um[$class][$name])) - return false; - $param=self::$_um[$class][$name]; - $behavior=$param->getBehavior(); - unset(self::$_um[$class][$name]); - $behaviorObject=is_string($behavior)?new $behavior:$behavior; - return $behaviorObject->raiseEvent('fxDetachClassBehavior',null,$param); - } - - /** - * Returns the named behavior object. - * The name 'asa' stands for 'as a'. - * @param string the behavior name - * @return IBehavior the behavior object, or null if the behavior does not exist - * @since 3.2.1 - */ - public function asa($behaviorname) - { - return isset($this->_m[$behaviorname])?$this->_m[$behaviorname]:null; - } - - /** - * Returns whether or not the object or any of the behaviors are of a particular class. - * The name 'isa' stands for 'is a'. This first checks if $this is an instanceof the class. - * It then checks each Behavior. If a behavior implements {@link IInstanceCheck}, - * then the behavior can determine what it is an instanceof. If this behavior function returns true, - * then this method returns true. If the behavior instance checking function returns false, - * then no further checking is performed as it is assumed to be correct. - * - * If the behavior instance check function returns nothing or null or the behavior - * doesn't implement the {@link IInstanceCheck} interface, then the default instanceof occurs. - * The default isa behavior is to check if the behavior is an instanceof the class. - * - * The behavior {@link IInstanceCheck} is to allow a behavior to have the host object - * act as a completely different object. - * - * @param class or string - * @return boolean whether or not the object or a behavior is an instance of a particular class - * @since 3.2.1 - */ - public function isa($class) - { - if($this instanceof $class) - return true; - if($this->_m!==null&&$this->_behaviorsenabled) - foreach($this->_m->toArray() as $behavior){ - if(($behavior instanceof IBehavior)&&!$behavior->getEnabled()) - continue; - - $check = null; - if(($behavior->isa('IInstanceCheck'))&&$check=$behavior->isinstanceof($class,$this)) - return true; - if($check===null&&($behavior->isa($class))) - return true; - } - return false; - } - - /** - * Attaches a list of behaviors to the component. - * Each behavior is indexed by its name and should be an instance of - * {@link IBehavior}, a string specifying the behavior class, or a - * {@link TClassBehaviorEventParameter}. - * @param array list of behaviors to be attached to the component - * @since 3.2.1 - */ - public function attachBehaviors($behaviors) - { - foreach($behaviors as $name=>$behavior) - if($behavior instanceof TClassBehaviorEventParameter) - $this->attachBehavior($behavior->getName(),$behavior->getBehavior(),$behavior->getPriority()); - else - $this->attachBehavior($name,$behavior); - } - - /** - * Detaches select behaviors from the component. - * Each behavior is indexed by its name and should be an instance of - * {@link IBehavior}, a string specifying the behavior class, or a - * {@link TClassBehaviorEventParameter}. - * @param array list of behaviors to be detached from the component - * @since 3.2.1 - */ - public function detachBehaviors($behaviors) - { - if($this->_m!==null) - { - foreach($behaviors as $name=>$behavior) - if($behavior instanceof TClassBehaviorEventParameter) - $this->detachBehavior($behavior->getName(),$behavior->getPriority()); - else - $this->detachBehavior(is_string($behavior)?$behavior:$name); - } - } - - /** - * Detaches all behaviors from the component. - * @since 3.2.1 - */ - public function clearBehaviors() - { - if($this->_m!==null) - { - foreach($this->_m->toArray() as $name=>$behavior) - $this->detachBehavior($name); - $this->_m=null; - } - } - - /** - * Attaches a behavior to this component. - * This method will create the behavior object based on the given - * configuration. After that, the behavior object will be initialized - * by calling its {@link IBehavior::attach} method. - * - * Already attached behaviors may implement the function: - * <code> - * public function dyAttachBehavior($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when attachBehavior is called. All attached behaviors are notified through - * dyAttachBehavior. - * - * @param string the behavior's name. It should uniquely identify this behavior. - * @param mixed the behavior configuration. This is passed as the first - * parameter to {@link YiiBase::createComponent} to create the behavior object. - * @return IBehavior the behavior object - * @since 3.2.1 - */ - public function attachBehavior($name,$behavior,$priority=null) - { - if(is_string($behavior)) - $behavior=Prado::createComponent($behavior); - if(!($behavior instanceof IBaseBehavior)) - throw new TInvalidDataTypeException('component_not_a_behavior',get_class($behavior)); - if($behavior instanceof IBehavior) - $behavior->setEnabled(true); - if($this->_m===null) - $this->_m=new TPriorityMap; - $behavior->attach($this); - $this->dyAttachBehavior($name,$behavior); - $this->_m->add($name,$behavior,$priority); - return $behavior; - } - - /** - * Detaches a behavior from the component. - * The behavior's {@link IBehavior::detach} method will be invoked. - * - * Behaviors may implement the function: - * <code> - * public function dyDetachBehavior($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when detachBehavior is called. All attached behaviors are notified through - * dyDetachBehavior. - * - * @param string the behavior's name. It uniquely identifies the behavior. - * @param numeric the behavior's priority. This defaults to false, aka any priority. - * @return IBehavior the detached behavior. Null if the behavior does not exist. - * @since 3.2.1 - */ - public function detachBehavior($name,$priority=false) - { - if($this->_m!=null&&isset($this->_m[$name])) - { - $this->_m[$name]->detach($this); - $behavior=$this->_m->itemAt($name); - $this->_m->remove($name,$priority); - $this->dyDetachBehavior($name,$behavior); - return $behavior; - } - } - - /** - * Enables all behaviors attached to this component independent of the behaviors - * - * Behaviors may implement the function: - * <code> - * public function dyEnableBehaviors($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when enableBehaviors is called. All attached behaviors are notified through - * dyEnableBehaviors. - * - * @since 3.2.1 - */ - public function enableBehaviors() - { - if(!$this->_behaviorsenabled) - { - $this->_behaviorsenabled=true; - $this->dyEnableBehaviors(); - } - } - - /** - * Disables all behaviors attached to this component independent of the behaviors - * - * Behaviors may implement the function: - * <code> - * public function dyDisableBehaviors($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when disableBehaviors is called. All attached behaviors are notified through - * dyDisableBehaviors. - * - * @since 3.2.1 - */ - public function disableBehaviors() - { - if($this->_behaviorsenabled) - { - $this->dyDisableBehaviors(); - $this->_behaviorsenabled=false; - } - } - - - /** - * Returns if all the behaviors are turned on or off for the object. - * @return boolean whether or not all behaviors are enabled (true) or not (false) - * @since 3.2.1 - */ - public function getBehaviorsEnabled() - { - return $this->_behaviorsenabled; - } - - /** - * Enables an attached object behavior. This cannot enable or disable whole class behaviors. - * A behavior is only effective when it is enabled. - * A behavior is enabled when first attached. - * - * Behaviors may implement the function: - * <code> - * public function dyEnableBehavior($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when enableBehavior is called. All attached behaviors are notified through - * dyEnableBehavior. - * - * @param string the behavior's name. It uniquely identifies the behavior. - * @since 3.2.1 - */ - public function enableBehavior($name) - { - if($this->_m!=null&&isset($this->_m[$name])){ - if($this->_m[$name] instanceof IBehavior) { - $this->_m[$name]->setEnabled(true); - $this->dyEnableBehavior($name,$this->_m[$name]); - return true; - } - return false; - } - return null; - } - - /** - * Disables an attached behavior. This cannot enable or disable whole class behaviors. - * A behavior is only effective when it is enabled. - * - * Behaviors may implement the function: - * <code> - * public function dyDisableBehavior($name,$behavior[, $chain]) { - * } - * </code> - * to be executed when disableBehavior is called. All attached behaviors are notified through - * dyDisableBehavior. - * - * @param string the behavior's name. It uniquely identifies the behavior. - * @since 3.2.1 - */ - public function disableBehavior($name) - { - if($this->_m!=null&&isset($this->_m[$name])){ - if($this->_m[$name] instanceof IBehavior) { - $this->_m[$name]->setEnabled(false); - $this->dyDisableBehavior($name,$this->_m[$name]); - return true; - } - return false; - } - return null; } /** @@ -1721,103 +548,12 @@ class TComponent $a = (array)$this; $a = array_keys($a); $exprops = array(); - if($this->_listeningenabled===false) - $exprops[] = "\0TComponent\0_listeningenabled"; - if($this->_behaviorsenabled===true) - $exprops[] = "\0TComponent\0_behaviorsenabled"; if ($this->_e===array()) $exprops[] = "\0TComponent\0_e"; - if ($this->_m===null) - $exprops[] = "\0TComponent\0_m"; return array_diff($a,$exprops); } } - -/** - * IDynamicMethods interface. - * IDynamicMethods marks an object to receive undefined global or dynamic events. - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -interface IDynamicMethods -{ - public function __dycall($method,$args); -} - - - -/** - * TClassBehaviorEventParameter class. - * TClassBehaviorEventParameter is the parameter sent with the class behavior changes. - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -class TClassBehaviorEventParameter extends TEventParameter -{ - private $_class; - private $_name; - private $_behavior; - private $_priority; - - /** - * Holds the parameters for the Class Behavior Events - * @param string $class this is the class to get the behavior - * @param string $name the name of the behavior - * @param object $behavior this is the behavior to implement the class behavior - */ - public function __construct($class,$name,$behavior,$priority) - { - $this->_class=$class; - $this->_name=$name; - $this->_behavior=$behavior; - $this->_priority=$priority; - } - - /** - * This is the class to get the behavior - * @return string the class to get the behavior - */ - public function getClass() - { - return $this->_class; - } - - /** - * name of the behavior - * @return string the name to get the behavior - */ - public function getName() - { - return $this->_name; - } - - /** - * This is the behavior which the class is to get - * @return object the behavior to implement - */ - public function getBehavior() - { - return $this->_behavior; - } - - /** - * This is the priority which the behavior is to get - * @return numeric the priority of the behavior - */ - public function getPriority() - { - return $this->_priority; - } -} - - /** * TEnumerable class. * TEnumerable is the base class for all enumerable types. @@ -1836,17 +572,17 @@ class TClassBehaviorEventParameter extends TEventParameter * TTextAlign::Right. * * @author Qiang Xue <qiang.xue@gmail.com> - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System * @since 3.0 */ class TEnumerable implements Iterator { - private $_enums=array(); + private $_enums = array(); public function __construct() { - $reflection=new ReflectionClass($this); - $this->_enums=$reflection->getConstants(); + $reflection = new ReflectionClass($this); + $this->_enums = $reflection->getConstants(); } public function current() { @@ -1866,7 +602,7 @@ class TEnumerable implements Iterator } public function valid() { - return $this->current()!==false; + return $this->current() !== false; } } @@ -1899,7 +635,7 @@ class TEnumerable implements Iterator * - enum: enumerable type, represented by an array of strings. * * @author Qiang Xue <qiang.xue@gmail.com> - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System * @since 3.0 */ @@ -2043,7 +779,7 @@ class TPropertyValue */ public static function ensureNullIfEmpty($value) { - return empty($value)?null:$value; + return empty($value) ? null : $value; } } @@ -2052,7 +788,7 @@ class TPropertyValue * TEventParameter is the base class for all event parameter classes. * * @author Qiang Xue <qiang.xue@gmail.com> - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System * @since 3.0 */ @@ -2060,12 +796,6 @@ class TEventParameter extends TComponent { } -class TEventResults extends TEnumerable { - const EVENT_RESULT_FEED_FORWARD=1; - const EVENT_RESULT_FILTER=2; - const EVENT_RESULT_ALL=4; -} - /** * TComponentReflection class. * @@ -2080,7 +810,7 @@ class TEventResults extends TEnumerable { * </code> * * @author Qiang Xue <qiang.xue@gmail.com> - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System * @since 3.0 */ @@ -2248,117 +978,6 @@ class TComponentReflection extends TComponent } } - - - - -/** - * IBaseBehavior interface is the base behavior class from which all other - * behaviors types are derived - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -interface IBaseBehavior { - /** - * Attaches the behavior object to the component. - * @param CComponent the component that this behavior is to be attached to. - */ - public function attach($component); - /** - * Detaches the behavior object from the component. - * @param CComponent the component that this behavior is to be detached from. - */ - public function detach($component); -} - -/** - * IBehavior interfaces is implemented by instance behavior classes. - * - * A behavior is a way to enhance a component with additional methods and - * events that are defined in the behavior class and not available in the - * class. Objects may signal behaviors through dynamic events. - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -interface IBehavior extends IBaseBehavior -{ - /** - * @return boolean whether this behavior is enabled - */ - public function getEnabled(); - /** - * @param boolean whether this behavior is enabled - */ - public function setEnabled($value); -} - - -/** - * IClassBehavior interface is implements behaviors across all instances of - * a particular class - * - * Any calls to functions not present in the original object but to behaviors - * derived from this class, will have inserted as the first argument parameter - * the object containing the behavior. - * - * For example: - * <code> - * $objWithClassBehavior->MethodOfClassBehavior(1, 20); - * </code> - * will be acted within the class behavior like this: - * <code> - * public function MethodOfClassBehavior($object, $firstParam, $secondParam){ - * // $object === $objWithClassBehavior, $firstParam === 1, $secondParam === 20 - * } - * </code> - * - * This also holds for 'dy' events as well. For dynamic events, method arguments would be: - * <code> - * public function dyMethodOfClassBehavior($object, $firstParam, $secondParam, $callchain){ - * // $object === $objWithClassBehavior, $firstParam === 1, $secondParam === 20, $callchain instanceof {@link TCallChain} - * } - * </code> - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -interface IClassBehavior extends IBaseBehavior { -} - - -/** - * IInstanceCheck This interface allows objects to determine their own - * 'instanceof' results when {@link TComponent::isa} is called. This is - * important with behaviors because behaviors may want to look like - * particular objects other than themselves. - * - * @author Brad Anderson <javalizard@mac.com> - * @version $Id$ - * @package System - * @since 3.2.1 - */ -interface IInstanceCheck { - /** - * The method checks $this or, if needed, the parameter $instance is of type - * class. In the case of a Class Behavior, the instance to which the behavior - * is attached may be important to determine if $this is an instance - * of a particular class. - * @param class|string the component that this behavior is checking if it is an instanceof. - * @param object the object which the behavior is attached to. default: null - * @return boolean|null if the this or the instance is of type class. When null, no information could be derived and - * the default mechanisms take over. - */ - public function isinstanceof($class,$instance=null); -} - /** * TJavaScriptLiteral class that encloses string literals that are not * supposed to be escaped by {@link TJavaScript::encode() } @@ -2377,9 +996,9 @@ interface IInstanceCheck { * $raw=_js($js); * </code> * - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System - * @since 3.2.0 + * @since prado 3.2 */ class TJavaScriptLiteral { @@ -2405,9 +1024,9 @@ class TJavaScriptLiteral * TJavaScriptString class is an internal class that marks strings that will be * forcibly encoded when rendered inside a javascript block * - * @version $Id$ + * @version $Id: TComponent.php 3245 2013-01-07 20:23:32Z ctrlaltca $ * @package System - * @since 3.2.0 + * @since prado 3.2 */ class TJavaScriptString extends TJavaScriptLiteral { @@ -2416,4 +1035,3 @@ class TJavaScriptString extends TJavaScriptLiteral return TJavaScript::jsonEncode((string)$this->_s,JSON_HEX_QUOT | JSON_HEX_APOS | JSON_HEX_TAG); } } - |