Skip to content

Commit

Permalink
Refactoring CommandArgumentsParser
Browse files Browse the repository at this point in the history
  • Loading branch information
Chemaclass committed Apr 18, 2021
1 parent 146b942 commit 13ca3ab
Show file tree
Hide file tree
Showing 18 changed files with 265 additions and 49 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
/.idea/
/.vscode/
/vendor/
/TestModule/
.phpunit.*
.php_cs.cache
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
}
],
"require": {
"ext-json": "*",
"php": ">=7.4"
},
"require-dev": {
Expand All @@ -39,12 +40,14 @@
"scripts": {
"test-all": [
"@test-quality",
"@test-unit",
"@test-integration"
],
"test-quality": [
"@csrun",
"@psalm"
],
"test-unit": "./vendor/bin/phpunit --testsuite=unit",
"test-integration": "./vendor/bin/phpunit --testsuite=integration",
"test-coverage": "XDEBUG_MODE=coverage ./vendor/bin/phpunit --testsuite=integration --coverage-html=coverage",
"psalm": "./vendor/bin/psalm",
Expand Down
4 changes: 4 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
</php>

<testsuites>
<testsuite name="unit">
<directory suffix="Test.php">tests/Unit</directory>
</testsuite>

<testsuite name="integration">
<directory suffix="Test.php">tests/Integration</directory>
</testsuite>
Expand Down
11 changes: 11 additions & 0 deletions src/CodeGenerator/CodeGeneratorConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Gacela\CodeGenerator;

use Gacela\Framework\AbstractConfig;
use Gacela\Framework\Config;

final class CodeGeneratorConfig extends AbstractConfig
{
Expand Down Expand Up @@ -32,4 +33,14 @@ private function getCommandTemplateContent(string $filename): string
{
return file_get_contents(__DIR__ . '/Infrastructure/Template/Command/' . $filename);
}

public function getComposerJsonContentAsArray(): array
{
$filename = Config::getApplicationRootDir() . '/composer.json';
if (!file_exists($filename)) {
return [];
}

return json_decode(file_get_contents($filename), true);
}
}
4 changes: 3 additions & 1 deletion src/CodeGenerator/CodeGeneratorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ private function createGeneratorIo(): MakerIoInterface

public function createCommandArgumentsParser(): CommandArgumentsParser
{
return new CommandArgumentsParser();
return new CommandArgumentsParser(
$this->getConfig()->getComposerJsonContentAsArray()
);
}
}
9 changes: 3 additions & 6 deletions src/CodeGenerator/Domain/Command/AbstractMaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,10 @@ public function __construct(MakerIoInterface $io, string $template)

public function make(CommandArguments $commandArguments): void
{
$pieces = explode('/', $commandArguments->targetDirectory());
$moduleName = end($pieces);
$this->io->createDirectory($commandArguments->directory());

$this->io->createDirectory($commandArguments->targetDirectory());

$path = sprintf('%s/%s.php', $commandArguments->targetDirectory(), $this->className());
$this->io->filePutContents($path, $this->generateFileContent("{$commandArguments->rootNamespace()}\\$moduleName"));
$path = sprintf('%s/%s.php', $commandArguments->directory(), $this->className());
$this->io->filePutContents($path, $this->generateFileContent($commandArguments->namespace()));

$this->io->writeln("> Path '$path' created successfully");
}
Expand Down
2 changes: 1 addition & 1 deletion src/CodeGenerator/Domain/Command/ModuleMaker.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function make(CommandArguments $commandArguments): void
$generator->make($commandArguments);
}

$pieces = explode('/', $commandArguments->targetDirectory());
$pieces = explode('/', $commandArguments->directory());
$moduleName = end($pieces);
$this->io->writeln("Module $moduleName created successfully");
}
Expand Down
65 changes: 59 additions & 6 deletions src/CodeGenerator/Domain/Io/CommandArgumentsParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,77 @@

use Gacela\CodeGenerator\Domain\ReadModel\CommandArguments;
use InvalidArgumentException;
use LogicException;

