lib/Ajde/Event.php

Summary

Maintainability
C
1 day
Test Coverage
<?php

class Ajde_Event extends Ajde_Object_Static
{
    protected static $eventStack = [];

    /**
     * Register a callback on an object event. Note that when an object instance
     * is passed, only the classname is used. Thus, an Ajde_Event can not be used
     * to trigger different callbacks for the same event on different object instances
     * of the same class.
     *
     * @param mixed  $object   Object instance or classname triggering the event
     * @param string $event    Event name
     * @param mixed  $callback Callback
     *
     * @return bool true
     */
    public static function register($object, $event, $callback)
    {
        self::$eventStack[self::className($object)][$event][] = $callback;

        return true;
    }

    public static function unregister($object, $event)
    {
        if (isset(self::$eventStack[self::className($object)][$event])) {
            unset(self::$eventStack[self::className($object)][$event]);

            return true;
        }

        return false;
    }

    public static function has($object, $event, $callback = null)
    {
        if (isset($callback)) {
            return
                isset(self::$eventStack[self::className($object)][$event]) &&
                in_array($callback, self::$eventStack[self::className($object)][$event]);
        } else {
            return isset(self::$eventStack[self::className($object)][$event]);
        }
    }

    public static function trigger($object, $event, array $parameters = [])
    {
        foreach (self::$eventStack as $className => $eventStack) {
            if (self::className($object) == $className ||
                is_subclass_of(self::className($object), $className)
            ) {
                if (isset($eventStack[$event])) {
                    foreach ($eventStack[$event] as $eventCallback) {
                        $retval = null;
                        $callback = null;
                        if (is_callable($eventCallback)) {
                            $callback = $eventCallback;
                        } elseif (is_string($eventCallback)) {
                            if (is_callable([$object, $eventCallback])) {
                                $callback = [$object, $eventCallback];
                            }
                        }
                        if (isset($callback)) {
                            $trace = debug_backtrace();
                            $current = array_shift($trace);
                            $caller = array_shift($trace);

                            if (isset($caller['object'])) {
                                // http://www.php.net/manual/en/function.call-user-func.php
                                // Note: Note that the parameters for call_user_func() are not passed by reference.
                                $parameterArray = array_merge([&$caller['object']], $parameters);
                                $retval = call_user_func_array($callback, $parameterArray);
                                if (isset($retval)) {
                                    // TODO: Aborts execution of cueue!
                                    return $retval;
                                }
                            } elseif (isset($caller['class']) && isset($caller['function']) && $caller['type'] === '::') {
                                // triggered from static context
                                // TODO: update exception 90015
                                $retval = call_user_func_array($callback, $parameters);
                                if (isset($retval)) {
                                    // TODO: Aborts execution of cueue!
                                    return $retval;
                                }
                            } elseif ($callback instanceof Closure) {
                                $retval = $callback();
                                if (isset($retval)) {
                                    // TODO: Aborts execution of cueue!
                                    return $retval;
                                }
                            } else {
                                throw new Ajde_Exception('Event context needed to
                                    fire, none detected', 90015);
                            }
                        } else {
                            // TODO: right now never fires in Object_Magic objects
                            // because of the __call magic function. Workaround
                            // could be something like in_array("bar",get_class_methods($f1)
                            // see: http://php.net/manual/en/function.method-exists.php
                            throw new Ajde_Exception('Callback is not valid', 90016);
                        }
                    }
                }
            }
        }
    }

    protected static function className($object)
    {
        if (is_object($object)) {
            return get_class($object);
        } elseif (is_string($object) && class_exists($object)) {
            return $object;
        }
        throw new Ajde_Exception('No classname or object instance given, or classname is incorrect', 90012);
    }
}