- Introducción
- Controladores básicos
- Middleware de controlador
- Controladores de recursos
- Inyección de dependencias y controladores
- Caché de rutas
Introducción
En lugar de definir toda la lógica de manejo de solicitud como Closure en archivos de ruta, puedes desear organizar este comportamiento usando clases Controller. Los controladores pueden agrupar la lógica de manejo de solicitud relacionada dentro de una sola clase. Los controladores son almacenados en el directorio app/Http/Controllers
.
Controladores básicos
Definiendo controladores
A continuación se muestra un ejemplo de una clase de controlador básica. Nota que el controlador extiende la clase de controlador base incluida con Laravel. La clase base proporciona unos cuantos métodos de conveniencia tal como el método middleware
, el cual puede ser usado para conectar un middleware a acciones de controlador:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\User; class UserController extends Controller { /** * Show the profile for the given user. * * @param int $id * @return View */ public function show($id) { return view('user.profile', ['user' => User::findOrFail($id)]); } }
Puedes definir una ruta a esta acción de controlador de esta forma:
Route::get('user/{id}', 'UserController@show');
Ahora, cuando una solicitud coincide con la URI de la ruta especificada, se ejecutará el método show
de la clase UserController
. Los parámetros de ruta también se pasarán al método.
Los controladores no están obligados a extender de la clase base. Sin embargo, no tendrás acceso a características de conveniencia tales como los métodos middleware
, validate
y dispatch
.
Controladores y espacios de nombres
Es muy importante notar que no necesitamos especificar el espacio de nombres completo del controlador al momento de definir la ruta del controlador. Debido a que el RouteServiceProvider
carga sus archivos de ruta dentro de un grupo de ruta que contiene el espacio de nombres, solamente necesitaremos la porción del nombre de la clase que viene después de la porción App\Http\Controllers
del espacio de nombres.
Si eliges anidar tus controladores dentro del directorio App\Http\Controllers
, usa el nombre de clase específico relativo al espacio de nombres raíz App\Http\Controllers
. Así, si tu clase de controlador completa es App\Http\Controllers\Photos\AdminController
, deberías registrar rutas al controlador de esta forma:
Route::get('foo', 'Photos\AdminController@method');
Controladores de acción única
Si prefieres definir un controlador que maneje solamente una acción única, debes colocar un único método __invoke
en el controlador:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\User; class ShowProfile extends Controller { /** * Show the profile for the given user. * * @param int $id * @return View */ public function __invoke($id) { return view('user.profile', ['user' => User::findOrFail($id)]); } }
Al momento de registrar rutas para controladores de acción única, no necesitarás especificar un método:
Route::get('user/{id}', 'ShowProfile');
Puedes generar un controlador invocable usando la opción --invokable
del comando Artisan make:controller
:
php artisan make:controller ShowProfile --invokable
Middleware de controlador
Los Middleware pueden ser asignados a las rutas del controlador en tus archivos de ruta:
Route::get('profile', 'UserController@show')->middleware('auth');
Sin embargo, es más conveniente especificar los middleware dentro del constructor de tu controlador. Usando el método middleware
del constructor de tu controlador, puedes asignar fácilmente los middleware a la acción del controlador. Incluso puedes restringir los middleware a sólo ciertos métodos en la clase del controlador:
class UserController extends Controller { /** * Instantiate a new controller instance. * * @return void */ public function __construct() { $this->middleware('auth'); $this->middleware('log')->only('index'); $this->middleware('subscribed')->except('store'); } }
También los controladores permiten que registres los middleware usando una Closure. Esto proporciona una forma conveniente de definir un middleware para un solo controlador sin definir una clase middleware completa:
$this->middleware(function ($request, $next) { // ... return $next($request); });
Puedes asignar los middleware a un subconjunto de acciones de controlador; sin embargo, esto puede indicar que tu controlador está creciendo demasiado. En lugar de eso, considera dividir tu controlador en varios controladores más pequeños.
Controladores de recursos
El enrutamiento de recurso de Laravel asigna las rutas típicas «CRUD» a un controlador con una sola línea de código. Por ejemplo, puedes desear crear un controlador que maneje todas las solicitudes HTTP para «photos» almacenadas por tu aplicación. Usando el comando Artisan make:controller
, podemos crear fácilmente tal controlador:
php artisan make:controller PhotoController --resource
Este comando creará un controlador en app/Http/Controllers/PhotoController.php
. El controlador contendrá un método para cada una de las operaciones de recursos disponibles.
Seguidamente, puedes registrar una ruta de recurso genérica al controlador:
Route::resource('photos', 'PhotoController');
Esta declaración de ruta única crea varias rutas para manejar una variedad de acciones del recurso. El controlador generado ya tendrá los métodos separados para cada una de las acciones, incluyendo comentarios que te informan de los verbos HTTP y URIs que manejan.
Puedes registrar muchos controladores de recursos a la vez pasando un arreglo al método resources
:
Route::resources([ 'photos' => 'PhotoController', 'posts' => 'PostController' ]);
Acciones manejadas por el controlador de recursos
Tipo | URI | Acción | Nombre de la 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 |
Especificando el modelo del recurso
Si estás usando el enlace de modelo de ruta (route model binding) y deseas que los métodos del controlador de recursos declaren el tipo de una instancia de modelo, puedes usar la opción --model
al momento de generar el controlador:
php artisan make:controller PhotoController --resource --model=Photo
Suplantar los métodos de formulario
Debido a que los formularios no pueden hacer solicitudes PUT
, PATCH
o DELETE
, necesitarás agregar un campo _method
oculto para suplantar estos verbos HTTP. La directiva de Blade @method
puede crear este campo para ti:
<form action="/foo/bar" method="POST"> @method('PUT') </form>
Rutas de recursos parciales
Al momento de declarar una ruta de recurso, puedes especificar un subconjunto de acciones que el controlador debería manejar en lugar del conjunto completo de acciones por defecto:
Route::resource('photos', 'PhotoController')->only([ 'index', 'show' ]); Route::resource('photos', 'PhotoController')->except([ 'create', 'store', 'update', 'destroy' ]);
Rutas de recursos para APIs
Al momento de declarar rutas de recursos que serán consumidas por APIs, normalmente te gustará excluir rutas que presentan plantillas HTML tales como create
y edit
. Por conveniencia, puedes usar el método apiResource
para excluir automáticamente estas dos rutas:
Route::apiResource('photos', 'PhotoController');
Puedes registrar muchos controladores de recursos de API de una sola vez pasando un arreglo al método apiResources
:
Route::apiResources([ 'photos' => 'PhotoController', 'posts' => 'PostController' ]);
Para generar rápidamente un controlador de recursos API que no incluya los métodos create
o edit
, usa la opción --api
cuando ejecutes el comando make:controller
:
php artisan make:controller API/PhotoController --api
Recursos anidados
Algunas veces necesitarás definir rutas a un recurso anidado. Por ejemplo, una imagen puede tener múltiples comentarios que podrían estar atados a ésta. Para anidar los controladores de recursos, usa la notación de «punto» en la declaración de tu ruta:
Route::resource('photos.comments', 'PhotoCommentController');
Esta ruta registrará un recurso anidado al cual se puede acceder mediante URLs como la siguiente:
/photos/{photo}/comments/{comment}
Anidación superficial
A menudo, no es completamente necesario tener tanto el ID del padre como del hijo dentro de una URI, dado que el ID del hijo es un identificador único. Al usar identificadores únicos, como claves primarias de auto incremento para identificar tus modelos en segmentos de una URI, puedes elegir usar «anidación superficial»:
Route::resource('photos.comments', 'CommentController')->shallow();
La definición de ruta anterior definirá las siguientes rutas:
Tipo | URI | Acción | Nombre de la 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
De forma predeterminada, todas las acciones de controlador de recursos tienen un nombre de ruta; sin embargo, puedes sobrescribir esos nombres al pasar el arreglo names
con tus opciones:
Route::resource('photos', 'PhotoController')->names([ 'create' => 'photos.build' ]);
Nombrando parámetros de rutas de recursos
De forma predeterminada, Route::resource
creará los parámetros de ruta para tus rutas de recursos basado en la versión «singularizada» del nombre de recurso. Puedes sobrescribir fácilmente esto para cada recurso usando el método parameters
. El arreglo pasado al método parameters
debería ser un arreglo asociativo de nombres de recursos y nombres de parámetros:
Route::resource('users', 'AdminUserController')->parameters([ 'users' => 'admin_user' ]);
El ejemplo anterior genera las URIs siguientes para la ruta show
del recurso:
/users/{admin_user}
Configuración regional para URIs de recursos
De forma predeterminada, Route::resource
creará URIs de recursos usando verbos en Inglés. Si necesitas configurar los verbos de acción create
y edit
a un idioma, puedes usar el método Route::resourceVerbs
. Esto puede ser hecho en el método boot
de tu AppServiceProvider
:
use Illuminate\Support\Facades\Route; /** * Bootstrap any application services. * * @return void */ public function boot() { Route::resourceVerbs([ 'create' => 'crear', 'edit' => 'editar', ]); }
Una vez que los verbos han sido personalizados, un registro de ruta de recurso tal como Route::resource('fotos', 'PhotoController')
producirá las siguientes URIs:
/fotos/crear /fotos/{foto}/editar
Complementando controladores de recursos
Si necesitas agregar rutas adicionales para un controlador de recursos más allá del conjunto predeterminado de rutas de recursos, deberías definir esas rutas antes de que ejecutes Route::resource
; de otra forma, las rutas definidas por el método resource
pueden tomar precedencia involuntariamente sobre tus rutas complementarias:
Route::get('photos/popular', 'PhotoController@method'); Route::resource('photos', 'PhotoController');
Recuerda mantener la lógica de tus controladores enfocada. Si te encuentras a ti mismo necesitando rutinariamente métodos fuera del conjunto típico de acciones de recurso, considera dividir tu controlador en dos controladores más pequeños.
Inyección de dependencias y controladores
Inyección al constructor
El contenedor de servicio de Laravel es usado para resolver todos los controladores de Laravel. Como resultado, estás habilitado para declarar el tipo de cualquier dependencia que tu controlador pueda necesitar en su constructor. Las dependencias declaradas serán automáticamente resueltas e inyectadas dentro de la instancia del controlador:
<?php namespace App\Http\Controllers; use App\Repositories\UserRepository; class UserController extends Controller { /** * The user repository instance. */ protected $users; /** * Create a new controller instance. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } }
También puedes declarar el tipo de cualquier Contrato de Laravel. Si el contenedor puede resolverlo, puedes declararlo. Dependiendo de tu aplicación, inyectar tus dependencias dentro de tu controlador puede proporcionar mejor capacidad para pruebas.
Inyección de métodos
Adicional a la inyección al constructor, también puedes declarar el tipo de dependencias en los métodos de tu controlador. Un caso de uso común para la inyección de métodos es inyectar la instancia Illuminate\Http\Request
dentro de tus métodos de controlador:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { /** * Store a new user. * * @param Request $request * @return Response */ public function store(Request $request) { $name = $request->name; // } }
Si tu método de controlador también está esperando entrada de un parámetro de ruta, lista tus argumentos de ruta después de tus otras dependencias. Por ejemplo, si tu ruta es definida como esto:
Route::put('user/{id}', 'UserController@update');
Aún puedes declarar el tipo de la clase Illuminate\Http\Request
y acceder a tu parámetro id
al definir tu método de controlador de la siguiente manera:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UserController extends Controller { /** * Update the given user. * * @param Request $request * @param string $id * @return Response */ public function update(Request $request, $id) { // } }
Caché de rutas
Las rutas basadas en Closure no pueden ser cacheadas. Para usar caché de rutas, debes convertir cualquiera de las rutas Closure a clases de controlador.
Si tu aplicación está usando exclusivamente rutas basadas en controlador, deberías tomar ventaja de la caché de rutas de Laravel. Usar la caché de rutas reducirá drásticamente la cantidad de tiempo que toma registrar todas las rutas de tu aplicación. En algunos casos, incluso la rapidez de tu registro de rutas puede llegar a ser hasta 100 veces más rápida. Para generar una caché de ruta, simplemente ejecuta el comando Artisan route:cache
:
php artisan route:cache
Después de ejecutar este comando, tu archivo de rutas cacheado será cargado en cada solicitud. Recuerda, si agregas cualquier ruta nueva necesitarás generar una caché de ruta nueva. Debido a esto, deberías ejecutar solamente el comando route:cache
durante el despliegue o puesta en producción del proyecto.
Puedes usar el comando route:clear
para limpiar la caché de ruta:
php artisan route:clear
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
Lección anterior Protección CSRF - Documentación de Laravel 6 Lección siguiente Solicitudes HTTP - Documentación de Laravel 6