Skip to content

Instantly share code, notes, and snippets.

@ejunker
Created November 11, 2019 21:26
Show Gist options
  • Save ejunker/e084a1c5b812bbb48afd3717ec167bbe to your computer and use it in GitHub Desktop.
Save ejunker/e084a1c5b812bbb48afd3717ec167bbe to your computer and use it in GitHub Desktop.
Lazy-loaded artisan console commands
<?php
namespace App\Console;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
use Symfony\Component\Console\Exception\CommandNotFoundException;
class ContainerCommandLoader implements CommandLoaderInterface
{
private $container;
private $commandMap;
/**
* @param ContainerInterface $container A container from which to load command services
* @param array $commandMap An array with command names as keys and service ids as values
*/
public function __construct(ContainerInterface $container, array $commandMap)
{
$this->container = $container;
$this->commandMap = $commandMap;
}
/**
* {@inheritdoc}
*/
public function get($name)
{
if (!$this->has($name)) {
throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name));
}
return $this->container->get($this->commandMap[$name]);
}
/**
* {@inheritdoc}
*/
public function has($name)
{
//return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]);
return $name && isset($this->commandMap[$name]);
}
/**
* {@inheritdoc}
*/
public function getNames()
{
return array_keys($this->commandMap);
}
}
<?php
namespace App\Console;
use Illuminate\Console\Command;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use ReflectionClass;
use Symfony\Component\Finder\Finder;
use Illuminate\Console\Application as Artisan;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
];
protected $commandMap = [];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
* @return void
*/
protected function schedule(Schedule $schedule)
{
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
// override parent
protected function getArtisan()
{
if (is_null($this->artisan)) {
$this->artisan = (new Artisan($this->app, $this->events, $this->app->version()))
->resolveCommands($this->commands);
$this->artisan->setCommandLoader(new ContainerCommandLoader($this->app, $this->commandMap));
return $this->artisan;
}
return $this->artisan;
}
// override parent
protected function load($paths)
{
$paths = array_unique(Arr::wrap($paths));
$paths = array_filter($paths, function ($path) {
return is_dir($path);
});
if (empty($paths)) {
return;
}
$namespace = $this->app->getNamespace();
foreach ((new Finder())->in($paths)->files() as $command) {
$command = $namespace.str_replace(
['/', '.php'],
['\\', ''],
Str::after($command->getPathname(), app_path().DIRECTORY_SEPARATOR)
);
if (is_subclass_of($command, Command::class) &&
!(new ReflectionClass($command))->isAbstract()) {
$commandName = $command::getDefaultName();
if ($commandName) {
$this->commandMap[$commandName] = $command;
continue;
}
Artisan::starting(function ($artisan) use ($command) {
$artisan->resolve($command);
});
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment