---
title: "Aprende Laravel: Controllers"
excerpt: "Aprende a organizar la lógica de tu aplicación con Controllers en Laravel. Desde controllers básicos hasta resource controllers y Single Action Controllers."
date: "2026-02-14T10:00:00.000Z"
lastModified: "2026-03-29T00:00:00.000Z"
category: "Laravel"
author:
  name: "angel cruz"
  picture: "https://angelcruzdevcdn.nyc3.cdn.digitaloceanspaces.com/images/me/angel-cruz.png"
ogImage:
  url: "/images/open-graph/laravel-opengraph-image.png"
seo_title: "Controllers en Laravel 13: Resource, Single Action y Buenas Prácticas"
seo_description: "Aprende a usar Controllers en Laravel 13: desde controllers básicos hasta resource controllers, dependency injection y Single Action Controllers."
keywords:
  - laravel
  - controllers
  - php
  - resource controller
  - laravel español
learning_path:
  series: "laravel-fundamentals"
  order: 4
  total: 6
  prev_slug: "aprende-laravel-vistas-layouts"
  next_slug: "aprende-laravel-models-database"
---

![Laravel Controllers](https://angelcruzdevcdn.nyc3.cdn.digitaloceanspaces.com/images/laravel-banner.svg)

En los posts anteriores hemos visto cómo crear [rutas](/post/aprende-laravel-rutas) y [vistas](/post/aprende-laravel-vistas-layouts). 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:

```php
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:

```php
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:

```bash
php artisan make:controller PostController
```

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

```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
<?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`:

```bash
php artisan make:controller PostController --resource
```

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

```php
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:

```php
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:
```php
public function index()
{
    $posts = Post::latest()->paginate(10);
    return view('posts.index', compact('posts'));
}
```

**2. create** - Muestra el formulario de creación:
```php
public function create()
{
    return view('posts.create');
}
```

**3. store** - Guarda el nuevo recurso:
```php
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:
```php
public function show(Post $post)
{
    return view('posts.show', compact('post'));
}
```

**5. edit** - Muestra el formulario de edición:
```php
public function edit(Post $post)
{
    return view('posts.edit', compact('post'));
}
```

**6. update** - Actualiza el recurso:
```php
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:
```php
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`:

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

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

```php
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**:

```bash
php artisan make:controller ShowDashboard --invokable
```

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

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

Y lo usas en rutas así:

```php
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:

```php
// ❌ 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**:

```php
// ✅ 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`:

```php
// 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:

```php
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:

```php
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:

```php
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](/servicios/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

- [Documentación oficial de Controllers](https://laravel.com/docs/12.x/controllers)
- [Resource Controllers](https://laravel.com/docs/12.x/controllers#resource-controllers)
- [Dependency Injection](https://laravel.com/docs/12.x/controllers#dependency-injection-and-controllers)

### Video de la lección

Ver video tutorial: [Aprende Laravel - Controllers](https://www.youtube.com/watch?v=8Fv2BNGLw_8)

Playlist completa en YouTube: [Aprende Laravel @ YouTube](https://www.youtube.com/playlist?list=PLPFfjDS32gikCkR3s7pLN40MJuSlOFu6h)

---

## Sitemap

Índice completo del sitio: [/sitemap.md](https://angelcruz.dev/sitemap.md)

Canónico HTML: [https://angelcruz.dev/post/aprende-laravel-controllers](https://angelcruz.dev/post/aprende-laravel-controllers)
