A base command and set of useful support trait/classes for Laravel or Laravel Zero commands.
composer require surgiie/console
All arguments and options are merged into a single $this->data
collection, giving a fluent object to pull and work with option/arg data.
<?php
namespace App\Console\Commands;
use Surgiie\Console\Command;
class ExampleCommand extends Command
{
public function handle()
{
$this->data->get("some-arg-or-option", 'default');
}
}
<?php
namespace App\Console\Commands;
use Surgiie\Console\Command;
class ExampleCommand extends Command
{
protected $signature = "example {--iterations=}";
public function handle()
{
// check if the user passed the --iterations flag in the command call.
if($this->optionWasPassed("iterations")){
}
}
}
Helpful for caching instances into a array property if going to be called repeatedly.
protected function example()
{
// get a value or store it in the cache array if it doesnt exist
return $this->fromArrayCache('example', fn () => new Example);
}
Utilize Laravel Validation for Arguments & Options
<?php
namespace App\Console\Commands;
use Surgiie\Console\Command;
class ExampleCommand extends Command
{
protected $signature = "example {--iterations=}";
public function rules()
{
return [
'interations'=>'required|numeric'
];
}
public function messages()
{
// custom validation messages
return ['...'];
}
public function attributes()
{
// custom validation attributes
return ['...'];
}
}
To allow your command to accept arbitrary options not part of the command signature:
<?php
namespace App\Console\Commands;
use Surgiie\Console\Command;
class ExampleCommand extends Command
{
public function arbitraryOptions()
{
return true;
}
public function handle()
{
// available if --something option is passed:
$something = $this->arbitraryData->get("something")
}
}
Note Arbitrary options are parsed as is, without any validation or transformation, so ensure you run escapeshellarg
or validate on any values that will be used in a shell command.
Transform, format, or sanitize input and arguments easily before handle
is called, using a validation rule like syntax:
protected function transformers() : array
{
return [
'some-option'=>['trim', 'ucwords']
];
}
protected function transformersAfterValidation() : array
{
return [
'some-option'=>['strtoupper']
];
}
*Note - For more, read the surgiie/tranformer readme docs.
Note - The base command performs some default tranformations before custom defined ones, they are as follows:
- All options with "date" in their name, are automatically converted to
\Carbon\Carbon
instances.
Provide a list of requirements before the handle is called:
public function requireSomethingOrFail(): string
{
// throw an exception:
throw new FailedRequirementException("Failed to meet some requirment");
// or return an error string:
return "Failed to meet some requirement";
}
public function requirements(): array
{
return [
'docker', //default for a string value checks if 'docker' is in $PATH with `which <value>`
"requireSomethingOrFail", //unless the method exists on the class, it will call that instead
function () { // can use callback that returns an error string
$process = new Process(['docker', 'info']);
$process->run();
return $process->getOutput() == '' ? 'Docker is not running' : '';
},
// can use also class constants or instances that have __invoke method.
new Example,
Example::class
];
}
Note If any of the methods above return an error string or raise FailedRequirementException
, the handle
method will not be called.
In addition, if you need custom logic to check if a string path is available, you can overwrite the following method:
/**
* Check if a executable is in $PATH.
*
* @param string $requirement
* @return string
*/
protected function checkWhichPath(string $requirement): string
{
$process = (new Process(['which', $requirement]));
$process->run();
return $process->getOutput() == '' ? "This command requires $requirement." : '';
}
An exented version of the blade engine is available to compile any textual file:
public function handle()
{
$contents = $this->render('/some/file', ['var'=>'example']);
}
// set a custom path for compiled/cached files. Default is /tmp/.compiled or tests/.compiled when running unit tests
public function bladeCompiledPath(): string
{
return '/custom/directory';
}
To give a better visual experience for long running tasks, you can use the runTask
method:
$this->runTask("Doing stuff", function($task){
sleep(4); // simulating stuff.
return true; // return whether task succeeded or not.
}, spinner: true); // show spinner while task is running.
Note - In order to show a animated spinner, the pcntl PHP extension must be installed. When this extension is not available, a static version of the spinner will appear instead.
When the task is completed, you can customize text shown the task has finished:
$this->runTask("Doing stuff", function($task){
sleep(4); // simulating stuff.
}, finishedText: "Finished doing stuff");
Automatically calls succeeded
and failed
based on handle
exit code.
public function succeeded()
{
// called when handle int is 0
$this->components->info("It ran successfully");
}
public function failed()
{
// called when handle int is 1
$this->components->info("It didnt run successfully");
}