Skip to content

4. Controladores en Laravel

Los controladores son una parte fundamental de la arquitectura MVC (Modelo-Vista-Controlador) de Laravel. Permiten organizar la lógica de tu aplicación en clases y separar las responsabilidades, haciendo que tu código sea más mantenible y escalable.

En lugar de definir toda la lógica de manejo de solicitudes en los archivos de rutas, los controladores permiten agrupar la lógica relacionada en clases. Los controladores se almacenan en el directorio

app/Http/Controllers
.

Laravel proporciona un comando Artisan para generar rápidamente controladores. Este comando crea un nuevo archivo de controlador con la estructura básica ya definida.

Para crear un controlador básico, ejecuta el siguiente comando en la terminal:

Terminal window
php artisan make:controller UsuarioController

Este comando creará un nuevo archivo

UsuarioController.php
en el directorio
app/Http/Controllers
con la siguiente estructura:

<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class UsuarioController extends Controller
{
//
}

Puedes organizar tus controladores en subdirectorios especificando la ruta relativa en el comando:

Terminal window
php artisan make:controller Admin/ProductoController

Este comando creará el controlador en

app/Http/Controllers/Admin/ProductoController.php
.

El comando

make:controller
admite varias opciones para generar diferentes tipos de controladores:

Para crear un controlador optimizado para APIs:

Terminal window
php artisan make:controller API/ProductoController --api

Esto generará un controlador con métodos para index, store, show, update y destroy, sin métodos para mostrar formularios.

Los controladores pueden contener cualquier número de métodos públicos que respondan a las solicitudes HTTP. Estos métodos reciben y procesan las solicitudes, interactúan con los modelos y devuelven respuestas.

Un método típico de controlador tiene la siguiente estructura:

public function show($id)
{
// Lógica para obtener datos
$usuario = Usuario::find($id);
// Devolver una respuesta (vista, JSON, redirección, etc.)
return view('usuarios.show', ['usuario' => $usuario]);
}

Puedes acceder a la solicitud HTTP actual mediante la inyección de dependencias de la clase

Request
:

use IlluminateHttpRequest;
public function store(Request $request)
{
// Acceder a los datos del formulario
$nombre = $request->input('nombre');
// O usando la sintaxis de array
$email = $request['email'];
// Validar datos
$validated = $request->validate([
'nombre' => 'required|string|max:255',
'email' => 'required|email|unique:usuarios'
]);
// Crear un nuevo registro
$usuario = Usuario::create($validated);
// Redireccionar
return redirect()->route('usuarios.show', ['id' => $usuario->id]);
}

Los controladores suelen seguir convenciones de nomenclatura para sus métodos, especialmente cuando se trabaja con recursos:

MétodoDescripciónVerbo HTTPRuta típica
index()
Mostrar listado de recursosGET/usuarios
create()
Mostrar formulario de creaciónGET/usuarios/create
store()
Almacenar nuevo recursoPOST/usuarios
show()
Mostrar un recurso específicoGET/usuarios/{id}
edit()
Mostrar formulario de ediciónGET/usuarios/{id}/edit
update()
Actualizar un recursoPUT/PATCH/usuarios/{id}
destroy()
Eliminar un recursoDELETE/usuarios/{id}

Aquí hay un ejemplo de un controlador completo para gestionar usuarios:

<?php
namespace AppHttpControllers;
use AppModelsUsuario;
use IlluminateHttpRequest;
use IlluminateSupportFacadesHash;
class UsuarioController extends Controller
{
/**
* Mostrar listado de usuarios.
*/
public function index()
{
$usuarios = Usuario::paginate(15);
return view('usuarios.index', ['usuarios' => $usuarios]);
}
/**
* Mostrar formulario de creación.
*/
public function create()
{
return view('usuarios.create');
}
/**
* Almacenar un nuevo usuario.
*/
public function store(Request $request)
{
$validated = $request->validate([
'nombre' => 'required|string|max:255',
'email' => 'required|email|unique:usuarios,email',
'password' => 'required|min:8|confirmed'
]);
$validated['password'] = Hash::make($validated['password']);
$usuario = Usuario::create($validated);
return redirect()
->route('usuarios.show', ['id' => $usuario->id])
->with('mensaje', 'Usuario creado correctamente');
}
/**
* Mostrar un usuario específico.
*/
public function show($id)
{
$usuario = Usuario::findOrFail($id);
return view('usuarios.show', ['usuario' => $usuario]);
}
/**
* Mostrar formulario de edición.
*/
public function edit($id)
{
$usuario = Usuario::findOrFail($id);
return view('usuarios.edit', ['usuario' => $usuario]);
}
/**
* Actualizar un usuario.
*/
public function update(Request $request, $id)
{
$usuario = Usuario::findOrFail($id);
$validated = $request->validate([
'nombre' => 'required|string|max:255',
'email' => 'required|email|unique:usuarios,email,' . $id,
'password' => 'nullable|min:8|confirmed'
]);
if (isset($validated['password'])) {
$validated['password'] = Hash::make($validated['password']);
} else {
unset($validated['password']);
}
$usuario->update($validated);
return redirect()
->route('usuarios.show', ['id' => $usuario->id])
->with('mensaje', 'Usuario actualizado correctamente');
}
/**
* Eliminar un usuario.
*/
public function destroy($id)
{
$usuario = Usuario::findOrFail($id);
$usuario->delete();
return redirect()
->route('usuarios.index')
->with('mensaje', 'Usuario eliminado correctamente');
}
}

Los controladores resource son una forma eficiente de crear un controlador que contiene todos los métodos CRUD (Crear, Leer, Actualizar, Eliminar) necesarios para gestionar un recurso. Laravel proporciona una forma sencilla de generar estos controladores y sus rutas correspondientes.

Para crear un controlador resource, utiliza la opción

--resource
con el comando
make:controller
:

Terminal window
php artisan make:controller ProductoController --resource

Este comando generará un controlador con los siguientes métodos predefinidos:

  • index()
    : Mostrar listado de recursos
  • create()
    : Mostrar formulario de creación
  • store()
    : Almacenar un nuevo recurso
  • show()
    : Mostrar un recurso específico
  • edit()
    : Mostrar formulario de edición
  • update()
    : Actualizar un recurso
  • destroy()
    : Eliminar un recurso

Registrar rutas para un controlador resource

Section titled “Registrar rutas para un controlador resource”

Para registrar todas las rutas necesarias para un controlador resource, puedes utilizar el método

Route::resource()
en tu archivo de rutas:

use AppHttpControllersProductoController;
Route::resource('productos', ProductoController::class);

Este único comando creará automáticamente las siguientes rutas:

Verbo HTTPURIAcciónNombre de ruta
GET/productosindexproductos.index
GET/productos/createcreateproductos.create
POST/productosstoreproductos.store
GET/productos/{producto}showproductos.show
GET/productos/{producto}/editeditproductos.edit
PUT/PATCH/productos/{producto}updateproductos.update
DELETE/productos/{producto}destroyproductos.destroy

Puedes personalizar las rutas resource de varias maneras:

// Solo incluir estas acciones
Route::resource('productos', ProductoController::class)->only([
'index', 'show'
]);
// Excluir estas acciones
Route::resource('productos', ProductoController::class)->except([
'create', 'store', 'update', 'destroy'
]);

Por defecto, Laravel utiliza el nombre del recurso en singular como parámetro (por ejemplo, {producto}). Puedes cambiar esto con el método

parameters()
:

Route::resource('productos', ProductoController::class)
->parameters(['productos' => 'producto_id']);

Esto cambiará las rutas a /productos/{producto_id}.

Puedes crear rutas resource anidadas para representar relaciones entre recursos:

Route::resource('categorias', CategoriaController::class);
Route::resource('categorias.productos', CategoriaProductoController::class);

Esto creará rutas como /categorias/{categoria}/productos/{producto}.

