Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ composer require --dev boundwize/structarmed

```bash
vendor/bin/structarmed init
vendor/bin/structarmed init --preset=ddd
vendor/bin/structarmed init --preset=mvc
vendor/bin/structarmed init --preset=psr4
vendor/bin/structarmed init --preset=all
```

Generates a `structarmed.php` in your project root. Edit it to match your structure, then run:
Expand Down Expand Up @@ -177,6 +181,10 @@ vendor/bin/structarmed analyze --report=json

# Generate initial config
vendor/bin/structarmed init
vendor/bin/structarmed init --preset=ddd
vendor/bin/structarmed init --preset=mvc
vendor/bin/structarmed init --preset=psr4
vendor/bin/structarmed init --preset=all
```

## Layer resolution
Expand Down
52 changes: 43 additions & 9 deletions bin/structarmed.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
}
}

$basePath = getcwd();
$command = $argv[1] ?? null;
$basePath = getcwd();
$command = $argv[1] ?? null;

$printUsage = static function (): void {
echo <<<'TXT'
Usage:
structarmed init
structarmed init [--preset=ddd|mvc|psr4|all]
structarmed analyse|analyze [path ...] [--config=path/to/structarmed.php] [--report=console|json]

TXT;
Expand All @@ -39,6 +39,41 @@

// Handle `init` command — generate a sample config
if ($command === 'init') {
$preset = 'psr4';
$arguments = array_slice($argv, 2);

for ($i = 0; $i < count($arguments); $i++) {
$argument = $arguments[$i];

if (str_starts_with($argument, '--preset=')) {
$preset = strtolower(substr($argument, strlen('--preset=')));
continue;
}

if ($argument === '--preset') {
$preset = strtolower($arguments[++$i] ?? '');
continue;
}

echo sprintf("Unknown option: %s\n\n", $argument);
$printUsage();
exit(1);
}

$presetConfig = match ($preset) {
'ddd' => ' ->withPreset(Preset::DDD());',
'mvc' => ' ->withPreset(Preset::MVC());',
'psr4' => ' ->withPreset(Preset::PSR4());',
'all' => ' ->withPresets(Preset::PSR4(), Preset::DDD(), Preset::MVC());',
default => null,
};

if ($presetConfig === null) {
echo sprintf("Invalid preset: %s\n\n", $preset);
$printUsage();
exit(1);
}

$target = $basePath . '/structarmed.php';

if (file_exists($target)) {
Expand All @@ -55,8 +90,8 @@
use Boundwize\StructArmed\Preset\Preset;

return Architecture::define()
->withPreset(Preset::PSR4());
PHP);
file_put_contents($target, "\n" . $presetConfig . "\n", FILE_APPEND);

echo "Created structarmed.php\n";
exit(0);
Expand All @@ -68,7 +103,7 @@
exit(1);
}

$options = [];
$options = [];
$scanPaths = [];
$arguments = array_slice($argv, 2);

Expand Down Expand Up @@ -99,7 +134,6 @@
echo sprintf("Unknown option: %s\n\n", $argument);
$printUsage();
exit(1);
continue;
}

$scanPaths[] = $argument;
Expand Down Expand Up @@ -132,10 +166,10 @@
}

// Run analysis
$start = microtime(true);
$analyser = new Analyser($basePath);
$start = microtime(true);
$analyser = new Analyser($basePath);
$violations = $analyser->analyse($architecture, $scanPaths);
$elapsed = microtime(true) - $start;
$elapsed = microtime(true) - $start;

// Render report
$report = match ($reportType) {
Expand Down
161 changes: 161 additions & 0 deletions tests/Cli/InitCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php

declare(strict_types=1);

namespace Boundwize\StructArmed\Tests\Cli;

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

use function array_map;
use function bin2hex;
use function chdir;
use function dirname;
use function escapeshellarg;
use function exec;
use function file_exists;
use function file_get_contents;
use function getcwd;
use function implode;
use function is_dir;
use function mkdir;
use function random_bytes;
use function rmdir;
use function sprintf;
use function sys_get_temp_dir;
use function unlink;

use const PHP_BINARY;

final class InitCommandTest extends TestCase
{
/**
* @return iterable<string, array{list<string>, string}>
*/
public static function presetProvider(): iterable
{
yield 'default' => [
[],
' ->withPreset(Preset::PSR4());',
];

yield 'ddd' => [
['--preset=ddd'],
' ->withPreset(Preset::DDD());',
];

yield 'mvc' => [
['--preset=mvc'],
' ->withPreset(Preset::MVC());',
];

yield 'psr4' => [
['--preset=psr4'],
' ->withPreset(Preset::PSR4());',
];

yield 'all' => [
['--preset=all'],
' ->withPresets(Preset::PSR4(), Preset::DDD(), Preset::MVC());',
];
}

/**
* @param list<string> $arguments
*/
#[DataProvider('presetProvider')]
public function testInitGeneratesConfigForPreset(array $arguments, string $expectedPreset): void
{
$basePath = $this->createTempDirectory();

try {
[$exitCode, $output] = $this->runInit($basePath, $arguments);

$this->assertSame(0, $exitCode, $output);
$this->assertStringContainsString('Created structarmed.php', $output);
$this->assertSame(
$this->expectedConfig($expectedPreset),
(string) file_get_contents($basePath . '/structarmed.php')
);
} finally {
$this->removeTempDirectory($basePath);
}
}

public function testInitRejectsInvalidPreset(): void
{
$basePath = $this->createTempDirectory();

try {
[$exitCode, $output] = $this->runInit($basePath, ['--preset=unknown']);

$this->assertSame(1, $exitCode);
$this->assertStringContainsString('Invalid preset: unknown', $output);
$this->assertFileDoesNotExist($basePath . '/structarmed.php');
} finally {
$this->removeTempDirectory($basePath);
}
}

/**
* @param list<string> $arguments
* @return array{int, string}
*/
private function runInit(string $basePath, array $arguments): array
{
$previousDirectory = getcwd();
$output = [];
$exitCode = 0;
$command = sprintf(
'%s %s init %s',
escapeshellarg(PHP_BINARY),
escapeshellarg(dirname(__DIR__, 2) . '/bin/structarmed.php'),
implode(' ', array_map(escapeshellarg(...), $arguments))
);

chdir($basePath);

try {
exec($command . ' 2>&1', $output, $exitCode);
} finally {
chdir((string) $previousDirectory);
}

return [$exitCode, implode("\n", $output)];
}

private function createTempDirectory(): string
{
$basePath = sys_get_temp_dir() . '/structarmed-init-' . bin2hex(random_bytes(6));
mkdir($basePath);

return $basePath;
}

private function expectedConfig(string $presetConfig): string
{
return <<<PHP
<?php

declare(strict_types=1);

use Boundwize\StructArmed\Architecture;
use Boundwize\StructArmed\Preset\Preset;

return Architecture::define()
{$presetConfig}

PHP;
}

private function removeTempDirectory(string $basePath): void
{
if (file_exists($basePath . '/structarmed.php')) {
unlink($basePath . '/structarmed.php');
}

if (is_dir($basePath)) {
rmdir($basePath);
}
}
}
Loading