It is helpful sometimes to write your own CLI commands to automate some tasks. You can write CLI commands using PHP and call them anywhere from the command line.
To get started create a folder where you will place your executable PHP file and add the newly created folder to the environment variable.
Linux environment variable
Edit /etc/environment and add your path and then restart the system.
Or see Linux $PATH.
Windows environment variable
See windows enviroment variable.
Create a file named drupal in it without any extension. this file can now be called from anywhere using the terminal because we have added its folder path to the environment variable.
To run the PHP script in the terminal add the below code to the top of the file.
#!/usr/bin/env php
Every CLI command has input/output in PHP to access user input we use $argv or $_SERVER[‘argv’] variable which contains an array of arguments the user entered into the terminal. and for output can use any of the PHP output functions echo, print, print_r, and var_dump.
drupal
#!/usr/bin/env php
<?php
//echo message to the terminal
echo "Hello world";
//debug user arguments
print_r($argv);
Now if you type drupal in your terminal above code will be executed.
CLI class
we will use the PHP CLI class to write our own commands
Cli.php
<?php
classCLI
{
//array of commands
private $commands = [];
//user input
private $input = "";
//arguments list
private $args = [];
//options list
private $options = [];
//current directory
private $dir;
//command
private $command = null;
publicfunction__construct()
{
//set dir to current directory
$this->dir =getcwd();
//get args from server
$args = $_SERVER['argv'];
//remove first arg it is executable file name
array_shift($args);
//set input to plain text of input args
$this->input =implode(" ",array_slice($args, 1));
foreach ($argsas $arg) {
if (strpos($arg, "--") === 0) {
//remove -- from option
$option =substr($arg, 2);
//seperate name value
$option_array =explode("=", $option);
$name = $option_array[0];
$value =isset($option_array[1]) ? $option_array[1] : true;
//add to options
$this->options[$name] = $value;
}else {
//add to args
$this->args[] = $arg;
}
}
}
publicfunctionrun()
{
//if no args run help
if (!$this->args) {
$this->help();
die();
}
$command_name =array_shift($this->args);
if (!isset($this->commands[$command_name])) {
die("\\e[31mError: \\e[39mUnkown command $command_name");
}
$command = $this->commands[$command_name];
$fn = $command['fn'];
//Binds and calls the closure
$fn->call($this);
}
publicfunctionaddCommand($name, $fn, $help = "")
{
$this->commands[$name] = [
'name' => $name,
'fn' => $fn,
'help' => $help
];
}
publicfunctionhelp()
{
echo "\\e[34m==== HELP ====" . PHP_EOL;
foreach ($this->commandsas $command) {
$length =strlen($command['name']);
echo "\\e[33m" . $command['name'] . "\\e[39m ";
if ($command['help']) {
printf("%".(30-$length)."s", "");
echo $command['help'];
echo PHP_EOL . PHP_EOL;
}
}
}
}
This class will help us create different commands to handle user input easily.
How to use the CLI class
include the CLI class in your drupal file and create an object of Cli class and register a test command.
drupal
#!/usr/bin/env php
<?php
require_once "Cli.php";
$cli =newCli();
/**
* add commands
*/
//test command
$cli->addCommand("test", function(){
echo "Current directory ".$this->dir.PHP_EOL;
echo "User input ".$this->input.PHP_EOL;
echo "arguments ".print_r($this->args, 1).PHP_EOL;
echo "options ".print_r($this->options, 1).PHP_EOL;
}, "Test command");
$cli->run();
$cli->addCommand method has 3 arguments first for the name of the command, the second is the closure function which will be executed and the third is the help text
$cli->addCommand($name, $fn, $help);
Now if you run the drupal command again without any arguments it will show the help.
and if you type test after drupal it will run the test function.
****
Adding drupal console launcher
Drupal console command can be added the same way we added the drush launcher.
drupal
#!/usr/bin/env php
<?php
require_once "Cli.php";
$cli =newCli();
/**
* add commands
*/
//Test command
$cli->addCommand("test", function () {
echo "Current directory " . $this->dir . PHP_EOL;
echo "User input " . $this->input . PHP_EOL;
echo "arguments " .print_r($this->args, 1) . PHP_EOL;
echo "options " .print_r($this->options, 1) . PHP_EOL;
}, "Test command");
//Drush command
$cli->addCommand("drush", function () {
$path = './vendor/drush/drush/drush';
//if we don't find the executable show error
if (!is_file($path)) {
echo "\\e[31mError: \\e[39mThe Drush launcher could not find a Drupal site to operate on. Please do *one* of the following:" . PHP_EOL;
echo " - Navigate to any where within your Drupal project and try again." . PHP_EOL;
echo " or install using \\e[34mcomposer require drush/drush" . PHP_EOL;
exit(1);
}
$cmd =realpath($path) . ' ' . $this->input;
echo PHP_EOL."\\e[32mGOING TO RUN $cmd\\e[39m".PHP_EOL.PHP_EOL;
//create a process
$process =proc_open($cmd, [0 => STDIN, 1 => STDOUT, 2 => STDERR], $pipes);
$proc_status =proc_get_status($process);
$exit_code =proc_close($process);
$exit_code = $proc_status["running"] ? $exit_code : $proc_status["exitcode"];
exit($exit_code);
}, "Run drush command");
//Drupal console command
$cli->addCommand("console", function () {
$path = './vendor/drupal/console/bin/drupal';
//if we don't find the executable show error
if (!is_file($path)) {
echo "\\e[31mError: \\e[39mDRupal console not found. maybe you haven\\'t install it or running in wrong dir" . PHP_EOL;
echo "to install run \\e[34mcomposer require drupal/console:~1.0 --prefer-dist --optimize-autoloader" . PHP_EOL;
exit(1);
}
$cmd =realpath($path) . ' ' . $this->input;
echo PHP_EOL."\\e[32mGOING TO RUN $cmd\\e[39m".PHP_EOL.PHP_EOL;
//create a process
$process =proc_open($cmd, [0 => STDIN, 1 => STDOUT, 2 => STDERR], $pipes);
$proc_status =proc_get_status($process);
$exit_code =proc_close($process);
$exit_code = $proc_status["running"] ? $exit_code : $proc_status["exitcode"];
exit($exit_code);
}, "Run drush command");
//run the cli
$cli->run();
Add a Comment