Para APIs, a menudo no necesitas las rutas para mostrar formularios (

create
y
edit
). Laravel proporciona un atajo para crear controladores y rutas resource optimizados para APIs:

Terminal window
php artisan make:controller API/ProductoController --api

Y para registrar solo las rutas API:

Route::apiResource('productos', APIProductoController::class);

Esto registrará solo las rutas

index
,
store
,
show
,
update
y
destroy
.

Para registrar múltiples recursos API a la vez:

Route::apiResources([
'productos' => APIProductoController::class,
'categorias' => APICategoriaController::class,
]);

Laravel utiliza un contenedor de servicios que permite la inyección de dependencias en los controladores. Esto facilita el acceso a los servicios de la aplicación y mejora la testabilidad del código.

Puedes inyectar dependencias en el constructor de tu controlador, y Laravel las resolverá automáticamente:

<?php
namespace AppHttpControllers;
use AppRepositoriesUserRepository;
use AppServicesNotificationService;
class UsuarioController extends Controller
{
protected $users;
protected $notificationService;
public function __construct(UserRepository $users, NotificationService $notificationService)
{
$this->users = $users;
$this->notificationService = $notificationService;
}
public function show($id)
{
$usuario = $this->users->find($id);
return view('usuarios.show', ['usuario' => $usuario]);
}
public function notify($id)
{
$usuario = $this->users->find($id);
$this->notificationService->sendWelcomeNotification($usuario);
return back()->with('mensaje', 'Notificación enviada');
}
}

También puedes inyectar dependencias directamente en los métodos del controlador:

<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
use AppServicesReporteService;
class ReporteController extends Controller
{
public function generar(Request $request, ReporteService $reporteService, $tipo)
{
$datos = $reporteService->generarReporte($tipo, $request->input('desde'), $request->input('hasta'));
return view('reportes.mostrar', ['datos' => $datos, 'tipo' => $tipo]);
}
}

En este ejemplo, Laravel inyectará automáticamente una instancia de

Request
y
ReporteService
.

Laravel permite la inyección implícita de modelos en las rutas y controladores. Esto significa que Laravel buscará automáticamente un modelo por su ID y lo inyectará:

use AppModelsUsuario;
Route::get('/usuarios/{usuario}', function (Usuario $usuario) {
return $usuario;
});
// En un controlador
public function show(Usuario $usuario)
{
return view('usuarios.show', ['usuario' => $usuario]);
}

En estos ejemplos, Laravel buscará automáticamente un

Usuario
con un ID que coincida con el valor del segmento de ruta
{usuario}
. Si no se encuentra, se devolverá automáticamente una respuesta 404.

Por defecto, la inyección implícita de modelos utiliza el campo

id
para buscar el modelo. Puedes personalizar esto sobrescribiendo el método
getRouteKeyName()
en tu modelo:

<?php
namespace AppModels;
use IlluminateDatabaseEloquentModel;
class Usuario extends Model
{
/**
* Obtener la clave utilizada por la inyección implícita de modelos.
*/
public function getRouteKeyName()
{
return 'nombre_usuario'; // En lugar de 'id'
}
}

Para que Laravel pueda inyectar tus servicios personalizados, debes registrarlos en el contenedor de servicios. Esto se hace típicamente en un proveedor de servicios (Service Provider):

<?php
namespace AppProviders;
use AppServicesReporteService;
use AppServicesReporteServiceImpl;
use IlluminateSupportServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(ReporteService::class, ReporteServiceImpl::class);
}
}

Los controladores en Laravel proporcionan una forma organizada y estructurada de manejar la lógica de tu aplicación. Utilizando controladores resource y la inyección de dependencias, puedes crear código limpio, mantenible y fácil de probar.

Recuerda que los controladores deben mantenerse “delgados” y enfocarse principalmente en recibir solicitudes HTTP y devolver respuestas. La lógica de negocio compleja debe delegarse a servicios o modelos para mantener una arquitectura limpia y escalable.

🐝