Console — overview
Everything done around the project is done through one file — call. It
starts the server, generates classes, applies the schema, manages background
components and runs scripts of your own. One argument parser, one output format, one
container.
Why a console
Development needs more than the request–response cycle: create a component, bring up the server, apply the schema, warm a cache, start a background handler, run a script once. Without a common tool that is a scatter of files in the project root, each with its own way of taking arguments and its own idea of how to print an error.
call gives one entry point: the same argument parsing, the same output, access to
the container and to the application configuration — for the built-in commands and
for yours alike.
How a call is structured
php call <command> [subcommand] [arguments] [-flags] [--options[=value]]Parsing splits $argv into three parts:
| Part | What it is | Example |
|---|---|---|
| Arguments | Positional values | call make .User → make, .User |
| Flags | Single-character, they stack | -csr → c, s, r |
| Options | --key or --key=value |
--port=9000, --mvc |
The first argument is the command name; without one, help runs. Flags may be
written separately or stuck together: -c -s -r and -csr are equivalent.
Short names
Four commands have aliases:
| Alias | Command |
|---|---|
sc |
script |
proc |
process |
dmn |
daemon |
sch |
schedule |
Running it from anywhere
The call file contains a chdir(__DIR__), so the commands work from any directory
— just give the path:
php /srv/my-app/call mapping showThat is also what makes calls from systemd, cron and docker exec predictable: the
working directory does not matter.
The commands
Development
| Command | What it does | |
|---|---|---|
make |
Creates components from templates | → |
run |
Starts the application | → |
mapping |
Shows the route table | → |
script |
Runs commands of yours (sc) |
→ |
Environment and data
| Command | What it does | |
|---|---|---|
cfg |
.env, the project key, Docker, shell completion |
→ |
db |
Connection, migrations, the connection pool | → |
storage |
The service directories | → |
di |
The scanner cache and #[Async] proxies |
→ |
Background components
| Command | What it does | |
|---|---|---|
process |
Processes: start, stop, state (proc) |
→ |
daemon |
Daemons and their worker fleets (dmn) |
→ |
schedule |
The scheduler and its task list (sch) |
→ |
Service
| Command | What it does |
|---|---|
help |
The command list, versions, help for one command |
complete |
The internal entry point for shell completion; not called by hand |
Help
php call # the same as help
php call help # the command list + PHP, kernel and project versions
php call help make # detailed help for one command
php call make -h # the same thing, as a flagcall help with no arguments also prints the environment — the kernel version, the
PHP version, the SAPI and the project root. That is the first thing worth attaching
to a “why does this not work for me” question.
Shell completion
php call cfg completion # print the script to stdout
php call cfg completion -i # install it
php call cfg completion -if # reinstall over the topThe shell is detected from $SHELL. For zsh the file goes to
~/.zsh/completions/_call and an fpath line is appended to ~/.zshrc; for bash, to
~/.bash_completion.d/call. Once installed, command names, subcommands and — where it
makes sense — the project’s class names are completed.
A command of your own
A class extending Cmd. The scaffold is php call make -n .Sync:
use Flytachi\Winter\Console\Inc\Cmd;
class Sync extends Cmd
{
public static string $title = 'sync external data';
public function handle(): void
{
$from = $this->args['options']['from'] ?? 'yesterday';
self::printInfo("syncing since {$from}");
// ...
self::printSuccess('done');
}
public static function help(): void
{
self::printInfo('call script main.command.Sync --from=2026-01-01');
}
}php call sc main.command.Sync --from=2026-01-01| Class member | Role |
|---|---|
handle() |
The command’s body |
static $title |
The line in the call script list listing |
static help() |
Help; printed on -h or --help automatically |
init() |
An optional hook before handle() |
The arguments arrive in $this->args — as those same three parts: arguments,
flags, options.
Dependencies
The command is created by the container, so injection works as it does everywhere else:
class Sync extends Cmd
{
#[Autowired] private ExchangeService $exchange;
#[Autowired] private LoggerInterface $logger;
public function handle(): void
{
$this->logger->info('sync started');
$this->exchange->pull();
}
}Cmd or CmdCustom
Cmd |
CmdCustom |
|
|---|---|---|
| A title in the listing | $title |
no |
Handling -h / --help |
Automatic | No |
The help() method |
Required | Not needed |
| When to take it | A command people will use | A one-off script |
Both are found by the scanner and both are run through call script. The only
difference is how much boilerplate is mandatory — see
script.
`call <name>` will not run your command
The first-level names — make, run, db — belong to the framework: they resolve
to kernel classes. Your commands live in your namespace and are called through
call script <path.Class> or the short call sc.
That way your command’s name will never collide with a new framework command.
Output
There is no need to echo: Printer has ready-made shapes, and the whole console
output looks alike:
| Method | What it gives |
|---|---|
printSuccess() · printError() |
A success, and an error block with a stack trace |
printInfo() · printWarning() |
The [i] and [!] marks |
printKeyValue() |
An aligned key–value pair |
printBadge() |
A line with a status on the right: OK, EXIST, FAILED |
printStep() |
Progress of the [3/12] kind |
printTitle() · printLabel() · printDivider() |
A heading, a subheading, a divider |
An exception escaping handle() is caught and printed through printError() — the
command does not crash into the console with a PHP stack trace.
Next
- make — generating components
- run — starting the application
- script — commands of your own
- Application components — what exactly
runstarts