263 lines
7.9 KiB
PHP
263 lines
7.9 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Class: Trigger
|
||
|
* Controls and keeps track of all of the Triggers and events.
|
||
|
*/
|
||
|
class Trigger {
|
||
|
# Array: $priorities
|
||
|
# Custom prioritized callbacks.
|
||
|
public $priorities = array();
|
||
|
|
||
|
# Array: $called
|
||
|
# Keeps track of called Triggers.
|
||
|
private $called = array();
|
||
|
|
||
|
# Array: $exists
|
||
|
# Caches trigger existence states.
|
||
|
private $exists = array();
|
||
|
|
||
|
/**
|
||
|
* Function: __construct
|
||
|
* Add predefined filters to implement Unicode emoji and Markdown support.
|
||
|
*/
|
||
|
private function __construct() {
|
||
|
$config = Config::current();
|
||
|
|
||
|
if ($config->enable_emoji)
|
||
|
$this->priorities["markup_text"][] = array(
|
||
|
"priority" => 10,
|
||
|
"function" => "emote"
|
||
|
);
|
||
|
|
||
|
if ($config->enable_markdown)
|
||
|
$this->priorities["markup_text"][] = array(
|
||
|
"priority" => 5,
|
||
|
"function" => "markdown"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: cmp
|
||
|
* Sorts actions by priority when used with usort.
|
||
|
*/
|
||
|
private function cmp($a, $b): int {
|
||
|
if (empty($a) or empty($b))
|
||
|
return 0;
|
||
|
|
||
|
if ($a["priority"] == $b["priority"])
|
||
|
return 0;
|
||
|
|
||
|
return ($a["priority"] < $b["priority"]) ? -1 : 1 ;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: decide
|
||
|
* Decides what to do with a call return value.
|
||
|
*/
|
||
|
private function decide($return, $val): mixed {
|
||
|
if ($return === false)
|
||
|
return $val;
|
||
|
|
||
|
if (is_string($return) and is_string($val))
|
||
|
return $return.$val;
|
||
|
|
||
|
return oneof($val, $return);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: call
|
||
|
* Calls a trigger action.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* $name - The name of the trigger, or an array of triggers to call.
|
||
|
*
|
||
|
* Returns:
|
||
|
* A concatenated string if all calls return a string, or;
|
||
|
* @false@ if none of the triggers exist, or;
|
||
|
* the most substantial returned value decided by oneof().
|
||
|
*
|
||
|
* Notes:
|
||
|
* Any additional arguments are passed on to the trigger responders.
|
||
|
*/
|
||
|
public function call($name): mixed {
|
||
|
$return = false;
|
||
|
|
||
|
if (is_array($name)) {
|
||
|
foreach ($name as $call) {
|
||
|
$args = func_get_args();
|
||
|
$args[0] = $call;
|
||
|
|
||
|
$val = call_user_func_array(
|
||
|
array($this, "call"),
|
||
|
$args
|
||
|
);
|
||
|
|
||
|
if ($val !== false)
|
||
|
$return = $this->decide($return, $val);
|
||
|
}
|
||
|
|
||
|
return $return;
|
||
|
}
|
||
|
|
||
|
if (!$this->exists($name))
|
||
|
return $return;
|
||
|
|
||
|
$arguments = func_get_args();
|
||
|
array_shift($arguments);
|
||
|
$this->called[$name] = array();
|
||
|
|
||
|
if (
|
||
|
isset($this->priorities[$name]) and
|
||
|
usort($this->priorities[$name], array($this, "cmp"))
|
||
|
)
|
||
|
foreach ($this->priorities[$name] as $action) {
|
||
|
$function = $action["function"];
|
||
|
|
||
|
if (is_array($function)) {
|
||
|
$object = $function[0];
|
||
|
|
||
|
if (is_object($object) and !empty($object->cancelled))
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$val = call_user_func_array($function, $arguments);
|
||
|
$return = $this->decide($return, $val);
|
||
|
|
||
|
$this->called[$name][] = $function;
|
||
|
}
|
||
|
|
||
|
foreach (Modules::$instances as $module)
|
||
|
if (
|
||
|
is_callable(array($module, $name)) and
|
||
|
!in_array(array($module, $name), $this->called[$name])
|
||
|
) {
|
||
|
if (!empty($module->cancelled))
|
||
|
continue;
|
||
|
|
||
|
$val = call_user_func_array(
|
||
|
array($module, $name),
|
||
|
$arguments
|
||
|
);
|
||
|
|
||
|
$return = $this->decide($return, $val);
|
||
|
}
|
||
|
|
||
|
return $return;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: filter
|
||
|
* Modify a variable by filtering it through a stack of trigger actions.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* &$target - The variable to filter.
|
||
|
* $name - The name of the trigger.
|
||
|
*
|
||
|
* Returns:
|
||
|
* $target, filtered through any/all actions for the trigger $name.
|
||
|
*
|
||
|
* Notes:
|
||
|
* Any additional arguments are passed on to the trigger responders.
|
||
|
*/
|
||
|
public function filter(&$target, $name): mixed {
|
||
|
if (is_array($name)) {
|
||
|
foreach ($name as $filter) {
|
||
|
$args = func_get_args();
|
||
|
$args[0] =& $target;
|
||
|
$args[1] = $filter;
|
||
|
|
||
|
$target = call_user_func_array(
|
||
|
array($this, "filter"),
|
||
|
$args
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return $target;
|
||
|
}
|
||
|
|
||
|
if (!$this->exists($name))
|
||
|
return $target;
|
||
|
|
||
|
$arguments = func_get_args();
|
||
|
array_shift($arguments);
|
||
|
array_shift($arguments);
|
||
|
|
||
|
$this->called[$name] = array();
|
||
|
|
||
|
if (isset($this->priorities[$name]) and
|
||
|
usort($this->priorities[$name], array($this, "cmp"))
|
||
|
)
|
||
|
foreach ($this->priorities[$name] as $action) {
|
||
|
$function = $action["function"];
|
||
|
|
||
|
if (is_array($function)) {
|
||
|
$object = $function[0];
|
||
|
|
||
|
if (is_object($object) and !empty($object->cancelled))
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$val = call_user_func_array(
|
||
|
$function,
|
||
|
array_merge(array(&$target), $arguments)
|
||
|
);
|
||
|
|
||
|
$this->called[$name][] = $function;
|
||
|
$target = fallback($val, $target);
|
||
|
}
|
||
|
|
||
|
foreach (Modules::$instances as $module)
|
||
|
if (
|
||
|
is_callable(array($module, $name)) and
|
||
|
!in_array(array($module, $name), $this->called[$name])
|
||
|
) {
|
||
|
if (!empty($module->cancelled))
|
||
|
continue;
|
||
|
|
||
|
$val = call_user_func_array(
|
||
|
array($module, $name),
|
||
|
array_merge(array(&$target), $arguments)
|
||
|
);
|
||
|
|
||
|
$target = fallback($val, $target);
|
||
|
}
|
||
|
|
||
|
return $target;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: exists
|
||
|
* Checks if there are any actions for a given $trigger.
|
||
|
*
|
||
|
* Parameters:
|
||
|
* $trigger - The trigger name.
|
||
|
*
|
||
|
* Returns:
|
||
|
* @true@ or @false@
|
||
|
*/
|
||
|
public function exists($name): bool {
|
||
|
if (isset($this->exists[$name]))
|
||
|
return $this->exists[$name];
|
||
|
|
||
|
foreach (Modules::$instances as $module) {
|
||
|
if (is_callable(array($module, $name)))
|
||
|
return $this->exists[$name] = true;
|
||
|
}
|
||
|
|
||
|
if (isset($this->priorities[$name]))
|
||
|
return $this->exists[$name] = true;
|
||
|
|
||
|
return $this->exists[$name] = false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Function: current
|
||
|
* Returns a singleton reference to the current class.
|
||
|
*/
|
||
|
public static function & current(): self {
|
||
|
static $instance = null;
|
||
|
$instance = (empty($instance)) ? new self() : $instance ;
|
||
|
return $instance;
|
||
|
}
|
||
|
}
|