Estamos actualizando el sitio. Durante unos días es posible que veas fallos de diseño o de traducción. La documentación sigue disponible: si una página se ve mal, recárgala más tarde.

Inicio Laravel 10.x Controladores

Controladores

10.x 7 de mar. de 2026

#Introducción

En lugar de definir toda la lógica para manejar solicitudes como closures en sus archivos de rutas, puede organizar este comportamiento usando clases "controladoras". Los controladores pueden agrupar la lógica relacionada con el manejo de solicitudes en una sola clase. Por ejemplo, una clase UserController podría manejar todas las solicitudes entrantes relacionadas con usuarios, incluyendo mostrar, crear, actualizar y eliminar usuarios. Por defecto, los controladores se almacenan en el directorio app/Http/Controllers.

#Escribiendo Controladores

#Controladores Básicos

Para generar rápidamente un nuevo controlador, puede ejecutar el comando Artisan make:controller. Por defecto, todos los controladores de su aplicación se almacenan en el directorio app/Http/Controllers:

php artisan make:controller UserController

Veamos un ejemplo de un controlador básico. Un controlador puede tener cualquier número de métodos públicos que responderán a solicitudes HTTP entrantes:

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Mostrar el perfil de un usuario dado.
     */
    public function show(string $id): View
    {
        return view('user.profile', [
            'user' => User::findOrFail($id)
        ]);
    }
}

Una vez que haya escrito una clase y método controlador, puede definir una ruta hacia el método del controlador de la siguiente manera:

use App\Http\Controllers\UserController;

Route::get('/user/{id}', [UserController::class, 'show']);

Cuando una solicitud entrante coincide con el URI de la ruta especificada, se invocará el método show en la clase App\Http\Controllers\UserController y los parámetros de la ruta serán pasados al método.

Примечание

No es obligatorio que los controladores extiendan una clase base. Sin embargo, no tendrá acceso a características convenientes como los métodos middleware y authorize.

#Controladores de Acción Única

Si una acción de controlador es particularmente compleja, puede ser conveniente dedicar una clase de controlador completa a esa única acción. Para lograr esto, puede definir un único método __invoke dentro del controlador:

<?php

namespace App\Http\Controllers;

class ProvisionServer extends Controller
{
    /**
     * Proveer un nuevo servidor web.
     */
    public function __invoke()
    {
        // ...
    }
}

Al registrar rutas para controladores de acción única, no necesita especificar un método del controlador. En su lugar, puede simplemente pasar el nombre del controlador al router:

use App\Http\Controllers\ProvisionServer;

Route::post('/server', ProvisionServer::class);

Puede generar un controlador invocable usando la opción --invokable del comando Artisan make:controller:

php artisan make:controller ProvisionServer --invokable
Примечание

Los stubs de controladores pueden personalizarse usando la publicación de stubs.

#Middleware en Controladores

El middleware puede asignarse a las rutas del controlador en sus archivos de rutas:

Route::get('profile', [UserController::class, 'show'])->middleware('auth');

O puede ser conveniente especificar middleware dentro del constructor de su controlador. Usando el método middleware dentro del constructor del controlador, puede asignar middleware a las acciones del controlador:

class UserController extends Controller
{
    /**
     * Instanciar una nueva instancia del controlador.
     */
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('log')->only('index');
        $this->middleware('subscribed')->except('store');
    }
}

Los controladores también permiten registrar middleware usando un closure. Esto proporciona una forma conveniente de definir un middleware en línea para un solo controlador sin definir una clase middleware completa:

use Closure;
use Illuminate\Http\Request;

$this->middleware(function (Request $request, Closure $next) {
    return $next($request);
});

#Controladores de Recursos

Si piensa en cada modelo Eloquent en su aplicación como un "recurso", es común realizar los mismos conjuntos de acciones sobre cada recurso en su aplicación. Por ejemplo, imagine que su aplicación contiene un modelo Photo y un modelo Movie. Es probable que los usuarios puedan crear, leer, actualizar o eliminar estos recursos.

Debido a este caso de uso común, el routing de recursos de Laravel asigna las rutas típicas de crear, leer, actualizar y eliminar ("CRUD") a un controlador con una sola línea de código. Para comenzar, podemos usar la opción --resource del comando Artisan make:controller para crear rápidamente un controlador que maneje estas acciones:

php artisan make:controller PhotoController --resource

