Skip to content

Commit

Permalink
Merge pull request #1068 from spiral/feature/issue-1063
Browse files Browse the repository at this point in the history
Adds `scaffolder:info` console command
  • Loading branch information
butschster committed Jan 30, 2024
2 parents 2c780fc + 1c00443 commit 8e874c7
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 25 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- **Medium Impact Changes**
- [spiral/core] Interface `Spiral\Core\Container\SingletonInterface` is deprecated,
use `Spiral\Core\Attribute\Singleton` instead. Will be removed in v4.0.
- **Other Features**
- Added `Spiral\Scaffolder\Command\InfoCommand` console command for getting information about available scaffolder
commands.

## 3.11.1 - 2023-12-29

Expand Down
12 changes: 7 additions & 5 deletions src/Scaffolder/src/Bootloader/ScaffolderBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use ReflectionClass;
use ReflectionException;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Boot\DirectoriesInterface;
use Spiral\Boot\KernelInterface;
use Spiral\Config\ConfiguratorInterface;
use Spiral\Config\Patch\Append;
Expand All @@ -29,8 +30,9 @@ public function __construct(
) {
}

public function init(ConsoleBootloader $console): void
public function init(ConsoleBootloader $console, DirectoriesInterface $dir): void
{
$console->addCommand(Command\InfoCommand::class);
$console->addCommand(Command\BootloaderCommand::class);
$console->addCommand(Command\CommandCommand::class);
$console->addCommand(Command\ConfigCommand::class);
Expand All @@ -56,7 +58,7 @@ public function init(ConsoleBootloader $console): void
* Base directory for generated classes, class will be automatically localed into sub directory
* using given namespace.
*/
'directory' => directory('app') . 'src/',
'directory' => $dir->get('app') . 'src/',

/*
* Default namespace to be applied for every generated class. By default uses Kernel namespace
Expand All @@ -83,7 +85,7 @@ public function init(ConsoleBootloader $console): void
'postfix' => 'Config',
'class' => Declaration\ConfigDeclaration::class,
'options' => [
'directory' => directory('config'),
'directory' => $dir->get('config'),
],
],
Declaration\ControllerDeclaration::TYPE => [
Expand All @@ -98,7 +100,7 @@ public function init(ConsoleBootloader $console): void
],
Declaration\MiddlewareDeclaration::TYPE => [
'namespace' => 'Middleware',
'postfix' => '',
'postfix' => 'Middleware',
'class' => Declaration\MiddlewareDeclaration::class,
],
Declaration\CommandDeclaration::TYPE => [
Expand All @@ -117,7 +119,7 @@ public function init(ConsoleBootloader $console): void
}

/**
* Register new Scaffolder declaration.
* Register a new Scaffolder declaration.
*
* @param non-empty-string $name
*/
Expand Down
84 changes: 84 additions & 0 deletions src/Scaffolder/src/Command/InfoCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace Spiral\Scaffolder\Command;

use Spiral\Boot\DirectoriesInterface;
use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Command;
use Spiral\Console\Console;
use Spiral\Scaffolder\Config\ScaffolderConfig;
use Symfony\Component\Console\Helper\TableSeparator;

#[AsCommand(name: 'scaffolder:info', description: 'Show information about available scaffolder commands.')]
final class InfoCommand extends Command
{
#[Argument(description: 'Class name')]
private string $name = 'Example';

public function perform(ScaffolderConfig $config, DirectoriesInterface $dirs, Console $console): int
{
$this->output->title('Scaffolder commands');
$this->writeln(
'Scaffolder enables developers to quickly and easily generate application code for various classes, using a set of console commands',
);

$this->newLine();

$table = $this->table(['Command', 'Target']);
$rootDir = $dirs->get('root');
$available = $config->getDeclarations();

$i = 0;
foreach ($available as $name) {
$command = 'create:' . $name;

if (!$console->getApplication()->has($command)) {
continue;
}

$command = $console->getApplication()->get($command);

if ($i > 0) {
$table->addRow(new TableSeparator());
}
$declaration = $config->getDeclaration($name);

$options = [];
foreach ($declaration['options'] ?? [] as $key => $value) {
$options[] = $key . ': <fg=yellow>' . \json_encode(\str_replace($rootDir, '', $value)) . '</>';
}

$file = \str_replace($rootDir, '', $config->classFilename($name, $this->name));
$namespace = $config->classNamespace($name, $this->name);
$table->addRow([
$command->getName() . "\n<fg=gray>{$command->getDescription()}</>",
<<<TARGET
path: <fg=green>/$file</>
namespace: <fg=yellow>$namespace</>
TARGET
.
($options !== [] ? "\n" . \implode("\n", $options) : ''),
]);

$i++;
}

$randomName = $available[\array_rand($available)];
$this->writeln(
"<info>Use `<fg=yellow>php app.php create:{$randomName} {$this->name}</>` command to generate desired class. Below is a list of available commands:</info>",
);

$table->render();

$this->writeln(
'<info>Use `<fg=yellow>php app.php create:*** --help</>` command to see available options.</info>',
);

$this->writeln('Read more about scaffolder in <fg=yellow>https://spiral.dev/docs/basics-scaffolding</> documentation section.');

return self::SUCCESS;
}
}
46 changes: 29 additions & 17 deletions src/Scaffolder/src/Config/ScaffolderConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ class ScaffolderConfig extends InjectableConfig
public const CONFIG = 'scaffolder';

protected array $config = [
'header' => [],
'directory' => '',
'namespace' => '',
'header' => [],
'directory' => '',
'namespace' => '',
'declarations' => [],
'defaults' => [
'defaults' => [
'declarations' => [],
],
];
Expand All @@ -38,6 +38,16 @@ public function baseDirectory(): string
return $this->config['directory'];
}

/**
* @return non-empty-string[]
*/
public function getDeclarations(): array
{
return \array_keys($this->config['defaults']['declarations'] ?? []) + \array_keys(
$this->config['declarations'],
);
}

/**
* @param non-empty-string $element
*/
Expand Down Expand Up @@ -109,7 +119,7 @@ public function declarationClass(string $element): string

if (empty($class)) {
throw new ScaffolderException(
\sprintf("Unable to scaffold '%s', no declaration class found", $element)
\sprintf("Unable to scaffold '%s', no declaration class found", $element),
);
}

Expand All @@ -126,6 +136,19 @@ public function declarationOptions(string $element): array
return $this->getOption($element, 'options', []);
}

