Repository navigation
Terminal
The Machinjiri Terminal is the CLI entry point of the Machinjiri framework. It is built on top of
Symfony\Component\Console\Applicationand provides:
- Scaffolding generators for controllers, models, middleware, notifications, service providers, views, webhooks, jobs, migrations, seeders, and factories.
- Runtime utilities for the dev server, database testing, queue management, and network diagnostics.
- Task scheduling with cron-like tasks.
- Testing utilities (PHPUnit / Paratest).
If you are familiar with Laravel's artisan, you will feel right at home. The Terminal is modular — every category of commands lives in its own class that returns a list of Symfony Command instances through a static getCommands() method.
The Terminal ships with the Machinjiri core.
The terminal binary is usually exposed via an artisan or machinjiri file in your project root:
php artisan listIf you need to bootstrap it manually:
<?php
// artisan
require __DIR__ . '/vendor/autoload.php';
use Mlangeni\Machinjiri\Core\Artisans\Terminal\Terminal;
$terminal = new Terminal();
$terminal->run();# List all available commands
php artisan list
# Get help for a specific command
php artisan help make:controller
# Scaffold a controller
php artisan make:controller UserController
# Scaffold a model
php artisan make:model User
# Start a dev server on port 3000
php artisan run:dev
# Create and run a migration
php artisan db:migration:create create_users_table --blueprint
php artisan db:migration:migrate
# Start a queue worker (daemonized)
php artisan queue:work --daemon --queue=defaultTerminal
├── extends Symfony\Component\Console\Application
├── registers command classes on construction
└── exposes addCommandClass() for runtime extension
Command Classes (each returns array<Command>):
├── App → make:controller, make:model, make:middleware, get:env
├── PHPServerCommands → run:dev, stop:dev
├── ServiceProviderCommand → provider:make, provider:remove, provider:list, ...
├── QueueWorkerCommand → queue:make, queue:work, queue:failed, ...
├── ViewCommands → view:make, view:make-layout, view:make-partial
├── WebhookCommand → make:webhook
├── Network → network:ping, network:scan, network:ports, ...
├── DatabaseCommands → db:migration:*, db:seeder:*, db:factory:*
├── NotificationCommand → make:notification, notify:send, notify:test, ...
└── TaskSchedulerCommand → scheduler:list, scheduler:run, scheduler:create-task, ...
Shared Traits:
├── CommandHelper → executeWithStyle(), artisanContainer()
├── MigrationInstances → handler(), creator(), seeder(), factory()
├── NetworkTrait → networkManager()
├── QueueCommandHelper → queue generator + DB helpers
└── QueueWorkerValidationTrait → name validators
class Terminal extends Application
{
public const TERMINAL_VERSION = "2.0";
protected $commandClasses = [
App::class,
PHPServerCommands::class,
// ... more
];
protected function registerCommands(): void
{
foreach ($this->commandClasses as $commandClass) {
foreach ($commandClass::getCommands() as $command) {
$this->add($command);
}
}
}
}Every command class must implement public static function getCommands(): array returning an array of Command objects. This design makes command registration declarative and stateless.
Almost every command uses CommandHelper, which provides two critical methods:
Wraps execution with:
- A standard title banner
- Event hooks (
command.execute.success/command.execute.failed) - Consistent error handling
- Verbose trace output
protected function execute(InputInterface $input, OutputInterface $output): int
{
return $this->executeWithStyle($input, $output, 'App Controller', function (SymfonyStyle $ss) use ($input) {
// your logic
$ss->success("Done");
return Command::SUCCESS;
});
}Walks up the directory tree to locate bootstrap/app.php, loads it, and returns the application's service container:
$container = $this->artisanContainer();
$service = $container->resolve(SomeService::class);This is what lets commands access services bound in your app, without needing to know how the app bootstraps.
| Command | Description |
|---|---|
make:controller <name> |
Create a controller in app/Controllers/
|
make:model <name> |
Create a model in app/Model/
|
make:middleware <name> |
Create a middleware class in app/Middleware/
|
get:env |
Display all environment variables |
Example:
php artisan make:controller UserController
php artisan make:model User// app/Controllers/UserController.php (generated)| Command | Description |
|---|---|
run:dev [--port=3000] |
Start a local PHP dev server (default port 3000) |
stop:dev |
Stop the running dev server |
Example:
php artisan run:dev --port=8080
# Server Started :)
# PID => 12345
# address => 127.0.0.1:8080Logs are written to storage/dev-server/dev_server_YYYY_MM_DD.log.
| Command | Description |
|---|---|
db:migration:create <name> [--blueprint] |
Create a migration file |
db:migration:list |
List all migration files |
db:migration:remove <name> |
Remove a migration file |
db:migration:get-ran |
List migrations that have been applied |
db:migration:migrate |
Run all pending migrations |
db:migration:rollback |
Roll back the latest batch |
Example:
php artisan db:migration:create create_users_table --blueprint
php artisan db:migration:migrate
php artisan db:migration:get-ran💡 Migration names must be lowercase with underscores (
create_users_table), and cannot collide with reserved keywords.
| Command | Description |
|---|---|
db:seeder:create <name> [--migration] |
Create a seeder (optionally with a migration) |
db:seeder:run <name> |
Run one seeder |
db:seeder:run-all [--with-transaction] |
Run all seeders (optionally in a transaction) |
db:seeder:list |
List available seeders |
db:seeder:refresh |
Re-run all seeders from scratch |
| Command | Description |
|---|---|
db:factory:create <name> [--migration] |
Create a factory file |
db:factory:run <model> [-c 10] [--fake-only] |
Generate fake records |
Example:
php artisan db:factory:run User --count=50
php artisan db:factory:run User --count=10 --fake-only # don't persistThe queue subsystem is arguably the most feature-rich part of the Terminal.
| Command | Description |
|---|---|
queue:init |
Initialize the queue driver (creates DB schema for database driver) |
queue:make <name> [--type=database] [--config] [--register] [--command] |
Scaffold a new queue driver class |
| Command | Description |
|---|---|
queue:work |
Process jobs from the queue (foreground) |
queue:job <name> |
Process jobs of a specific type defined in config/commands.php
|
queue:supervisor [--concurrency=1] |
Keep N workers alive |
queue:worker-start |
Start workers (managed) |
queue:worker-stop |
Stop workers |
queue:worker-restart |
Restart workers |
queue:worker-status |
Show worker table (PID, heartbeat, memory) |
queue:worker-cleanup |
Remove orphaned PID files |
Worker options (queue:work):
--queue=default # queue name
--sleep=3 # seconds to sleep when empty
--memory=128 # max MB before restarting
--timeout=60 # job timeout
--tries=3 # attempts before failure
--max-jobs=0 # limit total jobs (0 = unlimited)
--daemon # run as a daemon
--stop-on-empty # exit when queue is drained
--force # override maintenance mode
--pid-file=/tmp/q.pid # write PID to file
--instance=1 # instance number for supervisor modeExample:
php artisan queue:init
php artisan queue:work --daemon --queue=emails --memory=256| Command | Description |
|---|---|
queue:make-job <name> |
Create a job class |
queue:status |
Show queue stats |
queue:health |
Check health of the queue driver |
| Command | Description |
|---|---|
queue:failed |
List failed jobs |
queue:retry <id|all> |
Retry one or all failed jobs |
queue:forget <id> |
Remove a failed job |
queue:flush |
Clear all failed jobs |
queue:clear |
Empty a queue |
queue:db-info |
Show and test the database driver connection |
Example:
php artisan queue:make-job SendWelcomeEmail --type=email --queue=emails
php artisan queue:work --queue=emails --daemon
php artisan queue:failed
php artisan queue:retry all🔒
queue:worksupports graceful shutdown viapcntlsignals (SIGINT, SIGTERM) — press Ctrl+C and the current job completes before the worker exits.
| Command | Description |
|---|---|
provider:make <name> |
Generate a service provider |
provider:remove <name> [--config] |
Remove a service provider |
provider:list [--details] |
List all providers |
provider:init |
Create all basic providers |
provider:stub <name> <stub> |
Generate from a custom stub |
provider:register <name> |
Register a provider in config/providers.php
|
provider:unregister <name> |
Unregister a provider |
provider:info <name> |
Show provider info (bindings, singletons, aliases) |
provider:thirdparty-auth |
Scaffold ThirdPartyAuthServiceProvider with OAuth config |
Example:
php artisan provider:make PaymentServiceProvider --bind="PaymentGateway=StripeGateway"
php artisan provider:register PaymentServiceProvider
php artisan provider:info PaymentServiceProviderThe generated provider class template supports:
protected array $bindings = [
'PaymentGateway' => StripeGateway::class,
];
protected array $singletons = [
'PaymentConfig' => PaymentConfig::class,
];
protected array $aliases = [
'pay' => 'PaymentGateway',
];
protected bool $defer = false;| Command | Description |
|---|---|
view:make <name> [-l layout] [-f] |
Create a view template (dot notation) |
view:make-layout <name> |
Create a layout |
view:make-partial <name> |
Create a partial |
Example:
php artisan view:make admin.dashboard --layout=layouts.admin
php artisan view:make-layout layouts.admin
php artisan view:make-partial partials.headeradmin.dashboard becomes resources/views/admin/dashboard.php.
| Command | Description |
|---|---|
make:webhook <name> |
Generate webhook components (--controller, --config, --handler, --provider, --all) |
Generates:
-
Controller →
app/Controllers/{Name}WebhookController.php -
Handler →
app/Webhooks/Handlers/{Name}WebhookHandler.php -
Config entry →
config/core/webhooks.php -
Service Provider →
app/Providers/{Name}WebhookServiceProvider.php
Example:
php artisan make:webhook StripeNext steps printed after generation:
- Add route: $router->post('/webhook/stripe', [StripeWebhookController::class, 'handle'])
- Set STRIPE_WEBHOOK_SECRET in .env
| Command | Description |
|---|---|
make:notification <name> [-c mail,sms] [-Q] |
Create a notification class |
notify:channels [--json] |
List registered channels |
notify:list [--path] |
List discovered notification classes |
notify:show <class> |
Inspect a notification class |
notify:send <class> --to=... [--queue] |
Send a notification ad-hoc |
notify:test <channel> --to=... |
Fire a lightweight test notification |
notify:events |
List emitted notification events |
Example:
# Create a notification
php artisan make:notification OrderShipped -c mail,sms,database --queue
# Send it to a one-off recipient
php artisan notify:send OrderShipped \
--to=user@example.com \
--data='{"orderId":42}' \
--queue
# Test a channel
php artisan notify:test mail --to=admin@example.com| Command | Description |
|---|---|
network:ping <host> [--timeout=2] |
Ping a host |
network:scan <subnet> [--concurrent=20] |
Scan CIDR subnet for hosts |
network:ports <host> [start] [end] [--timeout=2] |
Scan ports |
network:interfaces |
List local network interfaces |
network:monitor [-a host[:alias]] [-w] |
Monitor hosts (optionally watch) |
network:dns <domain> [type] |
Perform DNS lookup (A, MX, NS, TXT, ...) |
Example:
php artisan network:ping google.com
php artisan network:scan 192.168.1.0/24 --concurrent=50
php artisan network:ports example.com 22 443
php artisan network:dns example.com MX
⚠️ These commands require anetwork.managerservice bound in your container:$container->singleton('network.manager', fn($c) => new NetworkManager(new NetworkConfig()));
A cron-like scheduler backed by TaskManager and TaskScheduler.
| Command | Description |
|---|---|
scheduler:list [--enabled] [-g group] |
List scheduled tasks |
scheduler:create-task <name> [-r] [-c cron] [-t type] |
Create a task class |
scheduler:run [-t taskId] [-f] |
Run due tasks (or a single one) |
scheduler:status |
Show scheduler status |
scheduler:enable <id> |
Enable a task |
scheduler:disable <id> |
Disable a task |
scheduler:clean [-d days] |
Remove execution history older than N days |
scheduler:stats [id] |
Show execution statistics |
scheduler:cache-preload |
Warm up the scheduler cache |
scheduler:cache-clear |
Clear the scheduler cache |
Example:
php artisan scheduler:create-task SendDailyReport --cron="0 9 * * *" --register
php artisan scheduler:list --enabled
php artisan scheduler:run
php artisan scheduler:stats 1Crontab integration:
* * * * * cd /path/to/project && php artisan scheduler:run >> /dev/null 2>&1| Command | Description |
|---|---|
test [--parallel] [--coverage] [--group=] [--filter=] [--testsuite=] |
Run the test suite |
Example:
php artisan test --parallel --coverage
php artisan test --filter=testUserCreation --testsuite=Feature$terminal = new Terminal();
$terminal->addCommandClass(MyCustomCommands::class);
$terminal->run();MyCustomCommands just needs:
class MyCustomCommands
{
public static function getCommands(): array
{
return [
new class extends Command {
use CommandHelper;
// ...
},
];
}
}<?php
namespace App\Console\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Style\SymfonyStyle;
use Mlangeni\Machinjiri\Core\Artisans\Terminal\Commands\CommandHelper;
class MyCommands
{
public static function getCommands(): array
{
return [
new class extends Command {
use CommandHelper;
public function __construct()
{
parent::__construct('my:hello');
$this->setDescription('Says hello');
}
protected function configure(): void
{
$this->addArgument('name', InputArgument::REQUIRED, 'Your name');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
return $this->executeWithStyle($input, $output, 'Hello Command', function (SymfonyStyle $ss) use ($input) {
$name = $input->getArgument('name');
$ss->success("Hello, {$name}!");
return Command::SUCCESS;
});
}
},
];
}
}Register it:
$terminal->addCommandClass(\App\Console\Commands\MyCommands::class);It guarantees:
- Consistent styling
- Structured error handling
- Event hooks fire automatically
return $this->executeWithStyle($input, $output, 'My Task', function (SymfonyStyle $ss) use ($input) {
// Your business logic
return Command::SUCCESS;
});Use $this->artisanContainer() to resolve paths:
$app = $this->artisanContainer();
$controllersDir = $app->app . '/Controllers/';Reserved names like class, interface, trait should never collide with user-supplied migration/seeder names.
For rich CLI output use:
$ss->table(['Column A', 'Column B'], $rows);
$ss->section('Section Title');
$ss->listing(['item 1', 'item 2']);
$ss->progressStart(100);if ($output->isVerbose()) {
$ss->text('Debug: ' . print_r($data, true));
}Wrap heavy loops with signal checks, especially queue workers. The ArtisanBackgroundWorker already does this.
CommandHelper::artisanContainer() walks up to 10 levels looking for bootstrap/app.php. Make sure:
- You run commands from within the project directory.
-
bootstrap/app.phpexists and returns aContainer.
Check write permissions in app/Controllers, database/migrations, etc.
php artisan queue:initThis will create queue_jobs and queue_failed_jobs tables via DatabaseQueueSchema.
Queue workers will fall back to polling without signal handling. Install pcntl for graceful shutdown.
You need to bind network.manager and network.config in a service provider:
$this->app->singleton('network.manager', function ($app) {
return new \Mlangeni\Machinjiri\Core\Components\Network\Tools\Manager(
new \Mlangeni\Machinjiri\Core\Components\Network\Tools\NetworkConfig()
);
});Every command executed through executeWithStyle() fires:
EventListener::artisan('command.execute.success', ['module' => $title, 'handler' => $handler]);
EventListener::artisan('command.execute.failed', ['module' => $title, 'error' => $e->getMessage()]);You can subscribe to these to add metrics, logging, or notifications:
EventListener::listen('command.execute.failed', function ($ctx) {
Log::error("Command failed: {$ctx['module']}", $ctx);
});DatabaseQueueSchema provides static helpers:
DatabaseQueueSchema::getMySqlEssentialSchema('queue_jobs', 'queue_failed_jobs');
DatabaseQueueSchema::getPgsqlFullSchema();
DatabaseQueueSchema::getSqliteFullSchema();You can extend this pattern for other subsystems (e.g., CacheSchema, SessionSchema).
ArtisanBackgroundWorker orchestrates:
-
Maintenance mode check (skipped with
--force). - Options assembly (sleep, memory, timeout, etc.).
-
PID file creation (with
register_shutdown_function()cleanup). -
Signal registration (SIGINT/SIGTERM →
worker->stop()). -
Heartbeat callbacks (if the worker implements
setHeartbeatCallback()). - Statistics printed after each run: processed, failed, memory, last job.
php artisan queue:supervisor --concurrency=4 --daemonBackgroundWorkerManager keeps exactly N workers alive, restarting crashed ones and cleaning orphaned PIDs on demand via queue:worker-cleanup.
Register in your NotificationManager:
$manager->extend('slack', function ($config) {
return new SlackChannel($config['webhook_url']);
});Then in a notification:
public function via(NotifiableInterface $notifiable): array
{
return ['mail', 'slack'];
}
public function toSlack(NotifiableInterface $n): array
{
return ['text' => 'Order shipped!'];
}The Machinjiri Terminal is a modular, extensible command framework that covers:
| Area | Purpose |
|---|---|
| Generators | Scaffold classes for controllers, models, migrations, jobs, notifications, providers, views, webhooks |
| Runtime | Dev server, database connectivity tests, network diagnostics |
| Data | Migrations, seeders, factories |
| Async | Queue workers, jobs, failed job retry, supervisor management |
| Messaging | Notification channels, ad-hoc sends, inspection |
| Ops | Task scheduler with cron expressions, cache preload/clear, execution stats |
Its design (getCommands() + CommandHelper + artisanContainer()) makes it trivial to add your own commands without touching the framework core.
Machinjiri Docs
- Home
- Learn
- Build
-
Tutorials
- Routing
- Controllers and Middleware
- Views and Templates
- Database ORM
- Eloquent Database ORM
- Errors and Exceptions
- Forms and Validation
- Http
- Events and Logging
- Services and DI
- Security
- Authentication
- Caching
- File System
- Date and Time
- Debugging
- Queue and Jobs
- Task Scheduling
- Transport (Mail, SMS)
- LDAP
- Notifications
- Webhooks
- UUID Generations
- Terminal
- Helper Function
- Reference