Skip to content

Commit

Permalink
Merge pull request #1003 from spiral/feature/prototype-list
Browse files Browse the repository at this point in the history
[spiral/prototype] Introducing new `prototype:list` console command for listing prototype dependencies
  • Loading branch information
butschster authored Oct 18, 2023
2 parents 13cd72c + 2c70a90 commit 67363ef
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [spiral/monolog-bridge] Added the ability to configure the **Monolog** messages format via environment variable
`MONOLOG_FORMAT`.
- [spiral/translator] Added the ability to register additional locales directories.
- [spiral/prototype] Added console command `Spiral\Prototype\Command\ListCommand` for listing prototype dependencies.

## 3.8.4 - 2023-09-08

Expand Down
1 change: 1 addition & 0 deletions src/Prototype/src/Bootloader/PrototypeBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public function init(ConsoleBootloader $console): void
{
$console->addCommand(Command\DumpCommand::class);
$console->addCommand(Command\ListCommand::class);
$console->addCommand(Command\UsageCommand::class);
$console->addCommand(Command\InjectCommand::class);

$console->addConfigureSequence(
Expand Down
21 changes: 8 additions & 13 deletions src/Prototype/src/Command/ListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,22 @@

final class ListCommand extends AbstractCommand
{
public const NAME = 'prototype:list';
public const DESCRIPTION = 'List all prototyped classes';
public const NAME = 'prototype:list';
public const DESCRIPTION = 'List all declared prototype dependencies';

/**
* List all prototype classes.
*/
public function perform(): int
{
$prototyped = $this->locator->getTargetClasses();
if ($prototyped === []) {
$this->writeln('<comment>No prototyped classes found.</comment>');
$bindings = $this->registry->getPropertyBindings();
if ($bindings === []) {
$this->comment('No prototype dependencies found.');

return self::SUCCESS;
}

$grid = $this->table(['Class:', 'Property:', 'Target:']);
$grid = $this->table(['Name:', 'Target:']);

foreach ($prototyped as $class) {
$proto = $this->getPrototypeProperties($class, $prototyped);

$grid->addRow([$class->getName(), $this->mergeNames($proto), $this->mergeTargets($proto)]);
foreach ($bindings as $binding) {
$grid->addRow([$binding->property, $binding->type->name()]);
}

$grid->render();
Expand Down
36 changes: 36 additions & 0 deletions src/Prototype/src/Command/UsageCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Spiral\Prototype\Command;

final class UsageCommand extends AbstractCommand
{
public const NAME = 'prototype:usage';
public const DESCRIPTION = 'List all prototyped classes';

/**
* List all prototype classes.
*/
public function perform(): int
{
$prototyped = $this->locator->getTargetClasses();
if ($prototyped === []) {
$this->writeln('<comment>No prototyped classes found.</comment>');

return self::SUCCESS;
}

$grid = $this->table(['Class:', 'Property:', 'Target:']);

foreach ($prototyped as $class) {
$proto = $this->getPrototypeProperties($class, $prototyped);

$grid->addRow([$class->getName(), $this->mergeNames($proto), $this->mergeTargets($proto)]);
}

$grid->render();

return self::SUCCESS;
}
}
10 changes: 10 additions & 0 deletions src/Prototype/tests/Commands/InjectCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@

class InjectCommandTest extends AbstractCommandsTestCase
{
public function testCommandRegistered(): void
{
$out = new BufferedOutput();
$this->app->get(Console::class)->run('list', new ArrayInput([]), $out);

$result = $out->fetch();

$this->assertStringContainsString('prototype:inject', $result);
}

public function testEmptyInjection(): void
{
$target = EmptyInjectionClass::class;
Expand Down
110 changes: 70 additions & 40 deletions src/Prototype/tests/Commands/ListCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,60 +9,90 @@
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

class ListCommandTest extends AbstractCommandsTestCase
final class ListCommandTest extends AbstractCommandsTestCase
{
public function testList(): void
public function testCommandRegistered(): void
{
$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('list', $inp, $out);
$this->app->get(Console::class)->run('list', new ArrayInput([]), $out);

$result = $out->fetch();

$this->assertStringContainsString('prototype:list', $result);
$this->assertStringContainsString('prototype:inject', $result);
}

public function testPrototypes(): void
{
$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:list', $inp, $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringContainsString('undefined', $result);
}

public function testPrototypesBound(): void
{
$this->app->bindApp();

$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:list', $inp, $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringNotContainsString('undefined', $result);
$this->assertStringNotContainsString('Undefined class', $result);
$this->assertStringContainsString(TestApp::class, $result);
}

public function testPrototypesBoundWithoutResolve(): void
public function testList(): void
{
$this->app->bindWithoutResolver();

$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:list', $inp, $out);
$this->app->get(Console::class)->run('prototype:list', new ArrayInput([]), $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringContainsString('Can\'t resolve', $result);
$this->assertStringContainsString('app', $result);
$this->assertStringContainsString(TestApp::class, $result);
$this->assertStringContainsString('classLocator', $result);
$this->assertStringContainsString(\Spiral\Tokenizer\ClassesInterface::class, $result);
$this->assertStringContainsString('console', $result);
$this->assertStringContainsString(\Spiral\Console\Console::class, $result);
$this->assertStringContainsString('broadcast', $result);
$this->assertStringContainsString(\Spiral\Broadcasting\BroadcastInterface::class, $result);
$this->assertStringContainsString('container', $result);
$this->assertStringContainsString(\Psr\Container\ContainerInterface::class, $result);
$this->assertStringContainsString('encrypter', $result);
$this->assertStringContainsString(\Spiral\Encrypter\EncrypterInterface::class, $result);
$this->assertStringContainsString('env', $result);
$this->assertStringContainsString(\Spiral\Boot\EnvironmentInterface::class, $result);
$this->assertStringContainsString('files', $result);
$this->assertStringContainsString(\Spiral\Files\FilesInterface::class, $result);
$this->assertStringContainsString('guard', $result);
$this->assertStringContainsString(\Spiral\Security\GuardInterface::class, $result);
$this->assertStringContainsString('http', $result);
$this->assertStringContainsString(\Spiral\Http\Http::class, $result);
$this->assertStringContainsString('i18n', $result);
$this->assertStringContainsString(\Spiral\Translator\TranslatorInterface::class, $result);
$this->assertStringContainsString('input', $result);
$this->assertStringContainsString(\Spiral\Http\Request\InputManager::class, $result);
$this->assertStringContainsString('session', $result);
$this->assertStringContainsString(\Spiral\Session\SessionScope::class, $result);
$this->assertStringContainsString('cookies', $result);
$this->assertStringContainsString(\Spiral\Cookies\CookieManager::class, $result);
$this->assertStringContainsString('logger', $result);
$this->assertStringContainsString(\Psr\Log\LoggerInterface::class, $result);
$this->assertStringContainsString('logs', $result);
$this->assertStringContainsString(\Spiral\Logger\LogsInterface::class, $result);
$this->assertStringContainsString('memory', $result);
$this->assertStringContainsString(\Spiral\Boot\MemoryInterface::class, $result);
$this->assertStringContainsString('paginators', $result);
$this->assertStringContainsString(\Spiral\Pagination\PaginationProviderInterface::class, $result);
$this->assertStringContainsString('queue', $result);
$this->assertStringContainsString(\Spiral\Queue\QueueInterface::class, $result);
$this->assertStringContainsString('queueManager', $result);
$this->assertStringContainsString(\Spiral\Queue\QueueConnectionProviderInterface::class, $result);
$this->assertStringContainsString('request', $result);
$this->assertStringContainsString(\Spiral\Http\Request\InputManager::class, $result);
$this->assertStringContainsString('response', $result);
$this->assertStringContainsString(\Spiral\Http\ResponseWrapper::class, $result);
$this->assertStringContainsString('router', $result);
$this->assertStringContainsString(\Spiral\Router\RouterInterface::class, $result);
$this->assertStringContainsString('snapshots', $result);
$this->assertStringContainsString(\Spiral\Snapshots\SnapshotterInterface::class, $result);
$this->assertStringContainsString('storage', $result);
$this->assertStringContainsString(\Spiral\Storage\BucketInterface::class, $result);
$this->assertStringContainsString('serializer', $result);
$this->assertStringContainsString(\Spiral\Serializer\SerializerManager::class, $result);
$this->assertStringContainsString('validator', $result);
$this->assertStringContainsString(\Spiral\Validation\ValidationInterface::class, $result);
$this->assertStringContainsString('views', $result);
$this->assertStringContainsString(\Spiral\Views\ViewsInterface::class, $result);
$this->assertStringContainsString('auth', $result);
$this->assertStringContainsString(\Spiral\Auth\AuthScope::class, $result);
$this->assertStringContainsString('authTokens', $result);
$this->assertStringContainsString(\Spiral\Auth\TokenStorageInterface::class, $result);
$this->assertStringContainsString('cache', $result);
$this->assertStringContainsString(\Psr\SimpleCache\CacheInterface::class, $result);
$this->assertStringContainsString('cacheManager', $result);
$this->assertStringContainsString(\Spiral\Cache\CacheStorageProviderInterface::class, $result);
$this->assertStringContainsString('exceptionHandler', $result);
$this->assertStringContainsString(\Spiral\Exceptions\ExceptionHandlerInterface::class, $result);
}
}
66 changes: 66 additions & 0 deletions src/Prototype/tests/Commands/UsageCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Prototype\Commands;

use Spiral\Console\Console;
use Spiral\Tests\Prototype\Fixtures\TestApp;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

class UsageCommandTest extends AbstractCommandsTestCase
{
public function testCommandRegistered(): void
{
$out = new BufferedOutput();
$this->app->get(Console::class)->run('list', new ArrayInput([]), $out);

$result = $out->fetch();

$this->assertStringContainsString('prototype:usage', $result);
}

public function testPrototypes(): void
{
$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:usage', $inp, $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringContainsString('undefined', $result);
}

public function testPrototypesBound(): void
{
$this->app->bindApp();

$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:usage', $inp, $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringNotContainsString('undefined', $result);
$this->assertStringNotContainsString('Undefined class', $result);
$this->assertStringContainsString(TestApp::class, $result);
}

public function testPrototypesBoundWithoutResolve(): void
{
$this->app->bindWithoutResolver();

$inp = new ArrayInput([]);
$out = new BufferedOutput();
$this->app->get(Console::class)->run('prototype:usage', $inp, $out);

$result = $out->fetch();

$this->assertStringContainsString('testClass', $result);
$this->assertStringContainsString('Can\'t resolve', $result);
$this->assertStringContainsString(TestApp::class, $result);
}
}

0 comments on commit 67363ef

Please sign in to comment.