Seditio Source
Root |
./othercms/PHPFusion 9.10.20/includes/classes/PHPFusion/Hooks.php
<?php
/*-------------------------------------------------------+
| PHPFusion Content Management System
| Copyright (C) PHP Fusion Inc
| https://phpfusion.com/
+--------------------------------------------------------+
| Filename: Hooks.php
| Author: Core Development Team
+--------------------------------------------------------+
| This program is released as free software under the
| Affero GPL license. You can redistribute it and/or
| modify it under the terms of this license which you
| can read by viewing the included agpl.txt or online
| at www.gnu.org/licenses/agpl.html. Removal of this
| copyright header is strictly prohibited without
| written permission from the original author(s).
+--------------------------------------------------------*/
namespace PHPFusion;

/**
 * Class Hooks
 * Core class for storing, removing and run hook functions.
 *
 * @package PHPFusion
 */
final class Hooks {

    private
$hooks = [];

    private static
$instances = NULL;

    private
$output = [];
    private
$filter_name;
   
/**
     * @var array
     */
   
private $hook_args;

   
/**
     * Get an instance by key
     *
     * @param string $key
     *
     * @return static
     */
   
public static function get_instance($key = 'default') {
        if (!isset(
self::$instances[$key])) {
           
self::$instances[$key] = new Hooks;
        }

        return
self::$instances[$key];
    }

   
/**
     * Register a hook into the $instance
     *
     * @param string $filter_name   The name of the hook, this is your identifier.
     * @param string $function      The callback function to run when the filter runs.
     * @param int    $que           Optional, values 1-10, where 1 runs first and 10 runs last.
     * @param array  $default_args  Optional, the default state of parameter during adding hook.
     * @param int    $accepted_args Optional, the limitation of the hook parameters the hook can accept.
     *
     * @return bool
     */
   
public function add_hook($filter_name, $function, $que, $default_args, $accepted_args) {

       
$hooks = [

           
'function'      => $function,
           
'default_args'  => $default_args,
           
'accepted_args' => $accepted_args,
           
'que'           => $que,
        ];

       
$this->hooks[$que][$filter_name][] = $hooks;
        if (
count($this->hooks) > 1) {
           
ksort($this->hooks, SORT_NUMERIC);
        }

        return
TRUE;
    }

   
/**
     * Remove all hooks from the $instance
     *
     * @param bool $que
     */
   
public function remove_all_hook($que = FALSE) {

        if (
$que === FALSE) {
           
$this->hooks = [];

        } else if (isset(
$this->hooks[$que])) {
            unset(
$this->hooks[$que]);
        }

    }

   
/**
     * Run the hooks by $filter_name and $args parameters
     * There will be no output. If you need an output, use filter hook.
     *
     * @param $filter_name
     *
     * @throws \Exception
     */
   
public function apply_hook($filter_name) {

       
$this->hook_args = func_get_args();

       
$this->filter_name = $filter_name;

       
$current_hook = $this->get_hook($filter_name);

        if (!empty(
$current_hook)) {

            foreach (
$current_hook as $hook) {

               
// prevent the current hook from being called twice, executed or not, else crash
               
$this->remove_hook($filter_name, $hook['function'], $hook['que']);

                if (
function_exists($hook['function'])) {

                   
$args = (!empty($hook['default_args']) ? $hook['default_args'] : []);

                   
$this->hook_args = $this->getFunctionArgs($args);

                    if (
$hook['accepted_args'] && !empty($this->hook_args)) {
                        if (
$hook['accepted_args'] !== count($this->hook_args)) {
                            throw new \
Exception("Too many arguments during executing the $filter_name hook");
                        }
                    }

                   
$output = call_user_func_array($hook['function'], $this->hook_args);

                    if (!empty(
$output)) {

                       
$this->output[$filter_name][] = $output;

                    }
                }
            }

            if (!empty(
$this->get_hook($filter_name)))
               
$this->apply_hook($filter_name, $this->hook_args);

        }
    }

   
/**
     * Returns the hook by $filter_name and $function
     *
     * @param string $filter_name The name of the hook, this is your identifier.
     * @param string $function    The callback function to run when the filter runs.
     *
     * @return array
     */
   
public function get_hook($filter_name, $function = '') {
        if (!empty(
$this->hooks)) {
           
array_filter($this->hooks);
            foreach (
$this->hooks as $hooks) {
                if (!empty(
$hooks)) {
                    if (isset(
$hooks[$filter_name])) {
                        if (
$function == 'invalid_notices') {
                            return [];
                        }
                        if (!empty(
$function)) {
                            foreach (
$hooks[$filter_name] as $hook) {
                                if (
$hook['function'] === $function) {
                                    return
$hook;
                                }
                            }
                            return [];
                        } else {
                            return (array)
$hooks[$filter_name];
                        }
                    }
                }
            }
        }

        return [];

    }

   
/**
     * Remove a specified hook from the $instance
     *
     * @param string $filter_name The name of the hook, this is your identifier.
     * @param string $function    The callback function to run when the filter runs.
     * @param int    $que
     *
     * @return bool
     */
   
public function remove_hook($filter_name, $function, $que) {

        if (
$function) {
            if (isset(
$this->hooks[$que][$filter_name])) {
                foreach (
$this->hooks[$que][$filter_name] as $key => $hooks) {
                    if (
$hooks['function'] == $function) {
                        unset(
$this->hooks[$que][$filter_name][$key]);
                        if (empty(
$this->hooks[$que][$filter_name]))
                            unset(
$this->hooks[$que][$filter_name]);
                        return
TRUE;
                    }
                }
            }
        }

        unset(
$this->hooks[$que][$filter_name]);

        return
TRUE;
    }

   
/**
     * @param $default_args
     *
     * @return array
     */
   
private function getFunctionArgs($default_args) {

        if (!empty(
$this->hook_args) && is_array($this->hook_args)) {

            foreach (
$this->hook_args as $key => $value) {
                if (
$value == $this->filter_name) {
                    unset(
$this->hook_args[$key]);
                }
            }

        }

        if (!empty(
$this->hook_args)) {
            return
$this->hook_args;
        }

        return
$default_args;
    }

   
/**
     * Run the hook filter, can be used multiple times within a loop to get the parse.
     *
     * @param $filter_name
     *
     * @return mixed|string
     * @throws \Exception
     */
   
public function apply_hook_once($filter_name) {
       
$function_args = func_get_args();
       
$current_hook = $this->get_hook($filter_name);
        if (!empty(
$current_hook)) {
            foreach (
$current_hook as $hook) {
                if (
function_exists($hook['function'])) {
                   
$args = (!empty($hook['default_args']) ? $hook['default_args'] : []);
                    if (
count($function_args) > 1) {
                        unset(
$function_args[0]);
                       
$args = $function_args;
                    }
                    if (
$hook['accepted_args']) {

                        if (
$hook['accepted_args'] < (count($function_args) - 1)) {
                            throw new \
Exception("Too many arguments during executing the $filter_name hook");
                        }
                    }
                   
$output = call_user_func_array($hook['function'], $args);

                   
// remove the hook
                   
$this->remove_hook($filter_name, $hook['function'], $hook['que']);

                    if (!empty(
$output)) {
                        return
$output;
                    }
                }
            }
        }
        return
'';
    }

   
/**
     * Run the hook filter, can be used multiple times within a loop to get the parse.
     *
     * @param $filter_name
     *
     * @return mixed|string
     * @throws \Exception
     */
   
public function repeat_current_hook($filter_name) {
       
$function_args = func_get_args();
       
$current_hook = $this->get_hook($filter_name);
        if (!empty(
$current_hook)) {
            foreach (
$current_hook as $hook) {
                if (
function_exists($hook['function'])) {
                   
$args = (!empty($hook['default_args']) ? $hook['default_args'] : []);
                    if (
count($function_args) > 1) {
                        unset(
$function_args[0]);
                       
$args = $function_args;
                    }
                    if (
$hook['accepted_args']) {
                        if (
$hook['accepted_args'] < (count($function_args) - 1)) {
                            throw new \
Exception("Too many arguments during executing the $filter_name hook");
                        }
                    }
                   
$output = call_user_func_array($hook['function'], $args);
                   
// remove the hook
                    //$this->remove_hook( $filter_name, $hook['function'], $hook['que'] );
                   
if (!empty($output)) {
                        return
$output;
                    }
                }
            }
        }
        return
'';
    }

   
/**
     * Run the hooks by $filter_name and $args parameters
     * This filter must only run once in application.
     *
     * @param $filter_name
     *
     * @return array
     */
   
public function filter_hook($filter_name) {

       
$function_args = func_get_args();
       
call_user_func_array([$this, 'apply_hook'], $function_args);

        if (!empty(
$this->output[$filter_name]) && is_array($this->output[$filter_name])) {
            return
$this->output[$filter_name];
        }

        return [];
    }

   
/**
     * @param $filter_name
     *
     * @return string
     */
   
public function filter_hook_once($filter_name) {

       
$output = call_user_func_array([$this, 'apply_hook_once'], func_get_args());

        return (string)
$output;
    }

   
/**
     * @param $filter_name
     *
     * @return string
     */
   
public function repeat_hook_once($filter_name) {

       
$output = call_user_func_array([$this, 'repeat_current_hook'], func_get_args());

        return (string)
$output;
    }

   
/**
     * Apply all hooks
     */
   
public function apply_all_hook() {

        if (!empty(
$this->hooks)) {
            foreach (
$this->hooks as $que => $funcs_) {
                if (!empty(
$funcs_['function']) && function_exists($funcs_['function'])) {

                   
call_user_func_array($funcs_['function'], $funcs_['accepted_args']);
                   
array_shift($this->hooks[$que]);
                }
            }
        }
    }

}