Skip to content

Instantly share code, notes, and snippets.

@simonhamp
Last active February 10, 2021 10:41
Show Gist options
  • Save simonhamp/b3e628adcedc0af4ffdf5ae59e9fb6a3 to your computer and use it in GitHub Desktop.
Save simonhamp/b3e628adcedc0af4ffdf5ae59e9fb6a3 to your computer and use it in GitHub Desktop.
RemoteArtisan: A way to call another Laravel/Lumen application's artisan command from the context of the current application.
<?php
namespace App;
use Dotenv\Dotenv;
use Illuminate\Support\Str;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class RemoteArtisan
{
/**
* Implements an interface similar to Artisan::call.
*
* @param string $path The full path to the remote application's root
* @param string $command The Artisan command to run, e.g. 'vendor:publish'
* @param array $parameters The parameters to pass to the artisan command
* @param string $php The path to the PHP executable
* @return mixed
* @throws ProcessFailedException
*/
public static function call($path, $command, $parameters = [], $php = null)
{
// Prepare parameters for appending
$options = '';
foreach ($parameters as $name => $value) {
$value = '"'.$value.'"';
if (is_int($name)) {
$options .= " $value";
} else {
$value = ($value !== true ? "=$value" : '');
$options .= " {$name}{$value}";
}
}
// Swap out the full path to the current PHP executable binary
if (! $php) {
$php = PHP_BINDIR . '/php';
}
// Load .env for the target app
$env = new Dotenv($path);
$env->overload();
// Append the artisan command to the path
$artisan = Str::finish($path, '/').'artisan';
// Build up the final command
$command = "{$php} {$artisan} {$command}{$options}";
// Run the command in its environment
$process = new Process($command, $path);
$process->run();
// Restore original environment
$env = new Dotenv(base_path());
$env->overload();
// If there was no response
if (! $process->isSuccessful()) {
throw new ProcessFailedException($process);
}
return $process->getOutput();
}
}
@simonhamp
Copy link
Author

simonhamp commented Dec 21, 2017

For when you want/need to call a specific (local) Laravel/Lumen app's artisan command directly from another Laravel/Lumen application. (Of course, if you composer require the Symfony Process Component, Illuminate Support and PHP DotEnv you can use this from any PHP application to call a local artisan in another app.)

I had to create this a few weeks ago because I couldn't find any other way to do this and I finally had reason to pull it out into its own class for reuse, so I thought it was worth sharing.

It mimics the Artisan facade, providing a call static method. It's differences are that it needs the path to the application you're trying to run an artisan command against and optionally a path to the appropriate PHP binary to use (in case the default doesn't work for you for some reason).

I know it's quite rare that you'd ever really need this and I'm sure there must be a nicer solution out there that I'm missing, so I'd welcome comments, feedback and suggestions!

@simonhamp
Copy link
Author

simonhamp commented Dec 22, 2017

Simple usage example, from app located at /www/laravel-todo-app/ calling /www/laravel-invoice-app/:

<?php

use App\RemoteArtisan;

// For example, in an event handler when a Todo is completed...
RemoteArtisan::call('/www/laravel-invoice-app/', 'make:invoice', ['INV-0001', '[email protected]', '--send' => true]);

Of course, this assumes that the laravel-invoice-app defines and registers an Artisan command with the signature make:invoice and appropriate options.

@toxicchili
Copy link

Tested this with a vanilla php application calling a Lumen application and seems to work quite nicely. Thanks :-)

@kakposoe
Copy link

@simonhamp Thank you very much. This works perfectly

@simonhamp
Copy link
Author

@toxicchili @kakposoe glad that you've found this useful :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment