Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dispatcher Laravel Package

hoa/dispatcher

Hoa\Dispatcher is a PHP component for routing and dispatching requests to controllers, offering a flexible foundation for MVC-style applications. It integrates with Hoa\Router and supports customizable dispatch rules and controller resolution.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what this is before you composer require it. hoa/dispatcher is not an event dispatcher and has nothing to do with Illuminate\Contracts\Events\Dispatcher. It is the second half of the Hoa MVC stack: Hoa\Router matches a request and yields a (controller, action, variables) tuple; Hoa\Dispatcher turns that tuple into an actual method call. The closest Laravel analogue is Illuminate\Routing\ControllerDispatcher (Route::get('/x', [Foo::class, 'bar'])). If you were hoping for Event::listen(), close the tab.

Install and pin.

composer require hoa/dispatcher:^3.16

This drags in hoa/router, hoa/consistency, hoa/zformat, and hoa/protocol. The last release is 2017-05-02 — pin the exact version, and expect no further ones.

Spike before you commit. Run this fifteen-minute check on your target runtime:

php -v          # if 8.x, keep reading the Gotchas section first
php -r 'require "vendor/autoload.php"; var_dump(class_exists("Hoa\\Dispatcher\\Basic"));'

Hoa libraries of this vintage frequently break on PHP 8 because of $errcontext parameters in set_error_handler callbacks (removed in PHP 8). Find out in a scratch directory, not in app/.

Where to look first. The whole package is roughly one class plus a value object:

  • vendor/hoa/dispatcher/Basic.php — dispatch(), getController(), getAction(), getVariables().
  • vendor/hoa/dispatcher/Kit.php — the bag of context passed between dispatcher and controller.
  • vendor/hoa/dispatcher/ClassMethod.php — the thinner variant if Basic does too much.

Read all three in one sitting; it is a few hundred lines of readable PHP and you will understand the package completely.

First use case. A standalone script or an Artisan command where you already have a route table and want controller resolution without booting Laravel's HTTP kernel:

$router = new Hoa\Router\Http();
$router->get('hello', '/hello/(?<name>\w+)', 'App\Main', 'hello');

try {
    $router->route();
} catch (Hoa\Router\Exception\NotFound $e) {
    // 404 path
}

$dispatcher = new Hoa\Dispatcher\Basic();
$kit = $dispatcher->dispatch($router);

The Laravel equivalent you are replacing:

Route::get('/hello/{name}', [App\Main::class, 'hello']);

If your first use case is "inside a Laravel HTTP request", stop — you already have a better dispatcher.

Implementation Patterns

1. The honest pattern: use it as a reference, not a dependency. Basic::dispatch() is a service-locator-free string-to-callable resolver. The ~150 lines that actually matter are worth reading and reimplementing against Laravel's container rather than carrying a 2017 dependency. If you need the same shape, this is the whole idea:

$callable = app()->make($controller);
return $callable->{$action}(...array_values($variables));

That is genuinely most of what Hoa\Dispatcher\Basic does, minus the zformat configuration layer.

2. Standalone sub-app inside a Laravel project. If you must keep the dependency (e.g. porting a legacy Hoa module), isolate it behind a service provider and call it from one place:

// app/Providers/LegacyDispatcherServiceProvider.php
public function register(): void
{
    $this->app->singleton(\Hoa\Dispatcher\Basic::class, fn () => new \Hoa\Dispatcher\Basic([
        'controller' => 'App\\Http\\Legacy\\\\(:controller)',
        'action'     => '(:action)Action',
    ]));
}

Then invoke from a route closure or command — never let Hoa's router own your HTTP entry point, or you lose middleware, CSRF, session, and validation.

3. Handler-map dispatch via the router's tuple. The one transferable idea with real day-to-day value: treat (controller, action) as data and keep an explicit map instead of magic. In Laravel this beats both Route:: spaghetti and app($class) string calls scattered around:

