old-Event.php

<?php

namespace Lia\Compo;

/**
 * Events are the primary way that different packages and different parts of a package communicate with one another.  
 * Any component (using the base package) may declare `onNamespace_EventName($event,$arg1,$arg2,....)` to automatically have the event registered when the package is added.  
 * Namespaces aren't entirely required, but it's better that way.  
 * 
 * Each Event callable will receive an `$event` object. This object is always the same \Lia\Event component object. This needs to be improved.
 * 
 * 
 * @export(old.Event.Class)
 */
class oldEvent { //extends \Lia\Compo {


    public $name = null;

/**
 * - Figure out how events are going to work
 * - Implement an events directory, possibly
 * - Rename register & send to schedule & emit
 * - Should events offer return values? No, I don't think so
 * 
 * @export(TODO.Events)
 */

    protected $events = [];


    /**
     * - register($eventName, $object, $method=null): Register the event to be executed
     *    - if `$method` is `null`, `$object` MUST have a method 'on$eventName'
     *    - if `$method` is a string, the a callable will be stored as [$object, $method]
     *    - Uses the Event component of the base package
     *    - The first paramater of your callback must take an `$event` object (which is poorly implemented)
     *    - It may accept any paramaters after that, as specified by the registered event
     *    - This might be renamed soon
     * - send($eventName,$arg1, $arg2, $arg3, ....): Execute the given event, passing the list of args along.
     * - has($eventName): check if event has been registered.
     * @export(old.Event.register)
     */
    public function register($EventName,$compo,$methodName=null){
        $this->events[$EventName] = $this->events[$EventName] ?? [];
        $this->events[$EventName][] = $methodName==null ? [$compo,'on'.$EventName] : [$compo,$methodName];
    }
    public function has($EventName){
        $events = $this->events[$EventName] ?? [];
        return (count($events)>0);
    }
    public function send($EventName,...$args){
        if (!$this->has($EventName)){
            if (in_array($EventName,$this->package->lia->get('Events.debug_ignore',[]))){
                return;
            }
            trigger_error("Event '{$EventName}' has not been registered by any component.");
            if ($this->package->lia->get('Events.debug')){
                echo "\n\n";
                $events = [];
                foreach ($this->events as $key=>$eventList){
                    foreach ($eventList as $event){
                        $events[$key][] = get_class($event[0]).'->'.$event[1];
                    }
                }
                print_r($events);
                throw new \Exception("\n\nRegistered events are shown above.");
            }
            return;
        }
        $events = $this->events;
        $event = $this->_buildEvent($EventName, $args);
        $allReturns = [];
        $matchedEvents = $events[$EventName];
        if (count($matchedEvents)>1
            &&$EventName!='Events_Sort'){
            /** 
             * When an event has multiple methods registered to it, the Events_Sort event is called, to allow you to filter which methods to execute.  
             * If you implement the Events_Sort event, you must return an array of all the events that should be executed.  
             * Your method should be like:
             * ```php
             * onEvents_Sort($event,$EventName,$argsArray,$arrayOfEvents){
             *     //unset one of the events because... the dog barked
             *     return $arrayOfEvents;
             * }
             * ```
             * 
             * If there are multiple methods registered to Events_Sort... that's bad. It'll break stuff
             * 
             * @export(old.Event.Events_Sort)
             */
            $sortedEvents = $this->Events_Sort($EventName,$args,$matchedEvents);
        }
        $eventList = $sortedEvents ?? $matchedEvents;

        foreach ($eventList as $index=>$callable){
            $ret = 
            $allReturns[] = call_user_func($callable,$event,...$args);
        }
        $returnVal = $this->getReturnValue($allReturns,$EventName);
        return $returnVal;
    }
    public function __call($EventName, $args){
        if (ucfirst($EventName)!==$EventName){
            throw new \Exception("Event '{$EventName}' cannot be sent, because ALL events MUST start with a capital letter.\n");
        }
        return $this->send($EventName,...$args);
    }
    protected function _buildEvent($EventName, $args){
        return $this;
        return [
            'cats'
        ];
    }
    /**
     * Return values from an event call depend upon how many events are registered and what they return.
     * - 0 registered events: Return null
     * - 1 registered event: Return the exact value returned by that event
     * - 2+ registered events: Any return value === null will be discarded
     *      - all other return values will be added to an array
     *      - That null-filtered array will then be re-checked for 0 or 1 values
     *      - If the null-filtered array has more than 1 value, an array of return values will be returned, in no intentional order.
     * 
     * You may further refine this by registering to the event "Resolve{$EventName}".  
     * The resolve event will also follow the return value rules as listed here, so you could potentionally have an event like 'ResolveResolveResolveTooManyRegistered'.  
     * Like, please don't do that? Lol. But you caaannn... I think.
     * 
     * @export(old.Events.ReturnValue)
     */
    protected function getReturnValue($allReturns,$EventName){
        if (count($allReturns)==0)return null;
        else if (count($allReturns)==1) return $allReturns[0];
        else if (count($allReturns)>1){
            $nullFilteredCopy = [];
            foreach ($allReturns as $index => $return){
                if ($return!==null)
                    $nullFilteredCopy[] = $return;
            }
            if ($nullFilteredCopy!==$allReturns)return $this->getReturnValue($nullFilteredCopy,$EventName);

            if ($this->has($event='Resolve'.$EventName)){
                $rets = $this->$event($allReturns);
                return $rets;
            }
            throw new \Exception("Event '{$EventName}' cannot be returned becasue there were multiple return values.");
            // return $allReturns;
        }
    }
}