mirror of
https://github.com/pacnpal/thrillwiki_laravel.git
synced 2025-12-20 06:51:10 -05:00
- Added rides index view with search and filter options. - Created rides show view to display ride details. - Implemented API routes for rides. - Developed authentication routes for user registration, login, and email verification. - Created tests for authentication, email verification, password reset, and user profile management. - Added feature tests for rides and operators, including creation, updating, deletion, and searching. - Implemented soft deletes and caching for rides and operators. - Enhanced manufacturer and operator model tests for various functionalities.
392 lines
12 KiB
PHP
392 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Filesystem\Filesystem;
|
|
use Illuminate\Support\Str;
|
|
|
|
class MakeThrillWikiLivewire extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*/
|
|
protected $signature = 'make:thrillwiki-livewire {name : The name of the component}
|
|
{--reusable : Generate a reusable component with optimization traits}
|
|
{--with-tests : Generate test files for the component}
|
|
{--cached : Add caching optimization to the component}
|
|
{--paginated : Add pagination support to the component}
|
|
{--force : Overwrite existing files}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*/
|
|
protected $description = 'Create a ThrillWiki-optimized Livewire component with built-in patterns and performance optimization';
|
|
|
|
protected Filesystem $files;
|
|
|
|
public function __construct(Filesystem $files)
|
|
{
|
|
parent::__construct();
|
|
$this->files = $files;
|
|
}
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle(): int
|
|
{
|
|
$name = $this->argument('name');
|
|
$className = Str::studly($name);
|
|
$kebabName = Str::kebab($name);
|
|
|
|
$this->info("🚀 Generating ThrillWiki Livewire Component: {$className}");
|
|
|
|
// Generate the component class
|
|
$this->generateComponent($className, $kebabName);
|
|
|
|
// Generate the view file
|
|
$this->generateView($className, $kebabName);
|
|
|
|
// Generate tests if requested
|
|
if ($this->option('with-tests')) {
|
|
$this->generateTest($className);
|
|
}
|
|
|
|
$this->displaySummary($className, $kebabName);
|
|
|
|
return Command::SUCCESS;
|
|
}
|
|
|
|
protected function generateComponent(string $className, string $kebabName): void
|
|
{
|
|
$componentPath = app_path("Livewire/{$className}.php");
|
|
|
|
if ($this->files->exists($componentPath) && !$this->option('force')) {
|
|
$this->error("Component {$className} already exists! Use --force to overwrite.");
|
|
return;
|
|
}
|
|
|
|
$stub = $this->getComponentStub();
|
|
$content = $this->replaceStubPlaceholders($stub, $className, $kebabName);
|
|
|
|
$this->files->ensureDirectoryExists(dirname($componentPath));
|
|
$this->files->put($componentPath, $content);
|
|
|
|
$this->info("✅ Component created: app/Livewire/{$className}.php");
|
|
}
|
|
|
|
protected function generateView(string $className, string $kebabName): void
|
|
{
|
|
$viewPath = resource_path("views/livewire/{$kebabName}.blade.php");
|
|
|
|
if ($this->files->exists($viewPath) && !$this->option('force')) {
|
|
$this->error("View {$kebabName}.blade.php already exists! Use --force to overwrite.");
|
|
return;
|
|
}
|
|
|
|
$stub = $this->getViewStub();
|
|
$content = $this->replaceViewPlaceholders($stub, $className, $kebabName);
|
|
|
|
$this->files->ensureDirectoryExists(dirname($viewPath));
|
|
$this->files->put($viewPath, $content);
|
|
|
|
$this->info("✅ View created: resources/views/livewire/{$kebabName}.blade.php");
|
|
}
|
|
|
|
protected function generateTest(string $className): void
|
|
{
|
|
$testPath = base_path("tests/Feature/Livewire/{$className}Test.php");
|
|
|
|
if ($this->files->exists($testPath) && !$this->option('force')) {
|
|
$this->error("Test {$className}Test already exists! Use --force to overwrite.");
|
|
return;
|
|
}
|
|
|
|
$stub = $this->getTestStub();
|
|
$content = $this->replaceTestPlaceholders($stub, $className);
|
|
|
|
$this->files->ensureDirectoryExists(dirname($testPath));
|
|
$this->files->put($testPath, $content);
|
|
|
|
$this->info("✅ Test created: tests/Feature/Livewire/{$className}Test.php");
|
|
}
|
|
|
|
protected function getComponentStub(): string
|
|
{
|
|
$traits = [];
|
|
$imports = ['use Livewire\Component;'];
|
|
$properties = [];
|
|
$methods = [];
|
|
|
|
// Add pagination if requested
|
|
if ($this->option('paginated')) {
|
|
$imports[] = 'use Livewire\WithPagination;';
|
|
$traits[] = 'WithPagination';
|
|
$properties[] = ' protected $paginationTheme = \'tailwind\';';
|
|
}
|
|
|
|
// Add caching optimization if requested
|
|
if ($this->option('cached') || $this->option('reusable')) {
|
|
$imports[] = 'use Illuminate\Support\Facades\Cache;';
|
|
$methods[] = $this->getCachingMethods();
|
|
}
|
|
|
|
// Build traits string
|
|
$traitsString = empty($traits) ? '' : "\n use " . implode(', ', $traits) . ";\n";
|
|
|
|
// Build properties string
|
|
$propertiesString = empty($properties) ? '' : "\n" . implode("\n", $properties) . "\n";
|
|
|
|
// Build methods string
|
|
$methodsString = implode("\n\n", $methods);
|
|
|
|
return <<<PHP
|
|
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
{IMPORTS}
|
|
|
|
class {CLASS_NAME} extends Component
|
|
{{TRAITS}{PROPERTIES}
|
|
/**
|
|
* Component initialization
|
|
*/
|
|
public function mount(): void
|
|
{
|
|
// Initialize component state
|
|
}
|
|
|
|
/**
|
|
* Render the component
|
|
*/
|
|
public function render()
|
|
{
|
|
return view('livewire.{VIEW_NAME}');
|
|
}{METHODS}
|
|
}
|
|
PHP;
|
|
}
|
|
|
|
protected function getViewStub(): string
|
|
{
|
|
if ($this->option('reusable')) {
|
|
return <<<BLADE
|
|
{{-- ThrillWiki Reusable Component: {CLASS_NAME} --}}
|
|
<div class="thrillwiki-component"
|
|
x-data="{ loading: false }"
|
|
wire:loading.class="opacity-50">
|
|
|
|
{{-- Component Header --}}
|
|
<div class="component-header mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
|
|
{CLASS_NAME}
|
|
</h3>
|
|
</div>
|
|
|
|
{{-- Component Content --}}
|
|
<div class="component-content">
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
ThrillWiki component content goes here.
|
|
</p>
|
|
|
|
{{-- Example interactive element --}}
|
|
<button wire:click="\$refresh"
|
|
class="mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors">
|
|
Refresh Component
|
|
</button>
|
|
</div>
|
|
|
|
{{-- Loading State --}}
|
|
<div wire:loading wire:target="\$refresh"
|
|
class="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center">
|
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
</div>
|
|
BLADE;
|
|
}
|
|
|
|
return <<<BLADE
|
|
{{-- ThrillWiki Component: {CLASS_NAME} --}}
|
|
<div class="thrillwiki-component">
|
|
<h3 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">
|
|
{CLASS_NAME}
|
|
</h3>
|
|
|
|
<p class="text-gray-600 dark:text-gray-400">
|
|
ThrillWiki component content goes here.
|
|
</p>
|
|
</div>
|
|
BLADE;
|
|
}
|
|
|
|
protected function getTestStub(): string
|
|
{
|
|
return <<<PHP
|
|
<?php
|
|
|
|
namespace Tests\Feature\Livewire;
|
|
|
|
use App\Livewire\{CLASS_NAME};
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class {CLASS_NAME}Test extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
/** @test */
|
|
public function component_can_render(): void
|
|
{
|
|
Livewire::test({CLASS_NAME}::class)
|
|
->assertStatus(200)
|
|
->assertSee('{CLASS_NAME}');
|
|
}
|
|
|
|
/** @test */
|
|
public function component_can_mount_successfully(): void
|
|
{
|
|
Livewire::test({CLASS_NAME}::class)
|
|
->assertStatus(200);
|
|
}
|
|
|
|
/** @test */
|
|
public function component_follows_thrillwiki_patterns(): void
|
|
{
|
|
Livewire::test({CLASS_NAME}::class)
|
|
->assertViewIs('livewire.{VIEW_NAME}');
|
|
}
|
|
}
|
|
PHP;
|
|
}
|
|
|
|
protected function getCachingMethods(): string
|
|
{
|
|
return <<<PHP
|
|
/**
|
|
* Get cache key for this component
|
|
*/
|
|
protected function getCacheKey(string \$suffix = ''): string
|
|
{
|
|
return 'thrillwiki.' . class_basename(static::class) . '.' . \$suffix;
|
|
}
|
|
|
|
/**
|
|
* Remember data with caching
|
|
*/
|
|
protected function remember(string \$key, \$callback, int \$ttl = 3600)
|
|
{
|
|
return Cache::remember(\$this->getCacheKey(\$key), \$ttl, \$callback);
|
|
}
|
|
|
|
/**
|
|
* Invalidate component cache
|
|
*/
|
|
protected function invalidateCache(string \$key = null): void
|
|
{
|
|
if (\$key) {
|
|
Cache::forget(\$this->getCacheKey(\$key));
|
|
} else {
|
|
// Clear all cache for this component
|
|
Cache::flush();
|
|
}
|
|
}
|
|
PHP;
|
|
}
|
|
|
|
protected function replaceStubPlaceholders(string $stub, string $className, string $kebabName): string
|
|
{
|
|
$imports = ['use Livewire\Component;'];
|
|
$traits = [];
|
|
|
|
if ($this->option('paginated')) {
|
|
$imports[] = 'use Livewire\WithPagination;';
|
|
$traits[] = 'WithPagination';
|
|
}
|
|
|
|
if ($this->option('cached') || $this->option('reusable')) {
|
|
$imports[] = 'use Illuminate\Support\Facades\Cache;';
|
|
}
|
|
|
|
$traitsString = empty($traits) ? '' : "\n use " . implode(', ', $traits) . ";\n";
|
|
$importsString = implode("\n", $imports);
|
|
$methodsString = '';
|
|
|
|
if ($this->option('cached') || $this->option('reusable')) {
|
|
$methodsString = "\n\n" . $this->getCachingMethods();
|
|
}
|
|
|
|
return str_replace(
|
|
['{IMPORTS}', '{CLASS_NAME}', '{VIEW_NAME}', '{TRAITS}', '{PROPERTIES}', '{METHODS}'],
|
|
[$importsString, $className, $kebabName, $traitsString, '', $methodsString],
|
|
$stub
|
|
);
|
|
}
|
|
|
|
protected function replaceViewPlaceholders(string $stub, string $className, string $kebabName): string
|
|
{
|
|
return str_replace(
|
|
['{CLASS_NAME}', '{VIEW_NAME}'],
|
|
[$className, $kebabName],
|
|
$stub
|
|
);
|
|
}
|
|
|
|
protected function replaceTestPlaceholders(string $stub, string $className): string
|
|
{
|
|
return str_replace(
|
|
['{CLASS_NAME}', '{VIEW_NAME}'],
|
|
[$className, Str::kebab($className)],
|
|
$stub
|
|
);
|
|
}
|
|
|
|
protected function displaySummary(string $className, string $kebabName): void
|
|
{
|
|
$this->newLine();
|
|
$this->info("🎉 ThrillWiki Livewire Component '{$className}' created successfully!");
|
|
$this->newLine();
|
|
|
|
$this->comment("📁 Files Generated:");
|
|
$this->line(" • app/Livewire/{$className}.php");
|
|
$this->line(" • resources/views/livewire/{$kebabName}.blade.php");
|
|
|
|
if ($this->option('with-tests')) {
|
|
$this->line(" • tests/Feature/Livewire/{$className}Test.php");
|
|
}
|
|
|
|
$this->newLine();
|
|
$this->comment("🚀 Features Added:");
|
|
|
|
if ($this->option('reusable')) {
|
|
$this->line(" • Reusable component patterns with optimization traits");
|
|
}
|
|
|
|
if ($this->option('cached')) {
|
|
$this->line(" • Caching optimization methods");
|
|
}
|
|
|
|
if ($this->option('paginated')) {
|
|
$this->line(" • Pagination support with Tailwind theme");
|
|
}
|
|
|
|
if ($this->option('with-tests')) {
|
|
$this->line(" • Automated test suite with ThrillWiki patterns");
|
|
}
|
|
|
|
$this->newLine();
|
|
$this->comment("📝 Next Steps:");
|
|
$this->line(" 1. Customize the component logic in app/Livewire/{$className}.php");
|
|
$this->line(" 2. Update the view template in resources/views/livewire/{$kebabName}.blade.php");
|
|
$this->line(" 3. Include the component in your templates with <livewire:{$kebabName} />");
|
|
|
|
if ($this->option('with-tests')) {
|
|
$this->line(" 4. Run tests with: php artisan test --filter {$className}Test");
|
|
}
|
|
|
|
$this->newLine();
|
|
$this->info("✨ Happy coding with ThrillWiki acceleration patterns!");
|
|
}
|
|
} |