Description
The Application
class added in 3.3 is not currently used in the CLI context. This will prevent Application
from being the canonical way to bootstrap an application, load configuration, define routing and more. To remedy this the Console entry point needs to start using Application
.
We have also had a number of requests to allow console 'routing' and allow creating standalone CLI tools more easily.
Application::console hook
By adding a hook method to Application
we can enable applications to declare their CLI commands or continue using the auto-discovery we have today. The Application::console()
hook would be called after bootstrapping is complete, and is passed a CommandCollection
that allows commands to be added and aliases to be set
// In App\Application.
public function console(CommandCollection $collection)
{
$collection->add('bake', BakeShell::class);
$collection->add('asset_compress' AssetCompressShell::class);
// Auto-discover commands in the app/plugin (current behavior)
$collection->autoDiscover();
return $collection;
}
In addition to the hook method a Console.buildCommands
event would be emitted to enable plugins to register commands through the global event listener. This mirrors the Server.buildMiddleware
event for the HTTP server.
Each added command defines its option parser and sub-commands as they do today. The additional console hook lets users define the commands they want loaded, with short aliases, and load commands from plugins. It also makes it easier to split the console libraries into a standalone library.
The CommandCollection
class would provide the following methods:
addCommand($name, $command)
Add a command to the collection.removeCommand($name)
Remove a command.hasCommand($name)
Check if a command has been set.autoDiscover()
Search the application, and plugins for commands.- IteratorInterface for iterating attached commands.
- Other methods?
The CommandCollection
will be initialized with two commands. help/-h/--help
and -v/--version
will map to commands that provide their current behavior. Users will be able to replace/remove these commands if they wish.
Deprecate and replace ShellDispatcher
ShellDispatcher
is the current entry point into the console environment. To preserve full backwards compatibility, ShellDispatcher
would be left unchanged. A new class Cake\Console\CommandRunner
would be added. This new class would be responsible for:
- Accepting an
Application
instance and$argv
. - Use
Application::bootstrap()
to bootstrap the application - Use
Application::routes()
to load the HTTP routing so URL generation works. - Use `Application::console()`` to load the console routing.
- Use the created CommandCollection to dispatch the CLI command.
A sketch of the new CLI entrypoint is:
#!/usr/bin/php -q
<?php
// Check PHP version from composer.json, or default value.
$minVersion = '5.6.0';
if (file_exists('composer.json')) {
$composer = json_decode(file_get_contents('composer.json'));
if (isset($composer->require->php)) {
$minVersion = preg_replace('/([^0-9\.])/', '', $composer->requ
69FE
ire->php);
}
}
if (version_compare(phpversion(), $minVersion, '<')) {
fwrite(STDERR, sprintf("Minimum PHP version: %s. You are using: %s.\n", $minVersion, phpversion()));
exit(-1);
}
require dirname(__DIR__) . '/vendor/autoload.php';
use App\Application;
use Cake\Console\CommandRunner;
// Build the runner with an application and root executable name.
$runner = new CommandRunner(new Application(dirname(__DIR__) . '/config', 'cake');
exit($runner->run($argv));
Rename Shell to Command
To better fit the conventional names used across other frameworks and libraries, Cake\Console\Shell
should be renamed to Cake\Console\Command
.
Backwards Compatibility for upgrading applications
By leaving ShellDispatcher
alone, we ensure backwards compatibility. Upgrading applications would replace bin/cake.php
with a new file from the skeleton, and implement the console()
hook in their Application if the default auto-discovery was not sufficient.