dflydev/embedded-composer-console
Embed a Composer console in your app using dflydev’s embedded Composer. Provides a programmatic, in-process way to run Composer commands and capture output, useful for tooling, installers, and automation without shelling out.
Installation Add the package via Composer:
composer require dflydev/embedded-composer-console
Register the service in your Laravel service provider (e.g., AppServiceProvider):
use Dflydev\EmbeddedComposerConsole\ComposerConsole;
public function register()
{
$this->app->singleton(ComposerConsole::class, function ($app) {
return new ComposerConsole($app['path.base'], $app['composer.json']);
});
}
First Use Case Embed a Composer command in a Laravel Artisan command:
use Dflydev\EmbeddedComposerConsole\ComposerConsole;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
class RunComposerCommand extends Command
{
protected $composer;
public function __construct(ComposerConsole $composer)
{
parent::__construct();
$this->composer = $composer;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$command = $this->composer->getApplication();
$command->setAutoExit(false);
$outputBuffer = new BufferedOutput();
$inputBuffer = new ArrayInput(['command' => 'update']);
$exitCode = $command->run($inputBuffer, $outputBuffer);
$output->writeln($outputBuffer->fetch());
return $exitCode;
}
}
Embedding Composer in Artisan Commands
Use the ComposerConsole service to execute Composer commands programmatically:
$composer = app(ComposerConsole::class);
$app = $composer->getApplication();
$app->run(new ArrayInput(['command' => 'install']), new BufferedOutput());
Integration with Laravel Tasks Chain Composer commands with Laravel tasks (e.g., post-deploy):
// In a service or command
$composer->getApplication()->run(
new ArrayInput(['command' => 'dump-autoload']),
new NullOutput()
);
Customizing Composer Configuration Override Composer’s global config (e.g., repositories) via Laravel config:
$composerConfig = [
'config' => [
'github-protocols' => ['https'],
],
];
$composer->setConfig($composerConfig);
Handling Output Streams Redirect Composer output to Laravel’s logging or notifications:
$output = new StreamOutput(fopen('php://temp', 'w+'));
$composer->getApplication()->run(
new ArrayInput(['command' => 'validate']),
$output
);
rewind($output->getStream());
$log = stream_get_contents($output->getStream());
composer install --no-dev).post-update-cmd).Illuminate\Foundation\Bootstrapped):
event(new ComposerUpdateEvent());
// In listener:
$composer->getApplication()->run(new ArrayInput(['command' => 'update']));
Path Resolution
Ensure $app['path.base'] points to the root of your project (not vendor/ or storage/). Composer commands fail if paths are misconfigured.
// Wrong: $app['path.storage']
// Right: $app['path.base']
Composer Lock Conflicts
Embedded Composer may ignore your composer.lock if not explicitly passed. Always use:
$composer = new ComposerConsole($projectDir, $composerJson, $lockFilePath);
Output Buffering
BufferedOutput captures only stdout. For full Composer output (including stderr), use:
$output = new CompositeOutput([
new BufferedOutput(),
new StreamOutput(fopen('php://stderr', 'w')),
]);
Auto-Exit Behavior
ComposerConsole’s getApplication() returns a Symfony Application with autoExit enabled by default. Disable it:
$app = $composer->getApplication();
$app->setAutoExit(false); // Critical for programmatic use!
--dry-run to avoid side effects:
$input = new ArrayInput(['command' => 'update', '--dry-run' => true]);
$input = new ArrayInput(['command' => 'diagnose', '-v' => true]);
$output = new StreamOutput(fopen('php://temp', 'w+'));
$composer->getApplication()->run($input, $output);
Log::info('Composer Output: ' . stream_get_contents($output->getStream()));
Custom Composer Commands
Extend the embedded Composer by adding custom commands to your project’s composer.json:
{
"scripts": {
"post-autoload-dump": "your:custom-command"
}
}
Then trigger them via:
$composer->getApplication()->find('your:custom-command')->run();
Environment-Specific Config Load Composer config dynamically based on Laravel’s environment:
$config = config("composer.{$app->environment()}");
$composer->setConfig($config);
Parallel Execution
Use Laravel’s queues to run Composer commands asynchronously (e.g., for dump-autoload):
RunComposerJob::dispatch('dump-autoload')->onQueue('composer');
class RunComposerJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public function handle(ComposerConsole $composer)
{
$composer->getApplication()->run(new ArrayInput(['command' => $this->command]));
}
}
Security
if (!in_array($input->get('command'), ['install', 'update', 'validate'])) {
throw new \RuntimeException('Composer command not allowed.');
}
composer.json and vendor/. Use chmod or Laravel’s filesystem permissions.How can I help you explore Laravel packages today?