. */ /** * GNU social's event handler wrapper around Symfony's, * keeping our old interface, which is more convenient and just as powerful * * @package GNUsocial * @category Event * * @author Hugo Sales * @copyright 2020 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ namespace App\Util; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\GenericEvent; abstract class GSEvent { /** * Constants to be returned from event handlers, for increased clarity * * bool stop - Stop other handlers from processing the event * bool next - Allow the other handlers to process the event */ public const stop = false; public const next = true; private static EventDispatcherInterface $dispatcher; public static function setDispatcher(EventDispatcherInterface $dis): void { self::$dispatcher = $dis; } /** * Add an event handler * * To run some code at a particular point in GNU social processing. * Named events include receiving an XMPP message, adding a new notice, * or showing part of an HTML page. * * The arguments to the handler vary by the event. Handlers can return * two possible values: false means that the event has been replaced by * the handler completely, and no default processing should be done. * Non-false means successful handling, and that the default processing * should succeed. (Note that this only makes sense for some events.) * * Handlers can also abort processing by throwing an exception; these will * be caught by the closest code and displayed as errors. * * @param string $name Name of the event * @param callable $handler Code to run * @param int $priority Higher runs first * * @return void */ public static function addHandler(string $name, callable $handler, int $priority = 0, string $ns = 'GNUsocial/'): void { self::$dispatcher->addListener( $ns . $name, function ($event, $event_name, $dispatcher) use ($handler) { // Old style of events (preferred) if ($event instanceof GenericEvent) { if (call_user_func_array($handler, $event->getArguments()) == self::stop) { $event->stopPropagation(); } return $event; } // Symfony style of events call_user_func($handler, $event, $event_name, $dispatcher); return null; }, $priority ); } /** * Handle an event * * Events are any point in the code that we want to expose for admins * or third-party developers to use. * * We pass in an array of arguments (including references, for stuff * that can be changed), and each assigned handler gets run with those * arguments. Exceptions can be thrown to indicate an error. * * @param string $name Name of the event that's happening * @param array $args Arguments for handlers * @param string $ns Namspace for the event * * @return bool flag saying whether to continue processing, based * on results of handlers. */ public static function handle(string $name, array $args = [], string $ns = 'GNUsocial/'): bool { return !(self::$dispatcher->dispatch( new GenericEvent($ns . $name, $args), $name)->isPropagationStopped()); } /** * Check to see if an event handler exists * * Look to see if there's any handler for a given event, or narrow * by providing the name of a specific plugin class. * * @param string $name Name of the event to look for * @param string $plugin Optional name of the plugin class to look for * * @return bool flag saying whether such a handler exists */ public static function hasHandler(string $name, ?string $plugin = null): bool { $listeners = self::$dispatcher->getListeners($name); if (isset($plugin)) { foreach ($listeners as $handler) { if (\get_class($handler[0]) == $plugin) { return true; } } } else { return !empty($listeners); } return false; } /** * Get the array of handlers for $name * * @param string $name Name of event * * @return array * @return array */ public static function getHandlers(string $name): array { return self::$dispatcher->getListeners($name); } }