Laravel

Aprende Laravel: Controllers

Autorangel cruz
Publicado
Lectura4 min de lectura
Actualizado
Aprende Laravel: Controllers

Laravel Controllers

En los posts anteriores hemos visto cómo crear rutas y vistas. Ahora es momento de organizar la lógica de nuestra aplicación usando Controllers.

¿Qué es un Controller?

Un Controller es una clase PHP que agrupa la lógica relacionada con las solicitudes HTTP. En lugar de definir toda la lógica en las rutas (usando closures), puedes organizarla en clases Controller.

¿Por qué usar Controllers?

  • Mantiene tu código ordenado y fácil de encontrar
  • Podés reutilizar métodos en diferentes rutas
  • Es más fácil testear clases que closures
  • Código más limpio y profesional

Controllers vs Route Closures

Cuando defines una ruta simple, puedes usar un closure:

Route::get('/posts', function () {
    $posts = Post::all();
    return view('posts.index', compact('posts'));
});

Pero a medida que tu aplicación crece, es mejor usar Controllers:

Route::get('/posts', [PostController::class, 'index']);

Regla simple: Si tu lógica tiene más de 2-3 líneas, usa un Controller.

Creando tu Primer Controller

Laravel incluye el comando Artisan make:controller para crear controllers rápidamente:

php artisan make:controller PostController

Esto creará un archivo app/Http/Controllers/PostController.php:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class PostController extends Controller
{
    // Tus métodos van aquí
}

Anatomía de un Controller

Un Controller típico tiene varios actions (métodos públicos) que manejan diferentes solicitudes:

<?php
 
namespace App\Http\Controllers;
 
use App\Models\Post;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }
 
    public function show(Post $post)
    {
        return view('posts.show', compact('post'));
    }
}

Convenciones de naming:

  • Controller names: PostController, UserController (singular o plural, tú decides)
  • Actions: index, create, store, show, edit, update, destroy

Resource Controllers

Laravel facilita la creación de controllers CRUD (Create, Read, Update, Delete) con el flag --resource:

php artisan make:controller PostController --resource

Esto genera un controller con 7 métodos estándar:

class PostController extends Controller
{
    public function index()     // GET /posts
    public function create()    // GET /posts/create
    public function store()     // POST /posts
    public function show($id)   // GET /posts/{id}
    public function edit($id)   // GET /posts/{id}/edit
    public function update($id) // PUT/PATCH /posts/{id}
    public function destroy($id)// DELETE /posts/{id}
}

Para conectar todas estas rutas automáticamente:

Route::resource('posts', PostController::class);

Una línea = 7 rutas! Route::resource() es perfecta para operaciones CRUD estándar.

Controller Actions en Detalle

Veamos cada action del resource controller:

1. index - Lista todos los recursos:

public function index()
{
    $posts = Post::latest()->paginate(10);
    return view('posts.index', compact('posts'));
}

2. create - Muestra el formulario de creación:

public function create()
{
    return view('posts.create');
}

3. store - Guarda el nuevo recurso:

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|max:255',
        'content' => 'required',
    ]);
 
    Post::create($validated);
 
    return redirect()->route('posts.index')
        ->with('success', 'Post creado exitosamente!');
}

4. show - Muestra un recurso específico:

public function show(Post $post)
{
    return view('posts.show', compact('post'));
}

5. edit - Muestra el formulario de edición:

public function edit(Post $post)
{
    return view('posts.edit', compact('post'));
}

6. update - Actualiza el recurso:

public function update(Request $request, Post $post)
{
    $validated = $request->validate([
        'title' => 'required|max:255',
        'content' => 'required',
    ]);
 
    $post->update($validated);
 
    return redirect()->route('posts.show', $post)
        ->with('success', 'Post actualizado!');
}

7. destroy - Elimina el recurso:

public function destroy(Post $post)
{
    $post->delete();
 
    return redirect()->route('posts.index')
        ->with('success', 'Post eliminado!');
}

Dependency Injection en Controllers

Laravel automáticamente inyecta dependencias en los métodos del controller. Por ejemplo, el objeto Request:

public function store(Request $request)
{
    // Laravel automáticamente inyecta Request
    $title = $request->input('title');
    // ...
}

También funciona con Models (Route Model Binding):

public function show(Post $post)
{
    // Laravel automáticamente busca el Post por ID
    return view('posts.show', compact('post'));
}

Single Action Controllers

Si un controller solo tiene UNA acción, puedes usar un Invokable Controller:

php artisan make:controller ShowDashboard --invokable

Esto crea un controller con un método mágico __invoke:

class ShowDashboard extends Controller
{
    public function __invoke()
    {
        $stats = // ... obtener estadísticas
        return view('dashboard', compact('stats'));
    }
}