Este comando generará un controlador en app/Http/Controllers/PhotoController.php. El controlador contendrá un método para cada una de las operaciones disponibles del recurso. Luego, puede registrar una ruta de recurso que apunte al controlador:

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class);

Esta única declaración de ruta crea múltiples rutas para manejar una variedad de acciones sobre el recurso. El controlador generado ya tendrá métodos esbozados para cada una de estas acciones. Recuerde, siempre puede obtener una vista rápida de las rutas de su aplicación ejecutando el comando Artisan route:list.

Incluso puede registrar muchos controladores de recursos a la vez pasando un arreglo al método resources:

Route::resources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

#Acciones manejadas por controladores de recursos

Verbo URI Acción Nombre de Ruta
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy

#Personalizando el comportamiento cuando el modelo falta

Normalmente, se generará una respuesta HTTP 404 si un modelo de recurso enlazado implícitamente no se encuentra. Sin embargo, puede personalizar este comportamiento llamando al método missing al definir su ruta de recurso. El método missing acepta un closure que será invocado si no se puede encontrar un modelo enlazado implícitamente para cualquiera de las rutas del recurso:

use App\Http\Controllers\PhotoController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

Route::resource('photos', PhotoController::class)
        ->missing(function (Request $request) {
            return Redirect::route('photos.index');
        });

#Modelos eliminados suavemente (Soft Deleted)

Normalmente, el enlace implícito de modelos no recuperará modelos que hayan sido eliminados suavemente, y en su lugar devolverá una respuesta HTTP 404. Sin embargo, puede indicar al framework que permita modelos eliminados suavemente invocando el método withTrashed al definir su ruta de recurso:

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class)->withTrashed();

Llamar a withTrashed sin argumentos permitirá modelos eliminados suavemente para las rutas de recurso show, edit y update. Puede especificar un subconjunto de estas rutas pasando un arreglo al método withTrashed:

Route::resource('photos', PhotoController::class)->withTrashed(['show']);

#Especificando el modelo del recurso

Si está usando enlace de modelo en rutas y desea que los métodos del controlador de recursos tengan type-hint de una instancia del modelo, puede usar la opción --model al generar el controlador:

php artisan make:controller PhotoController --model=Photo --resource

#Generando Form Requests

Puede proporcionar la opción --requests al generar un controlador de recursos para indicar a Artisan que genere clases de form request para los métodos de almacenamiento y actualización del controlador:

php artisan make:controller PhotoController --model=Photo --resource --requests

#Rutas Parciales de Recursos

Al declarar una ruta de recurso, puede especificar un subconjunto de acciones que el controlador debe manejar en lugar del conjunto completo de acciones predeterminadas:

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class)->only([
    'index', 'show'
]);

Route::resource('photos', PhotoController::class)->except([
    'create', 'store', 'update', 'destroy'
]);

#Rutas de Recursos para API

Al declarar rutas de recursos que serán consumidas por APIs, comúnmente querrá excluir rutas que presentan plantillas HTML como create y edit. Para mayor comodidad, puede usar el método apiResource para excluir automáticamente estas dos rutas:

use App\Http\Controllers\PhotoController;

Route::apiResource('photos', PhotoController::class);

Puede registrar muchos controladores de recursos API a la vez pasando un arreglo al método apiResources:

use App\Http\Controllers\PhotoController;
use App\Http\Controllers\PostController;

Route::apiResources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

Para generar rápidamente un controlador de recurso API que no incluya los métodos create o edit, use el interruptor --api al ejecutar el comando make:controller:

php artisan make:controller PhotoController --api

#Recursos Anidados

A veces puede necesitar definir rutas para un recurso anidado. Por ejemplo, un recurso foto puede tener múltiples comentarios que pueden estar adjuntos a la foto. Para anidar los controladores de recursos, puede usar la notación de "punto" en su declaración de ruta:

use App\Http\Controllers\PhotoCommentController;

Route::resource('photos.comments', PhotoCommentController::class);

Esta ruta registrará un recurso anidado que puede ser accedido con URIs como los siguientes:

/photos/{photo}/comments/{comment}

#Limitando Recursos Anidados

La característica de enlace implícito de modelos de Laravel puede limitar automáticamente los enlaces anidados de modo que el modelo hijo resuelto se confirme que pertenece al modelo padre. Usando el método scoped al definir su recurso anidado, puede habilitar el limitador automático así como indicar a Laravel por qué campo debe recuperarse el recurso hijo. Para más información sobre cómo lograr esto, consulte la documentación sobre limitación de rutas de recursos.

#Anidamiento Superficial

