Skip to content

Commit f268dcc

Browse files
authored
Merge pull request #22 from techmahedy/techmahedy-1.x
console command handle() method dependency injection:
2 parents 352441b + cda3be9 commit f268dcc

4 files changed

Lines changed: 133 additions & 11 deletions

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "doppar/airbend",
3-
"description": "Doppar Airbend is a real-time broadcasting component of the Doppar PHP Frameworkc",
3+
"description": "Doppar Airbend is a real-time broadcasting component of the Doppar PHP Framework",
44
"type": "library",
55
"license": "MIT",
66
"authors": [

src/Console/Commands/MakeEventCommand.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,24 @@ class MakeEventCommand extends Command
2525
*
2626
* @return int
2727
*/
28-
protected function handle(): int
28+
public function handle(): int
2929
{
3030
return $this->executeWithTiming(function () {
31-
$name = $this->argument('name');
32-
$parts = explode('/', $name);
33-
$className = array_pop($parts);
31+
[$name, $parts, $className] = $this->splitGeneratedName((string) $this->argument('name'));
3432

3533
// Ensure class name ends with Event
3634
if (!str_ends_with($className, 'Event')) {
3735
$className .= 'Event';
3836
}
3937

4038
$namespace = 'App\\Events' . (count($parts) > 0 ? '\\' . implode('\\', $parts) : '');
41-
$parts[] = $className;
42-
43-
$filePath = base_path('app/Events/' . implode(DIRECTORY_SEPARATOR, $parts) . '.php');
39+
$fileName = count($parts) > 0 ? implode('/', $parts) . '/' . $className : $className;
40+
$filePath = $this->generatedFilePath('app/Events', $fileName);
4441

4542
// Check if Event already exists
4643
if (file_exists($filePath)) {
4744
$this->displayError('Event already exists at:');
48-
$this->line('<fg=white>' . str_replace(base_path(), '', $filePath) . '</>');
45+
$this->line('<fg=white>' . $this->relativePath($filePath) . '</>');
4946
return Command::FAILURE;
5047
}
5148

@@ -64,7 +61,7 @@ protected function handle(): int
6461
file_put_contents($filePath, $content);
6562

6663
$this->displaySuccess('Event created successfully');
67-
$this->line('<fg=yellow>📦 File:</> <fg=white>' . str_replace(base_path(), '', $filePath) . '</>');
64+
$this->line('<fg=yellow>📦 File:</> <fg=white>' . $this->relativePath($filePath) . '</>');
6865
$this->newLine();
6966
$this->line('<fg=yellow>⚙️ Class:</> <fg=white>' . $className . '</>');
7067

src/Console/Commands/WebSocketStartCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class WebSocketStartCommand extends Command
2929
*
3030
* @return int
3131
*/
32-
protected function handle(): int
32+
public function handle(): int
3333
{
3434
$host = $this->option('host');
3535
$port = $this->option('port');
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doppar\Airbend\Tests\Unit;
6+
7+
use Doppar\Airbend\Console\Commands\MakeEventCommand;
8+
use PHPUnit\Framework\TestCase;
9+
10+
class MakeEventCommandTest extends TestCase
11+
{
12+
private string $tempRoot;
13+
14+
protected function setUp(): void
15+
{
16+
parent::setUp();
17+
18+
$this->tempRoot = sys_get_temp_dir() . '/doppar-airbend-command-' . bin2hex(random_bytes(5));
19+
mkdir($this->tempRoot, 0755, true);
20+
}
21+
22+
protected function tearDown(): void
23+
{
24+
$this->deleteDirectory($this->tempRoot);
25+
26+
parent::tearDown();
27+
}
28+
29+
public function testMakeEventCommandSupportsBackslashesAndRelativeOutput(): void
30+
{
31+
$command = new class($this->tempRoot) extends MakeEventCommand
32+
{
33+
public array $capturedLines = [];
34+
public array $capturedSuccesses = [];
35+
36+
public function __construct(private string $tempRoot)
37+
{
38+
parent::__construct();
39+
}
40+
41+
protected function argument($key = null)
42+
{
43+
return $key === 'name' ? 'Realtime\\OrderPlaced' : null;
44+
}
45+
46+
protected function line(string $string, ?string $style = null): void
47+
{
48+
$this->capturedLines[] = $string;
49+
}
50+
51+
protected function newLine($count = 1): void
52+
{
53+
}
54+
55+
protected function displaySuccess(string $message): void
56+
{
57+
$this->capturedSuccesses[] = $message;
58+
}
59+
60+
protected function executeWithTiming(callable $callback): int
61+
{
62+
$result = $callback();
63+
64+
return is_int($result) ? $result : 0;
65+
}
66+
67+
protected function generatedFilePath(string $baseDirectory, string $name, string $extension = '.php'): string
68+
{
69+
$normalizedName = $this->normalizeGeneratedName($name);
70+
$relativePath = trim($baseDirectory, '/\\');
71+
72+
if ($normalizedName !== '') {
73+
$relativePath .= '/' . $normalizedName;
74+
}
75+
76+
return $this->tempRoot . '/' . $relativePath . $extension;
77+
}
78+
79+
protected function relativePath(string $path, ?string $basePath = null): string
80+
{
81+
$normalizedPath = str_replace('\\', '/', $path);
82+
$normalizedBase = rtrim(str_replace('\\', '/', $this->tempRoot), '/');
83+
84+
return substr($normalizedPath, strlen($normalizedBase) + 1);
85+
}
86+
};
87+
88+
$result = $command->handle();
89+
$file = $this->tempRoot . '/app/Events/Realtime/OrderPlacedEvent.php';
90+
$contents = (string) file_get_contents($file);
91+
92+
$this->assertSame(0, $result);
93+
$this->assertFileExists($file);
94+
$this->assertStringContainsString('namespace App\\Events\\Realtime;', $contents);
95+
$this->assertStringContainsString('class OrderPlacedEvent extends BaseBroadcastEvent', $contents);
96+
$this->assertContains('Event created successfully', $command->capturedSuccesses);
97+
$this->assertContains(
98+
'<fg=yellow>📦 File:</> <fg=white>app/Events/Realtime/OrderPlacedEvent.php</>',
99+
$command->capturedLines
100+
);
101+
}
102+
103+
private function deleteDirectory(string $directory): void
104+
{
105+
if (!is_dir($directory)) {
106+
return;
107+
}
108+
109+
$iterator = new \RecursiveIteratorIterator(
110+
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
111+
\RecursiveIteratorIterator::CHILD_FIRST
112+
);
113+
114+
foreach ($iterator as $item) {
115+
if ($item->isDir()) {
116+
rmdir($item->getPathname());
117+
continue;
118+
}
119+
120+
unlink($item->getPathname());
121+
}
122+
123+
rmdir($directory);
124+
}
125+
}

0 commit comments

Comments
 (0)