Y lo usas en rutas así:

Route::get('/dashboard', ShowDashboard::class);

Cuándo usar Invokable Controllers: Para acciones únicas que no encajan en un CRUD estándar (ej: exportar PDF, procesar webhook, generar reporte).

Evita "Fat Controllers"

Un error común es poner TODA la lógica de negocio en los controllers:

// ❌ MAL - Controller muy pesado
public function store(Request $request)
{
    $validated = $request->validate([...]);
 
    // Mucha lógica de negocio aquí
    $user = User::create($validated);
    Mail::to($user)->send(new WelcomeEmail());
    $user->assignRole('subscriber');
    event(new UserRegistered($user));
    // ... 50 líneas más
 
    return redirect()->route('home');
}

Mejor práctica: Delega lógica compleja a Services o Actions:

// ✅ MEJOR - Controller delgado
public function store(Request $request, RegisterUserService $service)
{
    $validated = $request->validate([...]);
 
    $user = $service->register($validated);
 
    return redirect()->route('home')
        ->with('success', 'Bienvenido!');
}

El controller solo debe:

  1. Validar input
  2. Llamar a services/models
  3. Retornar una respuesta (view, redirect, json)

Personalizando Resource Routes

Puedes limitar qué rutas generar con only o except:

// Solo index y show
Route::resource('posts', PostController::class)
    ->only(['index', 'show']);
 
// Todas excepto delete
Route::resource('posts', PostController::class)
    ->except(['destroy']);

También puedes cambiar los nombres de las rutas:

Route::resource('posts', PostController::class)
    ->names([
        'index' => 'posts.all',
        'show' => 'posts.detail',
    ]);

PHP Attributes en Laravel 13

Laravel 13 introduce soporte nativo para PHP Attributes en controllers. En lugar de registrar middleware en el constructor, puedes declararlo directamente sobre la clase o el método:

use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;
 
#[Middleware('auth')]
class PostController extends Controller
{
    #[Middleware('subscribed')]
    public function create()
    {
        return view('posts.create');
    }
}

También puedes usar #[Authorize] para políticas:

use Illuminate\Auth\Access\AuthorizesRequests;
 
#[Middleware('auth')]
class PostController extends Controller
{
    use AuthorizesRequests;
 
    #[Authorize('update', Post::class)]
    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }
}

Ambas formas son válidas en Laravel 13. Los attributes son opcionales y no reemplazan la forma tradicional con $this->middleware().

Siguiente Paso

Ahora que sabes organizar tu lógica con Controllers, en el próximo post veremos cómo trabajar con la base de datos usando Models y Eloquent ORM. Aprenderás a crear, leer, actualizar y eliminar datos de forma elegante.

¿Necesitas ayuda con tu proyecto Laravel? Ofrezco servicios de desarrollo Laravel con arquitectura SOLID, APIs RESTful escalables y código mantenible a largo plazo.

Preguntas Frecuentes

¿Por qué usar Controllers en lugar de closures en rutas?

Los Controllers organizan mejor el código (separan lógica de rutas), son más reutilizables (un método puede usarse en múltiples rutas), facilitan el testing (testear clases es más fácil que closures), y mejoran la mantenibilidad del proyecto a largo plazo.

¿Cómo creo un Controller en Laravel?

Usa el comando Artisan php artisan make:controller PostController. Para crear un resource controller con los 7 métodos CRUD automáticos, usa php artisan make:controller PostController --resource.

¿Qué son los Resource Controllers?

Son controllers con 7 métodos estándar para operaciones CRUD: index (lista), create (formulario crear), store (guardar), show (ver uno), edit (formulario editar), update (actualizar), destroy (eliminar). Una línea Route::resource('posts', PostController::class) genera las 7 rutas automáticamente.

¿Qué es Dependency Injection en Controllers?

Laravel automáticamente inyecta dependencias en los métodos del controller. Por ejemplo, public function store(Request $request) - Laravel inyecta el objeto Request automáticamente. También funciona con Models vía Route Model Binding.

¿Qué es un Invokable Controller?

Es un controller con un ÚNICO método __invoke() para una sola acción. Perfecto para acciones que no encajan en CRUD estándar (exportar PDF, procesar webhook, generar reporte). Se crea con php artisan make:controller ShowDashboard --invokable y se usa como Route::get('/dashboard', ShowDashboard::class).

Recursos Adicionales

Video de la lección

Ver video tutorial: Aprende Laravel - Controllers

Playlist completa en YouTube: Aprende Laravel @ YouTube

Bio
Angel Cruz

Desarrollador web full-stack enfocado en React, buenas prácticas y código abierto. Apasionado por construir productos útiles y compartir lo aprendido en el camino.