Shopware 6.7 introduces several enhancements to the platform's architecture, including significant improvements to console command development and execution. As developers working with Shopware, understanding how to create custom console commands is crucial for automating tasks, performing maintenance operations, and extending platform functionality.

Understanding Console Commands in Shopware 6.7

Console commands in Shopware 6.7 are part of the Symfony Console component integration, which provides a robust framework for command-line interface applications. These commands can be executed via the bin/console script and are particularly useful for administrative tasks, data processing, batch operations, and system maintenance.

The new version brings improved dependency injection handling, better error management, and enhanced debugging capabilities that make console command development more reliable and maintainable than previous versions.

Prerequisites and Setup

Before diving into command creation, ensure your Shopware 6.7 environment is properly configured. You'll need:

  • Shopware 6.7.x installed
  • Composer for dependency management
  • Basic understanding of Symfony Console commands
  • Access to the command line interface

The standard directory structure for console commands in Shopware follows the pattern of placing them in src/Core/Command or within your custom plugin's command directory.

Creating Your First Custom Console Command

To create a custom console command, you'll need to extend the Command class from Symfony's console component. Here's a comprehensive example demonstrating how to build a command that processes product data:

<?php declare(strict_types=1);

namespace MyPlugin\Command;

use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class ProductImportCommand extends Command
{
    protected static $defaultName = 'myplugin:product:import';
    
    private EntityRepositoryInterface $productRepository;
    private Context $context;

    public function __construct(
        EntityRepositoryInterface $productRepository,
        Context $context
    ) {
        parent::__construct();
        $this->productRepository = $productRepository;
        $this->context = $context;
    }

    protected function configure(): void
    {
        $this
            ->setDescription('Imports products from external source')
            ->setHelp('This command allows you to import products from an external API or file');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Product Import Command');
        
        try {
            // Your import logic here
            $products = $this->fetchProductsFromExternalSource();
            
            $io->progressStart(count($products));
            
            foreach ($products as $productData) {
                $this->importSingleProduct($productData);
                $io->progressAdvance();
            }
            
            $io->progressFinish();
            $io->success('Products imported successfully!');
            
            return Command::SUCCESS;
        } catch (\Exception $e) {
            $io->error('Import failed: ' . $e->getMessage());
            return Command::FAILURE;
        }
    }

    private function fetchProductsFromExternalSource(): array
    {
        // Implementation depends on your data source
        return [
            ['name' => 'Product 1', 'price' => 100],
            ['name' => 'Product 2', 'price' => 200],
        ];
    }

    private function importSingleProduct(array $productData): void
    {
        // Product import logic here
        $this->productRepository->create([
            [
                'name' => $productData['name'],
                'price' => $productData['price'],
            ]
        ], $this->context);
    }
}

Registering Your Command

In Shopware 6.7, command registration follows the standard Symfony service container approach. You'll need to register your command as a service in your plugin's services.xml file:

<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="MyPlugin\Command\ProductImportCommand">
            <argument type="service" id="product.repository"/>
            <argument type="service" id="Shopware\Core\Framework\Context"/>
            <tag name="console.command" command="myplugin:product:import"/>
        </service>
    </services>
</container>

Advanced Command Features

Input Validation and Options

Shopware 6.7 enhances input handling with better validation mechanisms. You can define required options and arguments:

protected function configure(): void
{
    $this
        ->setDescription('Imports products with advanced options')
        ->addArgument('source', InputArgument::REQUIRED, 'Source file or URL')
        ->addOption('limit', null, InputOption::VALUE_OPTIONAL, 'Limit number of products', 100)
        ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Run without actually importing');
}

Progress Indicators and Logging

The improved progress bar implementation in Shopware 6.7 provides better user feedback during long-running operations:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    $io = new SymfonyStyle($input, $output);
    $limit = (int) $input->getOption('limit');
    
    $progressBar = $io->createProgressBar($limit);
    $progressBar->start();
    
    // Processing logic here
    
    $progressBar->finish();
    $io->newLine(2);
    
    return Command::SUCCESS;
}

Error Handling and Logging