A menudo, no es completamente necesario tener tanto el ID del padre como el del hijo dentro de un URI, ya que el ID del hijo ya es un identificador único. Cuando usa identificadores únicos como claves primarias autoincrementales para identificar sus modelos en segmentos URI, puede optar por usar "anidamiento superficial":

use App\Http\Controllers\CommentController;

Route::resource('photos.comments', CommentController::class)->shallow();

Esta definición de ruta definirá las siguientes rutas:

Verbo URI Acción Nombre de Ruta
GET /photos/{photo}/comments index photos.comments.index
GET /photos/{photo}/comments/create create photos.comments.create
POST /photos/{photo}/comments store photos.comments.store
GET /comments/{comment} show comments.show
GET /comments/{comment}/edit edit comments.edit
PUT/PATCH /comments/{comment} update comments.update
DELETE /comments/{comment} destroy comments.destroy

#Nombrando Rutas de Recursos

Por defecto, todas las acciones del controlador de recursos tienen un nombre de ruta; sin embargo, puede sobrescribir estos nombres pasando un arreglo names con los nombres de ruta deseados:

use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class)->names([
    'create' => 'photos.build'
]);

#Nombrando Parámetros de Rutas de Recursos

Por defecto, Route::resource creará los parámetros de ruta para sus rutas de recursos basándose en la versión "singularizada" del nombre del recurso. Puede sobrescribir esto fácilmente por recurso usando el método parameters. El arreglo pasado al método parameters debe ser un arreglo asociativo de nombres de recursos y nombres de parámetros:

use App\Http\Controllers\AdminUserController;

Route::resource('users', AdminUserController::class)->parameters([
    'users' => 'admin_user'
]);

El ejemplo anterior genera el siguiente URI para la ruta show del recurso:

/users/{admin_user}

#Limitando Rutas de Recursos

La característica de enlace implícito de modelos con limitación de Laravel puede limitar automáticamente los enlaces anidados de modo que el modelo hijo resuelto se confirme que pertenece al modelo padre. Usando el método scoped al definir su recurso anidado, puede habilitar la limitación automática así como indicar a Laravel por qué campo debe recuperarse el recurso hijo:

use App\Http\Controllers\PhotoCommentController;

Route::resource('photos.comments', PhotoCommentController::class)->scoped([
    'comment' => 'slug',
]);

Esta ruta registrará un recurso anidado limitado que puede ser accedido con URIs como los siguientes:

/photos/{photo}/comments/{comment:slug}

Al usar un enlace implícito con clave personalizada como parámetro de ruta anidada, Laravel limitará automáticamente la consulta para recuperar el modelo anidado por su padre usando convenciones para adivinar el nombre de la relación en el padre. En este caso, se asumirá que el modelo Photo tiene una relación llamada comments (el plural del nombre del parámetro de ruta) que puede usarse para recuperar el modelo Comment.

#Localizando URIs de Recursos

Por defecto, Route::resource creará URIs de recursos usando verbos en inglés y reglas de pluralización en inglés. Si necesita localizar los verbos de acción create y edit, puede usar el método Route::resourceVerbs. Esto puede hacerse al inicio del método boot dentro del App\Providers\RouteServiceProvider de su aplicación:

/**
 * Defina sus enlaces de modelo para rutas, filtros de patrón, etc.
 */
public function boot(): void
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);

    // ...
}

El pluralizador de Laravel soporta varios idiomas que puede configurar según sus necesidades. Una vez que los verbos y el idioma de pluralización hayan sido personalizados, un registro de ruta de recurso como Route::resource('publicacion', PublicacionController::class) producirá los siguientes URIs:

/publicacion/crear

/publicacion/{publicaciones}/editar

#Complementando Controladores de Recursos

Si necesita agregar rutas adicionales a un controlador de recursos más allá del conjunto predeterminado de rutas de recursos, debe definir esas rutas antes de su llamada al método Route::resource; de lo contrario, las rutas definidas por el método resource pueden tomar precedencia involuntariamente sobre sus rutas complementarias:

use App\Http\Controller\PhotoController;

Route::get('/photos/popular', [PhotoController::class, 'popular']);
Route::resource('photos', PhotoController::class);
Примечание

Recuerde mantener sus controladores enfocados. Si se encuentra rutinariamente necesitando métodos fuera del conjunto típico de acciones de recursos, considere dividir su controlador en dos controladores más pequeños.

#Controladores de Recursos Singleton

