Console

The application CLI is built on Symfony Console. Entry point — bin/console.php; commands are registered through the DI container and ConsoleServiceProvider.

See also: Setup → bin/console.php, CLI providers, creating custom commands, Database → console commands.

Core classes

ClassRole
ConsoleServiceProvider Symfony\Component\Console\Application, registration from config/commands.php
ComponentsServiceProvider Adds component commands in boot()
DisabledCommand Stub when a command cannot be created from DI

Running

From the project root:

php bin/console.php

# help
php bin/console.php list

# help for one command
php bin/console.php help db:migrate

CLI bootstrap differs from HTTP: it loads bootstrap/providers/console.php. For details see Setup and the providers and commands section below.

How it works

require __DIR__ . '/../vendor/autoload.php';

$rootPath = dirname(__DIR__);
$paths = include $rootPath . '/bootstrap/paths.php';
$app = App::create($rootPath, $paths);
$app->registerServiceProviders([$rootPath . '/bootstrap/providers/console.php']);

$console = $app->getContainer()->get(ConsoleApplication::class);
$console->run();
  1. ConsoleServiceProvider creates Application with name/version from app.name / app.version
  2. Classes from config/commands.php (ConfigKey::COMMANDS) are resolved from DI and added to the application
  3. If a command dependency is unavailable — a DisabledCommand is registered with an error explanation
  4. ComponentsServiceProvider::boot() adds commands from ComponentInterface::commands() on each active component
// config/commands.php (fragment)
return [
    'commands' => [
        DbMigrateCommand::class,
        RouteListCommand::class,
        // ...
    ],
];

Providers and command dependencies

Each command is a regular Symfony Console service: dependencies are passed through the constructor and resolved from the DI container. If the provider that registers a service is missing from bootstrap/providers/console.php, the command is not created — instead a DisabledCommand appears.