final class CommandArgumentsParser
{
private array $composerJson;

public function __construct(array $composerJson)
{
$this->composerJson = $composerJson;
}

/**
* @throws InvalidArgumentException
*/
public function parse(array $arguments): CommandArguments
{
[$rootNamespace, $targetDirectory] = array_pad($arguments, 2, null);
if (empty($arguments)) {
throw new InvalidArgumentException('Expected argument to be the location of the new module. For example: App/TestModule');
}

return $this->createCommandArguments($arguments[0]);
}

private function createCommandArguments(string $desiredNamespace): CommandArguments
{
$psr4 = $this->composerJson['autoload']['psr-4'];
$allPsr4Combinations = $this->allPossiblePsr4Combinations($desiredNamespace);

if ($rootNamespace === null) {
throw new InvalidArgumentException('Expected 1st argument to be root-namespace of the project');
foreach ($allPsr4Combinations as $psr4Combination) {
$psr4Key = $psr4Combination . '\\';
if (isset($psr4[$psr4Key])) {
return $this->foundPsr4($psr4Key, $psr4[$psr4Key], $desiredNamespace);
}
}

if ($targetDirectory === null) {
throw new InvalidArgumentException('Expected 2nd argument to be target-directory inside the project');
throw new LogicException('No autoload psr-4 match found for ' . $desiredNamespace);
}

/**
* Combine all possible psr-4 combinations and return them ordered by longer to shorter.
* This way we'll be able to find the longer match first.
* For example: App/TestModule/TestSubModule will produce an array such as:
* [
* 'App/TestModule/TestSubModule',
* 'App/TestModule',
* 'App',
* ].
*/
private function allPossiblePsr4Combinations(string $desiredNamespace): array
{
$result = [];

foreach (explode('/', $desiredNamespace) as $explodedArg) {
if (empty($result)) {
$result[] = $explodedArg;
} else {
$prevValue = $result[count($result) - 1];
$result[] = $prevValue . '\\' . $explodedArg;
}
}

return new CommandArguments($rootNamespace, $targetDirectory);
return array_reverse($result);
}

private function foundPsr4(string $psr4Key, string $psr4Value, string $desiredNamespace): CommandArguments
{
$rootDir = substr($psr4Value, 0, -1);
$rootNamespace = substr($psr4Key, 0, -1);
$targetDirectory = str_replace(['/', $rootNamespace, '\\'], ['\\', $rootDir, '/'], $desiredNamespace);
$namespace = str_replace([$rootDir, '/'], [$rootNamespace, '\\'], $targetDirectory);

return new CommandArguments($namespace, $targetDirectory);
}
}
18 changes: 9 additions & 9 deletions src/CodeGenerator/Domain/ReadModel/CommandArguments.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@

final class CommandArguments
{
private string $rootNamespace;
private string $targetDirectory;
private string $namespace;
private string $directory;

public function __construct(string $rootNamespace, string $targetDirectory)
public function __construct(string $namespace, string $directory)
{
$this->rootNamespace = $rootNamespace;
$this->targetDirectory = $targetDirectory;
$this->namespace = $namespace;
$this->directory = $directory;
}

public function rootNamespace(): string
public function namespace(): string
{
return $this->rootNamespace;
return $this->namespace;
}

public function targetDirectory(): string
public function directory(): string
{
return $this->targetDirectory;
return $this->directory;
}
}
27 changes: 16 additions & 11 deletions tests/Integration/CodeGenerator/UsingIncorrectConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,37 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use InvalidArgumentException;
use LogicException;
use PHPUnit\Framework\TestCase;

final class UsingIncorrectConfigurationTest extends TestCase
{
public function test_make_unknown_command(): void
public function setUp(): void
{
$this->expectException(InvalidArgumentException::class);

$codeGeneratorConfig = new CodeGeneratorFacade();
$codeGeneratorConfig->runCommand('make:unknown', [__NAMESPACE__, __DIR__ . '/Generated']);
Config::setApplicationRootDir(__DIR__);
}

public function test_missing_target_directory(): void
public function test_make_unknown_command(): void
{
$this->expectException(InvalidArgumentException::class);

$codeGeneratorConfig = new CodeGeneratorFacade();
$codeGeneratorConfig->runCommand('', [__NAMESPACE__]);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:unknown', ['GacelaTest/Integration/CodeGenerator/Generated']);
}

public function test_missing_root_namespace_and_target_directory(): void
public function test_missing_target(): void
{
$this->expectException(InvalidArgumentException::class);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:module', []);
}

$codeGeneratorConfig = new CodeGeneratorFacade();
$codeGeneratorConfig->runCommand('', []);
public function test_unknown_target(): void
{
$this->expectException(LogicException::class);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:module', ['UnknownNamespace']);
}
}
10 changes: 8 additions & 2 deletions tests/Integration/CodeGenerator/UsingMakeConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use GacelaTest\Integration\CodeGenerator\Util\DirectoryUtil;
use PHPUnit\Framework\TestCase;

final class UsingMakeConfigTest extends TestCase
{
public function setUp(): void
{
Config::setApplicationRootDir(__DIR__);
}

public function test_make_config(): void
{
self::assertFileDoesNotExist(__DIR__ . '/Generated/Config.php');

$codeGeneratorConfig = new CodeGeneratorFacade();
$codeGeneratorConfig->runCommand('make:config', [__NAMESPACE__, __DIR__ . '/Generated']);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:config', ['GacelaTest/Integration/CodeGenerator/Generated']);

$this->expectOutputRegex("~/Generated/Config.php' created successfully~");
self::assertFileExists(__DIR__ . '/Generated/Config.php');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use GacelaTest\Integration\CodeGenerator\Util\DirectoryUtil;
use PHPUnit\Framework\TestCase;

final class UsingMakeDependencyProviderTest extends TestCase
{
public function setUp(): void
{
Config::setApplicationRootDir(__DIR__);
}

public function test_make_dependency_provider(): void
{
self::assertFileDoesNotExist(__DIR__ . '/Generated/DependencyProvider.php');

$codeGeneratorDependencyProvider = new CodeGeneratorFacade();
$codeGeneratorDependencyProvider->runCommand('make:dependency-provider', [__NAMESPACE__, __DIR__ . '/Generated']);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:dependency-provider', ['GacelaTest/Integration/CodeGenerator/Generated']);

$this->expectOutputRegex("~/Generated/DependencyProvider.php' created successfully~");
self::assertFileExists(__DIR__ . '/Generated/DependencyProvider.php');
Expand Down
10 changes: 8 additions & 2 deletions tests/Integration/CodeGenerator/UsingMakeFacadeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use GacelaTest\Integration\CodeGenerator\Util\DirectoryUtil;
use PHPUnit\Framework\TestCase;

final class UsingMakeFacadeTest extends TestCase
{
public function setUp(): void
{
Config::setApplicationRootDir(__DIR__);
}

public function test_make_facade(): void
{
self::assertFileDoesNotExist(__DIR__ . '/Generated/Facade.php');

$codeGeneratorFacade = new CodeGeneratorFacade();
$codeGeneratorFacade->runCommand('make:facade', [__NAMESPACE__, __DIR__ . '/Generated']);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:facade', ['GacelaTest/Integration/CodeGenerator/Generated']);

$this->expectOutputRegex("~/Generated/Facade.php' created successfully~");
self::assertFileExists(__DIR__ . '/Generated/Facade.php');
Expand Down
12 changes: 9 additions & 3 deletions tests/Integration/CodeGenerator/UsingMakeFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,27 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use GacelaTest\Integration\CodeGenerator\Util\DirectoryUtil;
use PHPUnit\Framework\TestCase;

final class UsingMakeFactoryTest extends TestCase
{
public function setUp(): void
{
Config::setApplicationRootDir(__DIR__);
}

public function test_make_factory(): void
{
self::assertFileDoesNotExist(__DIR__ . '/Generated/Factory.php');

$codeGeneratorFactory = new CodeGeneratorFacade();
$codeGeneratorFactory->runCommand('make:factory', [__NAMESPACE__, __DIR__ . '/Generated']);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:factory', ['GacelaTest/Integration/CodeGenerator/Generated']);

$this->expectOutputRegex("~/Generated/Factory.php' created successfully~");
self::assertFileExists(__DIR__ . '/Generated/Factory.php');

DirectoryUtil::removeDir(__DIR__ . '/Generated');
DirectoryUtil::removeDir(__DIR__ . '/Generated/');
}
}
10 changes: 8 additions & 2 deletions tests/Integration/CodeGenerator/UsingMakeModuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
namespace GacelaTest\Integration\CodeGenerator;

use Gacela\CodeGenerator\CodeGeneratorFacade;
use Gacela\Framework\Config;
use GacelaTest\Integration\CodeGenerator\Util\DirectoryUtil;
use PHPUnit\Framework\TestCase;

final class UsingMakeModuleTest extends TestCase
{
public function setUp(): void
{
Config::setApplicationRootDir(__DIR__);
}

public function test_make_module(): void
{
self::assertFileDoesNotExist(__DIR__ . '/Generated/Module.php');

$codeGeneratorModule = new CodeGeneratorFacade();
$codeGeneratorModule->runCommand('make:module', [__NAMESPACE__, __DIR__ . '/Generated']);
$facade = new CodeGeneratorFacade();
$facade->runCommand('make:module', ['GacelaTest/Integration/CodeGenerator/Generated']);

$this->expectOutputRegex("~/Generated/Facade.php' created successfully~");
$this->expectOutputRegex("~/Generated/Factory.php' created successfully~");
Expand Down
Loading

0 comments on commit 13ca3ab

Please sign in to comment.