Skip to content

Commit a4ab813

Browse files
feat(console): add make:view command (#864)
Co-authored-by: Enzo Innocenzi <[email protected]>
1 parent 08df98c commit a4ab813

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\View\Commands;
6+
7+
use InvalidArgumentException;
8+
use Tempest\Console\ConsoleArgument;
9+
use Tempest\Console\ConsoleCommand;
10+
use Tempest\Core\PublishesFiles;
11+
use Tempest\Generation\DataObjects\StubFile;
12+
use Tempest\Generation\Enums\StubFileType;
13+
use Tempest\Generation\Exceptions\FileGenerationAbortedException;
14+
use Tempest\Generation\Exceptions\FileGenerationFailedException;
15+
use Tempest\View\Enums\ViewType;
16+
use Tempest\View\Stubs\ViewStub;
17+
use function Tempest\Support\str;
18+
19+
final class MakeViewCommand
20+
{
21+
use PublishesFiles;
22+
23+
#[ConsoleCommand(
24+
name: 'make:view',
25+
description: 'Creates a view file',
26+
aliases: ['view:make', 'view:create', 'create:view'],
27+
)]
28+
public function __invoke(
29+
#[ConsoleArgument(
30+
description: 'The file name of the view',
31+
)]
32+
string $fileName,
33+
#[ConsoleArgument(
34+
name: 'type',
35+
description: 'The type of the view to create',
36+
)]
37+
ViewType $viewType = ViewType::RAW,
38+
): void {
39+
try {
40+
$suggestedPath = str($this->getSuggestedPath('Dummy'));
41+
$suggestedPath = ($viewType === ViewType::RAW)
42+
? $suggestedPath->replace('Dummy', $fileName . '.view')
43+
: $suggestedPath->replace('Dummy', $fileName);
44+
45+
$suggestedPath = $suggestedPath->toString();
46+
$targetPath = $this->promptTargetPath($suggestedPath);
47+
$shouldOverride = $this->askForOverride($targetPath);
48+
49+
$stubFile = $this->getStubFileFromViewType($viewType);
50+
51+
if ($stubFile->type === StubFileType::RAW_FILE) {
52+
$this->stubFileGenerator->generateRawFile(
53+
stubFile: $stubFile,
54+
targetPath: $targetPath,
55+
shouldOverride: $shouldOverride,
56+
);
57+
} else {
58+
$this->stubFileGenerator->generateClassFile(
59+
stubFile: $stubFile,
60+
targetPath: $targetPath,
61+
shouldOverride: $shouldOverride,
62+
replacements: [
63+
'dummy.view.php' => str($fileName)->kebab()->toString() . '.view.php',
64+
],
65+
);
66+
}
67+
68+
$this->success(sprintf('View successfully created at "%s".', $targetPath));
69+
} catch (FileGenerationAbortedException|FileGenerationFailedException|InvalidArgumentException $e) {
70+
$this->error($e->getMessage());
71+
}
72+
}
73+
74+
private function getStubFileFromViewType(ViewType $viewType): StubFile
75+
{
76+
try {
77+
return match ($viewType) {
78+
ViewType::RAW => StubFile::from(dirname(__DIR__) . '/Stubs/view.stub.php'),
79+
ViewType::OBJECT => StubFile::from(ViewStub::class), // @phpstan-ignore match.alwaysTrue (Because this is a guardrail for the future implementations)
80+
default => throw new InvalidArgumentException(sprintf('The "%s" view type has no supported stub file.', $viewType->value)),
81+
};
82+
} catch (InvalidArgumentException $invalidArgumentException) {
83+
throw new FileGenerationFailedException(sprintf('Cannot retrieve stub file: %s', $invalidArgumentException->getMessage()));
84+
}
85+
}
86+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\View\Enums;
6+
7+
/**
8+
* Represents the type of view.
9+
* Used to differentiate between raw and class views.
10+
*/
11+
enum ViewType: string
12+
{
13+
case RAW = 'raw';
14+
case OBJECT = 'class';
15+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\View\Stubs;
6+
7+
use Tempest\View\IsView;
8+
use Tempest\View\View;
9+
10+
final class ViewStub implements View
11+
{
12+
use IsView;
13+
14+
public function __construct()
15+
{
16+
$this->path = __DIR__ . '/dummy.view.php';
17+
}
18+
}

src/Tempest/View/src/Stubs/view.stub.php

Whitespace-only changes.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Tempest\Integration\Console\Commands;
6+
7+
use PHPUnit\Framework\Attributes\Test;
8+
use Tempest\Core\ComposerNamespace;
9+
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
10+
11+
/**
12+
* @internal
13+
*/
14+
final class MakeViewCommandTest extends FrameworkIntegrationTestCase
15+
{
16+
protected function setUp(): void
17+
{
18+
parent::setUp();
19+
20+
$this->installer->configure(
21+
__DIR__ . '/install',
22+
new ComposerNamespace('App\\', __DIR__ . '/install/App'),
23+
);
24+
}
25+
26+
protected function tearDown(): void
27+
{
28+
$this->installer->clean();
29+
30+
parent::tearDown();
31+
}
32+
33+
#[Test]
34+
public function make_view(): void
35+
{
36+
$this->console
37+
->call('make:view home')
38+
->submit();
39+
40+
$this->installer->assertFileExists('App/home.view.php');
41+
42+
$this->console
43+
->call('make:view HomeView class')
44+
->submit();
45+
46+
$filepath = 'App/HomeView.php';
47+
$this->installer
48+
->assertFileExists($filepath)
49+
->assertFileContains($filepath, 'implements View')
50+
->assertFileContains($filepath, "use Tempest\View\View")
51+
->assertFileContains($filepath, 'use IsView')
52+
->assertFileContains($filepath, "use Tempest\View\IsView");
53+
}
54+
}

0 commit comments

Comments
 (0)