11: Controladores en Laravel 12 - Guía Práctica y Avanzada
Introducción
Los controladores son el corazón de la lógica de negocio en una aplicación Laravel. Actúan como intermediarios entre las rutas (peticiones HTTP) y las vistas/modelos, organizando el código de manera estructurada y mantenible. En este tutorial, exploraremos en profundidad cómo crear y utilizar controladores en Laravel 12, desde los conceptos básicos hasta técnicas avanzadas.
Índice
¿Qué son los Controladores?
Creación de Controladores
Controladores Resource
Inyección de Dependencias
Controladores con Middleware
Controladores Invocables
Controladores para API
Controladores con Servicios
Manejo de Excepciones
Mejores Prácticas
Ejercicio Práctico: CRUD Completo
1. ¿Qué son los Controladores?
Los controladores son clases que organizan la lógica de las peticiones HTTP. En lugar de definir toda la lógica en el archivo routes.php, los controladores permiten agrupar funcionalidades relacionadas.
Estructura básica de un Controlador
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PastelController extends Controller
{
/**
* Muestra la lista de pasteles
*/
public function index()
{
// Lógica para mostrar pasteles
return view('pasteles.index');
}
/**
* Muestra el formulario para crear
*/
public function create()
{
return view('pasteles.create');
}
/**
* Almacena un nuevo pastel
*/
public function store(Request $request)
{
// Lógica para guardar
}
/**
* Muestra un pastel específico
*/
public function show($id)
{
// Lógica para mostrar un pastel
}
/**
* Muestra el formulario para editar
*/
public function edit($id)
{
// Lógica para editar
}
/**
* Actualiza un pastel específico
*/
public function update(Request $request, $id)
{
// Lógica para actualizar
}
/**
* Elimina un pastel
*/
public function destroy($id)
{
// Lógica para eliminar
}
}Métodos HTTP y su relación con los Controladores
| Método HTTP | Método del Controlador | Propósito |
|---|---|---|
| GET | index() | Listar recursos |
| GET | create() | Mostrar formulario de creación |
| POST | store() | Almacenar nuevo recurso |
| GET | show($id) | Mostrar recurso específico |
| GET | edit($id) | Mostrar formulario de edición |
| PUT/PATCH | update($id) | Actualizar recurso |
| DELETE | destroy($id) | Eliminar recurso |
2. Creación de Controladores
Comandos Artisan para crear Controladores
# Controlador básico
php artisan make:controller PastelController
# Controlador Resource (con todos los métodos)
php artisan make:controller PastelController --resource
# Controlador con modelo vinculado
php artisan make:controller PastelController --model=Pastel
# Controlador con modelo y resource
php artisan make:controller PastelController --resource --model=Pastel
# Controlador para API
php artisan make:controller Api/PastelController --api
# Controlador invocable (single action)
php artisan make:controller ListarPastelesController --invokableEjemplo de Controlador con Model Binding
php artisan make:controller PastelController --model=Pastel --resource<?php
namespace App\Http\Controllers;
use App\Models\Pastel;
use Illuminate\Http\Request;
use App\Http\Requests\StorePastelRequest;
use App\Http\Requests\UpdatePastelRequest;
class PastelController extends Controller
{
/**
* Listar todos los pasteles
*/
public function index()
{
$pasteles = Pastel::withTrashed()->paginate(10);
return view('pasteles.index', compact('pasteles'));
}
/**
* Mostrar formulario de creación
*/
public function create()
{
$sabores = ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco'];
return view('pasteles.create', compact('sabores'));
}
/**
* Almacenar nuevo pastel
*/
public function store(StorePastelRequest $request)
{
$pastel = Pastel::create($request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel creado exitosamente');
}
/**
* Mostrar pastel específico (Model Binding automático)
*/
public function show(Pastel $pastel)
{
return view('pasteles.show', compact('pastel'));
}
/**
* Mostrar formulario de edición
*/
public function edit(Pastel $pastel)
{
$sabores = ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco'];
return view('pasteles.edit', compact('pastel', 'sabores'));
}
/**
* Actualizar pastel
*/
public function update(UpdatePastelRequest $request, Pastel $pastel)
{
$pastel->update($request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel actualizado exitosamente');
}
/**
* Eliminar pastel
*/
public function destroy(Pastel $pastel)
{
$pastel->delete();
return redirect()
->route('pasteles.index')
->with('success', 'Pastel eliminado exitosamente');
}
}3. Controladores Resource
Ruta Resource Completa
// routes/web.php
Route::resource('pasteles', PastelController::class);Personalizar Nombres de Rutas Resource
Route::resource('pasteles', PastelController::class)
->names([
'index' => 'pasteles.list',
'create' => 'pasteles.crear',
'store' => 'pasteles.guardar',
'show' => 'pasteles.ver',
'edit' => 'pasteles.editar',
'update' => 'pasteles.actualizar',
'destroy' => 'pasteles.eliminar'
]);Especificar Solo Algunos Métodos
// Solo permitir lectura y creación
Route::resource('pasteles', PastelController::class)
->only(['index', 'show', 'create', 'store']);
// Excluir métodos específicos
Route::resource('pasteles', PastelController::class)
->except(['destroy', 'update']);Recursos Anidados
Route::resource('categorias.pasteles', PastelController::class)
->shallow();Recursos con Parámetros Personalizados
Route::resource('pasteles', PastelController::class)
->parameters(['pasteles' => 'pastel_id']);Tabla de Rutas Generadas
php artisan route:list| Método | URI | Nombre | Acción |
|---|---|---|---|
| GET | pasteles | pasteles.index | index |
| GET | pasteles/create | pasteles.create | create |
| POST | pasteles | pasteles.store | store |
| GET | pasteles/{pastel} | pasteles.show | show |
| GET | pasteles/{pastel}/edit | pasteles.edit | edit |
| PUT/PATCH | pasteles/{pastel} | pasteles.update | update |
| DELETE | pasteles/{pastel} | pasteles.destroy | destroy |
4. Inyección de Dependencias
Inyección en el Constructor
<?php
namespace App\Http\Controllers;
use App\Services\PastelService;
use App\Repositories\PastelRepository;
class PastelController extends Controller
{
protected $pastelService;
protected $pastelRepository;
public function __construct(
PastelService $pastelService,
PastelRepository $pastelRepository
) {
$this->pastelService = $pastelService;
$this->pastelRepository = $pastelRepository;
}
public function index()
{
$pasteles = $this->pastelRepository->getAll();
return view('pasteles.index', compact('pasteles'));
}
public function store(Request $request)
{
$pastel = $this->pastelService->create($request->all());
return redirect()->route('pasteles.index');
}
}Inyección en Métodos Específicos
<?php
namespace App\Http\Controllers;
use App\Services\PastelService;
use App\Services\ReporteService;
use Illuminate\Http\Request;
class PastelController extends Controller
{
public function index(PastelService $pastelService)
{
$pasteles = $pastelService->obtenerTodos();
return view('pasteles.index', compact('pasteles'));
}
public function reporte(ReporteService $reporteService)
{
$reporte = $reporteService->generarReportePasteles();
return response()->json($reporte);
}
public function exportar(Request $request, ExportService $exportService)
{
return $exportService->exportarPasteles($request->all());
}
}Inyección de Modelos (Route Model Binding)
// Sin model binding
public function show($id)
{
$pastel = Pastel::findOrFail($id);
return view('pasteles.show', compact('pastel'));
}
// Con model binding automático
public function show(Pastel $pastel)
{
return view('pasteles.show', compact('pastel'));
}
// Con model binding personalizado
public function show(Pastel $pastel, $id)
{
// $pastel tiene el modelo
// $id es el parámetro de la ruta
}5. Controladores con Middleware
Aplicar Middleware en el Constructor
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PastelController extends Controller
{
public function __construct()
{
// Aplicar middleware a todos los métodos
$this->middleware('auth');
// Aplicar middleware a métodos específicos
$this->middleware('admin')->only(['create', 'store', 'edit', 'update', 'destroy']);
// Excluir middleware de métodos específicos
$this->middleware('log')->except(['index', 'show']);
// Middleware con parámetros
$this->middleware('role:editor')->only(['edit', 'update']);
}
}Middleware en Rutas Resource
// Aplicar middleware a todo el resource
Route::resource('pasteles', PastelController::class)
->middleware('auth');
// Grupo de rutas con middleware
Route::middleware(['auth', 'admin'])->group(function () {
Route::resource('pasteles', PastelController::class)
->except(['index', 'show']);
});
// Middleware específico por método
Route::resource('pasteles', PastelController::class)
->only(['create', 'store', 'edit', 'update', 'destroy'])
->middleware('admin');Middleware Personalizado para Autorización
// Crear middleware
php artisan make:middleware CheckUserRole
// app/Http/Middleware/CheckUserRole.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckUserRole
{
public function handle(Request $request, Closure $next, ...$roles)
{
if (!auth()->check()) {
return redirect()->route('login');
}
foreach ($roles as $role) {
if (auth()->user()->hasRole($role)) {
return $next($request);
}
}
abort(403, 'No tienes permisos para acceder a esta sección.');
}
}
// Registrar en kernel
protected $routeMiddleware = [
// ...
'role' => \App\Http\Middleware\CheckUserRole::class,
];
// Usar en controlador
public function __construct()
{
$this->middleware('role:admin,editor')->only(['edit', 'update']);
$this->middleware('role:admin')->only(['destroy']);
}6. Controladores Invocables
Los controladores invocables son útiles cuando un controlador tiene una única acción.
php artisan make:controller ListarPastelesController --invokable<?php
namespace App\Http\Controllers;
use App\Models\Pastel;
use Illuminate\Http\Request;
use Illuminate\View\View;
class ListarPastelesController extends Controller
{
/**
* Invoke the controller.
*/
public function __invoke(Request $request): View
{
$query = Pastel::query();
// Filtrar por sabor
if ($request->has('sabor') && $request->sabor !== 'todos') {
$query->where('sabor', $request->sabor);
}
// Filtrar por disponibilidad
if ($request->has('disponible')) {
$query->where('disponible', $request->disponible === 'si');
}
// Buscar por nombre
if ($request->has('search')) {
$query->where('nombre', 'like', "%{$request->search}%");
}
$pasteles = $query->paginate(15);
$sabores = ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco'];
return view('pasteles.index', compact('pasteles', 'sabores'));
}
}Ruta para Controlador Invocable
Route::get('/pasteles/listar', ListarPastelesController::class);Múltiples Controladores Invocables
// Crear controladores para cada acción
php artisan make:controller CrearPastelController --invokable
php artisan make:controller EditarPastelController --invokable
php artisan make:controller EliminarPastelController --invokable
// Registrar rutas
Route::get('/pasteles/crear', CrearPastelController::class);
Route::get('/pasteles/{pastel}/editar', EditarPastelController::class);
Route::delete('/pasteles/{pastel}', EliminarPastelController::class);7. Controladores para API
Crear Controlador API
php artisan make:controller Api/PastelController --api<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Pastel;
use App\Http\Resources\PastelResource;
use App\Http\Resources\PastelCollection;
use App\Http\Requests\StorePastelRequest;
use App\Http\Requests\UpdatePastelRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class PastelController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request): PastelCollection
{
$query = Pastel::query();
// Filtros
if ($request->has('sabor')) {
$query->where('sabor', $request->sabor);
}
if ($request->has('disponible')) {
$query->where('disponible', filter_var($request->disponible, FILTER_VALIDATE_BOOLEAN));
}
// Ordenamiento
if ($request->has('sort_by') && in_array($request->sort_by, ['nombre', 'precio', 'created_at'])) {
$direction = $request->get('direction', 'asc');
$query->orderBy($request->sort_by, $direction);
}
// Paginación
$perPage = $request->get('per_page', 15);
$pasteles = $query->paginate($perPage);
return new PastelCollection($pasteles);
}
/**
* Store a newly created resource in storage.
*/
public function store(StorePastelRequest $request): PastelResource
{
$pastel = Pastel::create($request->validated());
return new PastelResource($pastel);
}
/**
* Display the specified resource.
*/
public function show(Pastel $pastel): PastelResource
{
return new PastelResource($pastel);
}
/**
* Update the specified resource in storage.
*/
public function update(UpdatePastelRequest $request, Pastel $pastel): PastelResource
{
$pastel->update($request->validated());
return new PastelResource($pastel);
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Pastel $pastel): JsonResponse
{
$pastel->delete();
return response()->json([
'message' => 'Pastel eliminado exitosamente'
], 200);
}
/**
* Restore a soft-deleted resource.
*/
public function restore($id): JsonResponse
{
$pastel = Pastel::withTrashed()->findOrFail($id);
$pastel->restore();
return response()->json([
'message' => 'Pastel restaurado exitosamente',
'pastel' => new PastelResource($pastel)
]);
}
/**
* Get available flavors.
*/
public function sabores(): JsonResponse
{
$sabores = Pastel::select('sabor')
->distinct()
->pluck('sabor')
->toArray();
return response()->json($sabores);
}
}Crear Resources para API
php artisan make:resource PastelResource
php artisan make:resource PastelCollection<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PastelResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'nombre' => $this->nombre,
'sabor' => $this->sabor,
'precio' => number_format($this->precio, 2),
'disponible' => $this->disponible,
'descripcion' => $this->descripcion,
'creado_en' => $this->created_at->toISOString(),
'actualizado_en' => $this->updated_at->toISOString(),
'links' => [
'self' => route('api.pasteles.show', $this->id),
'edit' => route('api.pasteles.edit', $this->id),
]
];
}
}Rutas API
// routes/api.php
use App\Http\Controllers\Api\PastelController;
Route::apiResource('pasteles', PastelController::class);
// Rutas adicionales
Route::prefix('pasteles')->group(function () {
Route::get('/sabores', [PastelController::class, 'sabores']);
Route::post('/{id}/restore', [PastelController::class, 'restore']);
});8. Controladores con Servicios
Crear Servicios
// app/Services/PastelService.php
<?php
namespace App\Services;
use App\Models\Pastel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
class PastelService
{
public function obtenerTodosConCache()
{
return Cache::remember('pasteles.todos', 3600, function () {
return Pastel::withTrashed()->get();
});
}
public function crearPastel(array $data): Pastel
{
// Procesar datos
$data['nombre'] = ucwords(strtolower($data['nombre']));
$data['disponible'] = $data['disponible'] ?? true;
// Crear pastel
$pastel = Pastel::create($data);
// Limpiar caché
Cache::forget('pasteles.todos');
return $pastel;
}
public function actualizarPastel(Pastel $pastel, array $data): Pastel
{
$pastel->update($data);
Cache::forget('pasteles.todos');
return $pastel;
}
public function eliminarPastel(Pastel $pastel): bool
{
$result = $pastel->delete();
Cache::forget('pasteles.todos');
return $result;
}
public function importarDesdeCSV($filePath): array
{
$importados = 0;
$errores = [];
if (($handle = fopen($filePath, 'r')) !== false) {
while (($row = fgetcsv($handle, 1000, ',')) !== false) {
try {
Pastel::create([
'nombre' => $row[0],
'sabor' => $row[1],
'precio' => $row[2] ?? 0,
'disponible' => $row[3] ?? true,
]);
$importados++;
} catch (\Exception $e) {
$errores[] = $e->getMessage();
}
}
fclose($handle);
}
return [
'importados' => $importados,
'errores' => $errores
];
}
}Controlador con Servicio
<?php
namespace App\Http\Controllers;
use App\Services\PastelService;
use App\Http\Requests\StorePastelRequest;
use App\Http\Requests\UpdatePastelRequest;
use App\Models\Pastel;
use Illuminate\Http\Request;
class PastelController extends Controller
{
protected $pastelService;
public function __construct(PastelService $pastelService)
{
$this->pastelService = $pastelService;
}
public function index()
{
$pasteles = $this->pastelService->obtenerTodosConCache();
return view('pasteles.index', compact('pasteles'));
}
public function store(StorePastelRequest $request)
{
$pastel = $this->pastelService->crearPastel($request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel creado exitosamente');
}
public function update(UpdatePastelRequest $request, Pastel $pastel)
{
$this->pastelService->actualizarPastel($pastel, $request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel actualizado exitosamente');
}
public function destroy(Pastel $pastel)
{
$this->pastelService->eliminarPastel($pastel);
return redirect()
->route('pasteles.index')
->with('success', 'Pastel eliminado exitosamente');
}
public function importar(Request $request)
{
$request->validate([
'archivo' => 'required|file|mimes:csv,txt'
]);
$path = $request->file('archivo')->store('imports');
$resultado = $this->pastelService->importarDesdeCSV(storage_path('app/' . $path));
return redirect()
->route('pasteles.index')
->with('success', "Se importaron {$resultado['importados']} pasteles");
}
}9. Manejo de Excepciones
Controladores con Manejo de Excepciones
<?php
namespace App\Http\Controllers;
use App\Models\Pastel;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Log;
class PastelController extends Controller
{
public function show($id)
{
try {
$pastel = Pastel::findOrFail($id);
return view('pasteles.show', compact('pastel'));
} catch (ModelNotFoundException $e) {
Log::error('Pastel no encontrado', ['id' => $id, 'error' => $e->getMessage()]);
return redirect()
->route('pasteles.index')
->with('error', 'El pastel solicitado no existe.');
}
}
public function store(Request $request)
{
try {
$validated = $request->validate([
'nombre' => 'required|string|max:100|unique:pasteles',
'sabor' => 'required|in:chocolate,vainilla,cheesecake',
'precio' => 'nullable|numeric|min:0'
]);
$pastel = Pastel::create($validated);
return redirect()
->route('pasteles.index')
->with('success', 'Pastel creado exitosamente.');
} catch (ValidationException $e) {
return redirect()
->back()
->withErrors($e->validator)
->withInput();
} catch (\Exception $e) {
Log::error('Error al crear pastel', [
'error' => $e->getMessage(),
'data' => $request->all()
]);
return redirect()
->back()
->with('error', 'Ocurrió un error al crear el pastel. Intenta nuevamente.')
->withInput();
}
}
public function destroy(Pastel $pastel)
{
try {
$pastel->delete();
return redirect()
->route('pasteles.index')
->with('success', 'Pastel eliminado exitosamente.');
} catch (\Exception $e) {
Log::error('Error al eliminar pastel', [
'id' => $pastel->id,
'error' => $e->getMessage()
]);
return redirect()
->back()
->with('error', 'No se pudo eliminar el pastel. Intenta nuevamente.');
}
}
}Excepciones Personalizadas
// app/Exceptions/PastelException.php
<?php
namespace App\Exceptions;
use Exception;
class PastelException extends Exception
{
public static function noEncontrado($id)
{
return new static("Pastel con ID {$id} no encontrado.", 404);
}
public static function sinStock($nombre)
{
return new static("El pastel {$nombre} no está disponible en stock.", 409);
}
public static function precioInvalido($precio)
{
return new static("El precio {$precio} no es válido.", 422);
}
}
// Uso en el controlador
public function show($id)
{
try {
$pastel = Pastel::findOrFail($id);
return view('pasteles.show', compact('pastel'));
} catch (ModelNotFoundException $e) {
throw PastelException::noEncontrado($id);
}
}10. Mejores Prácticas
1. Mantén tus Controladores Delgados
// ❌ Mal: Controlador con mucha lógica
public function store(Request $request)
{
// Validación
$this->validate($request, [...]);
// Procesamiento
$pastel = new Pastel();
$pastel->nombre = $request->nombre;
$pastel->sabor = $request->sabor;
// ... más lógica
// Envío de emails
Mail::to($request->email)->send(...);
// Log
Log::info(...);
}
// ✅ Bien: Usar servicios y repositorios
public function store(StorePastelRequest $request, PastelService $service)
{
$pastel = $service->create($request->validated());
return redirect()->route('pasteles.index')
->with('success', 'Pastel creado');
}2. Usa Route Model Binding
// ❌ Mal
public function show($id)
{
$pastel = Pastel::findOrFail($id);
return view('pasteles.show', compact('pastel'));
}
// ✅ Bien
public function show(Pastel $pastel)
{
return view('pasteles.show', compact('pastel'));
}3. Implementa Principios SOLID
// Responsabilidad Única
interface PastelRepositoryInterface
{
public function getAll();
public function findById($id);
public function create(array $data);
public function update($id, array $data);
public function delete($id);
}
// Implementación
class PastelRepository implements PastelRepositoryInterface
{
protected $model;
public function __construct(Pastel $model)
{
$this->model = $model;
}
public function getAll()
{
return $this->model->all();
}
// ... implementar otros métodos
}
// Controlador inyectando la interfaz
class PastelController extends Controller
{
protected $repository;
public function __construct(PastelRepositoryInterface $repository)
{
$this->repository = $repository;
}
}4. Usa Inyección de Dependencias
// ✅ Bien: Inyectar dependencias
public function __construct(PastelService $service, Logger $logger)
{
$this->service = $service;
$this->logger = $logger;
}
// ❌ Mal: Crear dependencias dentro del método
public function index()
{
$service = new PastelService();
$logger = new Logger();
}5. Organiza por Módulos
// Estructura de carpetas recomendada
app/
├── Http/
│ ├── Controllers/
│ │ ├── Admin/
│ │ │ └── PastelController.php
│ │ ├── Api/
│ │ │ └── PastelController.php
│ │ └── Web/
│ │ └── PastelController.php
│ ├── Requests/
│ │ ├── StorePastelRequest.php
│ │ └── UpdatePastelRequest.php
│ └── Resources/
│ └── PastelResource.php
├── Services/
│ └── PastelService.php
└── Repositories/
└── PastelRepository.php6. Usa Traits para Funcionalidades Compartidas
// app/Traits/Paginatable.php
<?php
namespace App\Traits;
trait Paginatable
{
protected function getPaginationParams(Request $request): array
{
return [
'per_page' => $request->get('per_page', 15),
'page' => $request->get('page', 1),
'sort_by' => $request->get('sort_by', 'id'),
'sort_direction' => $request->get('direction', 'desc')
];
}
}
// Uso en controlador
class PastelController extends Controller
{
use Paginatable;
public function index(Request $request)
{
$params = $this->getPaginationParams($request);
// Usar parámetros para la paginación
}
}7. Implementa Logging y Debug
public function store(StorePastelRequest $request)
{
Log::info('Creando nuevo pastel', [
'user_id' => auth()->id(),
'data' => $request->validated()
]);
try {
$pastel = Pastel::create($request->validated());
Log::info('Pastel creado exitosamente', [
'pastel_id' => $pastel->id
]);
return redirect()->route('pasteles.index')
->with('success', 'Pastel creado');
} catch (\Exception $e) {
Log::error('Error al crear pastel', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return back()
->with('error', 'Error al crear el pastel')
->withInput();
}
}8. Validación de Seguridad
public function update(UpdatePastelRequest $request, Pastel $pastel)
{
// Verificar autorización
if (auth()->user()->cannot('update', $pastel)) {
abort(403, 'No tienes permiso para editar este pastel.');
}
// Rate limiting
$this->rateLimit('update_pastel', 5, 60);
$pastel->update($request->validated());
return redirect()->route('pasteles.index');
}11. Ejercicio Práctico: CRUD Completo
Paso 1: Crear el Controlador
php artisan make:controller PastelController --resource --model=PastelPaso 2: Crear el Modelo con Migración
php artisan make:model Pastel -m// database/migrations/xxxx_create_pasteles_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('pasteles', function (Blueprint $table) {
$table->id();
$table->string('nombre', 100);
$table->enum('sabor', ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco']);
$table->decimal('precio', 8, 2)->nullable();
$table->boolean('disponible')->default(true);
$table->text('descripcion')->nullable();
$table->timestamps();
$table->softDeletes();
});
}
public function down(): void
{
Schema::dropIfExists('pasteles');
}
};Paso 3: Crear Form Requests
php artisan make:request StorePastelRequest
php artisan make:request UpdatePastelRequestPaso 4: Implementar el Controlador
<?php
namespace App\Http\Controllers;
use App\Models\Pastel;
use App\Http\Requests\StorePastelRequest;
use App\Http\Requests\UpdatePastelRequest;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
class PastelController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['index', 'show']);
$this->middleware('admin')->only(['destroy']);
}
public function index(): View
{
$pasteles = Pastel::withTrashed()->paginate(10);
return view('pasteles.index', compact('pasteles'));
}
public function create(): View
{
$sabores = ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco'];
return view('pasteles.create', compact('sabores'));
}
public function store(StorePastelRequest $request): RedirectResponse
{
$pastel = Pastel::create($request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel creado exitosamente');
}
public function show(Pastel $pastel): View
{
return view('pasteles.show', compact('pastel'));
}
public function edit(Pastel $pastel): View
{
$sabores = ['chocolate', 'vainilla', 'cheesecake', 'fresa', 'coco'];
return view('pasteles.edit', compact('pastel', 'sabores'));
}
public function update(UpdatePastelRequest $request, Pastel $pastel): RedirectResponse
{
$pastel->update($request->validated());
return redirect()
->route('pasteles.index')
->with('success', 'Pastel actualizado exitosamente');
}
public function destroy(Pastel $pastel): RedirectResponse
{
$pastel->delete();
return redirect()
->route('pasteles.index')
->with('success', 'Pastel eliminado exitosamente');
}
public function restore($id): RedirectResponse
{
$pastel = Pastel::withTrashed()->findOrFail($id);
$pastel->restore();
return redirect()
->route('pasteles.index')
->with('success', 'Pastel restaurado exitosamente');
}
}Paso 5: Configurar Rutas
// routes/web.php
use App\Http\Controllers\PastelController;
Route::resource('pasteles', PastelController::class);
Route::post('/pasteles/{id}/restore', [PastelController::class, 'restore'])->name('pasteles.restore');Paso 6: Verificar el Funcionamiento
# Ver todas las rutas
php artisan route:list
# Probar el servidor
php artisan serveComandos Útiles
# Crear controlador con métodos básicos
php artisan make:controller NombreController
# Crear controlador resource completo
php artisan make:controller NombreController --resource
# Crear controlador con modelo
php artisan make:controller NombreController --model=Modelo
# Crear controlador API
php artisan make:controller Api/NombreController --api
# Crear controlador invocable
php artisan make:controller NombreController --invokable
# Ver todas las rutas registradas
php artisan route:list
# Ver rutas con detalles
php artisan route:list -v
# Ver rutas de un controlador específico
php artisan route:list --path=pastelesResumen
| Concepto | Descripción | Comando |
|---|---|---|
| Controlador básico | Clase con métodos para HTTP | make:controller |
| Resource Controller | Controlador con 7 métodos CRUD | --resource |
| Model Binding | Inyección automática de modelos | --model |
| Invocable | Controlador con una sola acción | --invokable |
| API Controller | Controlador sin vistas | --api |
| Middleware | Filtros para peticiones | $this->middleware() |
| Inyección | Dependencias en constructor/métodos | __construct() |
¡Con este conocimiento de controladores en Laravel 12, estás listo para construir aplicaciones web robustas y bien organizadas
Comentarios
Publicar un comentario