laika-framework

CLI Reference

Every Laika project ships with a laika executable, generated by laikait/laika-engine when Composer builds the autoloader. Run php laika <command>.

php laika help                  # every command, grouped
php laika help model:make       # full usage for one command (partial names work: help model)

php laika help is always the authoritative list — it includes commands added by packages and by your own lf-app/Command/ classes.

How Arguments Work

Global Install (optional)

composer global require laikait/laika-engine

With Composer’s global vendor/bin on your PATH, run laika (no php prefix) from anywhere inside a Laika project — it finds the project by walking up from the current directory to the first folder containing lf-boot/app.php.


Application

Command Description
app:start [--host=127.0.0.1] [--port=8000] Start PHP’s built-in dev server. A busy port moves to the next free one. Serves public/ and sends every request through public/index.php, so static files follow lf-config/assets.php as in production. Dev only.
app:sync Write the laika and worker executables, ensure lf-storage/ (with a Deny from all .htaccess) and uploads/ exist, wipe lf-storage/cache/, write .htaccess if missing, generate the app key if missing or invalid, and rebuild the resource manifest. Runs on every composer install/update/dump-autoload. Run it by hand to restore a deleted laika or worker.
app:migrate [--table=<table>] Run up() on every discovered schema, then seed() on every schema. --table takes a table name (--table=users), not a class name.
app:cache Compile every resource into lf-storage/cache/resources.php. Used when DEBUG is false.
app:clear Delete the compiled resource manifest.
cache:clear [--data\|--templates] Flush the data cache and delete compiled Twig templates. The only command that clears compiled templates, which Twig does not refresh on its own with DEBUG off. With the memcached driver it clears the whole server.
cache:forget --key=<key> Remove one key from the data cache.
resource:list [--name=<resource>] List every resource, where it was declared, its path and entry count. Exits 1 if a class fails to load or breaks its contract — useful in CI.

Controllers

Command Description
controller:make <name> [--method=index] Create lf-app/Controller/<name>.php. If the file exists, append the method instead.
controller:list List controller classes.
controller:remove <name> Delete a controller (asks for confirmation).
controller:rename --old=<name> --new=<name> Rename the file and the class (asks for confirmation).

Models & Schemas

Command Description
model:make <name> [--table=<table>] [--id=id] [--uid=uid] [--connection=default] Create lf-app/Model/<name>.php and lf-app/Schema/<name>Schema.php. --table defaults to the lowercased name.
model:list List models, keyed by table.
model:remove <name> Delete the model and its <name>Schema, without asking.
model:rename --old=<name> --new=<name> [--table=] [--id=] [--uid=] Rename the model and its schema, optionally changing table/id/uid names.
schema:list List schemas app:migrate will run, keyed by table.

Routes

Command Description
route:make <name> [--method=get] [--file=web] Append Url::get('/<name>', '<Name>Controller@index')->name('<name>'); to lf-routes/<file>.php (created if missing). It does not create the controller.
route:list [--method=get] List routes: method, URI, handler and name.

Pipelines & Filters

Command Description
pipeline:make <name> Create lf-app/Pipeline/<name>.php.
pipeline:list List pipeline classes.
pipeline:remove <name> Delete a pipeline, without asking.
pipeline:rename --old=<name> --new=<name> Rename a pipeline class and file.
filter:make <name> Create lf-app/Filter/<name>.php.
filter:list List filter classes.
filter:remove <name> Delete a filter (asks for confirmation).
filter:rename --old=<name> --new=<name> Rename a filter class and file.

Jobs & Queue

Command Description
job:make <name> [--queue=default] [--max=3] Create lf-app/Job/<name>.php.
job:list List job classes.
job:remove <name> Delete a job (asks for confirmation).
job:rename --old=<name> --new=<name> Rename a job class and file.
queue:work [queue] Run the worker in the foreground for one queue (default default). Same as php worker [queue].
queue:failed [--queue=<name>] List failed jobs.
queue:retry <id> / queue:retry --all [--queue=<name>] Push failed jobs back onto their queue with the attempt count reset.
queue:flush [--hours=N] Delete all failed jobs, or those older than N hours (asks for confirmation).

See Queue.

Services & Relays

Command Description
service:make --name=<Name> --class=<Concrete\Class> Create lf-app/Service/<Name>.php (the relay) and lf-app/Relay/<Name>.php (the provider that binds --class as a singleton under <name>.accessor). --class must be an existing class.
service:remove <name> Delete both files.
relay:list List every container binding: accessor key → class.

See Services & Relay.

Templates

Command Description
template:make <name> [--ext=twig\|html] [--path=<sub/dir>] Create template/[<path>/]<name>.<ext>. For a sub-directory use --path — template:make dashboard --path=admin creates template/admin/dashboard.twig.
template:list List template files, grouped by directory.

Secrets

Command Description
secret:fix [--byte=32] Make sure lf-storage/keys/app.key exists and is valid; generate it only if not. Byte range 16–64.
secret:generate [--byte=32] Force a new key. Invalidates every encrypted value, signed value, CSRF token and JWT issued with the old one.

nginx

Command Description
nginx:make [--print] [--force] Write nginx.conf (deny rules + front-controller rewrite) as a fragment to include from a server block you already maintain. Keeps anything below its “YOU CAN EDIT AFTER THIS LINE” marker unless --force. --print writes to stdout.
nginx:server [--domain=localhost] [--port=80] [--php=<X.Y>] [--fastcgi=<socket or host:port>] [--root=<path>] [--upload=20M] [--output=<path>] Print a complete, self-contained server block rooted at public/ — rules, rewrite and PHP handler included, no include of any project file. --root is the project path on the target server, without /public. --output writes it to a path, e.g. /etc/nginx/sites-available/example.com — it refuses the project’s own nginx.conf, which is a fragment, not a server block.

See Deployment.

Commands

Command Description
command:make <name> [--signature=<group:action>] [--description="..."] Create lf-app/Command/<Name>Command.php.
help [command] The grouped command list, or detailed usage for one command.

What the Generators Create

Command Generated class
controller:make App\Controller\<Name> with one method
model:make App\Model\<Name> extending Laika\Engine\Model\Model ($table, $id, $uid, $connection, $softDelete, $casts) plus App\Schema\<Name>Schema
pipeline:make Implements PipelineInterface; handle() returns $next()
filter:make Implements FilterInterface; terminate() returns $next($response)
job:make Extends Laika\Engine\Queue\Abstracts\Job with handle() and failed()
service:make A Relay class plus a RelayProvider
command:make Implements Laika\Engine\Cli\Contracts\CommandInterface
template:make An HTML/Twig skeleton

Look over a generated schema before migrating. It adds deleted and deleted_at columns, and its seed() inserts an example row (only while the table is empty). Keep, change or delete them. See Models → Schemas.


Writing Your Own Commands

php laika command:make Report --signature=report:daily --description="Email the daily report"

Any class in lf-app/Command/ that implements Laika\Engine\Cli\Contracts\CommandInterface becomes a command — no registration.

namespace App\Command;

use Laika\Engine\Cli\Contracts\CommandInterface;
use Laika\Engine\Cli\Command\{Argument, Message};
use Laika\Engine\Cli\Table;

class ReportCommand implements CommandInterface
{
    public function signature(): string
    {
        return 'report:daily';
    }

    /** $args = everything after the signature; return 0 on success */
    public function handle(array $args, string $basePath): int
    {
        $date = Argument::getValue('date', $args, date('Y-m-d')); // --date=2026-09-01
        $dry  = Argument::getBool('dry', $args);                   // --dry

        if (!$dry && !Argument::readline("Send the report for {$date}?")) {
            Message::warning('Cancelled.');
            return 1;
        }

        Table::render('REPORT', ['Metric', 'Value'], [['orders', 42]]);
        Message::success('Report sent.');
        return 0;
    }

    public function command(): string
    {
        return 'php laika report:daily [--date=Y-m-d] [--dry]';
    }

    public function help(): array
    {
        return [
            'signature'   => $this->signature(),
            'description' => 'Email the daily report',
            'command'     => $this->command(),
            'inputs'      => [],
            'params'      => [],
        ];
    }
}
Helper Signature
Argument::getValue getValue(string $key, array $args, null\|int\|string $default = null): null\|int\|string
Argument::getBool getBool(string $key, array $args, bool $default = false): bool
Argument::readline readline(string $message, array $accepted = ['y','n'], string\|array $positive = 'y'): bool
Message::success/error/info/warning/suggestion (string $message, ...): void — coloured output
Table::render render(string $title, array $headers, array $rows): void

Things to know:


Example Workflow

# A model + schema for the users table
php laika model:make UsersModel --table=users

# A controller, and a route pointing at it
php laika controller:make UsersController --method=index
php laika route:make users                  # → Url::get('/users', 'UsersController@index')->name('users')

# Create the table
php laika app:migrate --table=users

# Middleware
php laika pipeline:make Authenticate
php laika filter:make LogAccess

# Check what got registered
php laika route:list
php laika resource:list