Command Dependencies (DI) Required providers
db:migrate, db:rollback Migrator, MigrationRegistry DatabaseServiceProvider (boot() — Capsule)
migration:list CapsuleManager, ConfigInterface ConfigServiceProvider, DatabaseServiceProvider
db:seed SeederManager DatabaseServiceProvider
seeders:list SeederRegistry DatabaseServiceProvider
route:list RouterInterface HttpServiceProvider, ConfigServiceProvider (paths to routes/*.php)
view:clear PathManager, ConfigInterface ConfigServiceProvider (Twig not required in CLI)
component:list, component:publish-assets ComponentRegistry ComponentsServiceProvider (last, after ConsoleServiceProvider)

Recommended minimum (bootstrap/providers/console.php):

return [
    ConfigServiceProvider::class,        // config, PathManager
    HttpServiceProvider::class,          // RouterInterface → route:list
    SessionServiceProvider::class,       // if commands/seeders touch session
    ErrorHandlerServiceProvider::class,
    LogServiceProvider::class,
    DatabaseServiceProvider::class,      // db:*, migration:list, seeders:list
    ConsoleServiceProvider::class,       // Application + commands from config/commands.php
    DebugLoggerServiceProvider::class,
    ComponentsServiceProvider::class,    // component:* + component commands
];

ConsoleServiceProvider must come before ComponentsServiceProvider: the latter adds component commands in boot() to an already created ConsoleApplication.

Why CLI needs HttpServiceProvider

At first glance the HTTP stack in the console seems unnecessary — CLI does not handle browser requests. But route:list injects RouterInterface, and the router is registered by HttpServiceProvider: it creates League\Route\Router, wires RouteStrategy, and loads files from config/routes.php (and component routes — via ComponentsServiceProvider).

Without HttpServiceProvider the container does not know RouterInterfaceRouteListCommand cannot be built → in php bin/console.php list you see route:list with a red disabled warning (as in the screenshot below). A full list of component routes additionally requires ComponentsServiceProvider, which loads each component’s routes.php.

In CLI App::run() is not called and no request is dispatched. The provider only builds the same route graph as the web application, so diagnostics (route:list, -F for middleware) show the real picture. ServerRequestInterface in CLI is an “empty” PSR-7 from fromGlobals(); that is enough for listing routes.

Twig, Validation, and ViewRegistry are intentionally omitted from the console bootstrap — no built-in command needs them. HttpServiceProvider also registers ResponseFactory and ViewResponseFactory, but CLI commands do not resolve them.

If a provider is missing — DisabledCommand

In ConsoleServiceProvider::addConsoleCommands() each class from config/commands.php is created via $container->get($className). Any Throwable (missing binding, autowire failure, provider not registered) is caught — instead of the real command a DisabledCommand is added with the same name (COMMAND_NAME from the original class).

In php bin/console.php list output such commands have the description:

!!! WARNING: This command is disabled (possible missing dependencies).
Run command to see details. !!!

Typical picture with a “trimmed” console.php (without HTTP and components):

  • route:list — disabled (no HttpServiceProvider)
  • component:list, component:publish-assets — disabled (no ComponentsServiceProvider)
  • db:migrate, db:rollback — disabled (missing or boot() not completed for DatabaseServiceProvider)
  • db:seed, seeders:list, migration:list, view:clear — often remain active because their dependencies are simpler or do not need the full HTTP stack

To see the exact reason, run the disabled command:

php bin/console.php route:list

Example output:

Command Disabled: route:list

 [WARNING] This command cannot be executed because its dependencies are not met.
           Likely a required ServiceProvider is not registered in bootstrap/providers/.

 Original Class   Concept\Core\Console\Commands\RouteListCommand
 Error Detail     ... (container exception text, e.g. class not found)

Fix: add the corresponding provider to bootstrap/providers/console.php (see table above) and restart the console. For custom commands — same rule: if a command needs DatabaseInterface, without DatabaseServiceProvider it will also become disabled.

Core commands

Registered in config/commands.php:

CommandPurpose
db:migrateRun migrations
migration:listList rows in the migrations table (-l — limit)
db:rollbackRollback the last migration batch
db:seedAll seeders; -c "Fully\Qualified\Class" — one (full FQCN)
seeders:listList registered seeders
route:listRoute table; -F / --full-middleware — middleware FQCN
view:clearClear Twig cache directory (storage/cache/{view.cache_dir})
component:listList enabled components (ComponentRegistry)
component:publish-assetsCopy assets from ComponentInterface::assets() to public/

Examples

php bin/console.php db:migrate
php bin/console.php migration:list
php bin/console.php db:seed
php bin/console.php db:seed -c "Concept\Components\AuthAdmin\Database\Seeders\UserSeeder"
php bin/console.php seeders:list
php bin/console.php route:list
php bin/console.php route:list -F
php bin/console.php component:list
php bin/console.php view:clear

Component commands

A component adds commands via ComponentInterface::commands(). During ComponentsServiceProvider::boot() they are resolved from the container and added to the same ConsoleApplication. CLI does not register component view extensions/paths (only commands, migrations, seeders, providers).

// AuthAdminComponent::commands()
public function commands(): array
{
    return [
        UserListCommand::class,
    ];
}

// php bin/console.php user:list
// php bin/console.php user:list --limit=5

Application custom commands go in config/commands.php under // Custom Business Commands. Details — Creating commands.

Exit codes

Commands return Command::SUCCESS (0) or Command::FAILURE (1). In CI scripts check the exit code after php bin/console.php ....

Environment and config

CLI uses the same .env and ConfigServiceProvider as HTTP. APP_ENV drives config/{env}/ overrides and the component list (for example DebugBar only in config/dev/components.php).

Migrations and seeders require a correct DB connection in config/db.php (or via .env).

The console is for maintenance (migrations, cache, diagnostics) and local development. Long-running business logic belongs in services; keep the command as a thin call. If a command is “disabled” — first check CLI providers, not the command itself.