files = $files; } /** * Execute the console command. */ public function handle(): int { $name = $this->argument('name'); $this->info("🚀 Generating ThrillWiki CRUD for: {$name}"); // Prepare naming conventions $names = $this->prepareNames($name); try { // Generate files $this->generateModel($names); $this->generateController($names); $this->generateFormRequest($names); $this->generateViews($names); $this->generateRoutes($names); if ($this->option('migration')) { $this->generateMigration($names); } if ($this->option('api')) { $this->generateApiResources($names); } if ($this->option('with-tests')) { $this->generateTests($names); } $this->displaySuccessMessage($names); } catch (\Exception $e) { $this->error("❌ Error generating CRUD: " . $e->getMessage()); return self::FAILURE; } return self::SUCCESS; } /** * Prepare all naming variations */ protected function prepareNames(string $name): array { $studly = Str::studly($name); $snake = Str::snake($name); $kebab = Str::kebab($name); $plural = Str::plural($snake); $pluralStudly = Str::studly($plural); return [ 'name' => $name, 'studly' => $studly, 'snake' => $snake, 'kebab' => $kebab, 'plural' => $plural, 'pluralStudly' => $pluralStudly, 'camel' => Str::camel($name), 'pluralCamel' => Str::camel($plural), 'title' => Str::title(str_replace('_', ' ', $snake)), 'pluralTitle' => Str::title(str_replace('_', ' ', $plural)), 'model' => $this->option('model') ?: $studly, 'controller' => $this->option('controller') ?: $studly . 'Controller', 'table' => $plural, ]; } /** * Generate the Eloquent model */ protected function generateModel(array $names): void { $path = app_path("Models/{$names['model']}.php"); if ($this->files->exists($path) && !$this->option('force')) { $this->warn("⚠️ Model already exists: {$path}"); return; } $stub = $this->getModelStub(); $content = $this->replaceStubVariables($stub, $names); $this->files->put($path, $content); $this->info("✅ Model created: app/Models/{$names['model']}.php"); } /** * Generate the controller */ protected function generateController(array $names): void { $path = app_path("Http/Controllers/{$names['controller']}.php"); if ($this->files->exists($path) && !$this->option('force')) { $this->warn("⚠️ Controller already exists: {$path}"); return; } $stub = $this->getControllerStub(); $content = $this->replaceStubVariables($stub, $names); $this->files->put($path, $content); $this->info("✅ Controller created: app/Http/Controllers/{$names['controller']}.php"); } /** * Generate form request validation */ protected function generateFormRequest(array $names): void { $requestName = $names['studly'] . 'Request'; $path = app_path("Http/Requests/{$requestName}.php"); if ($this->files->exists($path) && !$this->option('force')) { $this->warn("⚠️ Form Request already exists: {$path}"); return; } if (!$this->files->isDirectory(dirname($path))) { $this->files->makeDirectory(dirname($path), 0755, true); } $stub = $this->getFormRequestStub(); $content = $this->replaceStubVariables($stub, array_merge($names, ['requestName' => $requestName])); $this->files->put($path, $content); $this->info("✅ Form Request created: app/Http/Requests/{$requestName}.php"); } /** * Generate Blade views */ protected function generateViews(array $names): void { $viewPath = resource_path("views/{$names['plural']}"); if (!$this->files->isDirectory($viewPath)) { $this->files->makeDirectory($viewPath, 0755, true); } $views = ['index', 'show', 'create', 'edit']; foreach ($views as $view) { $path = "{$viewPath}/{$view}.blade.php"; if ($this->files->exists($path) && !$this->option('force')) { $this->warn("⚠️ View already exists: {$path}"); continue; } $stub = $this->getViewStub($view); $content = $this->replaceStubVariables($stub, $names); $this->files->put($path, $content); $this->info("✅ View created: resources/views/{$names['plural']}/{$view}.blade.php"); } } /** * Generate routes */ protected function generateRoutes(array $names): void { $webRoutesPath = base_path('routes/web.php'); $routeDefinition = $this->getRouteDefinition($names); // Check if route already exists $webRoutes = $this->files->get($webRoutesPath); if (strpos($webRoutes, "Route::resource('{$names['plural']}'") !== false) { $this->warn("⚠️ Routes may already exist for {$names['plural']}"); return; } // Append route to web.php $this->files->append($webRoutesPath, "\n" . $routeDefinition); $this->info("✅ Routes added to routes/web.php"); } /** * Generate migration */ protected function generateMigration(array $names): void { $migrationName = "create_{$names['table']}_table"; $timestamp = date('Y_m_d_His'); $path = database_path("migrations/{$timestamp}_{$migrationName}.php"); $stub = $this->getMigrationStub(); $content = $this->replaceStubVariables($stub, $names); $this->files->put($path, $content); $this->info("✅ Migration created: database/migrations/{$timestamp}_{$migrationName}.php"); } /** * Generate API resources */ protected function generateApiResources(array $names): void { // API Controller $apiPath = app_path("Http/Controllers/Api/{$names['controller']}.php"); if (!$this->files->isDirectory(dirname($apiPath))) { $this->files->makeDirectory(dirname($apiPath), 0755, true); } $stub = $this->getApiControllerStub(); $content = $this->replaceStubVariables($stub, $names); $this->files->put($apiPath, $content); $this->info("✅ API Controller created: app/Http/Controllers/Api/{$names['controller']}.php"); // API Resource $resourceName = $names['studly'] . 'Resource'; $resourcePath = app_path("Http/Resources/{$resourceName}.php"); if (!$this->files->isDirectory(dirname($resourcePath))) { $this->files->makeDirectory(dirname($resourcePath), 0755, true); } $stub = $this->getApiResourceStub(); $content = $this->replaceStubVariables($stub, array_merge($names, ['resourceName' => $resourceName])); $this->files->put($resourcePath, $content); $this->info("✅ API Resource created: app/Http/Resources/{$resourceName}.php"); // API Routes $apiRoutesPath = base_path('routes/api.php'); $apiRouteDefinition = $this->getApiRouteDefinition($names); $this->files->append($apiRoutesPath, "\n" . $apiRouteDefinition); $this->info("✅ API Routes added to routes/api.php"); } /** * Generate test files */ protected function generateTests(array $names): void { $testName = $names['controller'] . 'Test'; $testPath = base_path("tests/Feature/{$testName}.php"); if ($this->files->exists($testPath) && !$this->option('force')) { $this->warn("⚠️ Test already exists: {$testPath}"); return; } $stub = $this->getTestStub(); $content = $this->replaceStubVariables($stub, array_merge($names, ['testName' => $testName])); $this->files->put($testPath, $content); $this->info("✅ Test created: tests/Feature/{$testName}.php"); } /** * Get model stub content */ protected function getModelStub(): string { return ' \'boolean\', \'created_at\' => \'datetime\', \'updated_at\' => \'datetime\', \'deleted_at\' => \'datetime\', ]; /** * Scope for active records */ public function scopeActive($query) { return $query->where(\'is_active\', true); } /** * Get cache key for this model */ public function getCacheKey(string $suffix = \'\'): string { return \'thrillwiki.{{ snake }}.\'.$this->id.($suffix ? \'.\'.$suffix : \'\'); } }'; } /** * Get controller stub content */ protected function getControllerStub(): string { return 'filled(\'search\')) { $search = $request->get(\'search\'); $query->where(function ($q) use ($search) { $q->where(\'name\', \'ILIKE\', "%{$search}%") ->orWhere(\'description\', \'ILIKE\', "%{$search}%"); }); } // Filter by status if ($request->filled(\'status\')) { $query->where(\'is_active\', $request->get(\'status\') === \'active\'); } ${{ pluralCamel }} = $query->latest()->paginate(15)->withQueryString(); return view(\'{{ plural }}.index\', compact(\'{{ pluralCamel }}\')); } /** * Show the form for creating a new resource. */ public function create(): View { return view(\'{{ plural }}.create\'); } /** * Store a newly created resource in storage. */ public function store({{ studly }}Request $request): RedirectResponse { ${{ camel }} = {{ studly }}::create($request->validated()); return redirect() ->route(\'{{ plural }}.show\', ${{ camel }}) ->with(\'success\', \'{{ title }} created successfully!\'); } /** * Display the specified resource. */ public function show({{ studly }} ${{ camel }}): View { return view(\'{{ plural }}.show\', compact(\'{{ camel }}\')); } /** * Show the form for editing the specified resource. */ public function edit({{ studly }} ${{ camel }}): View { return view(\'{{ plural }}.edit\', compact(\'{{ camel }}\')); } /** * Update the specified resource in storage. */ public function update({{ studly }}Request $request, {{ studly }} ${{ camel }}): RedirectResponse { ${{ camel }}->update($request->validated()); return redirect() ->route(\'{{ plural }}.show\', ${{ camel }}) ->with(\'success\', \'{{ title }} updated successfully!\'); } /** * Remove the specified resource from storage. */ public function destroy({{ studly }} ${{ camel }}): RedirectResponse { ${{ camel }}->delete(); return redirect() ->route(\'{{ plural }}.index\') ->with(\'success\', \'{{ title }} deleted successfully!\'); } }'; } /** * Get form request stub content */ protected function getFormRequestStub(): string { return ' [\'required\', \'string\', \'max:255\'], \'description\' => [\'nullable\', \'string\'], \'is_active\' => [\'boolean\'], ]; // For updates, make name unique except for current record if ($this->route(\'{{ camel }}\')) { $rules[\'name\'][] = \'unique:{{ table }},name,\' . $this->route(\'{{ camel }}\')->id; } else { $rules[\'name\'][] = \'unique:{{ table }},name\'; } return $rules; } /** * Get custom messages for validator errors. */ public function messages(): array { return [ \'name.required\' => \'The {{ snake }} name is required.\', \'name.unique\' => \'A {{ snake }} with this name already exists.\', ]; } }'; } /** * Get view stub content */ protected function getViewStub(string $view): string { $stubs = [ 'index' => '@extends(\'layouts.app\') @section(\'content\')
{{ ${{ camel }}->description }}
@endif{{ ${{ camel }}->name }}
{{ ${{ camel }}->description }}
{{ ${{ camel }}->created_at->format(\'F j, Y \at g:i A\') }}
{{ ${{ camel }}->updated_at->format(\'F j, Y \at g:i A\') }}