diff --git a/CHANGELOG.md b/CHANGELOG.md index fabcd3c5b..dfc23ce9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/Prototype/src/Bootloader/PrototypeBootloader.php b/src/Prototype/src/Bootloader/PrototypeBootloader.php index ea1ddfebf..ddba47686 100644 --- a/src/Prototype/src/Bootloader/PrototypeBootloader.php +++ b/src/Prototype/src/Bootloader/PrototypeBootloader.php @@ -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( diff --git a/src/Prototype/src/Command/ListCommand.php b/src/Prototype/src/Command/ListCommand.php index ea7ee333b..bcae5f706 100644 --- a/src/Prototype/src/Command/ListCommand.php +++ b/src/Prototype/src/Command/ListCommand.php @@ -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('No prototyped classes found.'); + $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(); diff --git a/src/Prototype/src/Command/UsageCommand.php b/src/Prototype/src/Command/UsageCommand.php new file mode 100644 index 000000000..66f64057e --- /dev/null +++ b/src/Prototype/src/Command/UsageCommand.php @@ -0,0 +1,36 @@ +locator->getTargetClasses(); + if ($prototyped === []) { + $this->writeln('No prototyped classes found.'); + + 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; + } +} diff --git a/src/Prototype/tests/Commands/InjectCommandTest.php b/src/Prototype/tests/Commands/InjectCommandTest.php index fcfbefdb9..1577908a9 100644 --- a/src/Prototype/tests/Commands/InjectCommandTest.php +++ b/src/Prototype/tests/Commands/InjectCommandTest.php @@ -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; diff --git a/src/Prototype/tests/Commands/ListCommandTest.php b/src/Prototype/tests/Commands/ListCommandTest.php index 5a7f674a8..d12bb6956 100644 --- a/src/Prototype/tests/Commands/ListCommandTest.php +++ b/src/Prototype/tests/Commands/ListCommandTest.php @@ -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); } } diff --git a/src/Prototype/tests/Commands/UsageCommandTest.php b/src/Prototype/tests/Commands/UsageCommandTest.php new file mode 100644 index 000000000..cca71537e --- /dev/null +++ b/src/Prototype/tests/Commands/UsageCommandTest.php @@ -0,0 +1,66 @@ +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); + } +}