Curso de Laravel
Controladores en Laravel: organizar la lógica de tu aplicación
Por Víctor Peña · Publicado el
Hola, ¿cómo están? Continuando con el curso de Laravel, hoy veremos los controladores: el punto donde llega la petición y se decide qué hacer con ella.
¡Empecemos!
Qué es un controlador
Es la C del patrón MVC que vimos en la primera lección. Su trabajo es recibir la petición, coordinar y devolver una respuesta.
Podrías escribir toda la lógica dentro de las rutas, pero con quince pantallas el archivo web.php se vuelve ilegible. El controlador agrupa por entidad: todo lo relacionado con pacientes vive en PacienteController.
Crear un controlador
php artisan make:controller PacienteController
Se crea en app/Http/Controllers/. Y con la bandera de recurso, que es lo que vas a usar casi siempre:
php artisan make:controller PacienteController --resource --model=Paciente
Eso genera los siete métodos del CRUD, ya con el modelo inyectado.
El controlador de recurso
<?php
namespace App\Http\Controllers;
use App\Models\Paciente;
use Illuminate\Http\Request;
class PacienteController extends Controller
{
public function index()
{
$pacientes = Paciente::orderBy('apellido')->paginate(15);
return view('pacientes.index', compact('pacientes'));
}
public function create()
{
return view('pacientes.create');
}
public function store(Request $request)
{
$datos = $request->validate([
'cedula' => 'required|unique:pacientes|max:20',
'nombre' => 'required|max:100',
'apellido' => 'required|max:100',
'fecha_nacimiento' => 'required|date|before:today',
]);
Paciente::create($datos);
return redirect()
->route('pacientes.index')
->with('exito', 'Paciente registrado correctamente');
}
public function show(Paciente $paciente)
{
return view('pacientes.show', compact('paciente'));
}
public function edit(Paciente $paciente)
{
return view('pacientes.edit', compact('paciente'));
}
public function update(Request $request, Paciente $paciente)
{
$datos = $request->validate([
'nombre' => 'required|max:100',
'apellido' => 'required|max:100',
]);
$paciente->update($datos);
return redirect()
->route('pacientes.show', $paciente)
->with('exito', 'Datos actualizados');
}
public function destroy(Paciente $paciente)
{
$paciente->delete();
return redirect()
->route('pacientes.index')
->with('exito', 'Paciente eliminado');
}
}
Cada método corresponde a una de las rutas que genera Route::resource, y esa correspondencia es lo que hace que cualquier desarrollador de Laravel entienda tu proyecto sin explicaciones.
Qué hace cada método
| Método | Qué muestra o hace |
|---|---|
index |
La lista de registros |
create |
El formulario de creación |
store |
Guarda el registro nuevo |
show |
El detalle de uno |
edit |
El formulario de edición |
update |
Guarda los cambios |
destroy |
Elimina |
Fíjate en el patrón: los métodos que muestran algo devuelven una vista; los que modifican datos, una redirección.
Pasar datos a la vista
Tres formas, todas equivalentes:
return view('pacientes.index', compact('pacientes'));
return view('pacientes.index', ['pacientes' => $pacientes]);
return view('pacientes.index')->with('pacientes', $pacientes);
Y con varias variables:
return view('citas.create', compact('pacientes', 'doctores'));
compact() es la forma más habitual, y con dos o tres variables se lee bien. Con siete conviene el arreglo explícito.
La vinculación de modelos
Fíjate en los métodos show, edit, update y destroy: reciben directamente un Paciente, no un id.
public function show(Paciente $paciente)
Como vimos en la lección de rutas, Laravel busca el registro y lo inyecta ya resuelto. Si no existe, devuelve un 404 sin que tú hagas nada.
Eso elimina esta línea de todos tus métodos:
$paciente = Paciente::findOrFail($id); // ya no hace falta
Inyección de dependencias
El controlador puede recibir cualquier clase que la aplicación sepa construir:
use App\Services\GeneradorDeReportes;
public function reporte(Request $request, GeneradorDeReportes $generador)
{
return $generador->mensual($request->mes);
}
Laravel se encarga de crear la instancia. Es el mecanismo que vimos en la lección de interfaces del curso de PHP, y lo desarrollamos en la lección de inyección de dependencias del módulo avanzado.
Tipos de respuesta
return view('pacientes.index', compact('pacientes'));
return redirect()->route('pacientes.index');
return redirect()->back();
return redirect()->back()->withInput();
return response()->json($pacientes);
return response()->json(['error' => 'No encontrado'], 404);
return response()->download($rutaArchivo);
return response()->file($rutaArchivo);
abort(404);
abort(403, 'No tienes permiso');
redirect()->back()->withInput() es muy útil: vuelve al formulario conservando lo que el usuario había escrito. Sin withInput(), el formulario aparece vacío y la gente se molesta con razón.
Mensajes entre peticiones
return redirect()
->route('pacientes.index')
->with('exito', 'Paciente registrado correctamente');
Ese with() guarda el mensaje para la siguiente petición y lo descarta después. En la vista:
@if (session('exito'))
<div class="alerta">{{ session('exito') }}</div>
@endif
Es lo que permite mostrar la confirmación después de una redirección, en el patrón POST-Redirect-GET que vimos en el curso de PHP.
Controladores de acción única
Cuando un controlador hace una sola cosa:
php artisan make:controller GenerarReporteController --invokable
class GenerarReporteController extends Controller
{
public function __invoke(Request $request)
{
// ...
}
}
Y en la ruta, sin nombre de método:
Route::get('/reporte', GenerarReporteController::class);
Son útiles para acciones que no encajan en el CRUD: exportar, aprobar, enviar.
Middleware desde el controlador
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
class PacienteController extends Controller implements HasMiddleware
{
public static function middleware(): array
{
return [
'auth',
new Middleware('verified', only: ['destroy']),
];
}
}
Es la forma actual, con un método estático. Si ves tutoriales con $this->middleware() en el constructor, corresponden a versiones anteriores.
Mantener los controladores delgados
Aquí está el consejo más importante de la lección, y el que más se ignora.
El controlador coordina; no debe contener la lógica del negocio. Un método que hace ochenta líneas de cálculos es una señal de que algo pertenece a otro sitio.
// Mal: toda la lógica en el controlador
public function store(Request $request)
{
$datos = $request->validate([...]);
$subtotal = 0;
foreach ($request->items as $item) {
$producto = Producto::find($item['id']);
$subtotal += $producto->precio * $item['cantidad'];
// ... 40 líneas más
}
// ...
}
// Bien: el controlador coordina
public function store(GuardarPedidoRequest $request, ServicioDePedidos $servicio)
{
$pedido = $servicio->crear($request->validated());
return redirect()
->route('pedidos.show', $pedido)
->with('exito', 'Pedido creado');
}
Las tres cosas que sacar del controlador:
La validación, a un Form Request. Lo vemos en la lección de validación de formularios.
La lógica del negocio, a una clase de servicio o al propio modelo.
Las consultas complejas, a scopes del modelo, como vimos en la lección de consultas.
Con eso, un método de controlador rara vez pasa de diez líneas.
Errores comunes
- Controladores con métodos enormes.
- Validar a mano con
ifen lugar devalidate(). - Usar
find()y comprobarnullteniendo la vinculación de modelos. - Devolver una vista tras un POST en lugar de redirigir, y provocar el reenvío del formulario al recargar.
- Olvidar
withInput()al volver por error de validación. - Consultas dentro de bucles, provocando el problema N+1.
Para cerrar
El controlador es el director de orquesta: recibe, pide, y entrega. No toca los instrumentos.
Si te llevas una regla: si tu método de controlador pasa de veinte líneas, algo de ahí pertenece a otro sitio.
En la siguiente lección veremos Blade, el sistema de plantillas donde se construye lo que el usuario ve.
Saludos y éxitos.
Norvic Software
Desarrollamos el software que tu empresa necesita
Somos una empresa de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.
- Software a medida
- Desarrollo web
- Aplicaciones móviles
- Chatbots para WhatsApp
- Agentes de IA
- Integración de IA
- Consultoría técnica
Cotización sin costo · Respuesta directa por WhatsApp