Rev 1 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download
<?php namespace ProcessWire;/*** ProcessWire HookEvent** ProcessWire 3.x, Copyright 2016 by Ryan Cramer* https://processwire.com** Instances of HookEvent are passed to Hook handlers when their requested method has been called.** #pw-summary HookEvent is a type provided to hook functions with information about the event.* #pw-var $event* #pw-body =* ~~~~~~* // Example* $wire->addHookAfter('Pages::saved', function(HookEvent $event) {* $page = $event->arguments(0);* $event->message("You saved page $page->path");* });* ~~~~~~* #pw-body** HookEvents have the following properties available:** @property-read Wire|WireData|WireArray|Module $object Instance of the object where the Hook event originated.* @property-read string $method The name of the method that was called to generate the Hook event.* @property array $arguments A numerically indexed array of the arguments sent to the above mentioned method.* @property mixed $return Applicable only for 'after' or ('replace' + 'before' hooks), contains the value returned by the above mentioned method. The hook handling method may modify this return value.* @property bool $replace Set to boolean true in a 'before' hook if you want to prevent execution of the original hooked function. In such a case, your hook is replacing the function entirely. Not recommended, so be careful with this.* @property array $options An optional array of user-specified data that gets sent to the hooked function. The hook handling method may access it from $event->data. Also includes all the default hook properties.* @property-read string $id A unique identifier string that may be used with a call to `Wire::removeHook()`.* @property-read string $when In an active hook, contains either the string 'before' or 'after', indicating whether it is executing before or after the hooked method.* @property bool $cancelHooks When true, all remaining hooks will be cancelled, making this HookEvent the last one (be careful with this).**/class HookEvent extends WireData {/*** Cached argument names indexed by "className.method"**/static protected $argumentNames = array();/*** Construct the HookEvent and establish default values** @param array $eventData Optional event data to start with**/public function __construct(array $eventData = array()) {$data = array('object' => null,'method' => '','arguments' => array(),'return' => null,'replace' => false,'options' => array(),'id' => '','cancelHooks' => false);if(!empty($eventData)) $data = array_merge($data, $eventData);$this->data = $data;}/*** Retrieve or set a hooked function argument** ~~~~~* // Retrieve first argument by index (0=first)* $page = $event->arguments(0);** // Retrieve array of all arguments* $arguments = $event->arguments();** // Retrieve argument by name* $page = $event->arguments('page');** // Set first argument by index* $event->arguments(0, $page);** // Set first argument by name* $event->arguments('page', $page);* ~~~~~** @param int $n Zero based number of the argument you want to retrieve, where 0 is the first.* May also be a string containing the argument name.* Omit to return array of all arguments.* @param mixed $value Value that you want to set to this argument, or omit to only return the argument.* @return array|null|mixed**/public function arguments($n = null, $value = null) {if($n === null) return $this->data['arguments'];if($value !== null) {$this->setArgument($n, $value);return $value;}if(isset($this->data['arguments'][$n])) return $this->data['arguments'][$n];if(is_string($n)) return $this->argumentsByName($n);return null;}/*** Returns an array of all arguments indexed by name, or the value of a single specified argument** Note: `$event->arguments('name')` can also be used as a shorter synonym for `$event->argumentsByName('name')`.** ~~~~~* // Get an array of all arguments indexed by name* $arguments = $event->argumentsByName();** // Get a specific argument by name* $page = $event->argumentsByName('page');* ~~~~~** @param string $n Optional name of argument value to return. If not specified, array of all argument values returned.* @return mixed|array Depending on whether you specify $n**/public function argumentsByName($n = '') {$arguments = $this->data['arguments'];if(isset($arguments[$n])) return $arguments[$n];$names = $this->getArgumentNames();if($n) {$key = array_search($n, $names);if($key === false) return null;return array_key_exists($key, $arguments) ? $arguments[$key] : null;}$value = null;$argumentsByName = array();foreach($names as $key => $name) {$value = null;if(isset($arguments[$key])) $value = $arguments[$key];$argumentsByName[$name] = $value;}return $argumentsByName;}/*** Sets an argument value, handles the implementation of setting for the above arguments() function** Only useful with 'before' hooks, where the argument can be manipulated before being sent to the hooked function.** #pw-internal** @param int|string Argument name or key* @param mixed $value* @return $this* @throws WireException**/public function setArgument($n, $value) {if(is_string($n) && !ctype_digit($n)) {// convert argument name to position$names = $this->getArgumentNames();$n = array_search($n, $names);if($n === false) throw new WireException("Unknown argument name: $n");}$this->data['arguments'][(int)$n] = $value;return $this;}/*** Return an array of all argument names, indexed by their position** @return array**/protected function getArgumentNames() {$o = $this->get('object');$m = $this->get('method');$key = get_class($o) . '.' . $m;if(isset(self::$argumentNames[$key])) return self::$argumentNames[$key];$argumentNames = array();$method = new \ReflectionMethod($o, '___' . $m);$arguments = $method->getParameters();foreach($arguments as $a) {$pos = $a->getPosition();$argumentNames[$pos] = $a->getName();}self::$argumentNames[$key] = $argumentNames;return $argumentNames;}/*** Remove a hook by ID** To remove the hook that this event is for, call it with the $hookId argument as null or blank.** ~~~~~* // Remove this hook event, preventing it from executing again* $event->removeHook(null);* ~~~~~** @param string|HookEvent|null $hookId* @return HookEvent|WireData $this**/public function removeHook($hookId) {if(empty($hookId) || $hookId === $this) {if($this->object && $this->id) {$this->object->removeHook($this->id);}return $this;} else {return parent::removeHook($hookId);}}/*** Get** @param object|string $key* @return mixed|null**/public function get($key) {$value = parent::get($key);if($value === null && !ctype_digit("$key") && array_key_exists($key, $this->data['arguments'])) {// allow named arguments to be accessed from get()$value = $this->data['arguments'][$key];}return $value;}/*** Return a string representing the HookEvent**/public function __toString() {$s = $this->object->className() . '::' . $this->method . '(';foreach($this->arguments as $a) $s .= is_string($a) ? '"' . $a . '", ' : "$a, ";$s = rtrim($s, ", ") . ")";return $s;}}