// config/handlers.php
return [
    'user.created' => [App\Handlers\UserHandler::class, 'onCreated'],
];
[$class, $method] = config("handlers.{$eventName}");
app()->call([app($class), $method], $payload);

app()->call() gives you named injection and container resolution — everything Hoa\Dispatcher cannot do.

4. Variables in, positional out. Hoa\Dispatcher passes route variables as an ordered array; actions receive them positionally. There is no name-based injection, no type-hint resolution, no route-model binding. Laravel's RouteDependencyResolverTrait does all of that. If you replicate the look of the Hoa API in your own code, still delegate to app()->call() so you keep Laravel's resolution semantics.

5. Kit-based context. Hoa\Dispatcher\Kit carries router, dispatcher, data, view, controller, action, variables through the call chain — a poor man's request container. In Laravel, Request, the container, and View fill these roles natively. Do not try to mirror Kit in Laravel code; you will end up with an object nobody can trace.

6. No middleware, no pipeline. There is nothing to hook. If you need cross-cutting concerns around a Hoa dispatch, wrap the call in a Laravel middleware or a decorator. Bridging Illuminate\Pipeline into Hoa\Router is not worth the impedance mismatch.

7. Testing. Basic is trivially testable precisely because it has no container: pass a configuration array and a stub Hoa\Router\Router whose getTheRule() returns a fixed tuple. If you are evaluating whether to port the logic, write those two tests first — it takes ten minutes and tells you whether the abstraction earns its keep.

8. Extension surface. Subclass Hoa\Dispatcher\Basic and override getController(), getAction(), or getVariables(); set $_kitClass to swap the context object. That is the entire customization model. It is a fork-friendly package, which is another way of saying it is unmaintained.

Gotchas and Tips

  • It is abandoned, and the numbers say so. Last release 2017-05-02, 12 stars, zero dependents. There is no security policy, no CI matrix, and no PHP 8 verification. Treat any adoption as "we are forking this," and budget accordingly.
  • PHP 8 is the likely wall. Hoa packages of this era commonly register error handlers whose signatures include $errcontext, removed in PHP 8.0. If Hoa\Consistency fails to bootstrap on your runtime, the cost of patching a vendored dependency usually exceeds the value of the package. Check vendor/hoa/consistency/Consistency.php before anything else.
  • Global side effects from the autoloader. hoa/consistency can register its own autoloader and, in some versions, its own error and shutdown handlers. Inside a Laravel app that can hijack Ignition/Whoops error pages. Grep for set_error_handler, register_shutdown_function, and spl_autoload_register in vendor/hoa/consistency/ and audit what gets registered on boot.
  • Hoa\Zformat is its own mini-language. Configuration strings like 'App\\Http\\Legacy\\\\(:controller)' and '(:action)Action' use placeholder syntax with non-obvious backslash escaping for namespaced class names. When a controller "cannot be found," dump the resolved configuration from the dispatcher before touching your class names — nine times in ten the escaping is wrong, not the class.
  • Route before dispatch. Calling dispatch() without $router->route() first gives you a null or unset rule and an opaque Hoa\Router exception. Always try { $router->route(); } catch (Hoa\Router\Exception\NotFound $e) { ... } before dispatching.
  • Positional arguments only. No named parameters, no type-hint resolution, no container. An action needing a service ends up constructing it inline or reaching for a global — the exact service-locator pattern Laravel's container was designed to avoid.
  • Exception handling is opaque. Depending on version and configuration, Basic may catch throwables and forward to an error action instead of propagating. If you need Laravel's Handler to see failures, wrap the dispatch() call in try/catch, normalize, and rethrow.
  • Alien stack traces. Hoa\Exception subclasses print hoa://-style traces that look nothing like Laravel's log format and will confuse anyone triaging Sentry. Normalize the message and drop the Hoa trace before it reaches your logger.
  • The debug loop that works: var_dump($router->getTheRule()) → confirm the tuple → var_dump($dispatcher) → confirm the resolved controller/action strings → then look at your class. Almost every "dispatch failed" report is a mismatch in that first tuple, not a bug in the package.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle