Skip to content

Commit 009d81d

Browse files
ide-helper:actions (#5)
* Added ide-helper:actions for docblocks
1 parent 21fb23b commit 009d81d

22 files changed

+754
-15
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ Execute business logic with a single, expressive call. No more hunting through s
4545
### 📬 **Dispatchable Actions**
4646
Seamlessly queue your actions for background processing. It's as easy as changing `run()` to `dispatch()`!
4747

48+
### 💡 **Smart Code Completion**
49+
Full IntelliSense support with auto-completion for runnable and dispatchable actions across all major IDEs.
50+
4851
### 🔄 **Smart Array Conversion**
4952
Convert between arrays and objects effortlessly with our powerful attribute system. Perfect for APIs!
5053

@@ -247,6 +250,9 @@ php artisan make:action CalculateShipping --invokable
247250

248251
# DTO with array conversion
249252
php artisan make:dto OrderData
253+
254+
# Enable Smart Code Completion
255+
php artisan ide-helper:actions
250256
```
251257

252258
## 🌟 Real-World Examples

src/ActionableProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Support\ServiceProvider;
66
use LumoSolutions\Actionable\Console\BaseStubCommand;
7+
use LumoSolutions\Actionable\Console\Commands\ActionsIdeHelperCommand;
78
use LumoSolutions\Actionable\Console\Commands\MakeActionCommand;
89
use LumoSolutions\Actionable\Console\Commands\MakeDtoCommand;
910

@@ -17,6 +18,7 @@ public function boot(): void
1718
$this->commands([
1819
MakeActionCommand::class,
1920
MakeDtoCommand::class,
21+
ActionsIdeHelperCommand::class,
2022
]);
2123

2224
$this->publishes(
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
namespace LumoSolutions\Actionable\Console\Commands;
4+
5+
use Exception;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Support\Facades\File;
8+
use LumoSolutions\Actionable\Services\ActionDocBlockService;
9+
10+
class ActionsIdeHelperCommand extends Command
11+
{
12+
protected $signature = 'ide-helper:actions
13+
{--namespace=App\\ : The namespace to scan for actions}
14+
{--dry-run : Show what would be changed without modifying files}';
15+
16+
protected $description = 'Generate IDE helper doc blocks for Action classes using IsRunnable and IsDispatchable traits';
17+
18+
protected ActionDocBlockService $service;
19+
20+
public function __construct(ActionDocBlockService $service)
21+
{
22+
parent::__construct();
23+
$this->service = $service;
24+
}
25+
26+
public function handle(): int
27+
{
28+
$namespace = $this->option('namespace');
29+
$dryRun = $this->option('dry-run');
30+
31+
$this->info("Scanning for Action classes in namespace: {$namespace} ");
32+
33+
$files = $this->getPhpFiles($namespace);
34+
35+
if (empty($files)) {
36+
$this->error("No PHP files found in namespace: {$namespace}");
37+
38+
return self::FAILURE;
39+
}
40+
41+
$processedCount = 0;
42+
$skippedCount = 0;
43+
$errorCount = 0;
44+
45+
foreach ($files as $file) {
46+
$relativePath = str_replace(base_path().DIRECTORY_SEPARATOR, '', $file->getRealPath());
47+
48+
try {
49+
$result = $this->service->processFile($file->getPathname(), $dryRun);
50+
51+
if ($result['processed']) {
52+
$processedCount++;
53+
54+
if ($dryRun) {
55+
$this->line("<info>Would update:</info> {$relativePath}");
56+
$this->showDocBlockChanges($result['docBlocks']);
57+
} else {
58+
$this->info("Updated: {$relativePath}");
59+
}
60+
} else {
61+
$skippedCount++;
62+
if ($this->output->isVerbose()) {
63+
$this->line("<comment>Skipped:</comment> {$relativePath} - {$result['reason']}");
64+
}
65+
}
66+
} catch (Exception $e) {
67+
$errorCount++;
68+
$this->error("Error processing {$relativePath}: {$e->getMessage()}");
69+
70+
if ($this->output->isVeryVerbose()) {
71+
$this->line($e->getTraceAsString());
72+
}
73+
}
74+
}
75+
76+
$this->showSummary($processedCount, $skippedCount, $errorCount, $dryRun);
77+
78+
return ($errorCount > 0) ? self::FAILURE : self::SUCCESS;
79+
}
80+
81+
private function getPhpFiles(string $namespace): array
82+
{
83+
$path = app_path(str_replace(['App\\', '\\'], ['', '/'], $namespace));
84+
85+
if (! is_dir($path)) {
86+
return [];
87+
}
88+
89+
return collect(File::allFiles($path))
90+
->filter(fn ($file) => $file->getExtension() === 'php')
91+
->values()
92+
->all();
93+
}
94+
95+
private function showDocBlockChanges(array $docBlocks): void
96+
{
97+
if (empty($docBlocks)) {
98+
return;
99+
}
100+
101+
$this->line(' <comment>Doc blocks to add:</comment>');
102+
foreach ($docBlocks as $docBlock) {
103+
$this->line(" <info>*</info> {$docBlock}");
104+
}
105+
}
106+
107+
private function showSummary(int $processedCount, int $skippedCount, int $errorCount, bool $dryRun): void
108+
{
109+
$this->line('');
110+
$this->info('Summary:');
111+
112+
$action = $dryRun ? 'Would be updated' : 'Updated';
113+
$this->line(" <info>{$action}:</info> {$processedCount} files");
114+
115+
if ($skippedCount > 0 || $this->output->isVerbose()) {
116+
$this->line(" <comment>Skipped:</comment> {$skippedCount} files");
117+
}
118+
119+
if ($errorCount > 0) {
120+
$this->line(" <error>Errors:</error> {$errorCount} files");
121+
}
122+
123+
$this->line('');
124+
$status = $errorCount > 0 ? 'completed with errors' : 'completed successfully';
125+
$this->info("Process {$status}!");
126+
}
127+
}

0 commit comments

Comments
 (0)