jascha030 / cli
Service class for executing shell commands using symfony/process, heavily inspired by the CommandLine class in laravel/valet.
Requires
- symfony/console: ^6.0
- symfony/process: ^6.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.6
- phpunit/phpunit: ^9.5
- roave/security-advisories: dev-latest
This package is auto-updated.
Last update: 2025-03-01 00:37:16 UTC
README
Interface and implementation of a CLI Service class for executing shell commands with php, using symfony/process
and symfony/console
, heavily inspired
by the CommandLine class from laravel/valet
.
Getting Started
Requirements
- PHP
^8.0
- Composer
*
(but preferred2.2
or later)
Installation
composer require jascha030/cli
Usage
The package contents consist mostly of one simple service class implementing an interface. Next to that there are also some derivatives of these classes and interfaces.
ShellInterface
The main interface is the Jascha030\CLI\Shell\ShellInterface
, which requires a class to implement four methods.
interface ShellInterface { /** * Run a shell command. */ public function run(string $command, ?string $cwd = null, ?callable $onError = null): string; /** * Run a shell command with sudo user capabilities. */ public function runAsUser(string $command, ?string $cwd = null, ?callable $onError = null): string; /** * Run a shell command without writing output to the STDOUT or php. */ public function quietly(string $command, ?string $cwd = null, ?callable $onError = null): void; /** * Run a shell command with sudo user capabilities, without writing output to the STDOUT or php. */ public function quietlyAsUser(string $command, ?string $cwd = null, ?callable $onError = null): void; }
Default Implementation
This package also provides class as most-basic implementation of the Jascha030\CLI\Shell\ShellInterface
,
The Jascha030\CLI\Shell\Shell
class. This class implements all four methods.
All four methods use the Shell::runCommand
method, which is also directly available.
public function runCommand(string $command, ?string $cwd = null, ?callable $onError = null): string;
Below is a simple example of basic usage of the class
<?php use Jascha030\CLI\Shell\Shell; /** * Include Composer's autoloader. */ include __DIR__ . '/vendor/autoload.php'; $shell = new Shell(); // The console command's output is returned by the run method, as string. echo $shell->run("`which php` -v");
The above outputs the following
PHP 8.0.16 (cli) (built: Feb 18 2022 09:31:10) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.16, Copyright (c) Zend Technologies
with Xdebug v3.1.2, Copyright (c) 2002-2021, by Derick Rethans
with Zend OPcache v8.0.16, Copyright (c), by Zend Technologies
Note: this example output is specific to your environment, the specific version and extensions are, of-course dependent on your own environment.
Execute a command silently
$shell->quietly($command);
Executing commands as sudo user
// This acts as if you run your command prepended by sudo. $shell->runAsUser($command); // Which also can be done silently. $shell->quetlyAsUser($command);
All the methods, demonstrated above take the optional $cwd
(string) and $onError
(callable) parameters.
The $cwd
command, allows you to execute a command from another directory.
// Runs the command two directories above the current script's directory. $shell->run($command, dirname(__FILE__, 3));
The $onError
is a callback that can be passed to handle command failure.
Both these parameters are directly passed to the Process::fromShellCommandline()
method, for more info, refer
to the documentation of symfony's Process component.
Shell program binaries
If you are writing a CLI based around a commandline program which comes as executable binary, you can implement
the Jascha030\CLI\Shell\Binary\BinaryInterface
. These are just extensions on the ShellInterface
, requiring you to
provide a name, a version, and a path to the binary.
interface BinaryInterface extends ShellInterface { public function getName(): string; public function getPath(): string; public function getVersion(): ?string; }
To kickstart implementation, various Traits are available, together with an abstract class:
Jascha030\CLI\Shell\Binary\BinaryAbstract
Simple implementation of the threeBinaryInterface
methods, which values are provided through the constructor.Jascha030\CLI\Shell\Binary\Traits\ShellDecoratorTrait
The easiest way to implement the rest of the methods required by theShellInterface
, by delegating the commands to another instance of theShellInterface
, provided through the abstractShellDecoratorTrait::getShell()
method.Jascha030\CLI\Shell\Binary\Traits\SelfResolvingPathTrait
, For when the path to a binary can be provided by using thewhich
, command (e.g.which php
).Jascha030\CLI\Shell\Binary\Traits\SelfResolvingVersionTrait
, For when the version of a binary can be provided by using a command.- Defaults to
-v
, but can be overridden, by overloading theSelfResolvingVersionTrait::getVersionCommand()
method. - By default, it will match the output of the provided version command to a regex
pattern (
/\\d{1,2}\\.\\d{1,2}\\.\\d{1,2}/
), this can be overridden by overloading theSelfResolvingVersionTrait::getVersionRegex()
method. When this method returnsnull
it will skip the regex matching, and use the command's full output.
- Defaults to
Helpers
A set of helper functions is included in includes/helper.php
under the Jascha030\Cli\Helpers
namespace.
Get user, or sudo user when available.
\Jascha030\CLI\Helpers\user(): ?string;
Output a message to the console.
\Jascha030\CLI\Helpers\output(string $message, ?OutputInterface $output = null): void;
Output an error to the console.
\Jascha030\CLI\Helpers\error(string $message, ?OutputInterface $output = null): void;
Output an info message to the console.
\Jascha030\CLI\Helpers\info(string $message, ?OutputInterface $output = null): void;
Output a multiline message to the console.
\Jascha030\CLI\Helpers\multilineOutput(array $message, ?OutputInterface $output = null): void;
Output a multiline error to the console.
\Jascha030\CLI\Helpers\multilineError(array $message, ?OutputInterface $output = null): void;
Output a multiline info message to the console.
\Jascha030\CLI\Helpers\multilineInfo(array $message, ?OutputInterface $output = null): void;
Development
Clone this repo, and run composer install
inside the repo.
Code-style
A code-style is provided in the form of a php-cs-fixer
configuration in .php-cs-fixer.dist.php
. For easy execution,
use the provided Composer script command.
composer run format
If you have php-cs-fixer installed globally, pass it to the --config
argument of the fix
command.
php-cs-fixer fix --config=.php-cs-fixer.dist.php
Unit-testing
A configuration for phpunit
is provided in phpunit.xml
.
For easy execution, use the provided Composer script command.
composer run phpunit
If you have phpunit installed globally, and want to use that, pass the config in the --config
argument.
phpunit --config phpunit.xml
of the CommandLine class of
the laravel/valet
package.
Next to that, it obviously makes heavy use of various Symfony components, which makes your life as a php-developer a lot easier in many cases. For one, by not having to re-invent the wheel. And also, the usage of Symfony components, in almost every case guarantees, at least some level of interoperability with most other php frameworks, libraries and of-course composer.
License
This composer package is an open-sourced software licensed under the MIT License