Shopware 6.7 introduces enhanced logging capabilities within console commands. Proper error handling ensures that your commands fail gracefully:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    try {
        // Your command logic
        $this->performOperation();
        
        return Command::SUCCESS;
    } catch (Exception $e) {
        // Log the exception using Shopware's logging system
        $this->logger->error('Command failed: ' . $e->getMessage());
        
        return Command::FAILURE;
    }
}

Integration with Shopware's Context System

One of the key improvements in Shopware 6.7 is the seamless integration between console commands and the platform's context system. This allows you to leverage Shopware's built-in functionality:

public function __construct(
    EntityRepositoryInterface $productRepository,
    Context $context,
    LoggerInterface $logger
) {
    parent::__construct();
    $this->productRepository = $productRepository;
    $this->context = $context;
    $this->logger = $logger;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
    // Set context properties
    $this->context = $this->context->addExtension('command', 'product-import');
    
    // Use context in operations
    $this->productRepository->search(new Criteria(), $this->context);
    
    return Command::SUCCESS;
}

Performance Considerations

When developing console commands for Shopware 6.7, consider performance implications:

Batch Processing

For large datasets, implement batch processing to avoid memory issues:

private function processBatch(array $products): void
{
    $batchSize = 50;
    
    foreach (array_chunk($products, $batchSize) as $batch) {
        $this->importBatch($batch);
        // Optional: Add delay between batches
        usleep(100000); // 0.1 second delay
    }
}

Memory Management

Monitor memory usage and implement cleanup strategies:

protected function execute(InputInterface $input, OutputInterface $output): int
{
    $startMemory = memory_get_usage();
    
    // Your processing logic
    
    $endMemory = memory_get_usage();
    $memoryUsed = $endMemory - $startMemory;
    
    $output->writeln("Memory used: " . number_format($memoryUsed) . " bytes");
    
    return Command::SUCCESS;
}

Testing Your Commands

Shopware 6.7 provides better testing capabilities for console commands through the Symfony testing framework:

public function testCommandExecution(): void
{
    $command = new ProductImportCommand(
        $this->productRepository,
        $this->context
    );
    
    $tester = new CommandTester($command);
    $tester->execute(['--dry-run' => true]);
    
    $this->assertEquals(Command::SUCCESS, $tester->getStatusCode());
}

Best Practices

Command Naming Conventions

Follow Shopware's naming conventions for commands:

// Good: Plugin name prefix + category + action
protected static $defaultName = 'myplugin:product:import';

// Avoid: Generic names
protected static $defaultName = 'import';

Documentation and Help Text

Provide comprehensive help text to make your commands user-friendly:

protected function configure(): void
{
    $this
        ->setDescription('Imports products from external source')
        ->setHelp(
            <<<EOF
The <info>%command.name%</info> command imports products from an external API or file.
<comment>Example:</comment>
  bin/console myplugin:product:import /path/to/products.csv
EOF
        );
}

Error Recovery

Implement proper error recovery mechanisms:

private function importSingleProduct(array $productData): bool
{
    try {
        // Import logic
        return true;
    } catch (Exception $e) {
        $this->logger->error('Failed to import product: ' . $e->getMessage());
        return false;
    }
}

Running Your Command

Once registered, your command can be executed using:

# Basic execution
bin/console myplugin:product:import

# With options
bin/console myplugin:product:import --limit=50 --dry-run

# In production environment
bin/console myplugin:product:import --env=prod

Conclusion

Shopware 6.7 significantly enhances console command development with improved dependency injection, better error handling, and enhanced debugging capabilities. By following the patterns and best practices outlined in this article, you can create robust, maintainable console commands that integrate seamlessly with the Shopware platform.

The ability to process large datasets efficiently, handle errors gracefully, and provide meaningful user feedback makes console commands an invaluable tool for extending Shopware's functionality. As you continue developing custom solutions, remember to leverage Shopware's context system, implement proper logging, and consider performance implications when dealing with large-scale operations.

The improved Symfony Console integration in Shopware 6.7 ensures that your commands will be more reliable and easier to maintain while providing the flexibility needed for complex administrative tasks and data processing operations.