From 3a76db94f94fe37dd8de4afc3732815dea7af4e6 Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Tue, 13 Mar 2018 09:37:05 -0400 Subject: [PATCH] Some minor optimizations in WireHooks class, plus enable before/after option for $type argument in runHooks method that was mentioned in the phpdoc but wasn't fully supported yet --- wire/core/Wire.php | 6 ++-- wire/core/WireHooks.php | 68 ++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/wire/core/Wire.php b/wire/core/Wire.php index 0f1b769b..b27896d1 100644 --- a/wire/core/Wire.php +++ b/wire/core/Wire.php @@ -529,7 +529,7 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable { * * @param string $method Method or property to run hooks for. * @param array $arguments Arguments passed to the method and hook. - * @param string $type May be either 'method' or 'property', depending on the type of call. Default is 'method'. + * @param string|array $type May be either 'method', 'property' or array of hooks (from getHooks) to run. Default is 'method'. * @return array Returns an array with the following information: * [return] => The value returned from the hook or NULL if no value returned or hook didn't exist. * [numHooksRun] => The number of hooks that were actually run. @@ -597,8 +597,8 @@ abstract class Wire implements WireTranslatable, WireFuelable, WireTrackable { * - Also considers the class parents for hooks. * * ~~~~~ - * if($pages->hasHook('find')) { - * // the Pages::find method is hooked + * if($pages->hasHook('find()')) { + * // the Pages::find() method is hooked * } * ~~~~~ * diff --git a/wire/core/WireHooks.php b/wire/core/WireHooks.php index 4fb25a3d..74746ee9 100644 --- a/wire/core/WireHooks.php +++ b/wire/core/WireHooks.php @@ -673,11 +673,12 @@ class WireHooks { * @param Wire $object * @param string $method Method or property to run hooks for. * @param array $arguments Arguments passed to the method and hook. - * @param string $type May be any one of the following: + * @param string|array $type May be any one of the following: * - method: for hooked methods (default) * - property: for hooked properties * - before: only run before hooks and do nothing else * - after: only run after hooks and do nothing else + * - Or array[] of hooks (from getHooks method) to run (does not call hooked method) * @return array Returns an array with the following information: * [return] => The value returned from the hook or NULL if no value returned or hook didn't exist. * [numHooksRun] => The number of hooks that were actually run. @@ -688,33 +689,46 @@ class WireHooks { public function runHooks(Wire $object, $method, $arguments, $type = 'method') { $hookTimer = self::___debug ? $this->hookTimer($object, $method, $arguments) : null; + $realMethod = "___$method"; + $cancelHooks = false; + $profiler = $this->wire->wire('profiler'); + $hooks = null; + + if(is_array($type)) { + // array of hooks to run provided in $type argument + $hooks = $type; + $type = 'custom'; + } $result = array( 'return' => null, 'numHooksRun' => 0, - 'methodExists' => false, + 'methodExists' => ($type === 'method' ? method_exists($object, $realMethod) : false), 'replace' => false, ); - - $realMethod = "___$method"; - if($type == 'method') $result['methodExists'] = method_exists($object, $realMethod); - // if(!$result['methodExists'] && !$this->hasHook($object, $method . ($type == 'method' ? '()' : ''))) { - if(!$result['methodExists'] && !$this->isHookedOrParents($object, $method, $type)) { - return $result; // exit quickly when we can + + if($type === 'method' || $type === 'property') { + if(!$result['methodExists'] && !$this->isHookedOrParents($object, $method, $type)) { + return $result; // exit quickly when we can + } } - - $hooks = $this->getHooks($object, $method); - $cancelHooks = false; - $profiler = $this->wire->wire('profiler'); + + if($hooks === null) $hooks = $this->getHooks($object, $method); foreach(array('before', 'after') as $when) { - if($type === 'method' && $when === 'after' && $result['replace'] !== true) { - if($result['methodExists']) { - $result['return'] = $object->_callMethod($realMethod, $arguments); - } else { - $result['return'] = null; + if($type === 'method') { + if($when === 'after' && $result['replace'] !== true) { + if($result['methodExists']) { + $result['return'] = $object->_callMethod($realMethod, $arguments); + } else { + $result['return'] = null; + } } + } else if($type === 'after') { + if($when === 'before') continue; + } else if($type === 'before') { + if($when === 'after') break; } foreach($hooks as $priority => $hook) { @@ -843,6 +857,26 @@ class WireHooks { return $result; } + /** + * Filter and return hooks matching given property and value + * + * @param array $hooks Hooks from getHooks() method + * @param string $property Property name from hook (or hook options) + * @param string|bool|int $value Value to match + * @return array + * + */ + public function filterHooks(array $hooks, $property, $value) { + foreach($hooks as $key => $hook) { + if(array_key_exists($property, $hook)) { + if($hook[$property] !== $value) unset($hooks[$key]); + } else if(array_key_exists($property, $hook['options'])) { + if($hook['options'][$property] !== $value) unset($hooks[$key]); + } + } + return $hooks; + } + /** * Start timing a hook and return the timer name *