mrgoodbytes8667/command-bundle
A Laravel package that bundles commonly used Artisan commands into one installable set, giving you ready-made console tools for everyday tasks. Commands register automatically via package discovery, with config options to enable, disable, or customize what's provided.
mrgoodbytes8667/command-bundle is a console-command library in the Symfony bundle tradition: it packages a set of reusable CLI commands and command plumbing rather than Laravel-specific Artisan tooling. In a Laravel app you consume it as a plain Composer dependency and adapt it to Artisan yourself.
composer require mrgoodbytes8667/command-bundle:^2.0.1
Steps:
src/ for Command subclasses and any *Bundle/*Extension classes. Anything that extends Symfony\Component\Console\Command\Command can be reused inside Artisan; Symfony-only bundle wiring (DI extensions, Resources/config) cannot and should be ignored.// app/Providers/AppServiceProvider.php (or a dedicated CommandServiceProvider)
public function register(): void
{
$this->app->singleton(\MrGoodBytes\CommandBundle\Command\SomeCommand::class);
}
php artisan by registering them via the console kernel, or invoke the underlying services directly from your own Artisan command. Start with the simplest one, verify exit codes, then graduate to wrapping them in your own command classes so you control naming, options and output formatting.Note on v2.0.1: this is a patch release that fixes compatibility with TraceableCommand — the decorator Symfony's profiler wraps around commands in debug mode. If you were pinning 2.0.0 because the bundle misbehaved under debug: true/profiler, upgrade and drop the pin. No API changes, no migration steps.
Adapter command pattern (recommended). Don't expose third-party commands directly to users; wrap them so you can rename, default options, and re-shape output:
class SyncWidgetsCommand extends Command
{
protected $signature = 'widgets:sync {--dry-run}';
public function handle(SomeBundleCommand $inner): int
{
// configure the package command and delegate
return $this->call(...); // or invoke the underlying service directly
}
}
If the package command is designed to be constructed and run standalone, prefer instantiating it and driving it via Symfony's ArrayInput/BufferedOutput rather than Artisan::call(), which re-resolves through Laravel's container and may not know its dependencies.
Decorate, don't subclass. The v2.0.1 fix exists precisely because wrapping commands breaks naive type checks. Mirror that lesson in your own code: if you wrap a package command (for logging, timing, or dry-run interception), implement Symfony\Component\Console\Command\Command's contract surface — actually implement the interface / use composition — and never assume get_class($command) === SomeCommand::class. Consumers should type-hint the interface, not the concrete class.
Scheduling and chaining. Once wrapped, package behaviour becomes schedulable like anything else:
$schedule->command('widgets:sync')->hourly()->withoutOverlapping();
Testing. Use Laravel's artisan test helper against your adapter, and assert on exit codes rather than raw output when the package owns the formatting:
$this->artisan('widgets:sync', ['--dry-run' => true])->assertExitCode(0);
For direct unit tests of package commands, use Symfony's CommandTester — it bypasses Laravel's kernel and is far faster.
Version pinning. Treat ^2.0.1 as the floor for anything running with the profiler/debug tooling enabled, and pin exactly in CI if you also run the same commands under a decorated console.
TraceableCommand wrapping (the v2.0.1 bug class). In debug/profiler contexts, Symfony hands your command a decorator instead of the real class. Any instanceof, get_class(), or concrete type-hint check in the bundle — or in your wrapper code — silently fails there and only there. Reproduce bugs with the profiler on before blaming your own code, and inspect with getInnerCommand() (or the equivalent unwrap helper) when debugging.composer require it and nothing happens, that is correct behaviour.Artisan::call() resolves commands from its container. Register bindings explicitly or instantiate the command yourself; otherwise you get "too few arguments" style errors that look like package bugs.Artisan::call() returns the integer exit code; $this->call() returns it too, but returning 0 unconditionally from your handle() hides failures. Always propagate.OutputInterface, not Laravel's $this->info(). Verbosity flags (-v, -vvv) and --ansi are honoured, but $this->output styling helpers are not shared — don't mix the two in one command without a SymfonyStyle bridge.config/*.php, remember php artisan config:cache freezes them; stale values after a deploy are usually the cache, not the bundle.How can I help you explore Laravel packages today?