Skip to content

Commit

Permalink
Improve Prototype DumpCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
msmakouz committed Oct 19, 2023
1 parent 670c274 commit 6c607b6
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 76 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ Thumbs.db
clover.xml
.env
builds
build
3 changes: 2 additions & 1 deletion src/Prototype/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"nikic/php-parser": "^4.15.5",
"doctrine/inflector": "^1.4|^2.0",
"spiral/attributes": "^2.8|^3.0",
"spiral/config": "^3.9"
"spiral/config": "^3.9",
"spiral/reactor": "^3.9"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 2 additions & 0 deletions src/Prototype/src/Annotation/Line.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

/**
* Singular annotation line.
*
* @deprecated since v3.9.0
*/
final class Line
{
Expand Down
2 changes: 2 additions & 0 deletions src/Prototype/src/Annotation/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

/**
* Simple annotation parser and compiler.
*
* @deprecated since v3.9.0
*/
final class Parser
{
Expand Down
49 changes: 16 additions & 33 deletions src/Prototype/src/Command/DumpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

namespace Spiral\Prototype\Command;

use Spiral\Prototype\Annotation;
use Spiral\Prototype\Bootloader\PrototypeBootloader;
use Spiral\Prototype\Traits\PrototypeTrait;
use Spiral\Reactor\FileDeclaration;
use Spiral\Reactor\TraitDeclaration;
use Spiral\Reactor\Writer;

final class DumpCommand extends AbstractCommand
{
Expand All @@ -19,36 +20,25 @@ final class DumpCommand extends AbstractCommand
*
* @throws \ReflectionException
*/
public function perform(): int
public function perform(Writer $writer): int
{
$dependencies = $this->getRegistry()->getPropertyBindings();
if ($dependencies === []) {
$this->writeln('<comment>No prototyped shortcuts found.</comment>');
$this->comment('No prototyped shortcuts found.');

Check warning on line 27 in src/Prototype/src/Command/DumpCommand.php

View check run for this annotation

Codecov / codecov/patch

src/Prototype/src/Command/DumpCommand.php#L27

Added line #L27 was not covered by tests

return self::SUCCESS;
}

$this->write('Updating <fg=yellow>PrototypeTrait</fg=yellow> DOCComment... ');

$trait = new \ReflectionClass(PrototypeTrait::class);
$docComment = $trait->getDocComment();
if ($docComment === false) {
$this->write('<fg=red>DOCComment is missing</fg=red>');

return self::FAILURE;
}

$filename = $trait->getFileName();
$ref = new \ReflectionClass(PrototypeTrait::class);
$file = FileDeclaration::fromReflection($ref);
$trait = $file->getTrait(PrototypeTrait::class);

try {
\file_put_contents(
$filename,
\str_replace(
$docComment,
$this->buildAnnotation($dependencies),
\file_get_contents($filename)
)
);
$this->buildAnnotation($trait, $dependencies);

$writer->write($ref->getFileName(), $file);
} catch (\Throwable $e) {
$this->write('<fg=red>' . $e->getMessage() . "</fg=red>\n");

Expand All @@ -70,21 +60,14 @@ public function perform(): int
return self::SUCCESS;
}

private function buildAnnotation(array $dependencies): string
private function buildAnnotation(TraitDeclaration $trait, array $dependencies): void
{
$an = new Annotation\Parser('');
$an->lines[] = new Annotation\Line(
'This DocComment is auto-generated, do not edit or commit this file to repository.'
);
$an->lines[] = new Annotation\Line('');
$trait->setComment(null);
$trait->addComment('This DocComment is auto-generated, do not edit or commit this file to repository.');
$trait->addComment('');

foreach ($dependencies as $dependency) {
$an->lines[] = new Annotation\Line(
\sprintf('\\%s $%s', $dependency->type->fullName, $dependency->var),
'property'
);
$trait->addComment(\sprintf('@property \\%s $%s', $dependency->type->fullName, $dependency->var));
}

return $an->compile();
}
}
3 changes: 0 additions & 3 deletions src/Prototype/src/Traits/PrototypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
use Spiral\Prototype\Exception\PrototypeException;
use Spiral\Prototype\PrototypeRegistry;

/**
* This DocComment is auto-generated, do not edit or commit this file to repository.
*/
trait PrototypeTrait
{
/**
Expand Down
101 changes: 101 additions & 0 deletions src/Prototype/tests/Commands/DumpCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Prototype\Commands;

use Spiral\Console\Console;
use Spiral\Files\FilesInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

final class DumpCommandTest 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:dump', $result);
}

public function testDump(): void
{
$files = $this->createMock(FilesInterface::class);
$files
->expects($this->once())
->method('write')
->with(static::callback(fn () => true), static::callback($this->validateTrait(...)));

$this->app->getContainer()->bindSingleton(FilesInterface::class, $files, true);

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

$result = $out->fetch();

$this->assertStringContainsString('Updating PrototypeTrait DOCComment... complete', $result);
}

private function validateTrait(string $content): bool
{
$this->assertStringContainsString('namespace Spiral\Prototype\Traits;', $content);
$this->assertStringContainsString('use Spiral\Prototype\PrototypeRegistry;', $content);
$this->assertStringContainsString(
'This DocComment is auto-generated, do not edit or commit this file to repository.',
$content
);
$this->assertStringContainsString('@property \Spiral\Tests\Prototype\Fixtures\TestApp $app', $content);
$this->assertStringContainsString('@property \Spiral\Tokenizer\ClassesInterface $classLocator', $content);
$this->assertStringContainsString('@property \Spiral\Console\Console $console', $content);
$this->assertStringContainsString('@property \Spiral\Broadcasting\BroadcastInterface $broadcast', $content);
$this->assertStringContainsString('@property \Psr\Container\ContainerInterface $container', $content);
$this->assertStringContainsString('@property \Spiral\Encrypter\EncrypterInterface $encrypter', $content);
$this->assertStringContainsString('@property \Spiral\Boot\EnvironmentInterface $env', $content);
$this->assertStringContainsString('@property \Spiral\Files\FilesInterface $files', $content);
$this->assertStringContainsString('@property \Spiral\Security\GuardInterface $guard', $content);
$this->assertStringContainsString('@property \Spiral\Http\Http $http', $content);
$this->assertStringContainsString('@property \Spiral\Translator\TranslatorInterface $i18n', $content);
$this->assertStringContainsString('@property \Spiral\Http\Request\InputManager $input', $content);
$this->assertStringContainsString('@property \Spiral\Session\SessionScope $session', $content);
$this->assertStringContainsString('@property \Spiral\Cookies\CookieManager $cookies', $content);
$this->assertStringContainsString('@property \Psr\Log\LoggerInterface $logger', $content);
$this->assertStringContainsString('@property \Spiral\Logger\LogsInterface $logs', $content);
$this->assertStringContainsString('@property \Spiral\Boot\MemoryInterface $memory', $content);
$this->assertStringContainsString(
'@property \Spiral\Pagination\PaginationProviderInterface $paginators',
$content
);
$this->assertStringContainsString('@property \Spiral\Queue\QueueInterface $queue', $content);
$this->assertStringContainsString(
'@property \Spiral\Queue\QueueConnectionProviderInterface $queueManager',
$content
);
$this->assertStringContainsString('@property \Spiral\Http\Request\InputManager $request', $content);
$this->assertStringContainsString('@property \Spiral\Http\ResponseWrapper $response', $content);
$this->assertStringContainsString('@property \Spiral\Router\RouterInterface $router', $content);
$this->assertStringContainsString('@property \Spiral\Snapshots\SnapshotterInterface $snapshots', $content);
$this->assertStringContainsString('@property \Spiral\Storage\BucketInterface $storage', $content);
$this->assertStringContainsString('@property \Spiral\Serializer\SerializerManager $serializer', $content);
$this->assertStringContainsString('@property \Spiral\Validation\ValidationInterface $validator', $content);
$this->assertStringContainsString('@property \Spiral\Views\ViewsInterface $views', $content);
$this->assertStringContainsString('@property \Spiral\Auth\AuthScope $auth', $content);
$this->assertStringContainsString('@property \Spiral\Auth\TokenStorageInterface $authTokens', $content);
$this->assertStringContainsString('@property \Psr\SimpleCache\CacheInterface $cache', $content);
$this->assertStringContainsString(
'@property \Spiral\Cache\CacheStorageProviderInterface $cacheManager',
$content
);
$this->assertStringContainsString(
'@property \Spiral\Exceptions\ExceptionHandlerInterface $exceptionHandler',
$content
);
$this->assertStringContainsString('trait PrototypeTrait', $content);
$this->assertStringContainsString('public function __get(string $name): mixed', $content);
$this->assertStringContainsString('return $container->get($target->type->name());', $content);

return true;
}
}
8 changes: 7 additions & 1 deletion src/Prototype/tests/Fixtures/TestApp.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Spiral\Tests\Prototype\Fixtures;

use Spiral\Core\Container;
use Spiral\Framework\Kernel;
use Spiral\Prototype\Bootloader\PrototypeBootloader;
use Spiral\Prototype\PrototypeRegistry;
Expand Down Expand Up @@ -37,8 +38,13 @@ public function bindWithoutResolver(): void
$registry->bindProperty('two', InheritedInjection\InjectionTwo::class);
}

public function get(string $target)
public function get(string $target): mixed
{
return $this->container->get($target);
}

public function getContainer(): Container
{
return $this->container;
}
}
21 changes: 0 additions & 21 deletions src/Prototype/tests/Traits/PrototypeTraitTest.php

This file was deleted.

5 changes: 5 additions & 0 deletions src/Reactor/src/FileDeclaration.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public static function fromCode(string $code): static
return self::fromElement((new Factory())->fromCode($code));
}

public static function fromReflection(\ReflectionClass $reflection): static
{
return self::fromElement((new Factory())->fromCode(\file_get_contents($reflection->getFileName())));
}

public function addNamespace(string|PhpNamespace $namespace): PhpNamespace
{
if ($namespace instanceof PhpNamespace) {
Expand Down
13 changes: 10 additions & 3 deletions tests/Framework/Framework/CleanTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace Spiral\Tests\Framework\Framework;

use Spiral\Console\Sequence\RuntimeDirectory;
use Spiral\Tests\Framework\ConsoleTestCase;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

/**
Expand All @@ -14,10 +16,15 @@ final class CleanTest extends ConsoleTestCase
{
public int $defaultVerbosityLevel = OutputInterface::VERBOSITY_DEBUG;

public function testClean(): void
protected function setUp(): void
{
$this->runCommand('configure');
parent::setUp();

$this->getContainer()->get(RuntimeDirectory::class)->ensure(new NullOutput());
}

public function testClean(): void
{
$this->assertConsoleCommandOutputContainsStrings('cache:clean', strings: [
'Runtime cache has been cleared'
]);
Expand All @@ -33,7 +40,7 @@ public function testCleanWhenRuntimeDirectoryNotExists(): void

public function testCleanVerbose(): void
{
$this->runCommand('configure');
$this->runCommand('i18n:index');

$this->assertConsoleCommandOutputContainsStrings('cache:clean', strings: [
'i18n'
Expand Down
1 change: 0 additions & 1 deletion tests/Framework/I18n/ExportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public function testExport(): void
$this->assertFalse(is_file(sys_get_temp_dir().'/messages.ru.php'));

$this->runCommand('i18n:index');
$this->runCommand('configure');

$this->runCommand(
'i18n:export',
Expand Down
Loading

0 comments on commit 6c607b6

Please sign in to comment.