laminas/laminas-cli
Console tooling for Laminas applications and components. Provides a CLI entry point, command discovery/registration, and integration helpers to build and run project-specific commands via Composer and your framework configuration.
Installation:
composer require laminas/laminas-cli
This adds the vendor/bin/laminas CLI runner to your project.
First Use Case:
Run a built-in command (e.g., list to see available commands):
vendor/bin/laminas list
For Laminas MVC/Mezzio apps, this will display commands registered in your application’s configuration.
Where to Look First:
config/autoload/laminas-cli.global.php (or equivalent) for registered commands.Command Registration:
// config/autoload/laminas-cli.global.php
return [
'laminas-cli' => [
'commands' => [
'app:custom-command' => \App\Command\CustomCommand::class,
],
],
'service_manager' => [
'factories' => [
\App\Command\CustomCommand::class => \App\Factory\CustomCommandFactory::class,
],
],
];
// config/autoload/laminas-cli.global.php
return [
'laminas-cli' => [
'commands' => [
'app:custom-command' => \App\Command\CustomCommand::class,
],
],
'dependencies' => [
'factories' => [
\App\Command\CustomCommand::class => \App\Factory\CustomCommandFactory::class,
],
],
];
Command Execution:
vendor/bin/laminas app:custom-command [options]
Use --container=<path> to specify a custom container file (e.g., vendor/bin/laminas --container=config/container.php app:custom-command).
Dependency Injection:
CustomCommandFactory) to resolve them via the container.namespace App\Factory;
use Psr\Container\ContainerInterface;
use App\Command\CustomCommand;
class CustomCommandFactory
{
public function __invoke(ContainerInterface $container): CustomCommand
{
return new CustomCommand(
$container->get(\App\Service\SomeService::class)
);
}
}
Symfony Console Attributes (v1.15.0+): Decorate commands with attributes for metadata (e.g., descriptions, arguments):
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand(name: 'app:custom-command', description: 'Does something awesome')]
class CustomCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
// Command logic
}
}
Integration with Artisan-like Workflows:
vendor/bin/laminas as a drop-in replacement for php artisan in Laravel projects.bin/console symlink:
ln -s vendor/bin/laminas bin/console
Missing --container Flag:
InvalidArgumentException, ensure you’re either:
--container=<path> to point to a PSR-11 container file.laminas-cli v1.1.1+ (includes a bugfix for this).Command Not Found:
vendor/bin/laminas list shows no commands, verify:
laminas-cli config key exists in your autoload configuration.commands key (e.g., 'app:command-name' => \Namespace\Command::class).Symfony Console Version Mismatch:
laminas-cli v1.15.0+ requires Symfony Console v6+. Older versions may break with newer Symfony releases.laminas-cli or pin Symfony Console to a compatible version in composer.json.Circular Dependencies in Factories:
allow_override: true in config/autoload/global.php for development:
return [
'laminas-cli' => [
'allow_override' => true, // Debugging only!
],
];
Verbose Output:
Add -v or -vv to commands for debugging:
vendor/bin/laminas -vv app:custom-command
Container Inspection: Dump the container contents to verify service availability:
// In a command's execute() method:
$container = $this->getApplication()->getKernel()->getContainer();
var_dump($container->get(\App\Service\SomeService::class));
PSR-11 Container Validation:
Ensure your custom container implements Psr\Container\ContainerInterface and handles NotFoundException for missing services.
Dynamic Command Loading:
Register commands dynamically via a Laminas\Cli\Command\CommandProviderInterface:
$provider = new class implements CommandProviderInterface {
public function getCommands(): array
{
return [
'app:dynamic-command' => \DynamicCommand::class,
];
}
};
// Register the provider in your container.
Custom Command Helpers:
Extend Laminas\Cli\Command\Command for reusable logic:
abstract class BaseCommand extends Command
{
protected function log(string $message): void
{
$this->getApplication()->getKernel()->getLogger()->info($message);
}
}
Environment-Specific Commands:
Use config/autoload/{environment}.global.php to conditionally register commands:
// config/autoload/local.global.php
return [
'laminas-cli' => [
'commands' => [
'app:dev-only-command' => \DevCommand::class,
],
],
];
Integration with Laravel:
vendor/bin/laminas with a custom script to leverage Laravel’s service container:
# bin/laminas
#!/usr/bin/env php
<?php
require __DIR__.'/../vendor/autoload.php';
$container = require __DIR__.'/../bootstrap/app.php';
$cli = new \Laminas\Cli\Cli($container);
$cli->run();
AppServiceProvider:
public function register()
{
$this->app->extend('laminas-cli.commands', function ($commands) {
$commands['app:laravel-command'] = \App\Command\LaravelCommand::class;
return $commands;
});
}
Avoid Overhead in Production:
Disable debug mode in config/autoload/global.php:
return [
'laminas-cli' => [
'debug' => false,
],
];
Cache Command Metadata: For large applications, cache command metadata (e.g., descriptions) in a static file to avoid reflection overhead:
// In a command provider:
$metadata = require __DIR__.'/../data/command-metadata.php';
return $metadata['commands'];
How can I help you explore Laravel packages today?