CLI Application Example
CLI Application Example
Hazaar's console layer — the same one that powers bin/hazaar and bin/dbitool — is available to any application. This example builds a standalone tasks command that lists, adds, and completes tasks, reusing the same Task model from the Web Application example to show that a CLI tool and a web app can share one codebase without duplicating logic.
Project Structure
app/
└── Models/
└── Task.php
bin/
└── tasks
src/
└── Console/
└── TaskModule.phpapp/Models/Task.php is the exact model from the Web Application example — see that page if you have not created it yet.
1. The Module
A Module groups related commands. Create src/Console/TaskModule.php:
<?php
namespace App\Console;
use App\Models\Task;
use Hazaar\Console\Input;
use Hazaar\Console\Module;
use Hazaar\Console\Output;
class TaskModule extends Module
{
protected function configure(): void
{
$this->setName('task')->setDescription('Manage tasks from the command line');
$this->addCommand('list', [$this, 'listTasks'])
->setDescription('List all tasks')
;
$this->addCommand('add', [$this, 'addTask'])
->setDescription('Add a new task')
->addArgument('title', 'The task title', true)
;
$this->addCommand('complete', [$this, 'completeTask'])
->setDescription('Mark a task as complete')
->addArgument('id', 'The task ID', true)
;
}
protected function listTasks(Input $input, Output $output): int
{
$tasks = (new Task())->all();
if (0 === count($tasks)) {
$output->writeln('No tasks yet. Add one with: tasks add "Buy milk"');
return 0;
}
foreach ($tasks as $task) {
$status = $task['complete'] ? '<fg=green>[x]</fg>' : '[ ]';
$output->writeln("{$status} #{$task['id']} {$task['title']}");
}
return 0;
}
protected function addTask(Input $input, Output $output): int
{
$title = $input->getArgument('title');
(new Task())->create($title);
$output->writeln("<fg=green>Added:</fg> {$title}");
return 0;
}
protected function completeTask(Input $input, Output $output): int
{
$id = (int) $input->getArgument('id');
if (!(new Task())->complete($id)) {
$output->writeln("<fg=red>No task with ID {$id}</fg>");
return 1;
}
$output->writeln("<fg=green>Completed task #{$id}</fg>");
return 0;
}
}Each command maps to one method: configure() registers the command name, description, and arguments; the method itself receives the parsed Input and an Output writer, and returns a process exit code. <fg=green>...</fg>-style tags in write()/writeln() are ANSI colour markup.
2. The Entry Point
Create bin/tasks — a thin script that boots the app's autoloader, registers the module, and runs:
#!/usr/bin/env php
<?php
use App\Console\TaskModule;
use Hazaar\Console\Application;
require __DIR__.'/../vendor/autoload.php';
$app = new Application('Tasks', '1.0.0');
$app->add(new TaskModule());
exit($app->run());Make it executable:
chmod +x bin/tasks3. Try It Out
$ bin/tasks task add "Buy milk"
Tasks v1.0.0
Environment: development
...
Added: Buy milk
$ bin/tasks task add "Write docs"
Added: Write docs
$ bin/tasks task list
[ ] #1 Buy milk
[ ] #2 Write docs
$ bin/tasks task complete 1
Completed task #1
$ bin/tasks task list
[x] #1 Buy milk
[ ] #2 Write docsRun bin/tasks help task to see the generated help for every command in the module, including arguments and descriptions — Application wires this up automatically from what configure() registered.
4. Adding Global Options
Application and Module both support global options, available to every command. This mirrors how bin/hazaar exposes --env/-e:
$app->addGlobalOption(
long: 'quiet',
short: 'q',
description: 'Suppress non-essential output',
);Read it from any command with $input->getGlobalOption('quiet').
Next Steps
- CLI Tools — reference for the built-in
hazaar,dbitool, andwarlockCLIs built the same way. - Using Databases — more on the DBI table API used by the
Taskmodel. - Creating a Web Application — the web front end that shares this same model.