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 script to your project.
First Use Case:
Run a built-in command (e.g., list to see available commands):
vendor/bin/laminas list
Outputs registered commands (initially empty unless configured).
Where to Look First:
src/Command/Runner.php (core logic).config/autoload/laminas-cli.global.php (if it exists).Workflow:
Create a Symfony Console command (e.g., app/src/Command/MyCommand.php):
namespace App\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class MyCommand extends Command
{
protected function configure(): void
{
$this->setName('app:my-command');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Hello from MyCommand!');
return Command::SUCCESS;
}
}
Register the Command:
config/autoload/laminas-cli.global.php:
return [
'laminas-cli' => [
'commands' => [
'app:my-command' => App\Command\MyCommand::class,
],
],
'service_manager' => [
'factories' => [
App\Command\MyCommand::class => App\Command\MyCommandFactory::class,
],
],
];
dependencies array instead of service_manager.Run the Command:
vendor/bin/laminas app:my-command
Pattern: Use factories to inject dependencies (e.g., services, repositories) into commands.
Example Factory (app/src/Command/MyCommandFactory.php):
namespace App\Command;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
class MyCommandFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new MyCommand(
$container->get(MyService::class)
);
}
}
Command Update:
class MyCommand extends Command
{
private MyService $myService;
public function __construct(MyService $myService)
{
parent::__construct();
$this->myService = $myService;
}
// ... rest of the command
}
Pattern:
Leverage Symfony’s attribute syntax for cleaner command definitions (supported since 1.15.0).
Example:
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand(name: 'app:attribute-command')]
class AttributeCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('Attribute-based command!');
return Command::SUCCESS;
}
}
Registration:
No factory needed; register directly in laminas-cli config:
'laminas-cli' => [
'commands' => [
'app:attribute-command' => App\Command\AttributeCommand::class,
],
],
Pattern:
Use the --container flag to specify a custom PSR-11 container (e.g., for testing or modular apps).
Example:
vendor/bin/laminas --container=config/container.test.php app:my-command
Container File (config/container.test.php):
use Psr\Container\ContainerInterface;
use Laminas\ServiceManager\ServiceManager;
return new ServiceManager([
'factories' => [
MyService::class => MyServiceFactory::class,
],
]);
Pattern:
While laminas-cli is Laminas-focused, you can adapt it for Laravel by:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Symfony\Component\Console\Application;
class LaminasCliServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('laminas.cli', function ($app) {
return new Application();
});
}
}
$this->app->extend('laminas.cli', function ($cli) {
$cli->add(new MyCommand());
return $cli;
});
php artisan laminas:run app:my-command
(Note: Requires custom Artisan command wrapper.)| Issue | Solution |
|---|---|
| Command not found | Ensure the command is registered in laminas-cli.commands config. |
| Dependency injection fails | Verify the factory is correctly mapped in service_manager/dependencies. |
| Container not loaded | Use --container flag or ensure the default container is configured. |
| Symfony Console version mismatch | Update laminas-cli to >=1.15.0 for Symfony 7+ support. |
| PHP version errors | Use >=1.13.0 for PHP 8.5, >=1.11.0 for PHP 8.4, etc. |
Check Registered Commands:
vendor/bin/laminas list
Lists all available commands (useful for verifying registration).
Enable Verbose Output:
vendor/bin/laminas --verbose app:my-command
Shows DI container resolution steps.
Inspect Container: Add a temporary command to dump the container:
$container = $this->getApplication()->getKernel()->getContainer();
var_dump($container->get(MyService::class));
Symfony Debug: Use Symfony’s built-in debug mode:
vendor/bin/laminas --debug app:my-command
Global vs. Local Config:
laminas-cli.global.php) is loaded by default.laminas-cli.local.php) can override settings.Command Namespacing:
Prefix commands with a namespace (e.g., package:command) to avoid collisions:
'laminas-cli' => [
'commands' => [
'package:my-command' => App\Command\MyCommand::class,
],
],
Attribute Commands: Ensure your PHP version supports attributes (PHP 8.0+). For older versions, use traditional annotations or XML.
Custom Command Runner:
Extend Laminas\Cli\Command\Runner to modify command resolution logic.
Event Listeners:
Attach listeners to Symfony’s console events (e.g., CommandEvent):
use Symfony\Component\Console\Event\ConsoleCommandEvent;
$eventDispatcher->addListener(ConsoleCommandEvent::class, function (ConsoleCommandEvent $event) {
if ($event->getCommand()->getName() === 'app:my-command') {
// Pre/post-command logic
}
});
PSR-15 Middleware: Integrate middleware for cross-cutting concerns (e.g., logging, auth):
$container->get('laminas.cli.middleware')->push(
new MyMiddleware()
);
Avoid Over-Registration: Only register commands you need to reduce container overhead.
Lazy-Load Factories: Use lazy factories for heavy dependencies:
'service_manager' => [
'factories' => [
HeavyService::class => function (ContainerInterface $container) {
return new HeavyService(); // Lazy initialization
},
],
],
Cache Container:
For frequent CLI usage, cache the container (e.g., with laminas-servicemanager):
$container = new ServiceManager([
'cache_config' => 'config/container.cache.php',
]);
How can I help you explore Laravel packages today?