Weave Code
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

Console Laravel Package

fidry/console

Lightweight, robust wrapper around symfony/console. Uses a single IO object (SymfonyStyle-like, with access to Input/Output) plus typed, validated args/options. Prefer explicit interfaces over inheritance; works with Symfony or standalone CLI apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require theofidry/console
    

    Ensure Fidry\Console\FidryConsoleBundle is enabled in config/bundles.php.

  2. First Command: Create a class implementing Fidry\Console\Command\Command:

    // src/Command/MyFirstCommand.php
    namespace App\Command;
    
    use Fidry\Console\{Command\Command, Command\Configuration, ExitCode, IO};
    
    final class MyFirstCommand implements Command {
        public function getConfiguration(): Configuration {
            return new Configuration('app:hello', 'Says hello');
        }
    
        public function execute(IO $io): int {
            $io->writeln('Hello, World!');
            return ExitCode::SUCCESS;
        }
    }
    
  3. Run It:

    php bin/console app:hello
    

Where to Look First

  • Documentation: Start with doc/command.md for core concepts.
  • Usage Preview: The README usage preview shows a full example with typed input/output.
  • IO Object: Focus on Fidry\Console\IO for input/output handling—it’s the core abstraction.

Implementation Patterns

Core Workflow

  1. Define Command: Implement Command interface with getConfiguration() and execute().

    public function getConfiguration(): Configuration {
        return new Configuration(
            'app:my-command',
            'Description',
            'Help text',
            [/* arguments */],
            [/* options */]
        );
    }
    
  2. Typed Input Handling: Use IO methods for type-safe input:

    $username = $io->getTypedArgument('username')->asStringNonEmpty();
    $age = $io->getTypedOption('age')->asNullablePositiveInteger();
    
  3. Output Patterns:

    • Basic: $io->writeln('Message')
    • Sections: $section = $io->section(); $section->writeln('...')
    • Progress: Use Symfony\Component\Console\Helper\ProgressBar via $io->getOutput().
  4. Service Integration: Inject services via constructor (Laravel’s DI works seamlessly):

    public function __construct(private MyService $service) {}
    
  5. Lifecycle Hooks: Implement InitializableCommand for pre-execution logic:

    public function initialize(IO $io): void {
        $this->validateEnvironment();
    }
    

Integration Tips

  • Laravel-Specific:

    • Use Artisan::command() for Laravel-specific commands:
      Artisan::command('app:custom', function () {
          // Command logic
      });
      
    • Leverage Laravel’s Console/Kernel.php for grouping commands under php artisan.
  • Testing: Use Fidry\Console\Test\CommandTestCase for mocking IO:

    public function testExecute(): void {
        $io = $this->createMock(IO::class);
        $command = new MyCommand();
        $this->assertSame(ExitCode::SUCCESS, $command->execute($io));
    }
    
  • Lazy Loading: Implement LazyCommand for deferred command registration (see doc/lazy-command.md).


Gotchas and Tips

Pitfalls

  1. Input Validation:

    • Typed input methods (e.g., asPositiveInteger()) throw exceptions on failure. Handle them:
      try {
          $age = $io->getTypedArgument('age')->asPositiveInteger();
      } catch (InvalidArgumentException $e) {
          $io->error('Age must be a positive integer.');
          return ExitCode::FAILURE;
      }
      
  2. Output Sections:

    • Sections require ConsoleOutputInterface. Check before use:
      if (!$io->getOutput() instanceof ConsoleOutputInterface) {
          throw new LogicException('Sections require ConsoleOutputInterface.');
      }
      
  3. Service Container:

    • Commands must be tagged fidry.console_command for auto-registration. Laravel’s autowiring handles this if using Artisan::command().
  4. Missing Features:

    • No built-in support for hidden commands or aliases (track GitHub issues).

Debugging Tips

  • IO Mocking: For tests, mock IO and verify interactions:

    $io = $this->createMock(IO::class);
    $io->expects($this->once())
        ->method('writeln')
        ->with('Hello!');
    
  • Exit Codes: Always return ExitCode::SUCCESS/ExitCode::FAILURE for consistency. Custom codes require const definitions.

  • Configuration:

    • Use Configuration::fromArray() for dynamic command setup:
      $config = Configuration::fromArray([
          'name' => 'app:dynamic',
          'description' => 'Dynamic command',
      ]);
      

Extension Points

  1. Custom IO: Extend Fidry\Console\IO to add domain-specific methods:

    class CustomIO extends IO {
        public function logUserAction(string $action): void {
            $this->writeln(sprintf('<info>[USER] %s</info>', $action));
        }
    }
    
  2. Command Decorators: Wrap commands to add cross-cutting logic (e.g., logging):

    class LoggingCommandDecorator implements Command {
        public function __construct(private Command $command) {}
    
        public function execute(IO $io): int {
            $io->writeln('<comment>Starting command...</comment>');
            return $this->command->execute($io);
        }
    }
    
  3. Event Listeners: Use Symfony’s event system (via EventDispatcher) to hook into command lifecycle:

    $dispatcher->addListener(CommandEvents::EXECUTE, function (CommandEvent $event) {
        $event->getCommand()->initialize($event->getInput());
    });
    

Laravel-Specific Quirks

  • Artisan Integration:

    • Commands registered via Artisan::command() bypass fidry.console_command tagging. Ensure manual registration if needed.
    • Use Artisan::call() to execute commands programmatically:
      $exitCode = Artisan::call('app:my-command', ['username' => 'john']);
      
  • Configuration:

    • Override default Configuration via config/console.php:
      'commands' => [
          'app:my-command' => [
              'description' => 'Custom description',
          ],
      ],
      
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.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor