Writing Commands
Commands let you automate repetitive tasks—whether it's spinning up a project, running tests, or deploying your app. You can wrap all that logic into reusable commands that you or your team run in a heartbeat.
Choosing Seedling over Leaf MVC
If you're focused on building command-line tools rather than full web apps, consider using Leaf's Seedling over Leaf MVC. Seedling offers a lightweight, optimized environment solely for CLI workflows — no HTTP or view layers required. It's perfect when your project is all about commands and utilities.
This documentation covers both Leaf MVC and Seedling.
Creating a command
You can create a new command using the g:command command. This command will create a new command class in your app/console directory.
leaf g:command cache:purgeThis will create a CachePurgeCommand.php file in your app/console directory. The file will contain a class that extends the Command class and implements the handle() method.
<?php
namespace App\Console;
use Leaf\Sprout\Command;
class CachePurgeCommand extends Command
{
protected $signature = 'cache:purge
{argument? : argument description}
{--o|option? : option description}';
protected $description = 'cache:purge command\'s description';
protected $help = 'cache:purge command\'s help';
/**
* Main body for your command
*/
protected function handle()
{
$this->comment(
"cache:purge command's output {$this->argument('argument')} {$this->option('option')}"
);
return 0;
}
}This has a few parts:
protected $signature: This is where you define the name of your command, its arguments, and its options. In this example, the command is namedcache:purge, it has one optional argument namedargument, and one optional option namedoptionwith a shortcut ofo. This means that to call this command, you would runleaf cache:purgein your terminal, and it can accept an optional argument and option like this:leaf cache:purge myArgument --option myOptionorleaf cache:purge myArgument -o myOption.protected $description: This is a brief description of what your command does. This will be displayed when you runleaf listin your terminal.protected $help: This is a more detailed description of what your command does. This will be displayed when you runleaf cache:purge --helpin your terminal.protected function handle(): This is where you put the main logic for your command. This method will be called when you run your command in the terminal. In this example, it simply outputs a comment to the console with the values of the argument and option that were passed in.
Unlike in the Symfony console, you don't have to manually deal with the $input and $output, or use a config method to define your arguments and options. Sprout makes it easier to work with commands by providing methods that allow you to access the input and output directly from within your command class.
After creating the command, Leaf will automatically register it so you can start using it right away.
Command Arguments
Command arguments are values that are passed to the command when it is run in the console. For example, if you have a command named example and you run it like this:
leaf example argument1 argument2For example, with system commands like cd, the argument is the directory you want to change to. In this case, argument1 and argument2 are arguments that are passed to the command.
To define an argument for your command, you need to add it to the protected $signature property of your command class. You can define whether the argument is required or optional by adding a ? at the end of the argument name.
protected $signature = 'example
{argument1 : argument1 description}
{argument2? : argument2 description}';In this case, argument1 is a required argument and argument2 is an optional argument, so a user could run the command like this:
leaf example value1Or passing both arguments like this:
leaf example value1 value2You can then access the argument in the command's body using the argument() method.
protected function handle()
{
$this->comment("example command's output {$this->argument('argument1')} {$this->argument('argument2')}");
}In some cases, you might want to define an argument that can accept multiple values. You can do this by adding * at the end of the argument name.
protected $signature = 'example
{argument* : argument description}';In this case, argument can accept multiple values, so a user could run the command like this:
leaf example value1 value2 value3Command Options
Command options are also known as flags or switches, and they are additional parameters that modify the behavior of a command. They are typically optional and can be specified in various ways, such as with a -- prefix or a shorthand - prefix. For example, if you have a command named example and you run it like this:
leaf example --option1 --option2 valueForOption2 -o valueForOption3To add an option to your command, you need to add it to the protected $signature property of your command class. You can define whether the option is required or optional by adding a ? at the end of the option name. You can also define a shortcut for the option by adding it before the option name, separated by a |.
protected $signature = 'example
{--option1 : option1 description}
{--option2? : option2 description}
{--o|option3? : option3 description}';In this case, option1 is required, option2 is optional, and option3 is optional with a shortcut of o. A user could run the command like this:
leaf example --option1 --option2 valueForOption2 -o valueForOption3You can then access the option in the command's body using the option() method.
protected function handle()
{
$this->comment("example command's output {$this->option('option1')} {$this->option('option2')} {$this->option('option3')}");
}Command Output
Sprout allows you to easily output text to the console using various methods. This makes it easier to format your output and make it more readable. You can use write(), writeln(), comment(), info() and error() methods.
write()
This method writes text to the console.
public function handle()
{
$this->write('Hello World');
}writeln()
This method writes text to the console and adds a new line.
public function handle()
{
$this->writeln('Hello World');
}Styled Output
Leaf Sprout comes with a built-in output styling system that allows you to style your output using a simple API inspired by Symfony Console. Here's an example of how you can style your output:
$this->write("<info>Hello</info>, <comment>world</comment>!");
$this->write("<error>Error occurred!</error>");
$this->write("<question>Are you sure?</question>");Or you can use pre-configured styles like success(), error(), warning(), and info():
$this->success('Operation successful');
$this->error('Operation failed');
$this->warning('This is a warning');
$this->info('This is some information');Later versions will include more advanced styling options modelled after TailwindCSS and TermWind.
User Input/Prompts
Leaf Sprout provides a unique, dead-simple way to interact with users via the console. You can ask questions, get input, and even create interactive prompts. Prompts basically allow you to ask a question and get a response from the user.
$name = sprout()->prompt([
'type' => 'text',
'message' => 'What is your name?',
]);
$command->write("Hello, $name!"); // Hello, John Doe!This will display a prompt in the console asking the user for their name.
? What is your name?And when the user types their name and presses enter, it will be stored in the $name variable. This is a simple text prompt, but you can create more complex prompts as well.
Confirm Prompt
A confirm prompt is a simple yes/no question that the user can answer by typing y or n. You can create a confirm prompt like this:
$confirm = sprout()->prompt([
'type' => 'confirm',
'message' => 'Do you want to continue?',
]);
if ($confirm) {
$command->write("Continuing...");
} else {
$command->write("Exiting...");
}This will display a prompt in the console asking the user if they want to continue.
? Do you want to continue? (Y/n)And when the user types y or n, it will be stored in the $confirm variable as a boolean value.
Select Prompt
A select prompt allows the user to choose from a list of options. You can create a select prompt like this:
$appType = sprout()->prompt([
'type' => 'select',
'message' => 'What type of project do you want?',
'default' => 0,
'choices' => [
['title' => 'Leaf App', 'value' => 'leaf'],
['title' => 'Laravel App', 'value' => 'laravel'],
['title' => 'CodeIgniter App', 'value' => 'codeigniter'],
['title' => 'Symfony App', 'value' => 'symfony'],
['title' => 'CakePHP App', 'value' => 'cakephp'],
],
]);
$command->write("You selected: $appType"); // You selected: leafThis will display a prompt in the console asking the user to select a project type.
? What type of project do you want? (Use arrow keys)
> Leaf App
Laravel App
CodeIgniter App
Symfony App
CakePHP AppAnd when the user selects an option and presses enter, the value of the selected option will be stored in the $appType variable. In this case, if the user selects "Leaf App", the value leaf will be stored in the $appType variable.
Confirmation Prompt
For simple yes/no confirmations, you can use the confirm() method which is a shorthand for creating a confirm prompt.
if (sprout()->confirm('Do you want to continue?')) {
$command->write("Continuing...");
} else {
$command->write("Exiting...");
}This works the same way as the confirm prompt example above, but it's more concise.
Multi-question Prompts
You can also ask multiple questions in a single prompt by passing an array of questions to the prompt() method. Each question can have its own type, message, and other options.
$answers = sprout()->prompt([
[
'type' => 'text',
'name' => 'username',
'message' => 'What is your name?',
],
[
'type' => 'confirm',
'name' => 'userConfirm',
'message' => 'Are you above 18?',
],
[
'type' => 'select',
'name' => 'userSelect',
'message' => 'What is your favorite color?',
'choices' => [
['title' => 'Red', 'value' => 'red'],
['title' => 'Green', 'value' => 'green'],
['title' => 'Blue', 'value' => 'blue'],
],
],
]);
$command->write("Hello, {$answers['username']}!"); // Hello, John Doe!
$command->write($answers['userConfirm'] ? "You are above 18." : "You are below 18."); // You are above 18.
$command->write("Your favorite color is {$answers['userSelect']}."); // Your favorite color is red.This will display a series of prompts in the console asking the user for their name, if they are above 18, and their favorite color, one after the other. When the user answers all the questions, their answers will be stored in the $answers array, which you can then access using the question names as keys, as well as their order in the array.
We recommend using the name key to access the answers, as it makes your code more readable and easier to maintain. On top of that, some questions may be optional, and if the user skips them, the answers array may not have the same number of elements as the questions array. Using the name key ensures that you can always access the correct answer regardless of whether the question was answered or not.
Optional Questions
There are situations where you would want to skip asking the user a question based on some condition. You can do this by setting the type key to null based on a condition.
$askName = true; // Change this to false to skip the name question
$answers = sprout()->prompt([
[
'type' => $askName ? 'text' : null,
'name' => 'username',
'message' => 'What is your name?',
],
[
'type' => 'confirm',
'name' => 'userConfirm',
'message' => 'Are you above 18?',
],
]);You can also use a closure to determine whether to ask the question or not. The closure will receive the current answers array as its only argument, allowing you to make decisions based on previous answers.
$answers = sprout()->prompt([
[
'type' => 'text',
'name' => 'username',
'message' => 'What is your name?',
],
[
'type' => function ($answers) {
return strtolower($answers['username']) === 'admin' ? null : 'confirm';
},
'name' => 'userConfirm',
'message' => 'Are you above 18?',
],
]);Shell Processes
Sometimes, you may want to run a shell command from within your command. You can do this using the sprout()->process() method. This method allows you to run a shell command and capture its output.
$process = sprout()->process('ls -la');
$process->run();
if ($process->isSuccessful()) {
$output = $process->getOutput();
$command->write($output);
} else {
$error = $process->getErrorOutput();
$command->error($error);
}This will run the ls -la command and capture its output. If the command is successful, it will output the result to the console. If the command fails, it will output the error message to the console.
You can also use the shorter sprout()->run() method which is a shorthand for creating a process and running it.
sprout()->run('pnpm create naytive-app my-app');Composer/Npm Commands
Sprout also includes built-in methods for running Composer and NPM commands. This makes it easy to manage your dependencies from within your command.
sprout()->composer()->install('leafs/leaf');
sprout()->composer()->runScript('dev');
sprout()->composer()->remove('some/package');
$composerJsonFile = sprout()->composer()->json();
sprout()->npm()->install('express');
sprout()->npm()->runScript('build');
sprout()->npm()->remove('some-package');
$packageJsonFile = sprout()->npm()->json();