'How can I make a symfony 4 command to be registered only in dev environment and disabled in prod?

In my App I have a helper class App\Command\GenerateFixturesCommand that provides a command named my-nice-project:generate-fixtures.

This command consumes a service of my own project named App\Services\CatalogFixtureGenerator that generates 1000 random PDF documents for testing while developing the app.

To do so, this service uses the joshtronic\LoremIpsum class which is required in composer only in dev. LoremIpsum is a third-party library. I require it under composer's require-dev.

So the injection is:

  1. I run my GenerateFixturesCommand.
  2. Before that, the system transparently locates my CatalogFixtureGenerator and to inject it into the command.
  3. Before that, the system transparently locates the LoremIpsum third party service to inject it into my fixture generator service.

All is autowired.

When I deploy to prod and do composer install --no-dev --optimize-autoloader of course the LoremIpsum class is not installed.

But when I clear the cache with APP_ENV=prod php bin/console cache:clear the framework finds the command and cannot inject the autowired dependencies.

[WARNING] Some commands could not be registered:
In CatalogsFixtureGenerator.php line 26:
Class 'joshtronic\LoremIpsum' not found

This my-nice-project:generate-fixtures command is never going to be used in the production server.

Question

How can I "disable" the command in prod?

I mean: How can I tell the framework that the class GenerateFixturesCommand should not be loaded nor its autowired dependencies, and neither of them should be autowired in prod?



Solution 1:[1]

Use the isEnabled() method in Command. For example

    public function isEnabled(): bool
    {
        // disable on prod
        if ($this->appKernel->getEnvironment() === 'prod') {
            return false;
        }

        return true;
    }

Solution 2:[2]

In my last project, I need some commands to work only in dev environment. You use getenv function to achieve this:

# src/Command/SomeCommand.php
...

public function __construct()
{
    parent::__construct();
    if (getenv("APP_ENV") !== "dev") {
        exit('This command should work only "dev" environment.');
    }
}

This will do the trick.

Code fun :)

Solution 3:[3]

The solution @gusDeCooL suggests doesn't work with lazy-loaded commands (at least not for me).

I ended up implementing the isEnabled() method anyway, but then I added a guard in execute():

<?php


namespace App\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
    name: 'command:name',
    description: 'Some description',
)]
class CommandName extends Command
{
    public function isEnabled(): bool
    {
        return 'dev' === getenv('APP_ENV');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        if (!$this->isEnabled()) {
            $io->error('This command is only available in `dev` environment.');
            exit(1);
        }

        // the rest
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GusDeCooL
Solution 2 YahyaE
Solution 3 Jan Klan