A veces, su aplicación tendrá recursos que solo pueden tener una única instancia. Por ejemplo, el "perfil" de un usuario puede ser editado o actualizado, pero un usuario no puede tener más de un "perfil". De igual forma, una imagen puede tener un único "thumbnail". Estos recursos se llaman "recursos singleton", lo que significa que puede existir una y solo una instancia del recurso. En estos escenarios, puede registrar un controlador de recurso "singleton":

use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

Route::singleton('profile', ProfileController::class);

La definición de recurso singleton anterior registrará las siguientes rutas. Como puede ver, no se registran rutas de "creación" para recursos singleton, y las rutas registradas no aceptan un identificador ya que solo puede existir una instancia del recurso:

Verbo URI Acción Nombre de Ruta
GET /profile show profile.show
GET /profile/edit edit profile.edit
PUT/PATCH /profile update profile.update

Los recursos singleton también pueden estar anidados dentro de un recurso estándar:

Route::singleton('photos.thumbnail', ThumbnailController::class);

En este ejemplo, el recurso photos recibiría todas las rutas estándar de recursos; sin embargo, el recurso thumbnail sería un recurso singleton con las siguientes rutas:

Verbo URI Acción Nombre de Ruta
GET /photos/{photo}/thumbnail show photos.thumbnail.show
GET /photos/{photo}/thumbnail/edit edit photos.thumbnail.edit
PUT/PATCH /photos/{photo}/thumbnail update photos.thumbnail.update

#Recursos Singleton Creables

Ocasionalmente, puede querer definir rutas de creación y almacenamiento para un recurso singleton. Para lograr esto, puede invocar el método creatable al registrar la ruta del recurso singleton:

Route::singleton('photos.thumbnail', ThumbnailController::class)->creatable();

En este ejemplo, se registrarán las siguientes rutas. Como puede ver, también se registrará una ruta DELETE para recursos singleton creables:

Verbo URI Acción Nombre de Ruta
GET /photos/{photo}/thumbnail/create create photos.thumbnail.create
POST /photos/{photo}/thumbnail store photos.thumbnail.store
GET /photos/{photo}/thumbnail show photos.thumbnail.show
GET /photos/{photo}/thumbnail/edit edit photos.thumbnail.edit
PUT/PATCH /photos/{photo}/thumbnail update photos.thumbnail.update
DELETE /photos/{photo}/thumbnail destroy photos.thumbnail.destroy

Si desea que Laravel registre la ruta DELETE para un recurso singleton pero no registre las rutas de creación o almacenamiento, puede utilizar el método destroyable:

Route::singleton(...)->destroyable();

#Recursos Singleton para API

El método apiSingleton puede usarse para registrar un recurso singleton que será manipulado vía API, haciendo innecesarias las rutas create y edit:

Route::apiSingleton('profile', ProfileController::class);

Por supuesto, los recursos singleton API también pueden ser creatable, lo que registrará las rutas store y destroy para el recurso:

Route::apiSingleton('photos.thumbnail', ProfileController::class)->creatable();

#Inyección de Dependencias y Controladores

#Inyección en el Constructor

El contenedor de servicios de Laravel se usa para resolver todos los controladores de Laravel. Como resultado, puede type-hint cualquier dependencia que su controlador pueda necesitar en su constructor. Las dependencias declaradas serán resueltas e inyectadas automáticamente en la instancia del controlador:

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * Crear una nueva instancia del controlador.
     */
    public function __construct(
        protected UserRepository $users,
    ) {}
}

#Inyección en Métodos

Además de la inyección en el constructor, también puede type-hint dependencias en los métodos de su controlador. Un caso común para la inyección en métodos es inyectar la instancia Illuminate\Http\Request en los métodos del controlador:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Almacenar un nuevo usuario.
     */
    public function store(Request $request): RedirectResponse
    {
        $name = $request->name;

        // Almacenar el usuario...

        return redirect('/users');
    }
}

Si su método controlador también espera entrada de un parámetro de ruta, liste sus argumentos de ruta después de sus otras dependencias. Por ejemplo, si su ruta está definida así:

use App\Http\Controllers\UserController;

Route::put('/user/{id}', [UserController::class, 'update']);

Aún puede type-hint Illuminate\Http\Request y acceder a su parámetro id definiendo su método controlador de la siguiente manera:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Actualizar el usuario dado.
     */
    public function update(Request $request, string $id): RedirectResponse
    {
        // Actualizar el usuario...

        return redirect('/users');
    }
}