/**
* Get declaration options by element name.
*
* @param non-empty-string $element
*/
public function getDeclaration(string $element): array
{
$default = $this->config['defaults']['declarations'][$element] ?? [];
$declaration = $this->config['declarations'][$element] ?? [];

return $declaration + $default;
}

/**
* @param non-empty-string $element
*/
Expand Down Expand Up @@ -183,7 +206,7 @@ private function baseNamespace(string $element): string
$declaration = $this->getDeclaration($element);

if (\array_key_exists('baseNamespace', $declaration)) {
return \trim((string) $this->getOption($element, 'baseNamespace', ''), '\\');
return \trim((string)$this->getOption($element, 'baseNamespace', ''), '\\');
}

return \trim($this->config['namespace'], '\\');
Expand Down Expand Up @@ -211,15 +234,4 @@ private function classify(string $name): string
->build()
->classify($name);
}

/**
* @param non-empty-string $element
*/
private function getDeclaration(string $element): array
{
$default = $this->config['defaults']['declarations'][$element] ?? [];
$declaration = $this->config['declarations'][$element] ?? [];

return $declaration + $default;
}
}
30 changes: 30 additions & 0 deletions src/Scaffolder/tests/Command/InfoCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Command;

use Spiral\Tests\Scaffolder\Command\AbstractCommandTestCase;

final class InfoCommandTest extends AbstractCommandTestCase
{
public function testInfo(): void
{
$result = $this->console()->run('scaffolder:info')->getOutput()->fetch();

$strings = [
'Scaffolder commands',
'create:controller',
'create:bootloader',
'create:config',
'create:filter',
'create:command',
'create:middleware',
'create:jobHandler',
];

foreach ($strings as $string) {
$this->assertStringContainsString($string, $result);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function testAddDeclaration(): void

$this->assertSame(
['foo' => ['bar' => 'baz']],
$configs->getConfig(ScaffolderConfig::CONFIG)['defaults']['declarations']
$configs->getConfig(ScaffolderConfig::CONFIG)['defaults']['declarations'],
);
}

Expand Down Expand Up @@ -73,7 +73,7 @@ public function testDefaultConfig(): void
],
Declaration\MiddlewareDeclaration::TYPE => [
'namespace' => 'Middleware',
'postfix' => '',
'postfix' => 'Middleware',
'class' => Declaration\MiddlewareDeclaration::class,
],
Declaration\CommandDeclaration::TYPE => [
Expand All @@ -87,7 +87,7 @@ public function testDefaultConfig(): void
'class' => Declaration\JobHandlerDeclaration::class,
],
],
]
],
], $config);
}
}

0 comments on commit 8e874c7

Please sign in to comment.