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

Cli Laravel Package

hoa/cli

Hoa\Cli is a PHP library for building command-line interfaces, offering abstractions for commands, arguments, options, input/output, and terminal interaction. It fits the modular Hoa ecosystem for structured CLI application development.

View on GitHub
Deep Wiki
Context7

Getting Started

hoa/cli is a tiny, archived (last release July 2017) routing layer for command-line input. It is not a full console framework: it matches argv strings against patterns and invokes a callable. There is no option parser, no help generator, no input/output abstraction, and no Laravel integration.

Before installing, check whether you actually need it:

composer require hoa/cli

Expect old version constraints (PHP 5.x-era) and transitive hoa/* dependencies. On a modern Laravel app, install it in a throwaway branch first and run composer why-not hoa/cli / composer update --dry-run to see conflicts.

Where to look first:

  1. src/Router.php — registration and dispatch entry point.
  2. src/Router/Route.php — pattern compilation and matching.
  3. The Hoa project documentation for Hoa\Cli (the API surface is small enough to read in one sitting).

The smallest useful script looks roughly like this (verify exact pattern syntax against the source for your pinned version):

<?php
require __DIR__ . '/vendor/autoload.php';

$router = new Hoa\Cli\Router();

$router->add('greet (?<name>\w+)', function ($name) {
    echo "Hello, {$name}\n";
});

$router->add('sum (?<a>\d+) (?<b>\d+)', function ($a, $b) {
    echo ((int) $a + (int) $b) . "\n";
});

$router->route($_SERVER['argv']);

The realistic first use case in a Laravel codebase is not building a new CLI. It is wrapping an existing legacy Hoa-based script so it can be called from an Artisan command, or maintaining an inherited standalone tool. For anything new, use Illuminate\Console / Symfony Console instead.

Implementation Patterns

Artisan bridge (the only pattern that makes sense inside Laravel). Keep the Hoa router in a standalone script or a small service class, and expose it through one Artisan command:

// app/Console/Commands/LegacyCli.php
protected $signature = 'legacy:cli {args* : Raw arguments passed to the legacy router}';

public function handle()
{
    $router = app(\App\Cli\LegacyRouterFactory::class)->make();

    // Hoa expects argv-style input; prepend a fake script name.
    $argv = array_merge(['legacy'], $this->argument('args'));

    ob_start();
    $router->route($argv);
    $this->output->write(ob_get_clean());

    return self::SUCCESS;
}

This keeps argument parsing in Artisan (where --help, validation, and --no-interaction work) and only delegates dispatch to Hoa.

Table-driven route registration. Do not scatter $router->add() calls. Register routes from a config array or a dedicated class so handlers are discoverable and testable:

foreach (config('legacy-cli.routes', []) as $pattern => $handler) {
    $router->add($pattern, $handler);
}

Handlers can be invokable classes resolved through the container (fn (...$args) => app($handler)(...$args)), which is the cleanest way to get Laravel services into Hoa callbacks.

Order-sensitive dispatch. Register specific routes before catch-alls. Treat the route list like Laravel route definitions: the first match wins, and a permissive pattern at the top will shadow everything below it.

Explicit fallback and failure handling. Wrap route() in a try/catch for whatever the router throws on no match (inspect the source; it is not a documented contract), then return a non-zero exit code and print usage text you write yourself. Hoa will not do this for you.

Testing. The router is pure PHP and cheap to test. Instantiate it per test, call route() with a synthetic argv, and capture output with ob_start() / ob_get_clean(). Assert on both output and exit behaviour; do not shell out to php artisan for unit-level coverage.

Integration boundary. If you need prompts, progress bars, tables, or coloured output, you are in the wrong package — either keep I/O in the Artisan command or pair with hoa/console, accepting a second archived dependency.

Gotchas and Tips

  • Archived and unmaintained. No security fixes, no PHP 8+ compatibility guarantees, no support. Pin the exact version and treat any upgrade as a manual migration. For new code in 2024+, this is a hard no; use Symfony Console via Artisan.
  • Dependency rot. The 2017 constraints on hoa/* packages frequently collide with modern Laravel/Symfony requirements. If Composer refuses, do not force it with --ignore-platform-reqs in a production app; isolate the legacy tool in its own process/package instead.
  • It is a matcher, not a parser. There are no options, no --flag=value handling, no type coercion, no defaults. Anything beyond positional patterns must be parsed by your handler or by Artisan before dispatch.
  • argv includes the script name. Passing raw $_SERVER['argv'] means the first element is the script path. When bridging from Artisan, prepend a dummy element so indices line up.
  • Pattern syntax is regex-flavoured. Named captures become handler parameters in order. Escape literal dots/slashes, watch greedy \w+ captures, and remember the shell has already stripped quotes before PHP sees the string — spaces inside a single argument are fine, unquoted spaces split arguments.
  • Whitespace is significant. A route written for greet (?<name>\w+) will not match greet Alice (double space). Normalise or document the expected invocation.
  • Debugging. Dump the effective argv inside the command and log each pattern as it is registered. When a route silently fails to match, the cause is almost always an unescaped character, argument splitting, or an earlier greedy route.
  • No container awareness. Closures have no $this->app; use app() explicitly or bind invokable handler classes. There are no middleware, events, or lifecycle hooks.
  • Extension points are minimal. You can subclass Hoa\Cli\Router\Route or swap callables, but there is no plugin system. If you find yourself extending it heavily, that is the signal to replace it with Symfony Console.
  • Exit codes matter. Hoa's router does not manage process exit status for you. Set return self::FAILURE / exit(1) yourself; otherwise CI and shell scripts cannot detect failures.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console